Compare commits
55 Commits
FarseerPhy
...
Aether
Author | SHA1 | Date |
---|---|---|
|
304bdb06d4 | |
|
f264efd9ce | |
|
3d70992b1a | |
|
b6b078f8ce | |
|
3fe845b02f | |
|
e14c28920f | |
|
8a5ebe6ac6 | |
|
621ee8be39 | |
|
5e95459e3e | |
|
5f680b3a7a | |
|
d06607ccc6 | |
|
061007158d | |
|
0a52c543e6 | |
|
38ca212d9f | |
|
326c615887 | |
|
5ee91dd26a | |
|
67c6464ea1 | |
|
3dab570f5d | |
|
89745d15bf | |
|
633cd71d00 | |
|
8573d942c4 | |
|
3a2e87cd75 | |
|
dc164e96ef | |
|
e63577e5c3 | |
|
9f41401e40 | |
|
353b4b99e6 | |
|
261fe679d8 | |
|
c8abb98c7d | |
|
8fddbb409b | |
|
e09e4e710a | |
|
2fe1af47dc | |
|
f33273bbf6 | |
|
dc01704da6 | |
|
51e70b706f | |
|
759ee627e2 | |
|
922a46d616 | |
|
0f34e6cdaa | |
|
77c9f3db5e | |
|
506ee16ae1 | |
|
2187783fe2 | |
|
c58a264d38 | |
|
0305ae2506 | |
|
84725cc8d6 | |
|
84e7ac1c28 | |
|
0410c87e93 | |
|
1ce0371d18 | |
|
a1ecfca034 | |
|
47735ef00a | |
|
667cd18f5d | |
|
c1ac20964e | |
|
268b66ad76 | |
|
c4892b1f36 | |
|
09980689fb | |
|
56f8630a65 | |
|
c66be28764 |
28
App.xaml
|
@ -1,9 +1,27 @@
|
||||||
<Application x:Class="CtrEditor.App"
|
<Application x:Class="CtrEditor.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:CtrEditor"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:osExtraccion="clr-namespace:CtrEditor.ObjetosSim.Extraccion_Datos"
|
||||||
xmlns:local="clr-namespace:CtrEditor"
|
xmlns:os="clr-namespace:CtrEditor.ObjetosSim" StartupUri="MainWindow.xaml">
|
||||||
StartupUri="MainWindow.xaml">
|
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
|
<local:MeterToPixelConverter x:Key="MeterToPixelConverter" />
|
||||||
|
<local:LevelToHeightMultiConverter x:Key="LevelToHeightMultiConverter" />
|
||||||
|
<local:WidthPercentageConverter x:Key="WidthPercentageConverter" />
|
||||||
|
<local:DistanceToMarginConverter x:Key="DistanceToMarginConverter" />
|
||||||
|
<local:MarginConverter x:Key="MarginConverter" />
|
||||||
|
<local:FloatToFormattedStringConverter x:Key="floatFormatter" />
|
||||||
|
<local:DoubleToFormattedStringConverter x:Key="doubleFormatter" />
|
||||||
|
<local:BrushToColorNameConverter x:Key="BrushToColorNameConverter" />
|
||||||
|
<local:VerticalPositionConverter x:Key="VerticalPositionConverter" />
|
||||||
|
<local:SumConverter x:Key="SumConverter" />
|
||||||
|
<local:ColorToBrushConverter x:Key="ColorToBrushConverter" />
|
||||||
|
<local:StringToBrushConverter x:Key="StringToBrushConverter" />
|
||||||
|
<local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
||||||
|
<local:SubclassFilterConverter x:Key="SubclassFilterConverterosBuscarCoincidencias"
|
||||||
|
TargetType="{x:Type osExtraccion:osBuscarCoincidencias}" />
|
||||||
|
<local:SubclassFilterConverter x:Key="SubclassFilterConverterosVMMotor" TargetType="{x:Type os:osVMmotorSim}" />
|
||||||
|
<local:UnsavedChangesConverter x:Key="UnsavedChangesConverter"/>
|
||||||
|
<local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
</Application>
|
</Application>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,668 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"$type": "CtrEditor.ObjetosSim.Extraccion_Datos.osExtraccionTag, CtrEditor",
|
||||||
|
"AutoCreated": false,
|
||||||
|
"RemoverDesdeSimulacion": false,
|
||||||
|
"Nombre": "Ingresos E0.0",
|
||||||
|
"Extraer": false,
|
||||||
|
"New_Row": false,
|
||||||
|
"Id_Search_Templates": "Ingresos Plate Group",
|
||||||
|
"Tag_extract": "E3.0\n",
|
||||||
|
"Collumn_name": "IO",
|
||||||
|
"Collumn_number": 2,
|
||||||
|
"Copy_Number": 0,
|
||||||
|
"Show_Debug_Window": false,
|
||||||
|
"Opacity_oculto": 0.1,
|
||||||
|
"Id": {
|
||||||
|
"Value": 1202
|
||||||
|
},
|
||||||
|
"Show_On_This_Page": false,
|
||||||
|
"Left": 2.0471327,
|
||||||
|
"Top": 8.451157,
|
||||||
|
"Ancho": 1.3239104,
|
||||||
|
"Alto": 0.19122289,
|
||||||
|
"Angulo": 0.0,
|
||||||
|
"Enable_On_All_Pages": true,
|
||||||
|
"ShowOnThisPagesList": [
|
||||||
|
"94102.80_SE00_Página_050.png",
|
||||||
|
"94102.80_SE00_Página_051.png",
|
||||||
|
"94102.80_SE00_Página_052.png",
|
||||||
|
"94102.80_SE00_Página_053.png",
|
||||||
|
"94102.80_SE00_Página_054.png",
|
||||||
|
"94102.80_SE00_Página_055.png",
|
||||||
|
"94102.80_SE00_Página_056.png",
|
||||||
|
"94102.80_SE00_Página_057.png",
|
||||||
|
"94102.80_SE00_Página_058.png",
|
||||||
|
"94102.80_SE00_Página_059.png",
|
||||||
|
"94102.80_SE00_Página_060.png",
|
||||||
|
"94102.80_SE00_Página_061.png",
|
||||||
|
"94102.80_SE00_Página_062.png",
|
||||||
|
"94102.80_SE00_Página_063.png",
|
||||||
|
"94102.80_SE00_Página_064.png",
|
||||||
|
"94102.80_SE00_Página_065.png",
|
||||||
|
"94102.80_SE00_Página_066.png",
|
||||||
|
"94102.80_SE00_Página_067.png",
|
||||||
|
"94102.80_SE00_Página_068.png",
|
||||||
|
"94102.80_SE00_Página_069.png"
|
||||||
|
],
|
||||||
|
"Cloned": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "CtrEditor.ObjetosSim.Extraccion_Datos.osExtraccionTag, CtrEditor",
|
||||||
|
"AutoCreated": false,
|
||||||
|
"RemoverDesdeSimulacion": false,
|
||||||
|
"Nombre": "Ingresos Desc Italiano",
|
||||||
|
"Extraer": false,
|
||||||
|
"New_Row": false,
|
||||||
|
"Id_Search_Templates": "Ingresos Plate Group",
|
||||||
|
"Tag_extract": "MARCIA ASCIUGATORE\n",
|
||||||
|
"Collumn_name": "Description Italian",
|
||||||
|
"Collumn_number": 3,
|
||||||
|
"Copy_Number": 0,
|
||||||
|
"Show_Debug_Window": false,
|
||||||
|
"Opacity_oculto": 0.1,
|
||||||
|
"Id": {
|
||||||
|
"Value": 1203
|
||||||
|
},
|
||||||
|
"Show_On_This_Page": false,
|
||||||
|
"Left": 2.0339866,
|
||||||
|
"Top": 9.252491,
|
||||||
|
"Ancho": 1.3151709,
|
||||||
|
"Alto": 0.26124278,
|
||||||
|
"Angulo": 0.0,
|
||||||
|
"Enable_On_All_Pages": true,
|
||||||
|
"ShowOnThisPagesList": [
|
||||||
|
"94102.80_SE00_Página_050.png",
|
||||||
|
"94102.80_SE00_Página_051.png",
|
||||||
|
"94102.80_SE00_Página_052.png",
|
||||||
|
"94102.80_SE00_Página_053.png",
|
||||||
|
"94102.80_SE00_Página_054.png",
|
||||||
|
"94102.80_SE00_Página_055.png",
|
||||||
|
"94102.80_SE00_Página_056.png",
|
||||||
|
"94102.80_SE00_Página_057.png",
|
||||||
|
"94102.80_SE00_Página_058.png",
|
||||||
|
"94102.80_SE00_Página_059.png",
|
||||||
|
"94102.80_SE00_Página_060.png",
|
||||||
|
"94102.80_SE00_Página_061.png",
|
||||||
|
"94102.80_SE00_Página_062.png",
|
||||||
|
"94102.80_SE00_Página_063.png",
|
||||||
|
"94102.80_SE00_Página_064.png",
|
||||||
|
"94102.80_SE00_Página_065.png",
|
||||||
|
"94102.80_SE00_Página_066.png",
|
||||||
|
"94102.80_SE00_Página_067.png",
|
||||||
|
"94102.80_SE00_Página_068.png",
|
||||||
|
"94102.80_SE00_Página_069.png"
|
||||||
|
],
|
||||||
|
"Cloned": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "CtrEditor.ObjetosSim.Extraccion_Datos.osExtraccionTag, CtrEditor",
|
||||||
|
"AutoCreated": false,
|
||||||
|
"RemoverDesdeSimulacion": false,
|
||||||
|
"Nombre": "Ingresos Desc English",
|
||||||
|
"Extraer": false,
|
||||||
|
"New_Row": false,
|
||||||
|
"Id_Search_Templates": "Ingresos Plate Group",
|
||||||
|
"Tag_extract": "EMERGENCY PRESSED\nELECTRICAL CABINET\n",
|
||||||
|
"Collumn_name": "Description English",
|
||||||
|
"Collumn_number": 4,
|
||||||
|
"Copy_Number": 0,
|
||||||
|
"Show_Debug_Window": false,
|
||||||
|
"Opacity_oculto": 0.1,
|
||||||
|
"Id": {
|
||||||
|
"Value": 1204
|
||||||
|
},
|
||||||
|
"Show_On_This_Page": false,
|
||||||
|
"Left": 2.0329113,
|
||||||
|
"Top": 9.509013,
|
||||||
|
"Ancho": 1.323141,
|
||||||
|
"Alto": 0.2408835,
|
||||||
|
"Angulo": 0.0,
|
||||||
|
"Enable_On_All_Pages": true,
|
||||||
|
"ShowOnThisPagesList": [
|
||||||
|
"94102.80_SE00_Página_050.png",
|
||||||
|
"94102.80_SE00_Página_051.png",
|
||||||
|
"94102.80_SE00_Página_052.png",
|
||||||
|
"94102.80_SE00_Página_053.png",
|
||||||
|
"94102.80_SE00_Página_054.png",
|
||||||
|
"94102.80_SE00_Página_055.png",
|
||||||
|
"94102.80_SE00_Página_056.png",
|
||||||
|
"94102.80_SE00_Página_057.png",
|
||||||
|
"94102.80_SE00_Página_058.png",
|
||||||
|
"94102.80_SE00_Página_059.png",
|
||||||
|
"94102.80_SE00_Página_060.png",
|
||||||
|
"94102.80_SE00_Página_061.png",
|
||||||
|
"94102.80_SE00_Página_062.png",
|
||||||
|
"94102.80_SE00_Página_063.png",
|
||||||
|
"94102.80_SE00_Página_064.png",
|
||||||
|
"94102.80_SE00_Página_065.png",
|
||||||
|
"94102.80_SE00_Página_066.png",
|
||||||
|
"94102.80_SE00_Página_067.png",
|
||||||
|
"94102.80_SE00_Página_068.png",
|
||||||
|
"94102.80_SE00_Página_069.png"
|
||||||
|
],
|
||||||
|
"Cloned": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "CtrEditor.ObjetosSim.Extraccion_Datos.osExtraccionTag, CtrEditor",
|
||||||
|
"AutoCreated": false,
|
||||||
|
"RemoverDesdeSimulacion": false,
|
||||||
|
"Nombre": "Ingresos Card",
|
||||||
|
"Extraer": false,
|
||||||
|
"New_Row": false,
|
||||||
|
"Id_Search_Templates": "Ingresos Plate Group",
|
||||||
|
"Tag_extract": "A45311\n",
|
||||||
|
"Collumn_name": "Card",
|
||||||
|
"Collumn_number": 5,
|
||||||
|
"Copy_Number": 0,
|
||||||
|
"Show_Debug_Window": false,
|
||||||
|
"Opacity_oculto": 0.1,
|
||||||
|
"Id": {
|
||||||
|
"Value": 1260
|
||||||
|
},
|
||||||
|
"Show_On_This_Page": false,
|
||||||
|
"Left": 2.2931812,
|
||||||
|
"Top": 9.125617,
|
||||||
|
"Ancho": 0.3932013,
|
||||||
|
"Alto": 0.11076093,
|
||||||
|
"Angulo": 0.0,
|
||||||
|
"Enable_On_All_Pages": true,
|
||||||
|
"ShowOnThisPagesList": [
|
||||||
|
"94102.80_SE00_Página_050.png",
|
||||||
|
"94102.80_SE00_Página_051.png",
|
||||||
|
"94102.80_SE00_Página_052.png",
|
||||||
|
"94102.80_SE00_Página_053.png",
|
||||||
|
"94102.80_SE00_Página_054.png",
|
||||||
|
"94102.80_SE00_Página_055.png",
|
||||||
|
"94102.80_SE00_Página_056.png",
|
||||||
|
"94102.80_SE00_Página_057.png",
|
||||||
|
"94102.80_SE00_Página_058.png",
|
||||||
|
"94102.80_SE00_Página_059.png",
|
||||||
|
"94102.80_SE00_Página_060.png",
|
||||||
|
"94102.80_SE00_Página_061.png",
|
||||||
|
"94102.80_SE00_Página_062.png",
|
||||||
|
"94102.80_SE00_Página_063.png",
|
||||||
|
"94102.80_SE00_Página_064.png",
|
||||||
|
"94102.80_SE00_Página_065.png",
|
||||||
|
"94102.80_SE00_Página_066.png",
|
||||||
|
"94102.80_SE00_Página_067.png",
|
||||||
|
"94102.80_SE00_Página_068.png",
|
||||||
|
"94102.80_SE00_Página_069.png"
|
||||||
|
],
|
||||||
|
"Cloned": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "CtrEditor.ObjetosSim.Extraccion_Datos.osExtraccionTag, CtrEditor",
|
||||||
|
"AutoCreated": false,
|
||||||
|
"RemoverDesdeSimulacion": false,
|
||||||
|
"Nombre": "Ingresos Pin",
|
||||||
|
"Extraer": false,
|
||||||
|
"New_Row": false,
|
||||||
|
"Id_Search_Templates": "Ingresos Plate Group",
|
||||||
|
"Tag_extract": "",
|
||||||
|
"Collumn_name": "Pin",
|
||||||
|
"Collumn_number": 7,
|
||||||
|
"Copy_Number": 0,
|
||||||
|
"Show_Debug_Window": false,
|
||||||
|
"Opacity_oculto": 0.1,
|
||||||
|
"Id": {
|
||||||
|
"Value": 1264
|
||||||
|
},
|
||||||
|
"Show_On_This_Page": false,
|
||||||
|
"Left": 2.6119895,
|
||||||
|
"Top": 8.204032,
|
||||||
|
"Ancho": 0.16785541,
|
||||||
|
"Alto": 0.15966734,
|
||||||
|
"Angulo": 0.0,
|
||||||
|
"Enable_On_All_Pages": true,
|
||||||
|
"ShowOnThisPagesList": [
|
||||||
|
"94102.80_SE00_Página_050.png",
|
||||||
|
"94102.80_SE00_Página_051.png",
|
||||||
|
"94102.80_SE00_Página_052.png",
|
||||||
|
"94102.80_SE00_Página_053.png",
|
||||||
|
"94102.80_SE00_Página_054.png",
|
||||||
|
"94102.80_SE00_Página_055.png",
|
||||||
|
"94102.80_SE00_Página_056.png",
|
||||||
|
"94102.80_SE00_Página_057.png",
|
||||||
|
"94102.80_SE00_Página_058.png",
|
||||||
|
"94102.80_SE00_Página_059.png",
|
||||||
|
"94102.80_SE00_Página_060.png",
|
||||||
|
"94102.80_SE00_Página_061.png",
|
||||||
|
"94102.80_SE00_Página_062.png",
|
||||||
|
"94102.80_SE00_Página_063.png",
|
||||||
|
"94102.80_SE00_Página_064.png",
|
||||||
|
"94102.80_SE00_Página_065.png",
|
||||||
|
"94102.80_SE00_Página_066.png",
|
||||||
|
"94102.80_SE00_Página_067.png",
|
||||||
|
"94102.80_SE00_Página_068.png",
|
||||||
|
"94102.80_SE00_Página_069.png"
|
||||||
|
],
|
||||||
|
"Cloned": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "CtrEditor.ObjetosSim.Extraccion_Datos.osBuscarCoincidencias, CtrEditor",
|
||||||
|
"AutoCreated": false,
|
||||||
|
"RemoverDesdeSimulacion": false,
|
||||||
|
"Nombre": "Ingresos Plate Group",
|
||||||
|
"Search_rectangles": [
|
||||||
|
"200.6319122314453,815.1671752929688,137.59445190429688,161.43350219726562",
|
||||||
|
"350.22589111328125,815.4871215820312,137.59445190429688,161.43350219726562",
|
||||||
|
"499.9798583984375,815.4871215820312,137.59445190429688,161.43350219726562",
|
||||||
|
"649.7338256835938,815.4871215820312,137.59445190429688,161.43350219726562",
|
||||||
|
"799.6477661132812,815.4871215820312,137.59445190429688,161.43350219726562",
|
||||||
|
"949.2417602539062,815.4871215820312,137.59445190429688,161.43350219726562",
|
||||||
|
"1099.15576171875,815.4871215820312,137.59445190429688,161.43350219726562",
|
||||||
|
"1248.90966796875,815.4871215820312,137.59445190429688,161.43350219726562"
|
||||||
|
],
|
||||||
|
"Search_templates": false,
|
||||||
|
"Export_ocr": false,
|
||||||
|
"Opacity_oculto": 0.1,
|
||||||
|
"Show_debug_ocr": false,
|
||||||
|
"Threshold": 0.6,
|
||||||
|
"Coincidencias": 8,
|
||||||
|
"Id": {
|
||||||
|
"Value": 1201
|
||||||
|
},
|
||||||
|
"Show_On_This_Page": false,
|
||||||
|
"Left": 2.0069747,
|
||||||
|
"Top": 8.15955,
|
||||||
|
"Ancho": 1.3769451,
|
||||||
|
"Alto": 1.6148156,
|
||||||
|
"Angulo": 0.0,
|
||||||
|
"Enable_On_All_Pages": true,
|
||||||
|
"ShowOnThisPagesList": [
|
||||||
|
"94102.80_SE00_Página_050.png",
|
||||||
|
"94102.80_SE00_Página_051.png",
|
||||||
|
"94102.80_SE00_Página_052.png",
|
||||||
|
"94102.80_SE00_Página_053.png",
|
||||||
|
"94102.80_SE00_Página_054.png",
|
||||||
|
"94102.80_SE00_Página_055.png",
|
||||||
|
"94102.80_SE00_Página_056.png",
|
||||||
|
"94102.80_SE00_Página_057.png",
|
||||||
|
"94102.80_SE00_Página_058.png",
|
||||||
|
"94102.80_SE00_Página_059.png",
|
||||||
|
"94102.80_SE00_Página_060.png",
|
||||||
|
"94102.80_SE00_Página_061.png",
|
||||||
|
"94102.80_SE00_Página_062.png",
|
||||||
|
"94102.80_SE00_Página_063.png",
|
||||||
|
"94102.80_SE00_Página_064.png",
|
||||||
|
"94102.80_SE00_Página_065.png",
|
||||||
|
"94102.80_SE00_Página_066.png",
|
||||||
|
"94102.80_SE00_Página_067.png",
|
||||||
|
"94102.80_SE00_Página_068.png",
|
||||||
|
"94102.80_SE00_Página_069.png"
|
||||||
|
],
|
||||||
|
"Cloned": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "CtrEditor.ObjetosSim.Extraccion_Datos.osExtraccionTag, CtrEditor",
|
||||||
|
"AutoCreated": false,
|
||||||
|
"RemoverDesdeSimulacion": false,
|
||||||
|
"Nombre": "Page",
|
||||||
|
"Extraer": false,
|
||||||
|
"New_Row": false,
|
||||||
|
"Tag_extract": "690\n",
|
||||||
|
"Collumn_name": "Extraccion Tags",
|
||||||
|
"Collumn_number": 1,
|
||||||
|
"Copy_Number": 0,
|
||||||
|
"Show_Debug_Window": false,
|
||||||
|
"Opacity_oculto": 0.1,
|
||||||
|
"Id": {
|
||||||
|
"Value": 1231
|
||||||
|
},
|
||||||
|
"Show_On_This_Page": false,
|
||||||
|
"Left": 13.666122,
|
||||||
|
"Top": 10.413534,
|
||||||
|
"Ancho": 0.81436056,
|
||||||
|
"Alto": 0.2296054,
|
||||||
|
"Angulo": 0.0,
|
||||||
|
"Enable_On_All_Pages": true,
|
||||||
|
"ShowOnThisPagesList": [
|
||||||
|
"94102.80_SE00_Página_050.png",
|
||||||
|
"94102.80_SE00_Página_051.png",
|
||||||
|
"94102.80_SE00_Página_052.png",
|
||||||
|
"94102.80_SE00_Página_053.png",
|
||||||
|
"94102.80_SE00_Página_054.png",
|
||||||
|
"94102.80_SE00_Página_055.png",
|
||||||
|
"94102.80_SE00_Página_056.png",
|
||||||
|
"94102.80_SE00_Página_057.png",
|
||||||
|
"94102.80_SE00_Página_058.png",
|
||||||
|
"94102.80_SE00_Página_059.png",
|
||||||
|
"94102.80_SE00_Página_060.png",
|
||||||
|
"94102.80_SE00_Página_061.png",
|
||||||
|
"94102.80_SE00_Página_062.png",
|
||||||
|
"94102.80_SE00_Página_063.png",
|
||||||
|
"94102.80_SE00_Página_064.png",
|
||||||
|
"94102.80_SE00_Página_065.png",
|
||||||
|
"94102.80_SE00_Página_066.png",
|
||||||
|
"94102.80_SE00_Página_067.png",
|
||||||
|
"94102.80_SE00_Página_068.png",
|
||||||
|
"94102.80_SE00_Página_069.png",
|
||||||
|
"94102.80_SE00_Página_070.png",
|
||||||
|
"94102.80_SE00_Página_071.png",
|
||||||
|
"94102.80_SE00_Página_072.png",
|
||||||
|
"94102.80_SE00_Página_073.png",
|
||||||
|
"94102.80_SE00_Página_074.png",
|
||||||
|
"94102.80_SE00_Página_075.png"
|
||||||
|
],
|
||||||
|
"Cloned": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "CtrEditor.ObjetosSim.Extraccion_Datos.osExtraccionTag, CtrEditor",
|
||||||
|
"AutoCreated": false,
|
||||||
|
"RemoverDesdeSimulacion": false,
|
||||||
|
"Nombre": "Salidas A0.0",
|
||||||
|
"Extraer": false,
|
||||||
|
"New_Row": false,
|
||||||
|
"Id_Search_Templates": "Salidas Plate Group",
|
||||||
|
"Tag_extract": "E3.0\n",
|
||||||
|
"Collumn_name": "IO",
|
||||||
|
"Collumn_number": 2,
|
||||||
|
"Copy_Number": 0,
|
||||||
|
"Show_Debug_Window": false,
|
||||||
|
"Opacity_oculto": 0.1,
|
||||||
|
"Id": {
|
||||||
|
"Value": 63
|
||||||
|
},
|
||||||
|
"Show_On_This_Page": false,
|
||||||
|
"Left": 2.038601,
|
||||||
|
"Top": 2.4818933,
|
||||||
|
"Ancho": 1.3239104,
|
||||||
|
"Alto": 0.19122289,
|
||||||
|
"Angulo": 0.0,
|
||||||
|
"Enable_On_All_Pages": true,
|
||||||
|
"ShowOnThisPagesList": [
|
||||||
|
"94102.80_SE00_Página_070.png",
|
||||||
|
"94102.80_SE00_Página_071.png",
|
||||||
|
"94102.80_SE00_Página_072.png",
|
||||||
|
"94102.80_SE00_Página_073.png",
|
||||||
|
"94102.80_SE00_Página_074.png",
|
||||||
|
"94102.80_SE00_Página_075.png"
|
||||||
|
],
|
||||||
|
"Cloned": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "CtrEditor.ObjetosSim.Extraccion_Datos.osExtraccionTag, CtrEditor",
|
||||||
|
"AutoCreated": false,
|
||||||
|
"RemoverDesdeSimulacion": false,
|
||||||
|
"Nombre": "Salidas Desc Italiano",
|
||||||
|
"Extraer": false,
|
||||||
|
"New_Row": false,
|
||||||
|
"Id_Search_Templates": "Salidas Plate Group",
|
||||||
|
"Tag_extract": "MARCIA ASCIUGATORE\n",
|
||||||
|
"Collumn_name": "Description Italian",
|
||||||
|
"Collumn_number": 3,
|
||||||
|
"Copy_Number": 0,
|
||||||
|
"Show_Debug_Window": false,
|
||||||
|
"Opacity_oculto": 0.1,
|
||||||
|
"Id": {
|
||||||
|
"Value": 64
|
||||||
|
},
|
||||||
|
"Show_On_This_Page": false,
|
||||||
|
"Left": 2.0427365,
|
||||||
|
"Top": 1.3802159,
|
||||||
|
"Ancho": 1.3151709,
|
||||||
|
"Alto": 0.26124278,
|
||||||
|
"Angulo": 0.0,
|
||||||
|
"Enable_On_All_Pages": true,
|
||||||
|
"ShowOnThisPagesList": [
|
||||||
|
"94102.80_SE00_Página_070.png",
|
||||||
|
"94102.80_SE00_Página_071.png",
|
||||||
|
"94102.80_SE00_Página_072.png",
|
||||||
|
"94102.80_SE00_Página_073.png",
|
||||||
|
"94102.80_SE00_Página_074.png",
|
||||||
|
"94102.80_SE00_Página_075.png"
|
||||||
|
],
|
||||||
|
"Cloned": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "CtrEditor.ObjetosSim.Extraccion_Datos.osExtraccionTag, CtrEditor",
|
||||||
|
"AutoCreated": false,
|
||||||
|
"RemoverDesdeSimulacion": false,
|
||||||
|
"Nombre": "Salidas Desc English",
|
||||||
|
"Extraer": false,
|
||||||
|
"New_Row": false,
|
||||||
|
"Id_Search_Templates": "Salidas Plate Group",
|
||||||
|
"Tag_extract": "EMERGENCY PRESSED\nELECTRICAL CABINET\n",
|
||||||
|
"Collumn_name": "Description English",
|
||||||
|
"Collumn_number": 4,
|
||||||
|
"Copy_Number": 0,
|
||||||
|
"Show_Debug_Window": false,
|
||||||
|
"Opacity_oculto": 0.1,
|
||||||
|
"Id": {
|
||||||
|
"Value": 65
|
||||||
|
},
|
||||||
|
"Show_On_This_Page": false,
|
||||||
|
"Left": 2.0372825,
|
||||||
|
"Top": 1.6332868,
|
||||||
|
"Ancho": 1.323141,
|
||||||
|
"Alto": 0.2408835,
|
||||||
|
"Angulo": 0.0,
|
||||||
|
"Enable_On_All_Pages": true,
|
||||||
|
"ShowOnThisPagesList": [
|
||||||
|
"94102.80_SE00_Página_070.png",
|
||||||
|
"94102.80_SE00_Página_071.png",
|
||||||
|
"94102.80_SE00_Página_072.png",
|
||||||
|
"94102.80_SE00_Página_073.png",
|
||||||
|
"94102.80_SE00_Página_074.png",
|
||||||
|
"94102.80_SE00_Página_075.png"
|
||||||
|
],
|
||||||
|
"Cloned": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "CtrEditor.ObjetosSim.Extraccion_Datos.osExtraccionTag, CtrEditor",
|
||||||
|
"AutoCreated": false,
|
||||||
|
"RemoverDesdeSimulacion": false,
|
||||||
|
"Nombre": "Salidas Card",
|
||||||
|
"Extraer": false,
|
||||||
|
"New_Row": false,
|
||||||
|
"Id_Search_Templates": "Salidas Plate Group",
|
||||||
|
"Tag_extract": "A45311\n",
|
||||||
|
"Collumn_name": "Card",
|
||||||
|
"Collumn_number": 5,
|
||||||
|
"Copy_Number": 0,
|
||||||
|
"Show_Debug_Window": false,
|
||||||
|
"Opacity_oculto": 0.1,
|
||||||
|
"Id": {
|
||||||
|
"Value": 66
|
||||||
|
},
|
||||||
|
"Show_On_This_Page": false,
|
||||||
|
"Left": 2.3019588,
|
||||||
|
"Top": 1.9661419,
|
||||||
|
"Ancho": 0.3932013,
|
||||||
|
"Alto": 0.11076093,
|
||||||
|
"Angulo": 0.0,
|
||||||
|
"Enable_On_All_Pages": true,
|
||||||
|
"ShowOnThisPagesList": [
|
||||||
|
"94102.80_SE00_Página_070.png",
|
||||||
|
"94102.80_SE00_Página_071.png",
|
||||||
|
"94102.80_SE00_Página_072.png",
|
||||||
|
"94102.80_SE00_Página_073.png",
|
||||||
|
"94102.80_SE00_Página_074.png",
|
||||||
|
"94102.80_SE00_Página_075.png"
|
||||||
|
],
|
||||||
|
"Cloned": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "CtrEditor.ObjetosSim.Extraccion_Datos.osExtraccionTag, CtrEditor",
|
||||||
|
"AutoCreated": false,
|
||||||
|
"RemoverDesdeSimulacion": false,
|
||||||
|
"Nombre": "Salidas Pin",
|
||||||
|
"Extraer": false,
|
||||||
|
"New_Row": false,
|
||||||
|
"Id_Search_Templates": "Salidas Plate Group",
|
||||||
|
"Tag_extract": "",
|
||||||
|
"Collumn_name": "Pin",
|
||||||
|
"Collumn_number": 7,
|
||||||
|
"Copy_Number": 0,
|
||||||
|
"Show_Debug_Window": false,
|
||||||
|
"Opacity_oculto": 0.1,
|
||||||
|
"Id": {
|
||||||
|
"Value": 68
|
||||||
|
},
|
||||||
|
"Show_On_This_Page": false,
|
||||||
|
"Left": 2.613817,
|
||||||
|
"Top": 2.771892,
|
||||||
|
"Ancho": 0.16785541,
|
||||||
|
"Alto": 0.15966734,
|
||||||
|
"Angulo": 0.0,
|
||||||
|
"Enable_On_All_Pages": true,
|
||||||
|
"ShowOnThisPagesList": [
|
||||||
|
"94102.80_SE00_Página_070.png",
|
||||||
|
"94102.80_SE00_Página_071.png",
|
||||||
|
"94102.80_SE00_Página_072.png",
|
||||||
|
"94102.80_SE00_Página_073.png",
|
||||||
|
"94102.80_SE00_Página_074.png",
|
||||||
|
"94102.80_SE00_Página_075.png"
|
||||||
|
],
|
||||||
|
"Cloned": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "CtrEditor.ObjetosSim.Extraccion_Datos.osBuscarCoincidencias, CtrEditor",
|
||||||
|
"AutoCreated": false,
|
||||||
|
"RemoverDesdeSimulacion": false,
|
||||||
|
"Nombre": "Salidas Plate Group",
|
||||||
|
"Search_rectangles": [
|
||||||
|
"200.471923828125,134.23458862304688,137.59445190429688,161.43350219726562",
|
||||||
|
"350.22589111328125,134.39459228515625,137.59445190429688,161.43350219726562",
|
||||||
|
"499.8198547363281,134.55458068847656,137.59445190429688,161.43350219726562",
|
||||||
|
"649.5738525390625,134.55458068847656,137.59445190429688,161.43350219726562",
|
||||||
|
"799.3278198242188,134.55458068847656,137.59445190429688,161.43350219726562",
|
||||||
|
"949.2417602539062,134.55458068847656,137.59445190429688,161.43350219726562",
|
||||||
|
"1098.9957275390625,134.55458068847656,137.59445190429688,161.43350219726562",
|
||||||
|
"1248.749755859375,134.55458068847656,137.59445190429688,161.43350219726562",
|
||||||
|
"1398.503662109375,134.87457275390625,137.59445190429688,161.43350219726562"
|
||||||
|
],
|
||||||
|
"Search_templates": false,
|
||||||
|
"Export_ocr": false,
|
||||||
|
"Opacity_oculto": 0.1,
|
||||||
|
"Show_debug_ocr": false,
|
||||||
|
"Threshold": 0.6,
|
||||||
|
"Coincidencias": 9,
|
||||||
|
"Id": {
|
||||||
|
"Value": 69
|
||||||
|
},
|
||||||
|
"Show_On_This_Page": false,
|
||||||
|
"Left": 2.0056293,
|
||||||
|
"Top": 1.3495445,
|
||||||
|
"Ancho": 1.3769451,
|
||||||
|
"Alto": 1.6148156,
|
||||||
|
"Angulo": 0.0,
|
||||||
|
"Enable_On_All_Pages": true,
|
||||||
|
"ShowOnThisPagesList": [
|
||||||
|
"94102.80_SE00_Página_070.png",
|
||||||
|
"94102.80_SE00_Página_071.png",
|
||||||
|
"94102.80_SE00_Página_072.png",
|
||||||
|
"94102.80_SE00_Página_073.png",
|
||||||
|
"94102.80_SE00_Página_074.png",
|
||||||
|
"94102.80_SE00_Página_075.png"
|
||||||
|
],
|
||||||
|
"Cloned": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "CtrEditor.ObjetosSim.Extraccion_Datos.osExtraccionTag, CtrEditor",
|
||||||
|
"AutoCreated": false,
|
||||||
|
"RemoverDesdeSimulacion": false,
|
||||||
|
"Nombre": "Descrip Pagina",
|
||||||
|
"Extraer": false,
|
||||||
|
"New_Row": false,
|
||||||
|
"Tag_extract": "690\n",
|
||||||
|
"Collumn_name": "Descrip Pagina",
|
||||||
|
"Collumn_number": 1,
|
||||||
|
"Copy_Number": 0,
|
||||||
|
"Show_Debug_Window": false,
|
||||||
|
"Opacity_oculto": 0.1,
|
||||||
|
"Id": {
|
||||||
|
"Value": 70
|
||||||
|
},
|
||||||
|
"Show_On_This_Page": false,
|
||||||
|
"Left": 7.490359,
|
||||||
|
"Top": 10.734316,
|
||||||
|
"Ancho": 1.8668232,
|
||||||
|
"Alto": 0.17921503,
|
||||||
|
"Angulo": 0.0,
|
||||||
|
"Enable_On_All_Pages": true,
|
||||||
|
"ShowOnThisPagesList": [
|
||||||
|
"94102.80_SE00_Página_050.png",
|
||||||
|
"94102.80_SE00_Página_051.png",
|
||||||
|
"94102.80_SE00_Página_052.png",
|
||||||
|
"94102.80_SE00_Página_053.png",
|
||||||
|
"94102.80_SE00_Página_054.png",
|
||||||
|
"94102.80_SE00_Página_055.png",
|
||||||
|
"94102.80_SE00_Página_056.png",
|
||||||
|
"94102.80_SE00_Página_057.png",
|
||||||
|
"94102.80_SE00_Página_058.png",
|
||||||
|
"94102.80_SE00_Página_059.png",
|
||||||
|
"94102.80_SE00_Página_060.png",
|
||||||
|
"94102.80_SE00_Página_061.png",
|
||||||
|
"94102.80_SE00_Página_062.png",
|
||||||
|
"94102.80_SE00_Página_063.png",
|
||||||
|
"94102.80_SE00_Página_064.png",
|
||||||
|
"94102.80_SE00_Página_065.png",
|
||||||
|
"94102.80_SE00_Página_066.png",
|
||||||
|
"94102.80_SE00_Página_067.png",
|
||||||
|
"94102.80_SE00_Página_068.png",
|
||||||
|
"94102.80_SE00_Página_069.png",
|
||||||
|
"94102.80_SE00_Página_070.png",
|
||||||
|
"94102.80_SE00_Página_071.png",
|
||||||
|
"94102.80_SE00_Página_072.png",
|
||||||
|
"94102.80_SE00_Página_073.png",
|
||||||
|
"94102.80_SE00_Página_074.png",
|
||||||
|
"94102.80_SE00_Página_075.png"
|
||||||
|
],
|
||||||
|
"Cloned": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "CtrEditor.ObjetosSim.Extraccion_Datos.osExtraccionTag, CtrEditor",
|
||||||
|
"AutoCreated": false,
|
||||||
|
"RemoverDesdeSimulacion": false,
|
||||||
|
"Nombre": "Comessa",
|
||||||
|
"Extraer": false,
|
||||||
|
"New_Row": false,
|
||||||
|
"Tag_extract": "690\n",
|
||||||
|
"Collumn_name": "Comessa",
|
||||||
|
"Collumn_number": 1,
|
||||||
|
"Copy_Number": 0,
|
||||||
|
"Show_Debug_Window": false,
|
||||||
|
"Opacity_oculto": 0.1,
|
||||||
|
"Id": {
|
||||||
|
"Value": 71
|
||||||
|
},
|
||||||
|
"Show_On_This_Page": false,
|
||||||
|
"Left": 11.119476,
|
||||||
|
"Top": 10.6297865,
|
||||||
|
"Ancho": 0.5749816,
|
||||||
|
"Alto": 0.14187858,
|
||||||
|
"Angulo": 0.0,
|
||||||
|
"Enable_On_All_Pages": true,
|
||||||
|
"ShowOnThisPagesList": [
|
||||||
|
"94102.80_SE00_Página_050.png",
|
||||||
|
"94102.80_SE00_Página_051.png",
|
||||||
|
"94102.80_SE00_Página_052.png",
|
||||||
|
"94102.80_SE00_Página_053.png",
|
||||||
|
"94102.80_SE00_Página_054.png",
|
||||||
|
"94102.80_SE00_Página_055.png",
|
||||||
|
"94102.80_SE00_Página_056.png",
|
||||||
|
"94102.80_SE00_Página_057.png",
|
||||||
|
"94102.80_SE00_Página_058.png",
|
||||||
|
"94102.80_SE00_Página_059.png",
|
||||||
|
"94102.80_SE00_Página_060.png",
|
||||||
|
"94102.80_SE00_Página_061.png",
|
||||||
|
"94102.80_SE00_Página_062.png",
|
||||||
|
"94102.80_SE00_Página_063.png",
|
||||||
|
"94102.80_SE00_Página_064.png",
|
||||||
|
"94102.80_SE00_Página_065.png",
|
||||||
|
"94102.80_SE00_Página_066.png",
|
||||||
|
"94102.80_SE00_Página_067.png",
|
||||||
|
"94102.80_SE00_Página_068.png",
|
||||||
|
"94102.80_SE00_Página_069.png",
|
||||||
|
"94102.80_SE00_Página_070.png",
|
||||||
|
"94102.80_SE00_Página_071.png",
|
||||||
|
"94102.80_SE00_Página_072.png",
|
||||||
|
"94102.80_SE00_Página_073.png",
|
||||||
|
"94102.80_SE00_Página_074.png",
|
||||||
|
"94102.80_SE00_Página_075.png"
|
||||||
|
],
|
||||||
|
"Cloned": false
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,22 @@
|
||||||
|
<UserControl x:Class="CtrEditor.Controls.ObjectHierarchyView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:controls="clr-namespace:CtrEditor.Controls"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<Grid>
|
||||||
|
<TreeView x:Name="ObjectsTreeView" ItemsSource="{Binding RootNodes}"
|
||||||
|
SelectedItemChanged="TreeView_SelectedItemChanged">
|
||||||
|
<TreeView.ItemTemplate>
|
||||||
|
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock Text="{Binding Name}" />
|
||||||
|
<TextBlock Text="{Binding RelationshipType}" Margin="5,0,0,0" Foreground="Gray"
|
||||||
|
FontStyle="Italic" />
|
||||||
|
</StackPanel>
|
||||||
|
</HierarchicalDataTemplate>
|
||||||
|
</TreeView.ItemTemplate>
|
||||||
|
</TreeView>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,97 @@
|
||||||
|
using CtrEditor.ObjetosSim;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace CtrEditor.Controls
|
||||||
|
{
|
||||||
|
public partial class ObjectHierarchyView : UserControl
|
||||||
|
{
|
||||||
|
private MainViewModel _mainViewModel;
|
||||||
|
public ObservableCollection<OsTreeNode> RootNodes { get; set; }
|
||||||
|
|
||||||
|
public ObjectHierarchyView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
RootNodes = new ObservableCollection<OsTreeNode>();
|
||||||
|
this.DataContext = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialize(MainViewModel mainViewModel)
|
||||||
|
{
|
||||||
|
_mainViewModel = mainViewModel;
|
||||||
|
_mainViewModel.ObjetosSimulables.CollectionChanged += ObjetosSimulables_CollectionChanged;
|
||||||
|
UpdateTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ObjetosSimulables_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
UpdateTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateTree()
|
||||||
|
{
|
||||||
|
RootNodes.Clear();
|
||||||
|
|
||||||
|
// Agrupar por tipos
|
||||||
|
var groupsByType = _mainViewModel.ObjetosSimulables
|
||||||
|
.GroupBy(obj => obj.GetType());
|
||||||
|
|
||||||
|
foreach (var group in groupsByType)
|
||||||
|
{
|
||||||
|
// Usar GetTypeDisplayName para obtener el nombre de la clase
|
||||||
|
var typeNode = new OsTreeNode(OsTreeNode.GetTypeDisplayName(group.Key));
|
||||||
|
RootNodes.Add(typeNode);
|
||||||
|
|
||||||
|
foreach (var obj in group)
|
||||||
|
{
|
||||||
|
var objNode = new OsTreeNode(obj.Nombre, obj);
|
||||||
|
typeNode.Children.Add(objNode);
|
||||||
|
|
||||||
|
// Agregar relaciones group_Panel
|
||||||
|
if (!string.IsNullOrEmpty(obj.Group_Panel))
|
||||||
|
{
|
||||||
|
var linkedPanel = _mainViewModel.ObjetosSimulables
|
||||||
|
.FirstOrDefault(o => o.Nombre == obj.Group_Panel);
|
||||||
|
if (linkedPanel != null)
|
||||||
|
{
|
||||||
|
objNode.Children.Add(new OsTreeNode(linkedPanel.Nombre, linkedPanel, "(group_Panel)"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Agregar relaciones group_FramePanel
|
||||||
|
if (!string.IsNullOrEmpty(obj.Group_FramePanel))
|
||||||
|
{
|
||||||
|
var linkedFrame = _mainViewModel.ObjetosSimulables
|
||||||
|
.FirstOrDefault(o => o.Nombre == obj.Group_FramePanel);
|
||||||
|
if (linkedFrame != null)
|
||||||
|
{
|
||||||
|
objNode.Children.Add(new OsTreeNode(linkedFrame.Nombre, linkedFrame, "(group_FramePanel)"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Agregar objetos que hacen referencia a este objeto
|
||||||
|
var referencingObjects = _mainViewModel.ObjetosSimulables
|
||||||
|
.Where(o => o.Group_Panel == obj.Nombre || o.Group_FramePanel == obj.Nombre);
|
||||||
|
|
||||||
|
foreach (var refObj in referencingObjects)
|
||||||
|
{
|
||||||
|
var relationType = refObj.Group_Panel == obj.Nombre ? "(referenced by group_Panel)" : "(referenced by group_FramePanel)";
|
||||||
|
objNode.Children.Add(new OsTreeNode(refObj.Nombre, refObj, relationType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
||||||
|
{
|
||||||
|
if (e.NewValue is OsTreeNode node && node.AssociatedObject != null)
|
||||||
|
{
|
||||||
|
// Actualizar la selección en el MainViewModel
|
||||||
|
_mainViewModel.SelectedItemOsList = node.AssociatedObject;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CtrEditor.ObjetosSim;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace CtrEditor
|
||||||
|
{
|
||||||
|
public partial class OsTreeNode : ObservableObject
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private string name;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<OsTreeNode> children;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private osBase associatedObject;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string relationshipType;
|
||||||
|
|
||||||
|
public OsTreeNode(string name, osBase obj = null, string relationship = "")
|
||||||
|
{
|
||||||
|
this.Name = name;
|
||||||
|
this.Children = new ObservableCollection<OsTreeNode>();
|
||||||
|
this.AssociatedObject = obj;
|
||||||
|
this.RelationshipType = relationship;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetTypeDisplayName(Type type)
|
||||||
|
{
|
||||||
|
var methodInfo = type.GetMethod("NombreClase", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
|
||||||
|
return methodInfo != null ? methodInfo.Invoke(null, null)?.ToString() : type.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
<UserControl x:Class="CtrEditor.Controls.PanelEdicionControl"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||||
|
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||||
|
xmlns:ObjetosSim="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
|
xmlns:ObjetosExtraccion="clr-namespace:CtrEditor.ObjetosSim.Extraccion_Datos"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<xctk:PropertyGrid x:Name="PropertyGridControl"
|
||||||
|
Margin="5"
|
||||||
|
AutoGenerateProperties="False"
|
||||||
|
ShowDescriptionByTooltip="True"
|
||||||
|
FocusManager.IsFocusScope="True">
|
||||||
|
<xctk:PropertyGrid.EditorDefinitions>
|
||||||
|
<!-- String -->
|
||||||
|
<xctk:EditorTemplateDefinition>
|
||||||
|
<xctk:EditorTemplateDefinition.TargetProperties>
|
||||||
|
<xctk:TargetPropertyType Type="{x:Type sys:String}" />
|
||||||
|
</xctk:EditorTemplateDefinition.TargetProperties>
|
||||||
|
<xctk:EditorTemplateDefinition.EditingTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBox Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
|
||||||
|
Text="{Binding Value, UpdateSourceTrigger=LostFocus}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</xctk:EditorTemplateDefinition.EditingTemplate>
|
||||||
|
</xctk:EditorTemplateDefinition>
|
||||||
|
|
||||||
|
<!-- Float -->
|
||||||
|
<xctk:EditorTemplateDefinition>
|
||||||
|
<xctk:EditorTemplateDefinition.TargetProperties>
|
||||||
|
<xctk:TargetPropertyType Type="{x:Type sys:Single}" />
|
||||||
|
</xctk:EditorTemplateDefinition.TargetProperties>
|
||||||
|
<xctk:EditorTemplateDefinition.EditingTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<xctk:SingleUpDown Increment="0.01"
|
||||||
|
Text="{Binding Value, Converter={StaticResource floatFormatter}, UpdateSourceTrigger=LostFocus}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</xctk:EditorTemplateDefinition.EditingTemplate>
|
||||||
|
</xctk:EditorTemplateDefinition>
|
||||||
|
|
||||||
|
<!-- Double -->
|
||||||
|
<xctk:EditorTemplateDefinition>
|
||||||
|
<xctk:EditorTemplateDefinition.TargetProperties>
|
||||||
|
<xctk:TargetPropertyType Type="{x:Type sys:Double}" />
|
||||||
|
</xctk:EditorTemplateDefinition.TargetProperties>
|
||||||
|
<xctk:EditorTemplateDefinition.EditingTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBox Text="{Binding Value, Converter={StaticResource doubleFormatter}, UpdateSourceTrigger=LostFocus}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</xctk:EditorTemplateDefinition.EditingTemplate>
|
||||||
|
</xctk:EditorTemplateDefinition>
|
||||||
|
|
||||||
|
<!-- Velocidad -->
|
||||||
|
<xctk:EditorTemplateDefinition TargetProperties="VelocidadActual">
|
||||||
|
<xctk:EditorTemplateDefinition.EditingTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<xctk:SingleUpDown Increment="0.01" Background="Beige"
|
||||||
|
Text="{Binding Value, Converter={StaticResource floatFormatter}}"
|
||||||
|
FontWeight="Bold" />
|
||||||
|
</DataTemplate>
|
||||||
|
</xctk:EditorTemplateDefinition.EditingTemplate>
|
||||||
|
</xctk:EditorTemplateDefinition>
|
||||||
|
|
||||||
|
<!-- File Dialog -->
|
||||||
|
<xctk:EditorTemplateDefinition TargetProperties="ImagePath">
|
||||||
|
<xctk:EditorTemplateDefinition.EditingTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBox Grid.Column="0"
|
||||||
|
Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
<Button Grid.Column="1" Content="..." Width="25" Margin="2,0,0,0"
|
||||||
|
Click="ImagePathButton_Click" />
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</xctk:EditorTemplateDefinition.EditingTemplate>
|
||||||
|
</xctk:EditorTemplateDefinition>
|
||||||
|
|
||||||
|
<!-- osBuscarCoincidencias -->
|
||||||
|
<xctk:EditorTemplateDefinition>
|
||||||
|
<xctk:EditorTemplateDefinition.TargetProperties>
|
||||||
|
<xctk:TargetPropertyType Type="{x:Type ObjetosExtraccion:osBuscarCoincidencias}" />
|
||||||
|
</xctk:EditorTemplateDefinition.TargetProperties>
|
||||||
|
<xctk:EditorTemplateDefinition.EditingTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<ComboBox ItemsSource="{Binding DataContext.ObjetosSimulables,
|
||||||
|
RelativeSource={RelativeSource AncestorType=Window},
|
||||||
|
Converter={StaticResource SubclassFilterConverterosBuscarCoincidencias}}"
|
||||||
|
SelectedItem="{Binding Value}" DisplayMemberPath="Nombre" IsEditable="True" />
|
||||||
|
</DataTemplate>
|
||||||
|
</xctk:EditorTemplateDefinition.EditingTemplate>
|
||||||
|
</xctk:EditorTemplateDefinition>
|
||||||
|
|
||||||
|
<!-- osVMmotorSim -->
|
||||||
|
<xctk:EditorTemplateDefinition>
|
||||||
|
<xctk:EditorTemplateDefinition.TargetProperties>
|
||||||
|
<xctk:TargetPropertyType Type="{x:Type ObjetosSim:osVMmotorSim}" />
|
||||||
|
</xctk:EditorTemplateDefinition.TargetProperties>
|
||||||
|
<xctk:EditorTemplateDefinition.EditingTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<ComboBox ItemsSource="{Binding DataContext.ObjetosSimulables,
|
||||||
|
RelativeSource={RelativeSource AncestorType=Window},
|
||||||
|
Converter={StaticResource SubclassFilterConverterosVMMotor}}"
|
||||||
|
SelectedItem="{Binding Value}" DisplayMemberPath="Nombre" />
|
||||||
|
</DataTemplate>
|
||||||
|
</xctk:EditorTemplateDefinition.EditingTemplate>
|
||||||
|
</xctk:EditorTemplateDefinition>
|
||||||
|
|
||||||
|
<!-- osBase -->
|
||||||
|
<xctk:EditorTemplateDefinition>
|
||||||
|
<xctk:EditorTemplateDefinition.TargetProperties>
|
||||||
|
<xctk:TargetPropertyType Type="{x:Type ObjetosSim:osBase}" />
|
||||||
|
</xctk:EditorTemplateDefinition.TargetProperties>
|
||||||
|
<xctk:EditorTemplateDefinition.EditingTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<ComboBox
|
||||||
|
ItemsSource="{Binding DataContext.ObjetosSimulables, RelativeSource={RelativeSource AncestorType=Window}}"
|
||||||
|
SelectedItem="{Binding Value}" DisplayMemberPath="Nombre" />
|
||||||
|
</DataTemplate>
|
||||||
|
</xctk:EditorTemplateDefinition.EditingTemplate>
|
||||||
|
</xctk:EditorTemplateDefinition>
|
||||||
|
|
||||||
|
</xctk:PropertyGrid.EditorDefinitions>
|
||||||
|
</xctk:PropertyGrid>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,40 @@
|
||||||
|
using CtrEditor.ObjetosSim;
|
||||||
|
using Ookii.Dialogs.Wpf;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using Xceed.Wpf.Toolkit.PropertyGrid;
|
||||||
|
|
||||||
|
namespace CtrEditor.Controls
|
||||||
|
{
|
||||||
|
public partial class PanelEdicionControl : UserControl
|
||||||
|
{
|
||||||
|
public PanelEdicionControl()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CargarPropiedades(osBase selectedObject)
|
||||||
|
{
|
||||||
|
UserControlFactory.CargarPropiedadesosDatos(selectedObject, PropertyGridControl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsKeyboardFocusWithin => PropertyGridControl.IsKeyboardFocusWithin;
|
||||||
|
|
||||||
|
private void ImagePathButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var dlg = new VistaOpenFileDialog
|
||||||
|
{
|
||||||
|
Filter = "Image files (*.png;*.jpg;*.bmp)|*.png;*.jpg;*.bmp|All files (*.*)|*.*"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dlg.ShowDialog() == true)
|
||||||
|
{
|
||||||
|
// El DataContext de este botón es el PropertyItem asociado
|
||||||
|
if ((sender as Button)?.DataContext is PropertyItem propertyItem)
|
||||||
|
{
|
||||||
|
propertyItem.Value = dlg.FileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
<UserControl x:Class="CtrEditor.Controls.osVisFilter" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:CtrEditor.Controls"
|
||||||
|
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="200">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<Style x:Key="FilterCheckBoxStyle" TargetType="CheckBox">
|
||||||
|
<Setter Property="Margin" Value="0,2,0,2" />
|
||||||
|
<Setter Property="FontSize" Value="12" />
|
||||||
|
</Style>
|
||||||
|
<Style x:Key="FilterHeaderStyle" TargetType="TextBlock">
|
||||||
|
<Setter Property="FontWeight" Value="Bold" />
|
||||||
|
<Setter Property="Margin" Value="0,5,0,2" />
|
||||||
|
</Style>
|
||||||
|
<Style x:Key="FilterSeparatorStyle" TargetType="Separator">
|
||||||
|
<Setter Property="Margin" Value="0,5,0,5" />
|
||||||
|
</Style>
|
||||||
|
</UserControl.Resources>
|
||||||
|
|
||||||
|
<Border BorderBrush="LightGray" BorderThickness="1" Padding="5">
|
||||||
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
|
<StackPanel>
|
||||||
|
<!-- Fixed Filter Options -->
|
||||||
|
<TextBlock Text="Filter Options" Style="{StaticResource FilterHeaderStyle}" />
|
||||||
|
<CheckBox Content="All" IsChecked="{Binding ShowAll, Mode=TwoWay}"
|
||||||
|
Style="{StaticResource FilterCheckBoxStyle}" />
|
||||||
|
<CheckBox Content="Cloned" IsChecked="{Binding ShowCloned, Mode=TwoWay}"
|
||||||
|
Style="{StaticResource FilterCheckBoxStyle}" />
|
||||||
|
<CheckBox Content="Auto Created" IsChecked="{Binding ShowAutoCreated, Mode=TwoWay}"
|
||||||
|
Style="{StaticResource FilterCheckBoxStyle}" />
|
||||||
|
<CheckBox Content="Enable On All Pages" IsChecked="{Binding ShowEnableOnAllPages, Mode=TwoWay}"
|
||||||
|
Style="{StaticResource FilterCheckBoxStyle}" />
|
||||||
|
<CheckBox Content="Show On This Page" IsChecked="{Binding ShowOnThisPage, Mode=TwoWay}"
|
||||||
|
Style="{StaticResource FilterCheckBoxStyle}" />
|
||||||
|
|
||||||
|
<!-- Separator between fixed and dynamic options -->
|
||||||
|
<Separator Style="{StaticResource FilterSeparatorStyle}" />
|
||||||
|
|
||||||
|
<!-- Type Filter Options -->
|
||||||
|
<TextBlock Text="Object Types" Style="{StaticResource FilterHeaderStyle}" />
|
||||||
|
<ItemsControl ItemsSource="{Binding TypeFilters}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<CheckBox Content="{Binding DisplayName}" IsChecked="{Binding IsSelected, Mode=TwoWay}"
|
||||||
|
Style="{StaticResource FilterCheckBoxStyle}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
</Border>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,223 @@
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.ComponentModel; // Add this for PropertyChangedEventHandler and PropertyChangedEventArgs
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CtrEditor.ObjetosSim;
|
||||||
|
|
||||||
|
namespace CtrEditor.Controls
|
||||||
|
{
|
||||||
|
public class FilterChangedEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public osVisFilterViewModel FilterViewModel { get; private set; }
|
||||||
|
|
||||||
|
public FilterChangedEventArgs(osVisFilterViewModel viewModel)
|
||||||
|
{
|
||||||
|
FilterViewModel = viewModel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for osVisFilter.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class osVisFilter : UserControl
|
||||||
|
{
|
||||||
|
public osVisFilter()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
DataContext = FilterViewModel = new osVisFilterViewModel { Parent = this }; // Set the Parent property
|
||||||
|
}
|
||||||
|
|
||||||
|
public osVisFilterViewModel FilterViewModel { get; private set; }
|
||||||
|
|
||||||
|
public event EventHandler<FilterChangedEventArgs> FilterChanged;
|
||||||
|
|
||||||
|
public virtual void OnFilterChanged() // Changed from protected to public
|
||||||
|
{
|
||||||
|
FilterChanged?.Invoke(this, new FilterChangedEventArgs(FilterViewModel));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the type filters based on the provided types
|
||||||
|
/// </summary>
|
||||||
|
public void UpdateAvailableTypes(IEnumerable<Type> types)
|
||||||
|
{
|
||||||
|
FilterViewModel.UpdateTypeFilters(types);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ViewModel for the osVisFilter control
|
||||||
|
/// </summary>
|
||||||
|
public partial class osVisFilterViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool showAll = true;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool showCloned;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool showAutoCreated;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool showEnableOnAllPages;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool showOnThisPage;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<TypeFilterItem> typeFilters = new ObservableCollection<TypeFilterItem>();
|
||||||
|
|
||||||
|
partial void OnShowAllChanged(bool value)
|
||||||
|
{
|
||||||
|
NotifyFilterChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnShowClonedChanged(bool value)
|
||||||
|
{
|
||||||
|
NotifyFilterChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnShowAutoCreatedChanged(bool value)
|
||||||
|
{
|
||||||
|
NotifyFilterChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnShowEnableOnAllPagesChanged(bool value)
|
||||||
|
{
|
||||||
|
NotifyFilterChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnShowOnThisPageChanged(bool value)
|
||||||
|
{
|
||||||
|
NotifyFilterChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnTypeFiltersChanged(ObservableCollection<TypeFilterItem> value)
|
||||||
|
{
|
||||||
|
if (value != null)
|
||||||
|
{
|
||||||
|
foreach (var filter in value)
|
||||||
|
{
|
||||||
|
filter.PropertyChanged += (s, e) =>
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(TypeFilterItem.IsSelected))
|
||||||
|
{
|
||||||
|
NotifyFilterChanged();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NotifyFilterChanged()
|
||||||
|
{
|
||||||
|
if (this.Parent is osVisFilter filter)
|
||||||
|
{
|
||||||
|
filter.OnFilterChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public osVisFilter Parent { get; set; }
|
||||||
|
|
||||||
|
public osVisFilterViewModel()
|
||||||
|
{
|
||||||
|
// PropertyChanged listeners could be added here if needed
|
||||||
|
if (this.Parent is osVisFilter filter)
|
||||||
|
{
|
||||||
|
filter.OnFilterChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the type filters based on the provided types
|
||||||
|
/// </summary>
|
||||||
|
public void UpdateTypeFilters(IEnumerable<Type> types)
|
||||||
|
{
|
||||||
|
// Remove types that are no longer present
|
||||||
|
var typesToRemove = TypeFilters
|
||||||
|
.Where(tf => !types.Contains(tf.Type))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var item in typesToRemove)
|
||||||
|
{
|
||||||
|
UnsubscribeFromTypeFilter(item);
|
||||||
|
TypeFilters.Remove(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new types that aren't already in the list
|
||||||
|
foreach (var type in types)
|
||||||
|
{
|
||||||
|
if (!TypeFilters.Any(tf => tf.Type == type))
|
||||||
|
{
|
||||||
|
var newFilter = new TypeFilterItem(type)
|
||||||
|
{
|
||||||
|
DisplayName = GetTypeDisplayName(type),
|
||||||
|
IsSelected = true
|
||||||
|
};
|
||||||
|
SubscribeToTypeFilter(newFilter);
|
||||||
|
TypeFilters.Add(newFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SubscribeToTypeFilter(TypeFilterItem filter)
|
||||||
|
{
|
||||||
|
filter.PropertyChanged += TypeFilter_PropertyChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UnsubscribeFromTypeFilter(TypeFilterItem filter)
|
||||||
|
{
|
||||||
|
filter.PropertyChanged -= TypeFilter_PropertyChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TypeFilter_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(TypeFilterItem.IsSelected))
|
||||||
|
{
|
||||||
|
NotifyFilterChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the display name for a type, using the NombreClase static method if available
|
||||||
|
/// </summary>
|
||||||
|
private string GetTypeDisplayName(Type type)
|
||||||
|
{
|
||||||
|
var methodInfo = type.GetMethod("NombreClase",
|
||||||
|
BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
|
||||||
|
return methodInfo != null ?
|
||||||
|
methodInfo.Invoke(null, null)?.ToString() :
|
||||||
|
type.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a type filter item with selection state
|
||||||
|
/// </summary>
|
||||||
|
public partial class TypeFilterItem : ObservableObject
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool isSelected = true;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string displayName;
|
||||||
|
|
||||||
|
public Type Type { get; }
|
||||||
|
|
||||||
|
public TypeFilterItem(Type type)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
DisplayName = type?.Name ?? "Unknown Type";
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnIsSelectedChanged(bool value)
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(IsSelected));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace CtrEditor
|
||||||
|
{
|
||||||
|
public class UnsavedChangesConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (value is string path)
|
||||||
|
{
|
||||||
|
var viewModel = Application.Current.MainWindow?.DataContext as MainViewModel;
|
||||||
|
if (viewModel?.HasUnsavedChanges == true)
|
||||||
|
{
|
||||||
|
return $"{path} *";
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,276 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace CtrEditor.Convertidores
|
|
||||||
{
|
|
||||||
|
|
||||||
public class HalfWidthConverter : IValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
if (value is double width)
|
|
||||||
{
|
|
||||||
return (width / 2.0) - (double.Parse(parameter.ToString()) / 2.0);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class WidthPercentageConverter : IValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
if (value is double width)
|
|
||||||
{
|
|
||||||
return width * 0.25;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LevelToHeightMultiConverter : IMultiValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
if (values[0] is float level && values[1] is double containerHeight)
|
|
||||||
{
|
|
||||||
return containerHeight * (level / 100);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class BrushToColorNameConverter : IValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
|
||||||
{
|
|
||||||
if (value is SolidColorBrush brush)
|
|
||||||
{
|
|
||||||
if (brush == Brushes.Red) return "Rojo";
|
|
||||||
if (brush == Brushes.Blue) return "Azul";
|
|
||||||
if (brush == Brushes.Black) return "Negro";
|
|
||||||
if (brush == Brushes.Green) return "Verde";
|
|
||||||
if (brush == Brushes.Gray) return "Gris";
|
|
||||||
}
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
|
||||||
{
|
|
||||||
if (value is string colorName)
|
|
||||||
{
|
|
||||||
switch (colorName)
|
|
||||||
{
|
|
||||||
case "Rojo":
|
|
||||||
return Brushes.Red;
|
|
||||||
case "Azul":
|
|
||||||
return Brushes.Blue;
|
|
||||||
case "Negro":
|
|
||||||
return Brushes.Black;
|
|
||||||
case "Verde":
|
|
||||||
return Brushes.Green;
|
|
||||||
case "Gris":
|
|
||||||
return Brushes.Gray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Brushes.Transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PixelToMeter
|
|
||||||
{
|
|
||||||
// Instancia privada estática, parte del patrón Singleton
|
|
||||||
private static PixelToMeter? _instance;
|
|
||||||
public UnitConverter calc = new UnitConverter(0.01f);
|
|
||||||
|
|
||||||
// Propiedad pública estática para acceder a la instancia
|
|
||||||
public static PixelToMeter Instance
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_instance == null)
|
|
||||||
{
|
|
||||||
_instance = new PixelToMeter();
|
|
||||||
}
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MeterToPixelConverter : IValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
if (value == null) return 0; // Aseguramos que el valor no sea nulo
|
|
||||||
|
|
||||||
// Convertimos el valor de entrada en un número flotante
|
|
||||||
float meters = System.Convert.ToSingle(value);
|
|
||||||
|
|
||||||
float factor = 1; // Valor por defecto del factor
|
|
||||||
|
|
||||||
// Si el parámetro no es nulo, intentamos convertirlo a float
|
|
||||||
if (parameter != null)
|
|
||||||
{
|
|
||||||
string paramStr = parameter.ToString();
|
|
||||||
|
|
||||||
// Normalizamos el parámetro para asegurar que el punto sea el separador decimal
|
|
||||||
paramStr = paramStr.Replace(',', '.');
|
|
||||||
|
|
||||||
// Utilizamos CultureInfo.InvariantCulture para evitar problemas con el separador decimal
|
|
||||||
if (float.TryParse(paramStr, NumberStyles.Any, CultureInfo.InvariantCulture, out float parsedFactor))
|
|
||||||
{
|
|
||||||
factor = parsedFactor; // Asignamos el factor parseado si la conversión es exitosa
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculamos los píxeles llamando a la instancia de PixelToMeter y multiplicamos por el factor
|
|
||||||
return PixelToMeter.Instance.calc.MetersToPixels(meters) * factor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
if (value == null) return 0; // Aseguramos que el valor no sea nulo
|
|
||||||
|
|
||||||
// Convertimos el valor de entrada en un número flotante
|
|
||||||
float pixels = System.Convert.ToSingle(value);
|
|
||||||
|
|
||||||
float factor = 1; // Valor por defecto del factor
|
|
||||||
|
|
||||||
// Si el parámetro no es nulo, intentamos convertirlo a float
|
|
||||||
if (parameter != null)
|
|
||||||
{
|
|
||||||
string paramStr = parameter.ToString();
|
|
||||||
|
|
||||||
// Normalizamos el parámetro para asegurar que el punto sea el separador decimal
|
|
||||||
paramStr = paramStr.Replace(',', '.');
|
|
||||||
|
|
||||||
// Utilizamos CultureInfo.InvariantCulture para evitar problemas con el separador decimal
|
|
||||||
if (float.TryParse(paramStr, NumberStyles.Any, CultureInfo.InvariantCulture, out float parsedFactor))
|
|
||||||
{
|
|
||||||
factor = parsedFactor; // Asignamos el factor parseado si la conversión es exitosa
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return PixelToMeter.Instance.calc.PixelsToMeters(pixels) * factor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class DistanceToMarginConverter : IValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
if (value is double distance)
|
|
||||||
{
|
|
||||||
return new Thickness(0, 0, 0, PixelToMeter.Instance.calc.MetersToPixels((float)distance)); // Ajustar Bottom a 'distance'
|
|
||||||
}
|
|
||||||
return new Thickness();
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("ConvertBack is not supported.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FloatToFormattedStringConverter : IValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
if (value is float floatValue)
|
|
||||||
{
|
|
||||||
return floatValue.ToString("0.00", culture); // Formatear a dos decimales
|
|
||||||
}
|
|
||||||
return value; // Devolver el valor original si no es un float
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
if (value is string stringValue && float.TryParse(stringValue, NumberStyles.Float, culture, out float result))
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return value; // Devolver el valor original si no se puede convertir
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class DoubleToFormattedStringConverter : IValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
if (value is double floatValue)
|
|
||||||
{
|
|
||||||
return floatValue.ToString("0.00", culture); // Formatear a dos decimales
|
|
||||||
}
|
|
||||||
return value; // Devolver el valor original si no es un float
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
if (value is string stringValue && double.TryParse(stringValue, NumberStyles.Float, culture, out double result))
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return value; // Devolver el valor original si no se puede convertir
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class UnitConverter
|
|
||||||
{
|
|
||||||
// La escala representa cuántos metros hay en un píxel
|
|
||||||
public float Scale { get; private set; }
|
|
||||||
|
|
||||||
|
|
||||||
public UnitConverter(float scale)
|
|
||||||
{
|
|
||||||
if (scale <= 0)
|
|
||||||
throw new ArgumentException("Scale must be greater than zero.");
|
|
||||||
|
|
||||||
Scale = scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convierte una distancia en metros a píxeles
|
|
||||||
public float MetersToPixels(float meters)
|
|
||||||
{
|
|
||||||
return meters / Scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convierte una distancia en píxeles a metros
|
|
||||||
public float PixelsToMeters(float pixels)
|
|
||||||
{
|
|
||||||
return pixels * Scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configurar o ajustar la escala
|
|
||||||
public void SetScale(float newScale)
|
|
||||||
{
|
|
||||||
if (newScale <= 0)
|
|
||||||
throw new ArgumentException("Scale must be greater than zero.");
|
|
||||||
|
|
||||||
Scale = newScale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"path": "."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../Libraries/LibS7Adv"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": {}
|
||||||
|
}
|
|
@ -6,9 +6,19 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<Optimize>True</Optimize>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<Optimize>True</Optimize>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Remove="ObjetosSim\ucBasicExample.xaml.cs" />
|
||||||
<Compile Remove="ObjetosSim\ucTransporteCurva.xaml.cs" />
|
<Compile Remove="ObjetosSim\ucTransporteCurva.xaml.cs" />
|
||||||
<Compile Remove="Simulacion\FPhysics.cs" />
|
<Compile Remove="Simulacion\FPhysics.cs" />
|
||||||
<Compile Remove="Simulacion\GeometrySimulator.cs" />
|
<Compile Remove="Simulacion\GeometrySimulator.cs" />
|
||||||
|
@ -17,45 +27,74 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove="app2.png" />
|
<None Remove="app2.png" />
|
||||||
<None Remove="CtrEditorE.png" />
|
<None Remove="CtrEditorE.png" />
|
||||||
|
<None Remove="Icons\allselect.png" />
|
||||||
|
<None Remove="Icons\analyze.png" />
|
||||||
<None Remove="Icons\app.256x256.ico" />
|
<None Remove="Icons\app.256x256.ico" />
|
||||||
<None Remove="Icons\app.png" />
|
<None Remove="Icons\app.png" />
|
||||||
<None Remove="Icons\app2.128x128.ico" />
|
<None Remove="Icons\app2.128x128.ico" />
|
||||||
<None Remove="Icons\app2.256x256.ico" />
|
<None Remove="Icons\app2.256x256.ico" />
|
||||||
<None Remove="Icons\app2.png" />
|
<None Remove="Icons\app2.png" />
|
||||||
<None Remove="Icons\borrar.png" />
|
<None Remove="Icons\borrar.png" />
|
||||||
|
<None Remove="Icons\choose.png" />
|
||||||
<None Remove="Icons\connect.png" />
|
<None Remove="Icons\connect.png" />
|
||||||
<None Remove="Icons\CtrEditorA.png" />
|
<None Remove="Icons\CtrEditorA.png" />
|
||||||
<None Remove="Icons\CtrEditorC.png" />
|
<None Remove="Icons\CtrEditorC.png" />
|
||||||
<None Remove="Icons\CtrEditorE.png" />
|
<None Remove="Icons\CtrEditorE.png" />
|
||||||
<None Remove="Icons\disconnect.png" />
|
<None Remove="Icons\disconnect.png" />
|
||||||
<None Remove="Icons\duplicate.png" />
|
<None Remove="Icons\duplicate.png" />
|
||||||
|
<None Remove="Icons\extract.png" />
|
||||||
<None Remove="Icons\fotocelula.png" />
|
<None Remove="Icons\fotocelula.png" />
|
||||||
|
<None Remove="Icons\match.png" />
|
||||||
|
<None Remove="Icons\ocr.png" />
|
||||||
|
<None Remove="Icons\rotation.cur" />
|
||||||
|
<None Remove="Icons\rotation32x32.cur" />
|
||||||
|
<None Remove="Icons\rotationRx.cur" />
|
||||||
|
<None Remove="Icons\rotationSx.cur" />
|
||||||
<None Remove="Icons\save.png" />
|
<None Remove="Icons\save.png" />
|
||||||
<None Remove="Icons\start.png" />
|
<None Remove="Icons\start.png" />
|
||||||
<None Remove="Icons\stop.png" />
|
<None Remove="Icons\stop.png" />
|
||||||
|
<None Remove="Icons\unselect.png" />
|
||||||
<None Remove="imagenes\filler.png" />
|
<None Remove="imagenes\filler.png" />
|
||||||
|
<None Remove="imagenes\gear.png" />
|
||||||
<None Remove="imagenes\motorNegro.png" />
|
<None Remove="imagenes\motorNegro.png" />
|
||||||
<None Remove="imagenes\motorVerde.png" />
|
<None Remove="imagenes\motorVerde.png" />
|
||||||
|
<None Remove="Images\base.png" />
|
||||||
<None Remove="motor2.png" />
|
<None Remove="motor2.png" />
|
||||||
<None Remove="tank.png" />
|
<None Remove="tank.png" />
|
||||||
|
<None Remove="IA\appsettings.json" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Page Remove="ObjetosSim\ucBasicExample.xaml" />
|
||||||
<Page Remove="ObjetosSim\ucTransporteCurva.xaml" />
|
<Page Remove="ObjetosSim\ucTransporteCurva.xaml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<None Include="ObjetosSim\ucBasicExample.xaml" />
|
||||||
|
<None Include="ObjetosSim\ucBasicExample.xaml.cs" />
|
||||||
<None Include="Simulacion\FPhysics.cs" />
|
<None Include="Simulacion\FPhysics.cs" />
|
||||||
<None Include="Simulacion\GeometrySimulator.cs" />
|
<None Include="Simulacion\GeometrySimulator.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Aether.Physics2D" Version="2.1.0" />
|
<PackageReference Include="Aether.Physics2D" Version="2.1.0" />
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
<PackageReference Include="ClosedXML" Version="0.104.2" />
|
||||||
<PackageReference Include="FarseerPhysics" Version="3.5.0" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.77" />
|
<PackageReference Include="Emgu.CV" Version="4.9.0.5494" />
|
||||||
|
<PackageReference Include="Emgu.CV.runtime.windows" Version="4.9.0.5494" />
|
||||||
|
<PackageReference Include="Emgu.CV.UI" Version="4.9.0.5494" />
|
||||||
|
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.6.1" />
|
||||||
|
<PackageReference Include="LanguageDetection" Version="1.2.0" />
|
||||||
|
<PackageReference Include="LiveChartsCore.SkiaSharpView.WPF" Version="2.0.0-rc4.5" />
|
||||||
|
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.135" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
|
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
|
||||||
|
<PackageReference Include="Tesseract" Version="5.2.0" />
|
||||||
|
<PackageReference Include="Tesseract.Drawing" Version="5.2.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Libraries\LibS7Adv\LibS7Adv.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -68,23 +107,69 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Resource Include="app2.png" />
|
<Resource Include="app2.png" />
|
||||||
<Resource Include="CtrEditorE.png" />
|
<Resource Include="CtrEditorE.png" />
|
||||||
|
<Resource Include="Icons\allselect.png" />
|
||||||
|
<Resource Include="Icons\analyze.png" />
|
||||||
<Resource Include="Icons\app.png" />
|
<Resource Include="Icons\app.png" />
|
||||||
<Resource Include="Icons\app2.png" />
|
<Resource Include="Icons\app2.png" />
|
||||||
<Resource Include="Icons\borrar.png" />
|
<Resource Include="Icons\borrar.png" />
|
||||||
|
<Resource Include="Icons\choose.png" />
|
||||||
<Resource Include="Icons\connect.png" />
|
<Resource Include="Icons\connect.png" />
|
||||||
<Resource Include="Icons\CtrEditorA.png" />
|
<Resource Include="Icons\CtrEditorA.png" />
|
||||||
<Resource Include="Icons\CtrEditorC.png" />
|
<Resource Include="Icons\CtrEditorC.png" />
|
||||||
<Resource Include="Icons\CtrEditorE.png" />
|
<Resource Include="Icons\CtrEditorE.png" />
|
||||||
<Resource Include="Icons\disconnect.png" />
|
<Resource Include="Icons\disconnect.png" />
|
||||||
<Resource Include="Icons\duplicate.png" />
|
<Resource Include="Icons\duplicate.png" />
|
||||||
|
<Resource Include="Icons\extract.png">
|
||||||
|
<CopyToOutputDirectory></CopyToOutputDirectory>
|
||||||
|
</Resource>
|
||||||
<Resource Include="Icons\fotocelula.png" />
|
<Resource Include="Icons\fotocelula.png" />
|
||||||
|
<Resource Include="Icons\match.png" />
|
||||||
|
<Resource Include="Icons\ocr.png" />
|
||||||
|
<Resource Include="Icons\rotationRx.cur" />
|
||||||
|
<Resource Include="Icons\rotationSx.cur" />
|
||||||
<Resource Include="Icons\save.png" />
|
<Resource Include="Icons\save.png" />
|
||||||
<Resource Include="Icons\start.png" />
|
<Resource Include="Icons\start.png" />
|
||||||
<Resource Include="Icons\stop.png" />
|
<Resource Include="Icons\stop.png" />
|
||||||
|
<Resource Include="Icons\unselect.png" />
|
||||||
<Resource Include="imagenes\filler.png" />
|
<Resource Include="imagenes\filler.png" />
|
||||||
|
<Resource Include="imagenes\gear.png" />
|
||||||
<Resource Include="imagenes\motorNegro.png" />
|
<Resource Include="imagenes\motorNegro.png" />
|
||||||
<Resource Include="imagenes\motorVerde.png" />
|
<Resource Include="imagenes\motorVerde.png" />
|
||||||
<Resource Include="imagenes\tank.png" />
|
<Resource Include="imagenes\tank.png" />
|
||||||
|
<EmbeddedResource Include="Images\base.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Update="Properties\Settings.Designer.cs">
|
||||||
|
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Settings.settings</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="IA\appsettings.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Properties\Settings.settings">
|
||||||
|
<Generator>SettingsSingleFileGenerator</Generator>
|
||||||
|
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
<None Update="Tesseract\eng.traineddata">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Tesseract\ita.traineddata">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="Tesseract\spa.traineddata">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="IA\appsettings.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.9.34723.18
|
VisualStudioVersion = 17.9.34723.18
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CtrEditor", "CtrEditor.csproj", "{A4DC96D9-6C55-42ED-8E29-DCBC8D7AB831}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CtrEditor", "CtrEditor.csproj", "{A4DC96D9-6C55-42ED-8E29-DCBC8D7AB831}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibS7Adv", "..\Libraries\LibS7Adv\LibS7Adv.csproj", "{86A7FED2-AEB1-4766-819F-C6256FA7DD38}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
@ -15,6 +17,10 @@ Global
|
||||||
{A4DC96D9-6C55-42ED-8E29-DCBC8D7AB831}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{A4DC96D9-6C55-42ED-8E29-DCBC8D7AB831}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{A4DC96D9-6C55-42ED-8E29-DCBC8D7AB831}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{A4DC96D9-6C55-42ED-8E29-DCBC8D7AB831}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{A4DC96D9-6C55-42ED-8E29-DCBC8D7AB831}.Release|Any CPU.Build.0 = Release|Any CPU
|
{A4DC96D9-6C55-42ED-8E29-DCBC8D7AB831}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{86A7FED2-AEB1-4766-819F-C6256FA7DD38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{86A7FED2-AEB1-4766-819F-C6256FA7DD38}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{86A7FED2-AEB1-4766-819F-C6256FA7DD38}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{86A7FED2-AEB1-4766-819F-C6256FA7DD38}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
@ -0,0 +1,383 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows;
|
||||||
|
using CtrEditor.ObjetosSim;
|
||||||
|
using LibS7Adv;
|
||||||
|
|
||||||
|
namespace CtrEditor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Metadata de una página, incluyendo información sobre la imagen y configuración
|
||||||
|
/// </summary>
|
||||||
|
public class PageMetadata
|
||||||
|
{
|
||||||
|
public string PageId { get; set; }
|
||||||
|
public string PageName { get; set; }
|
||||||
|
public string ImagePath { get; set; }
|
||||||
|
public DateTime LastModified { get; set; }
|
||||||
|
public Dictionary<string, object> CustomMetadata { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Estado de un objeto dentro de una página específica
|
||||||
|
/// </summary>
|
||||||
|
public class PageObjectState
|
||||||
|
{
|
||||||
|
public string GlobalObjectId { get; set; }
|
||||||
|
public bool IsVisible { get; set; } = true;
|
||||||
|
public float Left { get; set; }
|
||||||
|
public float Top { get; set; }
|
||||||
|
public float Rotation { get; set; }
|
||||||
|
public Dictionary<string, object> CustomProperties { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Estado de una página específica
|
||||||
|
/// </summary>
|
||||||
|
public class PageState
|
||||||
|
{
|
||||||
|
public string PageId { get; set; }
|
||||||
|
public string PageName { get; set; }
|
||||||
|
public List<osBase> LocalObjects { get; set; } = new();
|
||||||
|
public Dictionary<string, PageObjectState> GlobalObjectStates { get; set; } = new();
|
||||||
|
public Dictionary<string, object> PageMetadata { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Estado global de la aplicación
|
||||||
|
/// </summary>
|
||||||
|
public class GlobalState
|
||||||
|
{
|
||||||
|
public List<osBase> SharedObjects { get; set; } = new();
|
||||||
|
public Dictionary<string, PageMetadata> PagesMetadata { get; set; } = new();
|
||||||
|
public PLCViewModel PLCConfiguration { get; set; }
|
||||||
|
public UnitConverter UnitConverter { get; set; }
|
||||||
|
public int LastUsedId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gestor principal de estados de la aplicación
|
||||||
|
/// </summary>
|
||||||
|
public class StateManager : IDisposable
|
||||||
|
{
|
||||||
|
private readonly string _basePath;
|
||||||
|
private GlobalState _globalState;
|
||||||
|
private Dictionary<string, PageState> _loadedPages;
|
||||||
|
private string _currentPageId;
|
||||||
|
private readonly object _lockObject = new();
|
||||||
|
private bool _hasUnsavedChanges;
|
||||||
|
private MainViewModel _mainViewModel;
|
||||||
|
|
||||||
|
public event EventHandler<string> PageStateChanged;
|
||||||
|
public event EventHandler GlobalStateChanged;
|
||||||
|
|
||||||
|
public StateManager(string basePath, MainViewModel mainViewModel)
|
||||||
|
{
|
||||||
|
_basePath = basePath;
|
||||||
|
_mainViewModel = mainViewModel;
|
||||||
|
_loadedPages = new Dictionary<string, PageState>();
|
||||||
|
Directory.CreateDirectory(basePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
await LoadGlobalStateAsync();
|
||||||
|
if (_mainViewModel.SelectedImage != null)
|
||||||
|
{
|
||||||
|
await LoadPageStateAsync(_mainViewModel.SelectedImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonSerializerSettings GetSerializerSettings()
|
||||||
|
{
|
||||||
|
return new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
TypeNameHandling = TypeNameHandling.Auto,
|
||||||
|
ObjectCreationHandling = ObjectCreationHandling.Replace,
|
||||||
|
Formatting = Formatting.Indented,
|
||||||
|
NullValueHandling = NullValueHandling.Ignore
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LoadGlobalStateAsync()
|
||||||
|
{
|
||||||
|
var path = Path.Combine(_basePath, "global.json");
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var json = await File.ReadAllTextAsync(path);
|
||||||
|
_globalState = JsonConvert.DeserializeObject<GlobalState>(json, GetSerializerSettings());
|
||||||
|
|
||||||
|
// Restaurar configuración global
|
||||||
|
_mainViewModel.PLCViewModel = _globalState.PLCConfiguration ?? new PLCViewModel();
|
||||||
|
if (_globalState.UnitConverter != null)
|
||||||
|
PixelToMeter.Instance.calc = _globalState.UnitConverter;
|
||||||
|
else
|
||||||
|
PixelToMeter.Instance.calc = new UnitConverter(1.0f); // Valor por defecto
|
||||||
|
|
||||||
|
// Restaurar objetos globales
|
||||||
|
foreach (var obj in _globalState.SharedObjects)
|
||||||
|
{
|
||||||
|
await RestoreObjectAsync(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Log error y crear nuevo estado global
|
||||||
|
_globalState = new GlobalState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_globalState = new GlobalState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SaveGlobalStateAsync()
|
||||||
|
{
|
||||||
|
var path = Path.Combine(_basePath, "global.json");
|
||||||
|
var backupPath = Path.ChangeExtension(path, ".bak");
|
||||||
|
|
||||||
|
// Actualizar estado global
|
||||||
|
_globalState.PLCConfiguration = _mainViewModel.PLCViewModel;
|
||||||
|
_globalState.UnitConverter = PixelToMeter.Instance.calc;
|
||||||
|
|
||||||
|
// Crear backup
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
File.Copy(path, backupPath, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Preparar objetos para serialización
|
||||||
|
foreach (var obj in _globalState.SharedObjects)
|
||||||
|
{
|
||||||
|
obj.SalvarDatosNoSerializables();
|
||||||
|
}
|
||||||
|
|
||||||
|
var json = JsonConvert.SerializeObject(_globalState, GetSerializerSettings());
|
||||||
|
await File.WriteAllTextAsync(path, json);
|
||||||
|
_hasUnsavedChanges = false;
|
||||||
|
GlobalStateChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Restaurar estado de objetos
|
||||||
|
foreach (var obj in _globalState.SharedObjects)
|
||||||
|
{
|
||||||
|
obj.RestaurarDatosNoSerializables();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PageState> LoadPageStateAsync(string pageId)
|
||||||
|
{
|
||||||
|
// Retornar página cacheada si existe
|
||||||
|
if (_loadedPages.TryGetValue(pageId, out var cachedState))
|
||||||
|
{
|
||||||
|
return cachedState;
|
||||||
|
}
|
||||||
|
|
||||||
|
var path = Path.Combine(_basePath, $"page_{pageId}.json");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PageState pageState;
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
var json = await File.ReadAllTextAsync(path);
|
||||||
|
pageState = JsonConvert.DeserializeObject<PageState>(json, GetSerializerSettings());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pageState = new PageState
|
||||||
|
{
|
||||||
|
PageId = pageId,
|
||||||
|
PageName = _globalState.PagesMetadata.GetValueOrDefault(pageId)?.PageName ?? pageId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_loadedPages[pageId] = pageState;
|
||||||
|
|
||||||
|
// Restaurar objetos locales
|
||||||
|
foreach (var obj in pageState.LocalObjects)
|
||||||
|
{
|
||||||
|
await RestoreObjectAsync(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aplicar estados de objetos globales
|
||||||
|
ApplyGlobalObjectStates(pageState);
|
||||||
|
|
||||||
|
return pageState;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Log error
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyGlobalObjectStates(PageState pageState)
|
||||||
|
{
|
||||||
|
foreach (var kvp in pageState.GlobalObjectStates)
|
||||||
|
{
|
||||||
|
var globalObj = _globalState.SharedObjects.FirstOrDefault(o => o.Id.Value.ToString() == kvp.Key);
|
||||||
|
if (globalObj != null)
|
||||||
|
{
|
||||||
|
var state = kvp.Value;
|
||||||
|
globalObj.Left = state.Left;
|
||||||
|
globalObj.Top = state.Top;
|
||||||
|
globalObj.Angulo = state.Rotation;
|
||||||
|
|
||||||
|
// Actualizar Show_On_This_Page que ahora maneja internamente showOnThisPagesList
|
||||||
|
if (state.IsVisible && !globalObj.Show_On_This_Page)
|
||||||
|
globalObj.Show_On_This_Page = true;
|
||||||
|
else if (!state.IsVisible && globalObj.Show_On_This_Page)
|
||||||
|
globalObj.Show_On_This_Page = false;
|
||||||
|
|
||||||
|
// Aplicar propiedades personalizadas
|
||||||
|
foreach (var prop in state.CustomProperties)
|
||||||
|
{
|
||||||
|
var property = globalObj.GetType().GetProperty(prop.Key);
|
||||||
|
if (property != null && property.CanWrite)
|
||||||
|
{
|
||||||
|
property.SetValue(globalObj, prop.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RestoreObjectAsync(osBase obj)
|
||||||
|
{
|
||||||
|
if (obj != null)
|
||||||
|
{
|
||||||
|
obj.CheckData();
|
||||||
|
await Task.Run(() =>
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
CrearUserControlDesdeObjetoSimulable(obj);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CrearUserControlDesdeObjetoSimulable(osBase osObjeto)
|
||||||
|
{
|
||||||
|
Type tipoObjeto = osObjeto.GetType();
|
||||||
|
UserControl userControl = UserControlFactory.GetControlForType(tipoObjeto);
|
||||||
|
|
||||||
|
if (userControl != null)
|
||||||
|
{
|
||||||
|
UserControlFactory.AssignDatos(userControl, osObjeto, _mainViewModel.simulationManager);
|
||||||
|
osObjeto._mainViewModel = _mainViewModel;
|
||||||
|
|
||||||
|
if (osObjeto.Id == null)
|
||||||
|
{
|
||||||
|
osObjeto.Id = new UniqueId().ObtenerNuevaID();
|
||||||
|
}
|
||||||
|
|
||||||
|
_mainViewModel.MainWindow.AgregarRegistrarUserControlCanvas(userControl);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SavePageStateAsync(string pageId)
|
||||||
|
{
|
||||||
|
if (!_loadedPages.TryGetValue(pageId, out var pageState))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var path = Path.Combine(_basePath, $"page_{pageId}.json");
|
||||||
|
var backupPath = Path.ChangeExtension(path, ".bak");
|
||||||
|
|
||||||
|
// Crear backup
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
File.Copy(path, backupPath, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actualizar estado de objetos globales
|
||||||
|
pageState.GlobalObjectStates.Clear();
|
||||||
|
foreach (var obj in _mainViewModel.ObjetosSimulables.Where(o => o.Enable_On_All_Pages))
|
||||||
|
{
|
||||||
|
var currentPageId = _mainViewModel.SelectedImage;
|
||||||
|
pageState.GlobalObjectStates[obj.Id.Value.ToString()] = new PageObjectState
|
||||||
|
{
|
||||||
|
GlobalObjectId = obj.Id.Value.ToString(),
|
||||||
|
IsVisible = obj.Show_On_This_Page,
|
||||||
|
Left = obj.Left,
|
||||||
|
Top = obj.Top,
|
||||||
|
Rotation = obj.Angulo,
|
||||||
|
CustomProperties = CaptureCustomProperties(obj)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Preparar objetos para serialización
|
||||||
|
foreach (var obj in pageState.LocalObjects)
|
||||||
|
{
|
||||||
|
obj.SalvarDatosNoSerializables();
|
||||||
|
}
|
||||||
|
|
||||||
|
var json = JsonConvert.SerializeObject(pageState, GetSerializerSettings());
|
||||||
|
await File.WriteAllTextAsync(path, json);
|
||||||
|
_hasUnsavedChanges = false;
|
||||||
|
PageStateChanged?.Invoke(this, pageId);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Restaurar estado de objetos
|
||||||
|
foreach (var obj in pageState.LocalObjects)
|
||||||
|
{
|
||||||
|
obj.RestaurarDatosNoSerializables();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, object> CaptureCustomProperties(osBase obj)
|
||||||
|
{
|
||||||
|
var customProps = new Dictionary<string, object>();
|
||||||
|
var properties = obj.GetType().GetProperties()
|
||||||
|
.Where(p => p.GetCustomAttributes(typeof(SerializeAttribute), true).Any());
|
||||||
|
|
||||||
|
foreach (var prop in properties)
|
||||||
|
{
|
||||||
|
customProps[prop.Name] = prop.GetValue(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
return customProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SaveAllAsync()
|
||||||
|
{
|
||||||
|
foreach (var pageId in _loadedPages.Keys)
|
||||||
|
{
|
||||||
|
await SavePageStateAsync(pageId);
|
||||||
|
}
|
||||||
|
await SaveGlobalStateAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_hasUnsavedChanges)
|
||||||
|
{
|
||||||
|
SaveAllAsync().Wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Atributo para marcar propiedades que deben ser serializadas como propiedades personalizadas
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Property)]
|
||||||
|
public class SerializeAttribute : Attribute { }
|
||||||
|
}
|
|
@ -28,6 +28,13 @@ namespace CtrEditor
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string? ObtenerPathAllPages(string extension)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(EstadoPersistente.Instance.directorio))
|
||||||
|
return Path.Combine(EstadoPersistente.Instance.directorio, "AllPages" + extension);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public void CargarImagenes()
|
public void CargarImagenes()
|
||||||
{
|
{
|
||||||
Imagenes.Clear();
|
Imagenes.Clear();
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
using LanguageDetection;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||||
|
|
||||||
|
namespace CtrEditor.FuncionesBase
|
||||||
|
{
|
||||||
|
public class Idiomas
|
||||||
|
{
|
||||||
|
public const string DEFAULT_LANGUAGE = "English";
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, string> _languageMap = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "en", "English" },
|
||||||
|
{ "es", "Spanish" },
|
||||||
|
{ "it", "Italian" },
|
||||||
|
{ "pt", "Portuguese" },
|
||||||
|
{ "fr", "French" },
|
||||||
|
{ "de", "German" }
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly LanguageDetector _languageDetector;
|
||||||
|
|
||||||
|
static Idiomas()
|
||||||
|
{
|
||||||
|
_languageDetector = new LanguageDetector();
|
||||||
|
_languageDetector.AddLanguages("en", "es", "it", "pt", "fr", "de");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<string> GetLanguageList()
|
||||||
|
{
|
||||||
|
return new List<string>(_languageMap.Values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string DetectarIdioma(string texto)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(texto)) return DEFAULT_LANGUAGE;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string detectedLanguageCode = _languageDetector.Detect(texto);
|
||||||
|
return _languageMap.GetValueOrDefault(detectedLanguageCode, DEFAULT_LANGUAGE);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return DEFAULT_LANGUAGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetLanguageCode(string languageName)
|
||||||
|
{
|
||||||
|
return _languageMap.FirstOrDefault(x => x.Value == languageName).Key ?? "en";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IdiomasItemsSource<T> : IItemsSource
|
||||||
|
{
|
||||||
|
public ItemCollection GetValues()
|
||||||
|
{
|
||||||
|
ItemCollection items = new ItemCollection();
|
||||||
|
foreach (string language in Idiomas.GetLanguageList())
|
||||||
|
{
|
||||||
|
items.Add(language);
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace CtrEditor.FuncionesBase
|
||||||
|
{
|
||||||
|
public struct MutableRect
|
||||||
|
{
|
||||||
|
public float Left { get; set; }
|
||||||
|
public float Top { get; set; }
|
||||||
|
public float Right { get; set; }
|
||||||
|
public float Bottom { get; set; }
|
||||||
|
|
||||||
|
public MutableRect(float left, float top, float right, float bottom)
|
||||||
|
{
|
||||||
|
Left = left;
|
||||||
|
Top = top;
|
||||||
|
Right = right;
|
||||||
|
Bottom = bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MutableRect(Rect r)
|
||||||
|
{
|
||||||
|
Left = (float) r.Left;
|
||||||
|
Top = (float)r.Top;
|
||||||
|
Right = (float)r.Right;
|
||||||
|
Bottom = (float)r.Bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public float Width => Right - Left;
|
||||||
|
public float Height => Bottom - Top;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
using System;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||||
|
|
||||||
|
namespace CtrEditor.FuncionesBase
|
||||||
|
{
|
||||||
|
public class TagPattern
|
||||||
|
{
|
||||||
|
public const string DEFAULT_PATTERN = "DESCRIPCION";
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, string> _patternDescriptions = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "Descripcion", "First letter capitalized" },
|
||||||
|
{ "DESCRIPCION", "All uppercase text" },
|
||||||
|
{ "Siemens IO Input", "Format: Exxxxx.y (x: 0-65535, y: 0-7)" },
|
||||||
|
{ "Siemens IO Output", "Format: Axxxxx.y (x: 0-65535, y: 0-7)" },
|
||||||
|
{ "LETRASNUMEROS", "Format: ABC...123... (1-10 letters + numbers)" },
|
||||||
|
{ "LETRASNUMEROSESPACIOS", "Format: ABC...123... (letters, numbers and spaces allowed)" },
|
||||||
|
{ "Numero", "Numeric value" }
|
||||||
|
};
|
||||||
|
|
||||||
|
public static List<string> GetPatternList()
|
||||||
|
{
|
||||||
|
return new List<string>(_patternDescriptions.Keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ApplyPattern(string text, string pattern)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(text)) return text;
|
||||||
|
|
||||||
|
return pattern switch
|
||||||
|
{
|
||||||
|
"Descripcion" => ApplyDescripcionPattern(text),
|
||||||
|
"DESCRIPCION" => text.ToUpper(),
|
||||||
|
"Siemens IO Input" => ApplySiemensPattern(text, "E"),
|
||||||
|
"Siemens IO Output" => ApplySiemensPattern(text, "A"),
|
||||||
|
"LETRASNUMEROS" => ApplyLetrasNumerosPattern(text),
|
||||||
|
"LETRASNUMEROSESPACIOS" => ApplyLetrasNumerosEspaciosPattern(text),
|
||||||
|
"Numero" => ApplyNumberPattern(text),
|
||||||
|
_ => text
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ApplyDescripcionPattern(string text)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(text)) return text;
|
||||||
|
return char.ToUpper(text[0]) + (text.Length > 1 ? text.Substring(1).ToLower() : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ApplySiemensPattern(string text, string prefix)
|
||||||
|
{
|
||||||
|
var match = Regex.Match(text, $"{prefix}?(\\d{{1,5}})\\.?(\\d)?", RegexOptions.IgnoreCase);
|
||||||
|
if (match.Success)
|
||||||
|
{
|
||||||
|
int address = Math.Min(int.Parse(match.Groups[1].Value), 65535);
|
||||||
|
int bit = match.Groups[2].Success ?
|
||||||
|
Math.Min(int.Parse(match.Groups[2].Value), 7) : 0;
|
||||||
|
return $"{prefix}{address}.{bit}";
|
||||||
|
}
|
||||||
|
return $"{prefix}0.0"; // Default value if pattern doesn't match
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ApplyLetrasNumerosPattern(string text)
|
||||||
|
{
|
||||||
|
// Extract letters and numbers from the text
|
||||||
|
var letters = new string(text.Where(c => char.IsLetter(c)).Take(10).ToArray());
|
||||||
|
var numbers = new string(text.Where(c => char.IsDigit(c)).ToArray());
|
||||||
|
|
||||||
|
// If no letters found, return "A" as default
|
||||||
|
if (string.IsNullOrEmpty(letters))
|
||||||
|
letters = "A";
|
||||||
|
|
||||||
|
// If no numbers found, return "0" as default
|
||||||
|
if (string.IsNullOrEmpty(numbers))
|
||||||
|
numbers = "0";
|
||||||
|
|
||||||
|
// Combine letters (uppercase) and numbers
|
||||||
|
return $"{letters.ToUpper()}{numbers}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ApplyLetrasNumerosEspaciosPattern(string text)
|
||||||
|
{
|
||||||
|
// Keep only letters, numbers and spaces
|
||||||
|
var cleanedText = new string(text.Where(c => char.IsLetterOrDigit(c) || char.IsWhiteSpace(c)).ToArray());
|
||||||
|
|
||||||
|
// Convert to uppercase
|
||||||
|
return cleanedText.ToUpper();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ApplyNumberPattern(string text)
|
||||||
|
{
|
||||||
|
var match = Regex.Match(text, @"-?\d+\.?\d*");
|
||||||
|
return match.Success ? match.Value : "0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TagPatternItemsSource<T> : IItemsSource
|
||||||
|
{
|
||||||
|
public ItemCollection GetValues()
|
||||||
|
{
|
||||||
|
ItemCollection items = new ItemCollection();
|
||||||
|
foreach (string pattern in TagPattern.GetPatternList())
|
||||||
|
{
|
||||||
|
items.Add(pattern);
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
namespace CtrEditor.FuncionesBase
|
||||||
|
{
|
||||||
|
public enum ZIndexEnum
|
||||||
|
{
|
||||||
|
Decorativos = 1,
|
||||||
|
Estaticos = 2,
|
||||||
|
Generadores = 3,
|
||||||
|
Guias = 4,
|
||||||
|
ExtraccionTag = 5,
|
||||||
|
Dinamicos = 10,
|
||||||
|
Descarte = 11,
|
||||||
|
Fotocelula = 12,
|
||||||
|
Trace = 13,
|
||||||
|
RectangulosPropiead = 14
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"ApiKeys": {
|
||||||
|
"OpenAI": "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",
|
||||||
|
"Groq": "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",
|
||||||
|
"Grok": "xai-yR7J4s9VIchdjdsaIMP3zzZJBPa98pySDbavh6hEosG3eII9OtQhoKsNUofKUsKrvNUIW15N11BD5cEa"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,421 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LanguageDetection;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
|
||||||
|
namespace GTPCorrgir
|
||||||
|
{
|
||||||
|
|
||||||
|
public class Opciones
|
||||||
|
{
|
||||||
|
public enum LLM_a_Usar
|
||||||
|
{
|
||||||
|
OpenAI,
|
||||||
|
Ollama,
|
||||||
|
Groq,
|
||||||
|
Grok
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum modoDeUso
|
||||||
|
{
|
||||||
|
Corregir,
|
||||||
|
Ortografia,
|
||||||
|
Traducir_a_Ingles,
|
||||||
|
Traducir_a_Italiano,
|
||||||
|
Traducir_a_Espanol,
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<LLM_a_Usar, string> nombreLLM = new Dictionary<LLM_a_Usar, string>
|
||||||
|
{
|
||||||
|
{ LLM_a_Usar.Ollama, "Ollama" },
|
||||||
|
{ LLM_a_Usar.Groq, "Groq" },
|
||||||
|
{ LLM_a_Usar.Grok, "Grok" },
|
||||||
|
{ LLM_a_Usar.OpenAI, "OpenAI" },
|
||||||
|
};
|
||||||
|
|
||||||
|
public LLM_a_Usar LLM { get; set; }
|
||||||
|
public modoDeUso modo { get; set; }
|
||||||
|
|
||||||
|
public string nombreDeLLM()
|
||||||
|
{
|
||||||
|
return nombreLLM[LLM];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Opciones() { } // Changed from private to public
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ApiSettings
|
||||||
|
{
|
||||||
|
public class ApiKeySection
|
||||||
|
{
|
||||||
|
public string OpenAI { get; set; }
|
||||||
|
public string Groq { get; set; }
|
||||||
|
public string Grok { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApiKeySection ApiKeys { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class gtpask : IDisposable
|
||||||
|
{
|
||||||
|
private string _openAiApiKey;
|
||||||
|
private string _groqApiKey;
|
||||||
|
private string _grokApiKey;
|
||||||
|
private readonly HttpClient _httpClient;
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
|
public string IdiomaDetectado { get; private set; }
|
||||||
|
public string TextoACorregir { get; set; }
|
||||||
|
public string TextoCorregido { get; private set; }
|
||||||
|
public string TextodeSistema { get; set; }
|
||||||
|
|
||||||
|
public gtpask()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_httpClient = new HttpClient();
|
||||||
|
|
||||||
|
LoadApiKeys();
|
||||||
|
InitializeHttpClient();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new ApplicationException("Failed to initialize gtpask", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadApiKeys()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "IA/appsettings.json");
|
||||||
|
if (!File.Exists(configPath))
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException("Configuration file (appsettings.json) not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
string jsonContent = File.ReadAllText(configPath);
|
||||||
|
var settings = JsonConvert.DeserializeObject<ApiSettings>(jsonContent);
|
||||||
|
|
||||||
|
_openAiApiKey = settings?.ApiKeys?.OpenAI;
|
||||||
|
_groqApiKey = settings?.ApiKeys?.Groq;
|
||||||
|
_grokApiKey = settings?.ApiKeys?.Grok;
|
||||||
|
|
||||||
|
ValidateApiKeys();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new ApplicationException("Failed to load API keys", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValidateApiKeys()
|
||||||
|
{
|
||||||
|
var missingKeys = new List<string>();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(_openAiApiKey)) missingKeys.Add("OpenAI");
|
||||||
|
if (string.IsNullOrEmpty(_groqApiKey)) missingKeys.Add("Groq");
|
||||||
|
if (string.IsNullOrEmpty(_grokApiKey)) missingKeys.Add("Grok");
|
||||||
|
|
||||||
|
if (missingKeys.Any())
|
||||||
|
{
|
||||||
|
string missingKeysStr = string.Join(", ", missingKeys);
|
||||||
|
throw new ApplicationException($"Missing API keys: {missingKeysStr}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeHttpClient()
|
||||||
|
{
|
||||||
|
_httpClient.Timeout = TimeSpan.FromSeconds(30);
|
||||||
|
_httpClient.DefaultRequestHeaders.Clear();
|
||||||
|
_httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool DetectarIdioma()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IdiomaDetectado = Idiomas.DetectarIdioma(TextoACorregir);
|
||||||
|
return IdiomaDetectado != "Unknown";
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ProcesarTextoConLLM( Opciones Modelo)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string respuestaLLM;
|
||||||
|
|
||||||
|
switch (Modelo.LLM)
|
||||||
|
{
|
||||||
|
case Opciones.LLM_a_Usar.OpenAI:
|
||||||
|
respuestaLLM = await CallOpenAiApi();
|
||||||
|
break;
|
||||||
|
case Opciones.LLM_a_Usar.Ollama:
|
||||||
|
respuestaLLM = await CallOllamaApi();
|
||||||
|
break;
|
||||||
|
case Opciones.LLM_a_Usar.Groq:
|
||||||
|
respuestaLLM = await CallGroqAiApi();
|
||||||
|
break;
|
||||||
|
case Opciones.LLM_a_Usar.Grok:
|
||||||
|
respuestaLLM = await CallGrokApi();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentException("LLM no válido");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(respuestaLLM))
|
||||||
|
{
|
||||||
|
throw new ApplicationException("No se recibió respuesta del LLM");
|
||||||
|
}
|
||||||
|
|
||||||
|
TextoCorregido = respuestaLLM;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SimularCorreccion()
|
||||||
|
{
|
||||||
|
await Task.Delay(1000);
|
||||||
|
TextoCorregido = "Texto simulado de prueba";
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> CallGrokApi()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_httpClient.DefaultRequestHeaders.Clear();
|
||||||
|
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_grokApiKey}");
|
||||||
|
|
||||||
|
var requestData = new
|
||||||
|
{
|
||||||
|
messages = new[]
|
||||||
|
{
|
||||||
|
new { role = "system", content = TextodeSistema },
|
||||||
|
new { role = "user", content = TextoACorregir }
|
||||||
|
},
|
||||||
|
model = "grok-beta",
|
||||||
|
stream = false,
|
||||||
|
temperature = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
return await EnviarSolicitudLLM("https://api.x.ai/v1/chat/completions", requestData);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> CallOllamaApi()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var requestData = new
|
||||||
|
{
|
||||||
|
model = "llama3.2:latest",
|
||||||
|
messages = new[]
|
||||||
|
{
|
||||||
|
new { role = "system", content = TextodeSistema },
|
||||||
|
new { role = "user", content = TextoACorregir }
|
||||||
|
},
|
||||||
|
stream = false
|
||||||
|
};
|
||||||
|
|
||||||
|
return await EnviarSolicitudLLM("http://127.0.0.1:11434/api/chat", requestData);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> CallOpenAiApi()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_httpClient.DefaultRequestHeaders.Clear();
|
||||||
|
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_openAiApiKey}");
|
||||||
|
|
||||||
|
var requestData = new
|
||||||
|
{
|
||||||
|
model = "gpt-4o-mini",
|
||||||
|
messages = new[]
|
||||||
|
{
|
||||||
|
new { role = "system", content = TextodeSistema },
|
||||||
|
new { role = "user", content = TextoACorregir }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return await EnviarSolicitudLLM("https://api.openai.com/v1/chat/completions", requestData);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> CallGroqAiApi()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_httpClient.DefaultRequestHeaders.Clear();
|
||||||
|
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_groqApiKey}");
|
||||||
|
|
||||||
|
var requestData = new
|
||||||
|
{
|
||||||
|
model = "llama-3.2-3b-preview",
|
||||||
|
messages = new[]
|
||||||
|
{
|
||||||
|
new { role = "system", content = TextodeSistema },
|
||||||
|
new { role = "user", content = TextoACorregir }
|
||||||
|
},
|
||||||
|
max_tokens = 2048,
|
||||||
|
stream = false
|
||||||
|
};
|
||||||
|
|
||||||
|
return await EnviarSolicitudLLM("https://api.groq.com/openai/v1/chat/completions", requestData);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> EnviarSolicitudLLM(string endpoint, object requestData)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var content = new StringContent(
|
||||||
|
JsonConvert.SerializeObject(requestData),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json"
|
||||||
|
);
|
||||||
|
|
||||||
|
using var response = await _httpClient.PostAsync(endpoint, content);
|
||||||
|
|
||||||
|
var responseContent = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
throw new HttpRequestException(
|
||||||
|
$"Error en la solicitud HTTP: {response.StatusCode} - {responseContent}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = JsonConvert.DeserializeObject<dynamic>(responseContent);
|
||||||
|
|
||||||
|
// Manejar diferentes formatos de respuesta según el LLM
|
||||||
|
if (endpoint.Contains("ollama"))
|
||||||
|
{
|
||||||
|
if (data.done == true && data.message != null)
|
||||||
|
{
|
||||||
|
return data.message.content;
|
||||||
|
}
|
||||||
|
throw new ApplicationException("Formato de respuesta de Ollama inválido");
|
||||||
|
}
|
||||||
|
else // OpenAI, Groq, Grok
|
||||||
|
{
|
||||||
|
if (data.choices != null && data.choices.Count > 0)
|
||||||
|
{
|
||||||
|
return data.choices[0].message.content;
|
||||||
|
}
|
||||||
|
throw new ApplicationException("No se encontró contenido en la respuesta del LLM");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CorregirTexto()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(TextoACorregir))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("TextoACorregir cannot be null or empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(TextodeSistema))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("TextodeSistema cannot be null or empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
var opciones = new Opciones { LLM = Opciones.LLM_a_Usar.Grok };
|
||||||
|
await ProcesarTextoConLLM(opciones);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new LLMException("Error during text correction", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!_disposed)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
_httpClient?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~gtpask()
|
||||||
|
{
|
||||||
|
Dispose(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clase auxiliar para manejar excepciones específicas de la aplicación
|
||||||
|
public class LLMException : Exception
|
||||||
|
{
|
||||||
|
public LLMException(string message) : base(message) { }
|
||||||
|
public LLMException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clase auxiliar para validación
|
||||||
|
public static class Validations
|
||||||
|
{
|
||||||
|
public static void ValidateNotNull(object value, string paramName)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(paramName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ValidateNotNullOrEmpty(string value, string paramName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Value cannot be null or empty", paramName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,147 @@
|
||||||
|
import pandas as pd
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import json
|
||||||
|
import PyLibrary.funciones_comunes as fc
|
||||||
|
from openai import OpenAI
|
||||||
|
from openai_api_key import openai_api_key
|
||||||
|
|
||||||
|
# Definir el logger a nivel de módulo
|
||||||
|
logger = None
|
||||||
|
|
||||||
|
def corregir_texto_batch(text_pairs, logger):
|
||||||
|
"""
|
||||||
|
Corrige errores de OCR en lotes de pares de texto usando GPT-4.
|
||||||
|
Cada par consiste en dos versiones del mismo texto en diferentes idiomas.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text_pairs: Lista de tuplas (texto1, texto2) donde cada texto es una lectura OCR
|
||||||
|
logger: Logger para registrar el proceso
|
||||||
|
"""
|
||||||
|
client = OpenAI(api_key=openai_api_key())
|
||||||
|
|
||||||
|
system_prompt = """You are an OCR correction specialist. For each pair of texts, which are OCR readings of the same text in different languages, analyze and correct any obvious OCR errors.
|
||||||
|
Pay special attention to:
|
||||||
|
- Incorrectly joined words (missing spaces)
|
||||||
|
- Wrong character recognition (0 vs O, 1 vs I, etc.)
|
||||||
|
- Extra or missing characters
|
||||||
|
Return the corrected versions maintaining the general structure and meaning.
|
||||||
|
|
||||||
|
Input format: List of text pairs
|
||||||
|
Expected output format: List of corrected pairs in the same order
|
||||||
|
Example input: [["PULSANTE DI STARTNASTRI", "START PUSHBUTTONTTOP"]]
|
||||||
|
Example output: [["PULSANTE DI START NASTRI", "START PUSH BUTTON TOP"]]"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Convertir los pares de texto a formato JSON
|
||||||
|
request_payload = json.dumps({"pairs": text_pairs})
|
||||||
|
logger.info(f"Solicitando corrección para el lote de textos:\n{request_payload}")
|
||||||
|
|
||||||
|
response = client.chat.completions.create(
|
||||||
|
model="gpt-4",
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": system_prompt},
|
||||||
|
{"role": "user", "content": request_payload},
|
||||||
|
],
|
||||||
|
max_tokens=2000,
|
||||||
|
temperature=0.3,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Procesar la respuesta
|
||||||
|
corrections = json.loads(response.choices[0].message.content)
|
||||||
|
logger.info(f"Correcciones recibidas:\n{corrections}")
|
||||||
|
return corrections["pairs"]
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error en la corrección por lotes: {str(e)}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def procesar_archivo(config, archivo_entrada):
|
||||||
|
"""
|
||||||
|
Procesa el archivo Excel con los textos OCR y genera un nuevo archivo con las correcciones.
|
||||||
|
"""
|
||||||
|
logger.info(f"Iniciando procesamiento de {archivo_entrada}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Leer el archivo de entrada
|
||||||
|
df = fc.read_dataframe_with_cleanup_retries(archivo_entrada)
|
||||||
|
|
||||||
|
if config.columna_origen1 not in df.columns or config.columna_origen2 not in df.columns:
|
||||||
|
logger.error(f"Columnas requeridas no encontradas en el archivo")
|
||||||
|
print(f"Error: Las columnas {config.columna_origen1} y/o {config.columna_origen2} no existen en el archivo")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Filtrar filas donde ambas columnas tienen contenido
|
||||||
|
df_filtered = df.dropna(subset=[config.columna_origen1, config.columna_origen2])
|
||||||
|
df_filtered = df_filtered[
|
||||||
|
(df_filtered[config.columna_origen1].astype(str).str.strip() != '') &
|
||||||
|
(df_filtered[config.columna_origen2].astype(str).str.strip() != '')
|
||||||
|
]
|
||||||
|
|
||||||
|
# Crear columnas para textos corregidos
|
||||||
|
df[f"{config.columna_origen1}_Corregido"] = df[config.columna_origen1]
|
||||||
|
df[f"{config.columna_origen2}_Corregido"] = df[config.columna_origen2]
|
||||||
|
|
||||||
|
# Procesar en lotes de 10 pares
|
||||||
|
batch_size = 10
|
||||||
|
total_rows = len(df_filtered)
|
||||||
|
|
||||||
|
progress_bar = fc.ProgressBar(
|
||||||
|
total_rows, prefix="Procesando textos:", suffix="Completado"
|
||||||
|
)
|
||||||
|
|
||||||
|
for i in range(0, total_rows, batch_size):
|
||||||
|
batch_df = df_filtered.iloc[i:i+batch_size]
|
||||||
|
|
||||||
|
# Preparar pares de textos para el lote
|
||||||
|
text_pairs = [
|
||||||
|
[str(row[config.columna_origen1]).strip(), str(row[config.columna_origen2]).strip()]
|
||||||
|
for _, row in batch_df.iterrows()
|
||||||
|
]
|
||||||
|
|
||||||
|
# Obtener correcciones para el lote
|
||||||
|
corrections = corregir_texto_batch(text_pairs, logger)
|
||||||
|
|
||||||
|
if corrections:
|
||||||
|
# Aplicar correcciones al DataFrame original
|
||||||
|
for j, correction in enumerate(corrections):
|
||||||
|
idx = batch_df.index[j]
|
||||||
|
df.at[idx, f"{config.columna_origen1}_Corregido"] = correction[0]
|
||||||
|
df.at[idx, f"{config.columna_origen2}_Corregido"] = correction[1]
|
||||||
|
|
||||||
|
progress_bar.update(min(i + batch_size, total_rows))
|
||||||
|
|
||||||
|
progress_bar.finish()
|
||||||
|
|
||||||
|
# Guardar resultados
|
||||||
|
output_path = config.get_output_path()
|
||||||
|
fc.save_dataframe_with_retries(df, output_path)
|
||||||
|
|
||||||
|
logger.info(f"Archivo procesado y guardado en: {output_path}")
|
||||||
|
print(f"\nArchivo procesado y guardado en: {output_path}")
|
||||||
|
print(f"Se procesaron {total_rows} pares de texto.")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error durante el procesamiento: {str(e)}")
|
||||||
|
print(f"Error durante el procesamiento: {str(e)}")
|
||||||
|
|
||||||
|
def run(config):
|
||||||
|
global logger
|
||||||
|
logger = fc.configurar_logger(config.work_dir)
|
||||||
|
script_name = os.path.basename(__file__)
|
||||||
|
print(f"\rIniciando: {script_name}\r")
|
||||||
|
|
||||||
|
# Solicitar archivo de entrada
|
||||||
|
from tkinter import filedialog
|
||||||
|
archivo_entrada = filedialog.askopenfilename(
|
||||||
|
title="Seleccione el archivo con textos OCR",
|
||||||
|
filetypes=[("Excel files", "*.xls*")]
|
||||||
|
)
|
||||||
|
|
||||||
|
if archivo_entrada:
|
||||||
|
procesar_archivo(config, archivo_entrada)
|
||||||
|
else:
|
||||||
|
print("No se seleccionó ningún archivo para procesar.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import menu_ocr_correction
|
||||||
|
menu_ocr_correction.main()
|
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 8.4 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 41 KiB |
790
MainViewModel.cs
290
MainWindow.xaml
|
@ -1,42 +1,53 @@
|
||||||
<Window
|
<Window xmlns:ctreditor="clr-namespace:CtrEditor"
|
||||||
xmlns:ctreditor="clr-namespace:CtrEditor"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:Siemens="clr-namespace:CtrEditor.Siemens"
|
xmlns:Siemens="clr-namespace:LibS7Adv;assembly=LibS7Adv"
|
||||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
xmlns:local="clr-namespace:CtrEditor"
|
||||||
xmlns:ObjetosSim="clr-namespace:CtrEditor.ObjetosSim" x:Class="CtrEditor.MainWindow"
|
xmlns:controls="clr-namespace:CtrEditor.Controls"
|
||||||
Height="900" Width="1600" WindowState="Maximized"
|
xmlns:uc="clr-namespace:CtrEditor.ObjetosSim.UserControls"
|
||||||
ResizeMode="CanResize" Title="{Binding directorioTrabajo}" Icon="/app2.png">
|
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||||
|
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||||
|
xmlns:ObjetosSim="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
|
xmlns:ObjetosExtraccion="clr-namespace:CtrEditor.ObjetosSim.Extraccion_Datos"
|
||||||
|
x:Class="CtrEditor.MainWindow"
|
||||||
|
Height="900" Width="1600" WindowState="Maximized" ResizeMode="CanResize" Title="{Binding directorioTrabajo, Converter={StaticResource UnsavedChangesConverter}}"
|
||||||
|
Icon="/app2.png">
|
||||||
|
|
||||||
<Window.DataContext>
|
<Window.DataContext>
|
||||||
<ctreditor:MainViewModel/>
|
<ctreditor:MainViewModel />
|
||||||
</Window.DataContext>
|
</Window.DataContext>
|
||||||
|
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
<convert:FloatToFormattedStringConverter x:Key="floatFormatter"/>
|
|
||||||
<convert:DoubleToFormattedStringConverter x:Key="doubleFormatter"/>
|
|
||||||
<convert:BrushToColorNameConverter x:Key="BrushToColorNameConverter"/>
|
|
||||||
|
|
||||||
<!-- Style for Start/Stop Button -->
|
<!-- Style for Start/Stop Button -->
|
||||||
<Style x:Key="StartStopButtonStyle" TargetType="Button">
|
<Style x:Key="StartStopButtonStyle" TargetType="Button">
|
||||||
<Setter Property="Background" Value="Transparent"/>
|
<Setter Property="Background" Value="Transparent" />
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
<DataTrigger Binding="{Binding IsSimulationRunning}" Value="True">
|
<DataTrigger Binding="{Binding IsSimulationRunning}" Value="True">
|
||||||
<Setter Property="Background" Value="LightGreen"/>
|
<Setter Property="Background" Value="LightGreen" />
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<!-- Style for Connect/Disconnect Button -->
|
<!-- Style for Connect/Disconnect Button -->
|
||||||
<Style x:Key="ConnectDisconnectButtonStyle" TargetType="Button">
|
<Style x:Key="ConnectDisconnectButtonStyle" TargetType="Button">
|
||||||
<Setter Property="Background" Value="Transparent"/>
|
<Setter Property="Background" Value="Transparent" />
|
||||||
|
<Setter Property="Padding" Value="5" />
|
||||||
|
<Setter Property="MinWidth" Value="80" />
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||||
<Setter Property="Background" Value="LightGreen"/>
|
<Setter Property="Background" Value="#90EE90" />
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<!-- Converter for PLC Connect/Disconnect button text -->
|
||||||
|
<local:ConnectStateToBtnTextConverter x:Key="ConnectStateToBtnTextConverter" />
|
||||||
|
|
||||||
|
<!-- Converter for PLC Connect/Disconnect image -->
|
||||||
|
<local:ConnectStateToImageConverter x:Key="ConnectStateToImageConverter" />
|
||||||
|
|
||||||
</Window.Resources>
|
</Window.Resources>
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
|
@ -44,8 +55,17 @@
|
||||||
<Menu VerticalAlignment="Top" HorizontalAlignment="Stretch">
|
<Menu VerticalAlignment="Top" HorizontalAlignment="Stretch">
|
||||||
<MenuItem Header="Projecto">
|
<MenuItem Header="Projecto">
|
||||||
<MenuItem Header="Abrir Directorio de trabajo" Command="{Binding OpenWorkDirectoryCommand}" />
|
<MenuItem Header="Abrir Directorio de trabajo" Command="{Binding OpenWorkDirectoryCommand}" />
|
||||||
|
<MenuItem Header="Ultimos Directorios Utilizados" ItemsSource="{Binding RecentDirectories}">
|
||||||
|
<MenuItem.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<MenuItem Header="{Binding}" Command="{Binding DataContext.OpenRecentDirectoryCommand, RelativeSource={RelativeSource AncestorType=MenuItem, AncestorLevel=2}}"
|
||||||
|
CommandParameter="{Binding}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</MenuItem.ItemTemplate>
|
||||||
|
</MenuItem>
|
||||||
<MenuItem Header="Iniciar Simulacion" Command="{Binding StartSimulationCommand}" />
|
<MenuItem Header="Iniciar Simulacion" Command="{Binding StartSimulationCommand}" />
|
||||||
<MenuItem Header="Detenet Simulacion" Command="{Binding StopSimulationCommand}" />
|
<MenuItem Header="Detenet Simulacion" Command="{Binding StopSimulationCommand}" />
|
||||||
|
<MenuItem Header="Debug Window" Command="{Binding DebugWindowCommand}" />
|
||||||
<MenuItem Header="Guardar" Command="{Binding SaveCommand}" />
|
<MenuItem Header="Guardar" Command="{Binding SaveCommand}" />
|
||||||
<MenuItem Header="Salir" Command="{Binding ExitCommand}" />
|
<MenuItem Header="Salir" Command="{Binding ExitCommand}" />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
@ -54,27 +74,31 @@
|
||||||
<Grid Margin="0,20,0,0">
|
<Grid Margin="0,20,0,0">
|
||||||
<!-- Margen superior para el menú -->
|
<!-- Margen superior para el menú -->
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="1*" MinWidth="100"/>
|
<ColumnDefinition Width="1*" MinWidth="200" />
|
||||||
<ColumnDefinition Width="8*" MinWidth="200"/>
|
<ColumnDefinition Width="8*" MinWidth="200" />
|
||||||
<ColumnDefinition Width="2*" MinWidth="100"/>
|
<ColumnDefinition Width="2*" MinWidth="100" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<!-- Primera Columna -->
|
<!-- Primera Columna -->
|
||||||
<Grid Grid.Column="0">
|
<Grid Grid.Column="0">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="1*"/>
|
<RowDefinition Height="1*" />
|
||||||
<RowDefinition Height="2*"/>
|
<RowDefinition Height="2*" />
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<ListBox x:Name="ListaImagenes" Grid.Row="0" Margin="5" ItemsSource="{Binding ListaImagenes}" SelectedItem="{Binding SelectedImage}" />
|
<ListBox x:Name="ListaImagenes" Grid.Row="0" Margin="5" ItemsSource="{Binding ListaImagenes}"
|
||||||
<ListBox x:Name="ListaFunciones" Grid.Row="1" Margin="5" ItemsSource="{Binding ListaOsBase}" DisplayMemberPath="Nombre" SelectedItem="{Binding SelectedItem}">
|
SelectedItem="{Binding SelectedImage}" />
|
||||||
|
<ListBox x:Name="ListaFunciones" Grid.Row="1" Margin="5" ItemsSource="{Binding ListaOsBase}"
|
||||||
|
DisplayMemberPath="Nombre" SelectedItem="{Binding SelectedItem}">
|
||||||
<i:Interaction.Triggers>
|
<i:Interaction.Triggers>
|
||||||
<i:EventTrigger EventName="MouseDoubleClick">
|
<i:EventTrigger EventName="MouseDoubleClick">
|
||||||
<i:InvokeCommandAction Command="{Binding ItemDoubleClickCommand}" CommandParameter="{Binding SelectedItem}"/>
|
<i:InvokeCommandAction Command="{Binding ItemDoubleClickCommand}"
|
||||||
|
CommandParameter="{Binding SelectedItem}" />
|
||||||
</i:EventTrigger>
|
</i:EventTrigger>
|
||||||
</i:Interaction.Triggers>
|
</i:Interaction.Triggers>
|
||||||
</ListBox>
|
</ListBox>
|
||||||
<Siemens:PLCControl x:Name="PLCSim" Grid.Row="2" Margin="5" DataContext="{Binding PLCViewModel}"/>
|
|
||||||
|
<Siemens:PLCControl x:Name="PLCSim" Grid.Row="2" Margin="5" DataContext="{Binding PLCViewModel}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<!-- GridSplitter -->
|
<!-- GridSplitter -->
|
||||||
<GridSplitter Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right" Width="5" Background="LightGray" />
|
<GridSplitter Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right" Width="5" Background="LightGray" />
|
||||||
|
@ -88,45 +112,100 @@
|
||||||
|
|
||||||
<ToolBarTray Grid.Row="0">
|
<ToolBarTray Grid.Row="0">
|
||||||
<ToolBar>
|
<ToolBar>
|
||||||
<Button Command="{Binding TBStartSimulationCommand}" ToolTip="Iniciar Simulación" Style="{StaticResource StartStopButtonStyle}">
|
<StackPanel Orientation="Horizontal">
|
||||||
<StackPanel>
|
<Button Command="{Binding TBStartSimulationCommand}" ToolTip="Iniciar Simulación"
|
||||||
<Image Source="Icons/start.png" Width="16" Height="16"/>
|
Style="{StaticResource StartStopButtonStyle}">
|
||||||
<TextBlock Text="Iniciar"/>
|
<StackPanel>
|
||||||
</StackPanel>
|
<Image Source="Icons/start.png" Width="24" Height="24" />
|
||||||
</Button>
|
<TextBlock Text="Iniciar" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- Grid para el indicador de Simulación -->
|
||||||
|
<Grid Width="15" Margin="2,0">
|
||||||
|
<TextBlock Text="{Binding SimulationSpeed, StringFormat={}{0:F1}}"
|
||||||
|
RenderTransformOrigin="0.5,0.5" TextAlignment="Center"
|
||||||
|
Background="{DynamicResource {x:Static SystemColors.ActiveCaptionBrushKey}}">
|
||||||
|
<TextBlock.LayoutTransform>
|
||||||
|
<RotateTransform Angle="-90"/>
|
||||||
|
</TextBlock.LayoutTransform>
|
||||||
|
</TextBlock>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
<Button Command="{Binding TBStopSimulationCommand}" ToolTip="Detener Simulación">
|
<Button Command="{Binding TBStopSimulationCommand}" ToolTip="Detener Simulación">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<Image Source="Icons/stop.png" Width="16" Height="16"/>
|
<Image Source="Icons/stop.png" Width="24" Height="24" />
|
||||||
<TextBlock Text="Detener"/>
|
<TextBlock Text="Detener" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Button>
|
</Button>
|
||||||
<Button Command="{Binding TBSaveCommand}" ToolTip="Guardar">
|
<Button Command="{Binding TBSaveCommand}" ToolTip="Guardar">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<Image Source="Icons/save.png" Width="16" Height="16"/>
|
<Image Source="Icons/save.png" Width="24" Height="24" />
|
||||||
<TextBlock Text="Guardar"/>
|
<TextBlock Text="Guardar" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Button>
|
</Button>
|
||||||
<Button Command="{Binding TBConnectPLCCommand}" ToolTip="Conectar PLC" Style="{StaticResource ConnectDisconnectButtonStyle}">
|
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Button Command="{Binding TBTogglePLCConnectionCommand}"
|
||||||
|
ToolTip="{Binding IsConnected, Converter={StaticResource ConnectStateToBtnTextConverter}}"
|
||||||
|
Style="{StaticResource ConnectDisconnectButtonStyle}">
|
||||||
|
<StackPanel>
|
||||||
|
<Image Source="{Binding IsConnected, Converter={StaticResource ConnectStateToImageConverter}}"
|
||||||
|
Width="24" Height="24" />
|
||||||
|
<TextBlock Text="{Binding IsConnected, Converter={StaticResource ConnectStateToBtnTextConverter}}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- Grid para el indicador de PLC -->
|
||||||
|
<Grid Width="15" Margin="2,0">
|
||||||
|
<TextBlock Text="{Binding PlcUpdateSpeed, StringFormat={}{0:F1}}"
|
||||||
|
RenderTransformOrigin="0.5,0.5" TextAlignment="Center"
|
||||||
|
Background="{DynamicResource {x:Static SystemColors.ActiveCaptionBrushKey}}">
|
||||||
|
<TextBlock.LayoutTransform>
|
||||||
|
<RotateTransform Angle="-90"/>
|
||||||
|
</TextBlock.LayoutTransform>
|
||||||
|
</TextBlock>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<Button Command="{Binding TBMultiPageAnalizeCommand}"
|
||||||
|
ToolTip="Analyze Tags in multiple pages.">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<Image Source="Icons/connect.png" Width="16" Height="16"/>
|
<Image Source="Icons/match.png" Width="24" Height="24" />
|
||||||
<TextBlock Text="Conectar"/>
|
<TextBlock Text="Multi Page Analyze" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Button>
|
</Button>
|
||||||
<Button Command="{Binding TBDisconnectPLCCommand}" ToolTip="Desconectar PLC">
|
|
||||||
|
<Button Command="{Binding TBMultiPageMatrixCommand}" ToolTip="Analyze Matrix (Multiple Pages)">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<Image Source="Icons/disconnect.png" Width="16" Height="16"/>
|
<Image Source="Icons/ocr.png" Width="24" Height="24" />
|
||||||
<TextBlock Text="Desconectar"/>
|
<TextBlock Text="Exportar Tags a Excel" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
</ToolBar>
|
</ToolBar>
|
||||||
</ToolBarTray>
|
</ToolBarTray>
|
||||||
|
|
||||||
<ScrollViewer Grid.Row="1" x:Name="ImagenEnTrabajoScrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" PanningMode="Both">
|
<ScrollViewer Grid.Row="1" x:Name="ImagenEnTrabajoScrollViewer"
|
||||||
<Canvas x:Name="ImagenEnTrabajoCanvas" Margin="400">
|
HorizontalScrollBarVisibility="Auto"
|
||||||
<!-- El Margin puede ser ajustado según el espacio adicional que quieras proporcionar -->
|
VerticalScrollBarVisibility="Auto"
|
||||||
<Canvas.LayoutTransform>
|
PanningMode="Both"
|
||||||
<ScaleTransform ScaleX="1" ScaleY="1"/>
|
PreviewKeyDown="ScrollViewer_PreviewKeyDown">
|
||||||
</Canvas.LayoutTransform>
|
<Canvas x:Name="ImagenEnTrabajoCanvas"
|
||||||
|
Margin="0"
|
||||||
|
Background="Transparent"
|
||||||
|
Focusable="True"
|
||||||
|
FocusVisualStyle="{x:Null}"
|
||||||
|
KeyDown="Canvas_KeyDown">
|
||||||
|
<!-- Agregar Background="Transparent" para que capture los eventos del mouse y -->
|
||||||
|
<!-- asegurar que el Canvas reciba los eventos del botón derecho -->
|
||||||
|
<Canvas.RenderTransform>
|
||||||
|
<TransformGroup>
|
||||||
|
<ScaleTransform x:Name="CanvasScaleTransform" ScaleX="1" ScaleY="1" />
|
||||||
|
<TranslateTransform x:Name="CanvasTranslateTransform" />
|
||||||
|
</TransformGroup>
|
||||||
|
</Canvas.RenderTransform>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -137,51 +216,114 @@
|
||||||
<!-- Tercera Columna -->
|
<!-- Tercera Columna -->
|
||||||
<Grid Grid.Column="2">
|
<Grid Grid.Column="2">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="*" />
|
|
||||||
<!-- Altura ajustable para el ListBox -->
|
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<!-- Espacio para el GridSplitter -->
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<!-- Altura ajustable para el PanelEdicion -->
|
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<ToolBarTray Grid.Row="0">
|
||||||
|
<ToolBar>
|
||||||
|
<Button Command="{Binding TBEliminarTodosCommand}" ToolTip="Eliminar Todos">
|
||||||
|
<StackPanel>
|
||||||
|
<Image Source="Icons/borrar.png" Width="16" Height="16" />
|
||||||
|
<TextBlock Text="All Objects" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Button Command="{Binding TBEliminarAutoCreatedCommand}" ToolTip="Eliminar Auto">
|
||||||
|
<StackPanel>
|
||||||
|
<Image Source="Icons/borrar.png" Width="16" Height="16" />
|
||||||
|
<TextBlock Text="Auto Created" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Button Command="{Binding TBEliminarClonedCommand}" ToolTip="Eliminar Cloned for tag Extraction">
|
||||||
|
<StackPanel>
|
||||||
|
<Image Source="Icons/borrar.png" Width="16" Height="16" />
|
||||||
|
<TextBlock Text="Cloned" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Button Command="{Binding TBAssingPagesCommand}" ToolTip="Assing Pages">
|
||||||
|
<StackPanel>
|
||||||
|
<Image Source="Icons/choose.png" Width="16" Height="16" />
|
||||||
|
<TextBlock Text="Assing Pages" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
</ToolBar>
|
||||||
|
</ToolBarTray>
|
||||||
|
<!-- Filter Control -->
|
||||||
|
<Expander Grid.Row="1" Header="Filters" IsExpanded="False">
|
||||||
|
<controls:osVisFilter x:Name="VisFilter" Margin="5"/>
|
||||||
|
</Expander>
|
||||||
|
|
||||||
<!-- ListBox -->
|
<!-- ListBox -->
|
||||||
<ListBox x:Name="ListaOs"
|
<Expander Grid.Row="2" Header="Objects List" IsExpanded="False">
|
||||||
Grid.Row="0"
|
<ListBox x:Name="ListaOs"
|
||||||
Margin="5"
|
Margin="5"
|
||||||
ItemsSource="{Binding ObjetosSimulables}"
|
MinHeight="100"
|
||||||
DisplayMemberPath="Nombre"
|
MaxHeight="300"
|
||||||
SelectedItem="{Binding SelectedItemOsList, Mode=TwoWay}"
|
ItemsSource="{Binding ObjetosSimulables}"
|
||||||
SelectionChanged="ListaOs_SelectionChanged"/>
|
SelectedItem="{Binding SelectedItemOsList, Mode=TwoWay}"
|
||||||
|
SelectionChanged="ListaOs_SelectionChanged">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBlock Text="{Binding Nombre}">
|
||||||
|
<TextBlock.Style>
|
||||||
|
<Style TargetType="TextBlock">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding Path=Enable_On_All_Pages}" Value="True">
|
||||||
|
<Setter Property="Foreground" Value="Blue" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding Path=Enable_On_All_Pages}" Value="False">
|
||||||
|
<Setter Property="Foreground" Value="Black" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding Path=IsVisFilter}" Value="False">
|
||||||
|
<Setter Property="Opacity" Value="0.5" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</TextBlock.Style>
|
||||||
|
</TextBlock>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
</Expander>
|
||||||
|
|
||||||
|
<!-- Object Hierarchy -->
|
||||||
|
<Expander Grid.Row="3" Header="Object Hierarchy" IsExpanded="True">
|
||||||
|
<controls:ObjectHierarchyView x:Name="ObjectHierarchy"
|
||||||
|
Margin="5"
|
||||||
|
MinHeight="100"
|
||||||
|
MaxHeight="300"/>
|
||||||
|
</Expander>
|
||||||
|
|
||||||
<!-- GridSplitter -->
|
<!-- GridSplitter -->
|
||||||
<GridSplitter Grid.Row="1"
|
<GridSplitter Grid.Row="4" Height="5"
|
||||||
Height="5"
|
HorizontalAlignment="Stretch"
|
||||||
HorizontalAlignment="Stretch"
|
Background="Gray"
|
||||||
Background="Gray"
|
ResizeDirection="Rows"
|
||||||
ResizeDirection="Rows"
|
VerticalAlignment="Center" />
|
||||||
VerticalAlignment="Center"/>
|
|
||||||
|
|
||||||
<!-- PanelEdicion -->
|
<!-- PanelEdicion -->
|
||||||
<ScrollViewer Grid.Row="2" Margin="5" VerticalScrollBarVisibility="Auto">
|
<controls:PanelEdicionControl Grid.Row="5"
|
||||||
<StackPanel x:Name="PanelEdicion">
|
x:Name="PanelEdicion"
|
||||||
<!-- Aquí puedes agregar los controles para editar propiedades -->
|
Margin="5"/>
|
||||||
</StackPanel>
|
|
||||||
</ScrollViewer>
|
|
||||||
|
|
||||||
<ToolBarTray Grid.Row="3">
|
<ToolBarTray Grid.Row="6">
|
||||||
<ToolBar>
|
<ToolBar>
|
||||||
<Button Command="{Binding TBEliminarUserControlCommand}" ToolTip="Eliminar Control">
|
<Button Command="{Binding TBEliminarUserControlCommand}" ToolTip="Eliminar Control">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<Image Source="Icons/borrar.png" Width="16" Height="16"/>
|
<Image Source="Icons/borrar.png" Width="16" Height="16" />
|
||||||
<TextBlock Text="Eliminar"/>
|
<TextBlock Text="Eliminar" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Button>
|
</Button>
|
||||||
<Button Command="{Binding TBDuplicarUserControlCommand}" ToolTip="Duplicar Control">
|
<Button Command="{Binding TBDuplicarUserControlCommand}" ToolTip="Duplicar Control">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<Image Source="Icons/duplicate.png" Width="16" Height="16"/>
|
<Image Source="Icons/duplicate.png" Width="16" Height="16" />
|
||||||
<TextBlock Text="Duplicar"/>
|
<TextBlock Text="Duplicar" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Button>
|
</Button>
|
||||||
</ToolBar>
|
</ToolBar>
|
||||||
|
|
|
@ -0,0 +1,268 @@
|
||||||
|
using CtrEditor.ObjetosSim;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace CtrEditor
|
||||||
|
{
|
||||||
|
public class ObjectAlignment
|
||||||
|
{
|
||||||
|
private readonly ObservableCollection<osBase> _selectedObjects;
|
||||||
|
private readonly osBase _referenceObject;
|
||||||
|
|
||||||
|
public ObjectAlignment(ObservableCollection<osBase> selectedObjects, osBase referenceObject = null)
|
||||||
|
{
|
||||||
|
_selectedObjects = selectedObjects;
|
||||||
|
_referenceObject = referenceObject ?? selectedObjects.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AlignLeft()
|
||||||
|
{
|
||||||
|
if (_selectedObjects.Count <= 1) return;
|
||||||
|
|
||||||
|
float leftMost = _selectedObjects.Min(obj => obj.Left);
|
||||||
|
foreach (var obj in _selectedObjects)
|
||||||
|
{
|
||||||
|
obj.Left = leftMost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AlignRight()
|
||||||
|
{
|
||||||
|
if (_selectedObjects.Count <= 1) return;
|
||||||
|
|
||||||
|
float rightMost = _selectedObjects.Max(obj => obj.Left + obj.Ancho);
|
||||||
|
foreach (var obj in _selectedObjects)
|
||||||
|
{
|
||||||
|
obj.Left = rightMost - obj.Ancho;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AlignTop()
|
||||||
|
{
|
||||||
|
if (_selectedObjects.Count <= 1) return;
|
||||||
|
|
||||||
|
float topMost = _selectedObjects.Min(obj => obj.Top);
|
||||||
|
foreach (var obj in _selectedObjects)
|
||||||
|
{
|
||||||
|
obj.Top = topMost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AlignBottom()
|
||||||
|
{
|
||||||
|
if (_selectedObjects.Count <= 1) return;
|
||||||
|
|
||||||
|
float bottomMost = _selectedObjects.Max(obj => obj.Top + obj.Alto);
|
||||||
|
foreach (var obj in _selectedObjects)
|
||||||
|
{
|
||||||
|
obj.Top = bottomMost - obj.Alto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AlignCenterHorizontally()
|
||||||
|
{
|
||||||
|
if (_selectedObjects.Count <= 1) return;
|
||||||
|
|
||||||
|
float averageY = _selectedObjects.Average(obj => obj.Top + obj.Alto / 2);
|
||||||
|
foreach (var obj in _selectedObjects)
|
||||||
|
{
|
||||||
|
obj.Top = averageY - obj.Alto / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AlignCenterVertically()
|
||||||
|
{
|
||||||
|
if (_selectedObjects.Count <= 1) return;
|
||||||
|
|
||||||
|
float averageX = _selectedObjects.Average(obj => obj.Left + obj.Ancho / 2);
|
||||||
|
foreach (var obj in _selectedObjects)
|
||||||
|
{
|
||||||
|
obj.Left = averageX - obj.Ancho / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DistributeHorizontally()
|
||||||
|
{
|
||||||
|
if (_selectedObjects.Count <= 2) return;
|
||||||
|
|
||||||
|
var objectsWithCenters = _selectedObjects
|
||||||
|
.Select(obj => new
|
||||||
|
{
|
||||||
|
Object = obj,
|
||||||
|
Center = GetObjectCenter(obj),
|
||||||
|
Dimensions = GetEffectiveDimensions(obj)
|
||||||
|
})
|
||||||
|
.OrderBy(x => x.Center.X)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
float leftMost = (float)objectsWithCenters.First().Center.X;
|
||||||
|
float rightMost = (float)objectsWithCenters.Last().Center.X;
|
||||||
|
float totalDistance = rightMost - leftMost;
|
||||||
|
float spacing = totalDistance / (_selectedObjects.Count - 1);
|
||||||
|
|
||||||
|
for (int i = 1; i < objectsWithCenters.Count - 1; i++)
|
||||||
|
{
|
||||||
|
var obj = objectsWithCenters[i];
|
||||||
|
var targetX = leftMost + (spacing * i);
|
||||||
|
float deltaX = (float)(targetX - obj.Center.X);
|
||||||
|
obj.Object.Left += deltaX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DistributeVertically()
|
||||||
|
{
|
||||||
|
if (_selectedObjects.Count <= 2) return;
|
||||||
|
|
||||||
|
var objectsWithCenters = _selectedObjects
|
||||||
|
.Select(obj => new
|
||||||
|
{
|
||||||
|
Object = obj,
|
||||||
|
Center = GetObjectCenter(obj),
|
||||||
|
Dimensions = GetEffectiveDimensions(obj)
|
||||||
|
})
|
||||||
|
.OrderBy(x => x.Center.Y)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
float topMost = (float)objectsWithCenters.First().Center.Y;
|
||||||
|
float bottomMost = (float)objectsWithCenters.Last().Center.Y;
|
||||||
|
float totalDistance = bottomMost - topMost;
|
||||||
|
float spacing = totalDistance / (_selectedObjects.Count - 1);
|
||||||
|
|
||||||
|
for (int i = 1; i < objectsWithCenters.Count - 1; i++)
|
||||||
|
{
|
||||||
|
var obj = objectsWithCenters[i];
|
||||||
|
var targetY = topMost + (spacing * i);
|
||||||
|
float deltaY = (float)(targetY - obj.Center.Y);
|
||||||
|
obj.Object.Top += deltaY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EqualWidth()
|
||||||
|
{
|
||||||
|
if (_selectedObjects.Count <= 1) return;
|
||||||
|
|
||||||
|
float referenceWidth = GetEffectiveDimensions(_referenceObject).Width;
|
||||||
|
foreach (var obj in _selectedObjects.Where(o => o != _referenceObject))
|
||||||
|
{
|
||||||
|
var currentDims = GetEffectiveDimensions(obj);
|
||||||
|
SetEffectiveDimensions(obj, referenceWidth, currentDims.Height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EqualHeight()
|
||||||
|
{
|
||||||
|
if (_selectedObjects.Count <= 1) return;
|
||||||
|
|
||||||
|
float referenceHeight = GetEffectiveDimensions(_referenceObject).Height;
|
||||||
|
foreach (var obj in _selectedObjects.Where(o => o != _referenceObject))
|
||||||
|
{
|
||||||
|
var currentDims = GetEffectiveDimensions(obj);
|
||||||
|
SetEffectiveDimensions(obj, currentDims.Width, referenceHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EqualAngle()
|
||||||
|
{
|
||||||
|
if (_selectedObjects.Count <= 1) return;
|
||||||
|
|
||||||
|
float referenceAngle = _referenceObject.Angulo;
|
||||||
|
foreach (var obj in _selectedObjects.Where(o => o != _referenceObject))
|
||||||
|
{
|
||||||
|
obj.Angulo = referenceAngle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void JoinHorizontally()
|
||||||
|
{
|
||||||
|
if (_selectedObjects.Count <= 1) return;
|
||||||
|
|
||||||
|
var sortedObjects = _selectedObjects
|
||||||
|
.OrderBy(obj => GetObjectCenter(obj).X)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
for (int i = 1; i < sortedObjects.Count; i++)
|
||||||
|
{
|
||||||
|
var previousObj = sortedObjects[i - 1];
|
||||||
|
var currentObj = sortedObjects[i];
|
||||||
|
var previousCenter = GetObjectCenter(previousObj);
|
||||||
|
var currentCenter = GetObjectCenter(currentObj);
|
||||||
|
var previousDims = GetEffectiveDimensions(previousObj);
|
||||||
|
|
||||||
|
float offset = previousDims.Width / 2;
|
||||||
|
float newX = (float)(previousCenter.X + offset);
|
||||||
|
float deltaX = (float)(newX - (currentCenter.X - GetEffectiveDimensions(currentObj).Width / 2));
|
||||||
|
currentObj.Left += deltaX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void JoinVertically()
|
||||||
|
{
|
||||||
|
if (_selectedObjects.Count <= 1) return;
|
||||||
|
|
||||||
|
var sortedObjects = _selectedObjects
|
||||||
|
.OrderBy(obj => GetObjectCenter(obj).Y)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
for (int i = 1; i < sortedObjects.Count; i++)
|
||||||
|
{
|
||||||
|
var previousObj = sortedObjects[i - 1];
|
||||||
|
var currentObj = sortedObjects[i];
|
||||||
|
var previousCenter = GetObjectCenter(previousObj);
|
||||||
|
var currentCenter = GetObjectCenter(currentObj);
|
||||||
|
var previousDims = GetEffectiveDimensions(previousObj);
|
||||||
|
|
||||||
|
float offset = previousDims.Height / 2;
|
||||||
|
float newY = (float)(previousCenter.Y + offset);
|
||||||
|
float deltaY = (float)(newY - (currentCenter.Y - GetEffectiveDimensions(currentObj).Height / 2));
|
||||||
|
currentObj.Top += deltaY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point GetObjectCenter(osBase obj)
|
||||||
|
{
|
||||||
|
double angleRad = obj.Angulo * Math.PI / 180.0;
|
||||||
|
float centerX = obj.Left + (obj.Ancho / 2);
|
||||||
|
float centerY = obj.Top + (obj.Alto / 2);
|
||||||
|
|
||||||
|
if (obj.Angulo != 0)
|
||||||
|
{
|
||||||
|
var rotatedX = obj.Left + (Math.Cos(angleRad) * obj.Ancho / 2 - Math.Sin(angleRad) * obj.Alto / 2);
|
||||||
|
var rotatedY = obj.Top + (Math.Sin(angleRad) * obj.Ancho / 2 + Math.Cos(angleRad) * obj.Alto / 2);
|
||||||
|
|
||||||
|
return new Point(rotatedX, rotatedY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Point(centerX, centerY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsObjectVertical(osBase obj)
|
||||||
|
{
|
||||||
|
double normalizedAngle = obj.Angulo % 180;
|
||||||
|
if (normalizedAngle < 0) normalizedAngle += 180;
|
||||||
|
return normalizedAngle >= 45 && normalizedAngle < 135;
|
||||||
|
}
|
||||||
|
|
||||||
|
private (float Width, float Height) GetEffectiveDimensions(osBase obj)
|
||||||
|
{
|
||||||
|
if (IsObjectVertical(obj))
|
||||||
|
{
|
||||||
|
return (obj.Alto, obj.Ancho);
|
||||||
|
}
|
||||||
|
return (obj.Ancho, obj.Alto);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetEffectiveDimensions(osBase obj, float width, float height)
|
||||||
|
{
|
||||||
|
if (IsObjectVertical(obj))
|
||||||
|
{
|
||||||
|
obj.Alto = width;
|
||||||
|
obj.Ancho = height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
obj.Ancho = width;
|
||||||
|
obj.Alto = height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,985 @@
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
using CtrEditor.ObjetosSim;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
using Color = System.Windows.Media.Color;
|
||||||
|
|
||||||
|
namespace CtrEditor
|
||||||
|
{
|
||||||
|
public enum AlignmentType
|
||||||
|
{
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Top,
|
||||||
|
Bottom,
|
||||||
|
CenterHorizontally,
|
||||||
|
CenterVertically,
|
||||||
|
DistributeHorizontally,
|
||||||
|
DistributeVertically,
|
||||||
|
EqualWidth,
|
||||||
|
EqualHeight,
|
||||||
|
EqualAngle,
|
||||||
|
JoinHorizontally,
|
||||||
|
JoinVertically
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ObjectManipulationManager
|
||||||
|
{
|
||||||
|
private enum ResizeMode
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Move,
|
||||||
|
Rotate,
|
||||||
|
ResizeWidth,
|
||||||
|
ResizeHeight,
|
||||||
|
ResizeBoth
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum HandleMode
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Move,
|
||||||
|
ResizeWidth,
|
||||||
|
ResizeHeight,
|
||||||
|
ResizeBoth,
|
||||||
|
Rotate
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResizeMode _currentResizeMode;
|
||||||
|
private readonly MainWindow _mainWindow;
|
||||||
|
private readonly Canvas _canvas;
|
||||||
|
private Point _lastMousePosition;
|
||||||
|
private bool _isDrawingCanvas = false;
|
||||||
|
private bool _isDraggingUserControl = false;
|
||||||
|
private bool _isMovingUserControl = false;
|
||||||
|
private UserControl _currentDraggingControl;
|
||||||
|
private Point _startPointUserControl;
|
||||||
|
private Point _transformedBoundingBoxCenter;
|
||||||
|
private float _lastAngle;
|
||||||
|
private List<Rectangle> _resizeRectangles = new List<Rectangle>();
|
||||||
|
private List<Rectangle> _highlightRectangles = new List<Rectangle>();
|
||||||
|
private System.Threading.Timer _timerRemoveHighlight = null;
|
||||||
|
private Rectangle _currentDraggingRectangle;
|
||||||
|
private dataDebug _dataDebug = new dataDebug();
|
||||||
|
private ObservableCollection<osBase> _selectedObjects = new ObservableCollection<osBase>();
|
||||||
|
private List<Rectangle> _selectionHighlightRectangles = new List<Rectangle>(); // Add this line
|
||||||
|
private List<(UserControl Control, Rectangle Highlight)> _selectionHighlightPairs = new List<(UserControl, Rectangle)>();
|
||||||
|
private Point _rectangleStart;
|
||||||
|
public Rectangle _selectionRectangle; // Cambiado a private
|
||||||
|
private ScrollViewer _scrollViewer; // Add this line
|
||||||
|
private Image _backgroundImage; // Add this line
|
||||||
|
internal bool IsDraggingCanvas { get; set; }
|
||||||
|
private bool _isRectangleSelectionActive;
|
||||||
|
public bool IsRectangleSelectionActive
|
||||||
|
{
|
||||||
|
get => _isRectangleSelectionActive;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_isRectangleSelectionActive = value;
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
// Al activar la selección por rectángulo, desactivar el panning
|
||||||
|
IsDraggingCanvas = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Propiedad pública para verificar si hay un rectángulo de selección activo
|
||||||
|
public bool HasActiveSelectionRectangle => _selectionRectangle != null;
|
||||||
|
|
||||||
|
public ObjectManipulationManager(MainWindow mainWindow, Canvas canvas)
|
||||||
|
{
|
||||||
|
_mainWindow = mainWindow;
|
||||||
|
_canvas = canvas;
|
||||||
|
_scrollViewer = mainWindow.ImagenEnTrabajoScrollViewer; // Add this line
|
||||||
|
_backgroundImage = mainWindow.ImagenDeFondo; // Add this line
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PurgeDeletedObjects()
|
||||||
|
{
|
||||||
|
var deletedObjects = _selectedObjects.Where(obj =>
|
||||||
|
obj.VisualRepresentation == null ||
|
||||||
|
!_canvas.Children.Contains(obj.VisualRepresentation)).ToList();
|
||||||
|
|
||||||
|
foreach (var obj in deletedObjects)
|
||||||
|
{
|
||||||
|
DeselectObject(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableCollection<osBase> SelectedObjects
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
PurgeDeletedObjects();
|
||||||
|
return _selectedObjects;
|
||||||
|
}
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
_selectedObjects = value;
|
||||||
|
UpdateSelectionVisuals();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateSelectionVisuals()
|
||||||
|
{
|
||||||
|
PurgeDeletedObjects();
|
||||||
|
// Asegurarse de que el canvas haya actualizado su layout
|
||||||
|
_canvas.UpdateLayout();
|
||||||
|
|
||||||
|
RemoveResizeRectangles();
|
||||||
|
if (_selectedObjects.Any())
|
||||||
|
{
|
||||||
|
// Verificar si la simulación está activa
|
||||||
|
if (_mainWindow.DataContext is MainViewModel viewModel && !viewModel.IsSimulationRunning)
|
||||||
|
{
|
||||||
|
AddResizeRectangles(_selectedObjects);
|
||||||
|
UpdateSelectionHighlights();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SuscribirEventos(UserControl userControl)
|
||||||
|
{
|
||||||
|
userControl.MouseEnter += UserControl_MouseEnter;
|
||||||
|
userControl.MouseLeave += UserControl_MouseLeave;
|
||||||
|
userControl.Cursor = Cursors.Hand;
|
||||||
|
|
||||||
|
userControl.MouseLeftButtonDown += UserControl_MouseLeftButtonDown;
|
||||||
|
userControl.MouseLeftButtonUp += UserControl_MouseLeftButtonUp;
|
||||||
|
userControl.MouseMove += UserControl_MouseMove;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UserControl_MouseEnter(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is UserControl userControl && userControl is IDataContainer dataContainer)
|
||||||
|
{
|
||||||
|
dataContainer.Highlight(true);
|
||||||
|
|
||||||
|
if (_mainWindow.DataContext is MainViewModel viewModel)
|
||||||
|
{
|
||||||
|
var selectedObject = viewModel.SelectedItemOsList;
|
||||||
|
|
||||||
|
if (selectedObject?.VisualRepresentation != userControl)
|
||||||
|
{
|
||||||
|
AddHighlightRectangles(userControl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UserControl_MouseLeave(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is UserControl userControl && userControl is IDataContainer dataContainer)
|
||||||
|
dataContainer.Highlight(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddResizeRectangles(IEnumerable<osBase> selectedObjects)
|
||||||
|
{
|
||||||
|
double rectHighlightSize = 1;
|
||||||
|
RemoveResizeRectangles();
|
||||||
|
|
||||||
|
// Calcular el bounding box que contenga todos los objetos seleccionados
|
||||||
|
Rect boundingBox = CalculateTotalBoundingBox(selectedObjects);
|
||||||
|
|
||||||
|
FuncionesBase.MutableRect rectBox = new FuncionesBase.MutableRect(boundingBox);
|
||||||
|
rectBox.Left -= (float)rectHighlightSize;
|
||||||
|
rectBox.Right += (float)rectHighlightSize;
|
||||||
|
rectBox.Top -= (float)rectHighlightSize;
|
||||||
|
rectBox.Bottom += (float)rectHighlightSize;
|
||||||
|
|
||||||
|
_transformedBoundingBoxCenter = new Point(
|
||||||
|
boundingBox.Left + boundingBox.Width / 2,
|
||||||
|
boundingBox.Top + boundingBox.Height / 2
|
||||||
|
);
|
||||||
|
|
||||||
|
// Selection rectangle
|
||||||
|
Rectangle selectionRect = CreateSelectionRectangle(rectBox, rectHighlightSize);
|
||||||
|
_resizeRectangles.Add(selectionRect);
|
||||||
|
_canvas.Children.Add(selectionRect);
|
||||||
|
|
||||||
|
// Load rotation cursors
|
||||||
|
Cursor rotationCursorRx = new Cursor(Application.GetResourceStream(
|
||||||
|
new Uri("pack://application:,,,/CtrEditor;component/Icons/rotationRx.cur")).Stream);
|
||||||
|
Cursor rotationCursorSx = new Cursor(Application.GetResourceStream(
|
||||||
|
new Uri("pack://application:,,,/CtrEditor;component/Icons/rotationSx.cur")).Stream);
|
||||||
|
|
||||||
|
// Add resize/rotation handles
|
||||||
|
AddResizeHandles(rectBox, 10, rotationCursorRx, rotationCursorSx);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rect CalculateTotalBoundingBox(IEnumerable<osBase> selectedObjects)
|
||||||
|
{
|
||||||
|
double left = double.MaxValue;
|
||||||
|
double top = double.MaxValue;
|
||||||
|
double right = double.MinValue;
|
||||||
|
double bottom = double.MinValue;
|
||||||
|
|
||||||
|
foreach (var obj in selectedObjects)
|
||||||
|
{
|
||||||
|
if (obj.VisualRepresentation != null)
|
||||||
|
{
|
||||||
|
// Obtener el bounding box del objeto actual
|
||||||
|
Rect objectBounds = VisualTreeHelper.GetDescendantBounds(obj.VisualRepresentation);
|
||||||
|
GeneralTransform transform = obj.VisualRepresentation.TransformToAncestor(_canvas);
|
||||||
|
Rect transformedBounds = transform.TransformBounds(objectBounds);
|
||||||
|
|
||||||
|
// Actualizar los límites del bounding box total
|
||||||
|
left = Math.Min(left, transformedBounds.Left);
|
||||||
|
top = Math.Min(top, transformedBounds.Top);
|
||||||
|
right = Math.Max(right, transformedBounds.Right);
|
||||||
|
bottom = Math.Max(bottom, transformedBounds.Bottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Rect(
|
||||||
|
new Point(left, top),
|
||||||
|
new Point(right, bottom)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rectangle CreateSelectionRectangle(FuncionesBase.MutableRect rectBox, double rectHighlightSize)
|
||||||
|
{
|
||||||
|
if (double.IsInfinity(rectBox.Width) || double.IsInfinity(rectBox.Height) ||
|
||||||
|
double.IsNaN(rectBox.Width) || double.IsNaN(rectBox.Height))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Invalid dimensions for selection rectangle.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var rect = new Rectangle
|
||||||
|
{
|
||||||
|
Width = rectBox.Width + (rectHighlightSize * 2),
|
||||||
|
Height = rectBox.Height + (rectHighlightSize * 2),
|
||||||
|
Fill = Brushes.Transparent,
|
||||||
|
Stroke = new SolidColorBrush(Color.FromArgb(180, 0, 120, 215)),
|
||||||
|
StrokeThickness = 1.5,
|
||||||
|
Tag = "Selection",
|
||||||
|
IsHitTestVisible = false,
|
||||||
|
StrokeDashArray = new DoubleCollection(new double[] { 3, 3 })
|
||||||
|
};
|
||||||
|
|
||||||
|
Canvas.SetLeft(rect, rectBox.Left - rectHighlightSize);
|
||||||
|
Canvas.SetTop(rect, rectBox.Top - rectHighlightSize);
|
||||||
|
Canvas.SetZIndex(rect, ((int)ZIndexEnum.RectangulosPropiead - 1));
|
||||||
|
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void AddResizeHandles(FuncionesBase.MutableRect rectBox, double defaultRectSize,
|
||||||
|
Cursor rotationCursorRx, Cursor rotationCursorSx)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Calcular el tamaño apropiado para los manejadores basado en el tamaño del objeto
|
||||||
|
double minObjectDimension = Math.Min(rectBox.Width, rectBox.Height);
|
||||||
|
double rectSize = Math.Min(defaultRectSize, minObjectDimension / 3);
|
||||||
|
|
||||||
|
// Asegurar un tamaño mínimo para los manejadores
|
||||||
|
rectSize = Math.Max(rectSize, 6);
|
||||||
|
|
||||||
|
// Calcular el offset para posicionar los manejadores fuera del rectángulo
|
||||||
|
double offset = rectSize / 2;
|
||||||
|
|
||||||
|
var positions = new List<(Point Position, string Tag, Cursor Cursor, Brush Stroke)>
|
||||||
|
{
|
||||||
|
// Esquinas - mover hacia afuera del rectángulo
|
||||||
|
(new Point(rectBox.Left - offset, rectBox.Top - offset), "TopLeft", Cursors.Arrow, Brushes.Gray),
|
||||||
|
(new Point(rectBox.Right + offset, rectBox.Top - offset), "TopRight", rotationCursorRx, Brushes.Red),
|
||||||
|
(new Point(rectBox.Left - offset, rectBox.Bottom + offset), "BottomLeft", rotationCursorSx, Brushes.DarkRed),
|
||||||
|
(new Point(rectBox.Right + offset, rectBox.Bottom + offset), "BottomRight", Cursors.SizeNWSE, Brushes.Blue),
|
||||||
|
|
||||||
|
// Centros de los bordes - mover hacia afuera del rectángulo
|
||||||
|
(new Point(rectBox.Left + rectBox.Width / 2, rectBox.Top - offset), "TopCenter", Cursors.Arrow, Brushes.Gray),
|
||||||
|
(new Point(rectBox.Left + rectBox.Width / 2, rectBox.Bottom + offset), "BottomCenter", Cursors.SizeNS, Brushes.Blue),
|
||||||
|
(new Point(rectBox.Left - offset, rectBox.Top + rectBox.Height / 2), "CenterLeft", rotationCursorRx, Brushes.Red),
|
||||||
|
(new Point(rectBox.Right + offset, rectBox.Top + rectBox.Height / 2), "CenterRight", Cursors.SizeWE, Brushes.Blue)
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var (Position, Tag, Cursor, Stroke) in positions)
|
||||||
|
{
|
||||||
|
var handle = CreateResizeHandle(rectSize, Tag, Cursor, Stroke);
|
||||||
|
SetHandlePosition(handle, Position, rectSize);
|
||||||
|
_resizeRectangles.Add(handle);
|
||||||
|
_canvas.Children.Add(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rectangle CreateResizeHandle(double rectSize, string tag, Cursor cursor, Brush stroke)
|
||||||
|
{
|
||||||
|
var handle = new Rectangle
|
||||||
|
{
|
||||||
|
Width = rectSize,
|
||||||
|
Height = rectSize,
|
||||||
|
Fill = Brushes.Transparent,
|
||||||
|
Stroke = stroke,
|
||||||
|
StrokeThickness = 1,
|
||||||
|
Tag = tag,
|
||||||
|
Cursor = cursor
|
||||||
|
};
|
||||||
|
|
||||||
|
handle.MouseLeftButtonDown += UserControl_MouseLeftButtonDown;
|
||||||
|
handle.MouseMove += UserControl_MouseMove;
|
||||||
|
handle.MouseLeftButtonUp += UserControl_MouseLeftButtonUp;
|
||||||
|
handle.MouseLeave += ResizeRectangle_MouseLeave;
|
||||||
|
|
||||||
|
Canvas.SetZIndex(handle, (int)ZIndexEnum.RectangulosPropiead);
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetHandlePosition(Rectangle handle, Point position, double rectSize)
|
||||||
|
{
|
||||||
|
if (!double.IsInfinity(position.X) && !double.IsNaN(position.X))
|
||||||
|
Canvas.SetLeft(handle, position.X - rectSize / 2);
|
||||||
|
if (!double.IsInfinity(position.Y) && !double.IsNaN(position.Y))
|
||||||
|
Canvas.SetTop(handle, position.Y - rectSize / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveResizeRectangles()
|
||||||
|
{
|
||||||
|
if (_resizeRectangles == null || _resizeRectangles.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var rect in _resizeRectangles)
|
||||||
|
{
|
||||||
|
_canvas.Children.Remove(rect);
|
||||||
|
}
|
||||||
|
_resizeRectangles.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MakeResizeRectanglesTransparent()
|
||||||
|
{
|
||||||
|
if (_resizeRectangles == null || _resizeRectangles.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var rect in _resizeRectangles)
|
||||||
|
{
|
||||||
|
rect.Opacity = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MakeResizeRectanglesNormal()
|
||||||
|
{
|
||||||
|
if (_resizeRectangles == null || _resizeRectangles.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var rect in _resizeRectangles)
|
||||||
|
{
|
||||||
|
rect.Opacity = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleObjectSelection(UserControl userControl, osBase datos)
|
||||||
|
{
|
||||||
|
|
||||||
|
PurgeDeletedObjects();
|
||||||
|
var viewModel = _mainWindow.DataContext as MainViewModel;
|
||||||
|
if (viewModel == null) return;
|
||||||
|
|
||||||
|
bool isControlPressed = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
|
||||||
|
|
||||||
|
if (viewModel.IsMultiSelectionActive)
|
||||||
|
{
|
||||||
|
if (isControlPressed)
|
||||||
|
{
|
||||||
|
// Deseleccionar objeto si está presionada la tecla Ctrl
|
||||||
|
if (_selectedObjects.Contains(datos))
|
||||||
|
{
|
||||||
|
DeselectObject(datos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!_selectedObjects.Contains(datos))
|
||||||
|
{
|
||||||
|
// Seleccionar objeto si no está ya seleccionado
|
||||||
|
SelectObject(datos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Modo selección única
|
||||||
|
ClearSelection();
|
||||||
|
SelectObject(datos);
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.SelectedItemOsList = datos;
|
||||||
|
UpdateSelectionVisuals();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SelectObject(osBase obj)
|
||||||
|
{
|
||||||
|
if (_mainWindow.DataContext is MainViewModel vm)
|
||||||
|
{
|
||||||
|
// Add new object if not already selected
|
||||||
|
if (!_selectedObjects.Contains(obj))
|
||||||
|
{
|
||||||
|
// If not in multi-selection mode, clear existing selection first
|
||||||
|
if (!vm.IsMultiSelectionActive)
|
||||||
|
ClearSelection();
|
||||||
|
|
||||||
|
_selectedObjects.Add(obj);
|
||||||
|
obj.IsSelected = true;
|
||||||
|
|
||||||
|
// Add highlight visual only if in multi-selection mode
|
||||||
|
if (vm.IsMultiSelectionActive)
|
||||||
|
{
|
||||||
|
AddSelectionHighlight(obj.VisualRepresentation);
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateSelectionVisuals();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeselectObject(osBase obj)
|
||||||
|
{
|
||||||
|
if (_selectedObjects.Contains(obj))
|
||||||
|
{
|
||||||
|
_selectedObjects.Remove(obj);
|
||||||
|
obj.IsSelected = false;
|
||||||
|
RemoveSelectionHighlight(obj.VisualRepresentation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearSelection()
|
||||||
|
{
|
||||||
|
foreach (var obj in _selectedObjects.ToList())
|
||||||
|
{
|
||||||
|
DeselectObject(obj);
|
||||||
|
}
|
||||||
|
RemoveAllSelectionHighlights();
|
||||||
|
RemoveResizeRectangles();
|
||||||
|
|
||||||
|
if (_mainWindow.DataContext is MainViewModel viewModel)
|
||||||
|
{
|
||||||
|
viewModel.SelectedItemOsList = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnMultiSelectionModeChanged(bool isActive)
|
||||||
|
{
|
||||||
|
if (!isActive)
|
||||||
|
{
|
||||||
|
// Mantener solo el último objeto seleccionado
|
||||||
|
if (_selectedObjects.Count > 1)
|
||||||
|
{
|
||||||
|
var lastSelected = _selectedObjects.Last();
|
||||||
|
ClearSelection();
|
||||||
|
SelectObject(lastSelected);
|
||||||
|
}
|
||||||
|
RemoveAllSelectionHighlights();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateAllSelectionHighlights();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddSelectionHighlight(UserControl userControl, bool isReference = false)
|
||||||
|
{
|
||||||
|
if (userControl == null) return;
|
||||||
|
|
||||||
|
RemoveSelectionHighlight(userControl);
|
||||||
|
|
||||||
|
Rect boundingBox = VisualTreeHelper.GetDescendantBounds(userControl);
|
||||||
|
GeneralTransform transform = userControl.TransformToAncestor(_canvas);
|
||||||
|
Rect transformedBoundingBox = transform.TransformBounds(boundingBox);
|
||||||
|
|
||||||
|
Rectangle highlightRect = new Rectangle
|
||||||
|
{
|
||||||
|
Width = transformedBoundingBox.Width,
|
||||||
|
Height = transformedBoundingBox.Height,
|
||||||
|
Fill = Brushes.Transparent,
|
||||||
|
Stroke = new SolidColorBrush(isReference ?
|
||||||
|
Color.FromArgb(180, 128, 0, 128) : // Purple for reference
|
||||||
|
Color.FromArgb(180, 255, 0, 0)), // Red for others
|
||||||
|
StrokeThickness = isReference ? 3 : 2, // Más grueso para el de referencia
|
||||||
|
Tag = "SelectionHighlight",
|
||||||
|
IsHitTestVisible = false
|
||||||
|
};
|
||||||
|
|
||||||
|
Canvas.SetLeft(highlightRect, transformedBoundingBox.Left);
|
||||||
|
Canvas.SetTop(highlightRect, transformedBoundingBox.Top);
|
||||||
|
Canvas.SetZIndex(highlightRect, (int)ZIndexEnum.RectangulosPropiead - 1);
|
||||||
|
|
||||||
|
_selectionHighlightPairs.Add((userControl, highlightRect));
|
||||||
|
_canvas.Children.Add(highlightRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveSelectionHighlight(UserControl userControl)
|
||||||
|
{
|
||||||
|
var pairsToRemove = _selectionHighlightPairs.Where(p => p.Control == userControl).ToList();
|
||||||
|
foreach (var pair in pairsToRemove)
|
||||||
|
{
|
||||||
|
_canvas.Children.Remove(pair.Highlight);
|
||||||
|
_selectionHighlightPairs.Remove(pair);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAllSelectionHighlights()
|
||||||
|
{
|
||||||
|
foreach (var pair in _selectionHighlightPairs)
|
||||||
|
{
|
||||||
|
_canvas.Children.Remove(pair.Highlight);
|
||||||
|
}
|
||||||
|
_selectionHighlightPairs.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateAllSelectionHighlights()
|
||||||
|
{
|
||||||
|
if (_mainWindow.DataContext is MainViewModel viewModel && viewModel.IsMultiSelectionActive)
|
||||||
|
{
|
||||||
|
RemoveAllSelectionHighlights();
|
||||||
|
bool isFirst = true;
|
||||||
|
foreach (var selectedObject in _selectedObjects)
|
||||||
|
{
|
||||||
|
if (selectedObject.VisualRepresentation != null)
|
||||||
|
{
|
||||||
|
AddSelectionHighlight(selectedObject.VisualRepresentation, isFirst);
|
||||||
|
isFirst = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateSelectionHighlights()
|
||||||
|
{
|
||||||
|
UpdateAllSelectionHighlights();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UserControl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
if (!_isDrawingCanvas)
|
||||||
|
{
|
||||||
|
if (_resizeRectangles != null && _resizeRectangles.Contains(sender))
|
||||||
|
{
|
||||||
|
_currentDraggingRectangle = sender as Rectangle;
|
||||||
|
_lastMousePosition = e.GetPosition(_canvas);
|
||||||
|
_currentDraggingRectangle.CaptureMouse();
|
||||||
|
_isMovingUserControl = true;
|
||||||
|
_startPointUserControl = e.GetPosition(_canvas);
|
||||||
|
e.Handled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var userControl = sender as UserControl;
|
||||||
|
if (userControl != null)
|
||||||
|
{
|
||||||
|
if (userControl.DataContext is osBase datos)
|
||||||
|
{
|
||||||
|
HandleObjectSelection(userControl, datos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Solo iniciar el arrastre si no se presionó Ctrl
|
||||||
|
if (!(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
|
||||||
|
{
|
||||||
|
userControl.CaptureMouse();
|
||||||
|
_currentDraggingControl = userControl;
|
||||||
|
_isMovingUserControl = true;
|
||||||
|
InitializeDrag(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeDrag(MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
_isDraggingUserControl = true;
|
||||||
|
_startPointUserControl = e.GetPosition(_canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UserControl_MouseMove(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
if (_isMovingUserControl)
|
||||||
|
{
|
||||||
|
var currentPosition = e.GetPosition(_canvas);
|
||||||
|
MakeResizeRectanglesTransparent();
|
||||||
|
|
||||||
|
if (_isDraggingUserControl)
|
||||||
|
{
|
||||||
|
HandleDrag(currentPosition);
|
||||||
|
}
|
||||||
|
else if (_currentDraggingRectangle != null)
|
||||||
|
{
|
||||||
|
string resizeDirection = _currentDraggingRectangle.Tag as string;
|
||||||
|
if (resizeDirection != null)
|
||||||
|
{
|
||||||
|
var mode = DetermineHandleMode(resizeDirection);
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case HandleMode.Rotate:
|
||||||
|
HandleRotation(currentPosition);
|
||||||
|
break;
|
||||||
|
case HandleMode.ResizeWidth:
|
||||||
|
case HandleMode.ResizeHeight:
|
||||||
|
case HandleMode.ResizeBoth:
|
||||||
|
HandleResize(currentPosition, mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleDrag(Point currentPosition)
|
||||||
|
{
|
||||||
|
PurgeDeletedObjects();
|
||||||
|
var dx = currentPosition.X - _startPointUserControl.X;
|
||||||
|
var dy = currentPosition.Y - _startPointUserControl.Y;
|
||||||
|
|
||||||
|
RemoveAllSelectionHighlights(); // Remover antes de mover
|
||||||
|
|
||||||
|
foreach (var selectedObject in _selectedObjects)
|
||||||
|
{
|
||||||
|
var newX = Canvas.GetLeft(selectedObject.VisualRepresentation) + dx;
|
||||||
|
var newY = Canvas.GetTop(selectedObject.VisualRepresentation) + dy;
|
||||||
|
selectedObject.Move((float)newX, (float)newY);
|
||||||
|
}
|
||||||
|
_startPointUserControl = currentPosition;
|
||||||
|
|
||||||
|
UpdateAllSelectionHighlights();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UserControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
if (_isMovingUserControl)
|
||||||
|
{
|
||||||
|
if (sender is UserControl userControl)
|
||||||
|
{
|
||||||
|
userControl.ReleaseMouseCapture();
|
||||||
|
}
|
||||||
|
else if (sender is Rectangle rectangle)
|
||||||
|
{
|
||||||
|
rectangle.ReleaseMouseCapture();
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveAllSelectionHighlights(); // Remover antes de actualizar
|
||||||
|
UpdateSelectionVisuals();
|
||||||
|
UpdateAllSelectionHighlights();
|
||||||
|
|
||||||
|
// Restaurar los rectángulos de selección si es necesario
|
||||||
|
if (_mainWindow.DataContext is MainViewModel viewModel && viewModel.IsMultiSelectionActive)
|
||||||
|
{
|
||||||
|
foreach (var selectedObject in _selectedObjects)
|
||||||
|
{
|
||||||
|
AddSelectionHighlight(selectedObject.VisualRepresentation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_isDraggingUserControl = false;
|
||||||
|
_isMovingUserControl = false;
|
||||||
|
_currentDraggingRectangle = null;
|
||||||
|
_currentResizeMode = ResizeMode.None;
|
||||||
|
_lastAngle = 0;
|
||||||
|
}
|
||||||
|
MarkUnsavedChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MarkUnsavedChanges()
|
||||||
|
{
|
||||||
|
if (_mainWindow.DataContext is MainViewModel viewModel)
|
||||||
|
{
|
||||||
|
if (_isMovingUserControl || _isDraggingUserControl)
|
||||||
|
{
|
||||||
|
viewModel.HasUnsavedChanges = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResizeRectangle_MouseLeave(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
var rect = sender as Rectangle;
|
||||||
|
if (rect != null)
|
||||||
|
{
|
||||||
|
rect.Fill = Brushes.Transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddHighlightRectangles(UserControl userControl)
|
||||||
|
{
|
||||||
|
double rectSize = 1;
|
||||||
|
RemoveHighlightRectangles();
|
||||||
|
|
||||||
|
if (userControl is IDataContainer dataContainer && dataContainer.Datos is osBase mvBase && mvBase.Show_On_This_Page)
|
||||||
|
{
|
||||||
|
Rect boundingBox = VisualTreeHelper.GetDescendantBounds(userControl);
|
||||||
|
GeneralTransform transform = userControl.TransformToAncestor(_canvas);
|
||||||
|
Rect transformedBoundingBox = transform.TransformBounds(boundingBox);
|
||||||
|
|
||||||
|
FuncionesBase.MutableRect rectBox = new FuncionesBase.MutableRect(transformedBoundingBox);
|
||||||
|
rectBox.Left -= (float)rectSize;
|
||||||
|
rectBox.Right += (float)rectSize;
|
||||||
|
rectBox.Top -= (float)rectSize;
|
||||||
|
rectBox.Bottom += (float)rectSize;
|
||||||
|
|
||||||
|
Rectangle highlightRect = new Rectangle
|
||||||
|
{
|
||||||
|
Width = rectBox.Width,
|
||||||
|
Height = rectBox.Height,
|
||||||
|
Fill = Brushes.Transparent,
|
||||||
|
Stroke = new SolidColorBrush(Color.FromArgb(128, 0, 0, 0)),
|
||||||
|
StrokeThickness = 1,
|
||||||
|
Tag = "Highlight",
|
||||||
|
IsHitTestVisible = false,
|
||||||
|
StrokeDashArray = new DoubleCollection(new double[] { 2, 2 })
|
||||||
|
};
|
||||||
|
|
||||||
|
Canvas.SetLeft(highlightRect, rectBox.Left);
|
||||||
|
Canvas.SetTop(highlightRect, rectBox.Top); // Corregido: usando rectBox.Top en lugar de highlightRect.Top
|
||||||
|
|
||||||
|
_highlightRectangles.Add(highlightRect);
|
||||||
|
_canvas.Children.Add(highlightRect);
|
||||||
|
Canvas.SetZIndex(highlightRect, ((int)ZIndexEnum.RectangulosPropiead));
|
||||||
|
|
||||||
|
if (_timerRemoveHighlight == null)
|
||||||
|
_timerRemoveHighlight = new System.Threading.Timer(TimerCallbackRemoveHighlight, null, Timeout.Infinite, Timeout.Infinite);
|
||||||
|
|
||||||
|
_timerRemoveHighlight.Change(2000, Timeout.Infinite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TimerCallbackRemoveHighlight(object state)
|
||||||
|
{
|
||||||
|
if (Application.Current != null)
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.Invoke(RemoveHighlightRectangles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveHighlightRectangles()
|
||||||
|
{
|
||||||
|
if (_highlightRectangles == null || _highlightRectangles.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var rect in _highlightRectangles)
|
||||||
|
{
|
||||||
|
_canvas.Children.Remove(rect);
|
||||||
|
}
|
||||||
|
_highlightRectangles.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private HandleMode DetermineHandleMode(string resizeDirection)
|
||||||
|
{
|
||||||
|
return resizeDirection switch
|
||||||
|
{
|
||||||
|
"TopLeft" => HandleMode.None,
|
||||||
|
"TopRight" or "BottomLeft" or "CenterLeft" => HandleMode.Rotate,
|
||||||
|
"BottomRight" => HandleMode.ResizeBoth,
|
||||||
|
"TopCenter" => HandleMode.None,
|
||||||
|
"BottomCenter" => HandleMode.ResizeHeight,
|
||||||
|
"CenterRight" => HandleMode.ResizeWidth,
|
||||||
|
_ => HandleMode.None
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleResize(Point currentPosition, HandleMode mode)
|
||||||
|
{
|
||||||
|
PurgeDeletedObjects();
|
||||||
|
RemoveAllSelectionHighlights(); // Remover antes de redimensionar
|
||||||
|
|
||||||
|
foreach (var selectedObject in _selectedObjects)
|
||||||
|
{
|
||||||
|
bool resizeWidth = mode == HandleMode.ResizeWidth || mode == HandleMode.ResizeBoth;
|
||||||
|
bool resizeHeight = mode == HandleMode.ResizeHeight || mode == HandleMode.ResizeBoth;
|
||||||
|
HandleResizeForObject(selectedObject, currentPosition, resizeWidth, resizeHeight);
|
||||||
|
}
|
||||||
|
_startPointUserControl = currentPosition;
|
||||||
|
|
||||||
|
UpdateAllSelectionHighlights();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleResizeForObject(osBase obj, Point currentPosition, bool activateSizeWidth, bool activateSizeHeight)
|
||||||
|
{
|
||||||
|
double widthChange = activateSizeWidth ? currentPosition.X - _startPointUserControl.X : 0;
|
||||||
|
double heightChange = activateSizeHeight ? currentPosition.Y - _startPointUserControl.Y : 0;
|
||||||
|
|
||||||
|
obj.Resize(widthChange, heightChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleRotation(Point currentPosition)
|
||||||
|
{
|
||||||
|
PurgeDeletedObjects();
|
||||||
|
RemoveAllSelectionHighlights(); // Remover antes de rotar
|
||||||
|
|
||||||
|
// Calcular el ángulo respecto al centro del bounding box que contiene todos los objetos seleccionados
|
||||||
|
double deltaX = currentPosition.X - _transformedBoundingBoxCenter.X;
|
||||||
|
double deltaY = currentPosition.Y - _transformedBoundingBoxCenter.Y;
|
||||||
|
double angle = Math.Atan2(deltaY, deltaX) * (180 / Math.PI);
|
||||||
|
|
||||||
|
if ((_lastAngle == 0 && angle != 0) || Math.Abs(angle - _lastAngle) > 45)
|
||||||
|
{
|
||||||
|
_lastAngle = (float)angle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double deltaAngle = angle - _lastAngle;
|
||||||
|
foreach (var selectedObject in _selectedObjects)
|
||||||
|
{
|
||||||
|
selectedObject.Rotate(deltaAngle);
|
||||||
|
}
|
||||||
|
_lastAngle = (float)angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateAllSelectionHighlights();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AlignObjects(AlignmentType alignmentType)
|
||||||
|
{
|
||||||
|
PurgeDeletedObjects();
|
||||||
|
if (_selectedObjects.Count <= 1) return;
|
||||||
|
|
||||||
|
var alignment = new ObjectAlignment(_selectedObjects, _selectedObjects.FirstOrDefault());
|
||||||
|
|
||||||
|
switch (alignmentType)
|
||||||
|
{
|
||||||
|
case AlignmentType.Left:
|
||||||
|
alignment.AlignLeft();
|
||||||
|
break;
|
||||||
|
case AlignmentType.Right:
|
||||||
|
alignment.AlignRight();
|
||||||
|
break;
|
||||||
|
case AlignmentType.Top:
|
||||||
|
alignment.AlignTop();
|
||||||
|
break;
|
||||||
|
case AlignmentType.Bottom:
|
||||||
|
alignment.AlignBottom();
|
||||||
|
break;
|
||||||
|
case AlignmentType.CenterHorizontally:
|
||||||
|
alignment.AlignCenterHorizontally();
|
||||||
|
break;
|
||||||
|
case AlignmentType.CenterVertically:
|
||||||
|
alignment.AlignCenterVertically();
|
||||||
|
break;
|
||||||
|
case AlignmentType.DistributeHorizontally:
|
||||||
|
alignment.DistributeHorizontally();
|
||||||
|
break;
|
||||||
|
case AlignmentType.DistributeVertically:
|
||||||
|
alignment.DistributeVertically();
|
||||||
|
break;
|
||||||
|
case AlignmentType.EqualWidth:
|
||||||
|
alignment.EqualWidth();
|
||||||
|
break;
|
||||||
|
case AlignmentType.EqualHeight:
|
||||||
|
alignment.EqualHeight();
|
||||||
|
break;
|
||||||
|
case AlignmentType.EqualAngle:
|
||||||
|
alignment.EqualAngle();
|
||||||
|
break;
|
||||||
|
case AlignmentType.JoinHorizontally:
|
||||||
|
alignment.JoinHorizontally();
|
||||||
|
break;
|
||||||
|
case AlignmentType.JoinVertically:
|
||||||
|
alignment.JoinVertically();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the selection visuals after alignment
|
||||||
|
UpdateSelectionVisuals();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EliminarObjetosSeleccionados()
|
||||||
|
{
|
||||||
|
if (_selectedObjects.Count == 0) return;
|
||||||
|
|
||||||
|
var viewModel = _mainWindow.DataContext as MainViewModel;
|
||||||
|
if (viewModel == null) return;
|
||||||
|
|
||||||
|
// Crear una copia de la lista para evitar modificaciones durante la iteración
|
||||||
|
var objectsToRemove = _selectedObjects.ToList();
|
||||||
|
|
||||||
|
foreach (var obj in objectsToRemove)
|
||||||
|
{
|
||||||
|
viewModel.RemoverObjetoSimulable(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limpiar la selección y actualizar la interfaz
|
||||||
|
ClearSelection();
|
||||||
|
RemoveResizeRectangles();
|
||||||
|
RemoveAllSelectionHighlights();
|
||||||
|
|
||||||
|
// Actualizar el estado de cambios sin guardar
|
||||||
|
if (viewModel != null)
|
||||||
|
{
|
||||||
|
viewModel.HasUnsavedChanges = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartRectangleSelection(Point startPoint)
|
||||||
|
{
|
||||||
|
_rectangleStart = startPoint;
|
||||||
|
_selectionRectangle = new Rectangle
|
||||||
|
{
|
||||||
|
Stroke = Brushes.Blue,
|
||||||
|
StrokeThickness = 1,
|
||||||
|
Fill = new SolidColorBrush(Color.FromArgb(50, 0, 0, 255))
|
||||||
|
};
|
||||||
|
|
||||||
|
Canvas.SetLeft(_selectionRectangle, startPoint.X);
|
||||||
|
Canvas.SetTop(_selectionRectangle, startPoint.Y);
|
||||||
|
Canvas.SetZIndex(_selectionRectangle, (int)ZIndexEnum.RectangulosPropiead);
|
||||||
|
|
||||||
|
_canvas.Children.Add(_selectionRectangle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateSelectionRectangle(Point currentPoint)
|
||||||
|
{
|
||||||
|
double left = Math.Min(_rectangleStart.X, currentPoint.X);
|
||||||
|
double top = Math.Min(_rectangleStart.Y, currentPoint.Y);
|
||||||
|
double width = Math.Abs(currentPoint.X - _rectangleStart.X);
|
||||||
|
double height = Math.Abs(currentPoint.Y - _rectangleStart.Y);
|
||||||
|
|
||||||
|
_selectionRectangle.Width = width;
|
||||||
|
_selectionRectangle.Height = height;
|
||||||
|
Canvas.SetLeft(_selectionRectangle, left);
|
||||||
|
Canvas.SetTop(_selectionRectangle, top);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FinishRectangleSelection(Point currentPoint)
|
||||||
|
{
|
||||||
|
if (_selectionRectangle != null)
|
||||||
|
{
|
||||||
|
var left = Canvas.GetLeft(_selectionRectangle);
|
||||||
|
var top = Canvas.GetTop(_selectionRectangle);
|
||||||
|
var right = left + _selectionRectangle.Width;
|
||||||
|
var bottom = top + _selectionRectangle.Height;
|
||||||
|
var selectionBounds = new Rect(new Point(left, top), new Point(right, bottom));
|
||||||
|
|
||||||
|
var itemsToProcess = _canvas.Children.OfType<UserControl>().Where(child => child is IDataContainer).ToList();
|
||||||
|
|
||||||
|
foreach (var child in itemsToProcess)
|
||||||
|
{
|
||||||
|
var childBounds = GetElementBounds(child);
|
||||||
|
if (selectionBounds.Contains(childBounds) || selectionBounds.IntersectsWith(childBounds))
|
||||||
|
{
|
||||||
|
if (child.DataContext is osBase osObject)
|
||||||
|
{
|
||||||
|
SelectObject(osObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_canvas.Children.Remove(_selectionRectangle);
|
||||||
|
_selectionRectangle = null;
|
||||||
|
|
||||||
|
UpdateSelectionVisuals();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rect GetElementBounds(FrameworkElement element)
|
||||||
|
{
|
||||||
|
var bounds = VisualTreeHelper.GetDescendantBounds(element);
|
||||||
|
var transform = element.TransformToAncestor(_canvas);
|
||||||
|
return transform.TransformBounds(bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateRectangleSelection(Point currentPoint)
|
||||||
|
{
|
||||||
|
if (_selectionRectangle != null)
|
||||||
|
{
|
||||||
|
UpdateSelectionRectangle(currentPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
<UserControl x:Class="CtrEditor.ObjetosSim.ucCustomImage"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="clr-namespace:CtrEditor.ObjetosSim">
|
||||||
|
|
||||||
|
<UserControl.DataContext>
|
||||||
|
<vm:osCustomImage />
|
||||||
|
</UserControl.DataContext>
|
||||||
|
|
||||||
|
<Grid RenderTransformOrigin="0.5,0.5">
|
||||||
|
<Grid.RenderTransform>
|
||||||
|
<TransformGroup>
|
||||||
|
<RotateTransform Angle="{Binding Angulo}"/>
|
||||||
|
</TransformGroup>
|
||||||
|
</Grid.RenderTransform>
|
||||||
|
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Image Source="{Binding ImageSource_oculta}"
|
||||||
|
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Stretch="Fill"
|
||||||
|
RenderTransformOrigin="0.5,0.5" />
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,106 @@
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using LibS7Adv;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace CtrEditor.ObjetosSim
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A custom image control that can display an image from a file path
|
||||||
|
/// </summary>
|
||||||
|
public partial class osCustomImage : osBase, IosBase
|
||||||
|
{
|
||||||
|
public static string NombreClase()
|
||||||
|
{
|
||||||
|
return "Custom Image";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string nombre = NombreClase();
|
||||||
|
public override string Nombre
|
||||||
|
{
|
||||||
|
get => nombre;
|
||||||
|
set => SetProperty(ref nombre, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[NotifyPropertyChangedFor(nameof(ImageSource_oculta))]
|
||||||
|
[property: Description("Path to the image file")]
|
||||||
|
[property: Category("Image:")]
|
||||||
|
private string imagePath;
|
||||||
|
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
[ObservableProperty]
|
||||||
|
public ImageSource imageSource_oculta;
|
||||||
|
|
||||||
|
partial void OnImagePathChanged(string value)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
ImageSource_oculta = ImageFromPath(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Si no hay path, usar la imagen por defecto
|
||||||
|
ImageSource_oculta = ImageFromPath("/Icons/unselect.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public osCustomImage()
|
||||||
|
{
|
||||||
|
Ancho = 0.30f;
|
||||||
|
Alto = 0.30f;
|
||||||
|
// Establecer la imagen por defecto al crear el objeto
|
||||||
|
ImageSource_oculta = ImageFromPath("/Icons/unselect.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ucLoaded()
|
||||||
|
{
|
||||||
|
base.ucLoaded();
|
||||||
|
if (!string.IsNullOrEmpty(ImagePath))
|
||||||
|
{
|
||||||
|
ImageSource_oculta = ImageFromPath(ImagePath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Si no hay path al cargar, usar la imagen por defecto
|
||||||
|
ImageSource_oculta = ImageFromPath("/Icons/unselect.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class ucCustomImage : UserControl, IDataContainer
|
||||||
|
{
|
||||||
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
|
public ucCustomImage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.Loaded += OnLoaded;
|
||||||
|
this.Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucUnLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Highlight(bool State) { }
|
||||||
|
|
||||||
|
public ZIndexEnum ZIndex_Base()
|
||||||
|
{
|
||||||
|
return ZIndexEnum.Estaticos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
<UserControl x:Class="CtrEditor.ObjetosSim.ucFramePlate"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:i="http://schemas.microsoft.com/xaml/behaviors" xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<UserControl.DataContext>
|
||||||
|
<vm:osFramePlate Color_Titulo="Black" Alto_Titulo="0.1" Color="WhiteSmoke" />
|
||||||
|
</UserControl.DataContext>
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Viewbox Grid.Row="0" Height="{Binding Alto_Titulo, Converter={StaticResource MeterToPixelConverter}}">
|
||||||
|
<Label Content="{Binding Titulo}" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold"
|
||||||
|
Foreground="{Binding Color_Titulo, Converter={StaticResource ColorToBrushConverter}}" />
|
||||||
|
</Viewbox>
|
||||||
|
<Rectangle Grid.Row="1" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Fill="{Binding Color, Converter={StaticResource ColorToBrushConverter}}" Stroke="Blue"
|
||||||
|
StrokeThickness="0.2"
|
||||||
|
Visibility="{Binding ShowPlate, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,268 @@
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
using DocumentFormat.OpenXml.Spreadsheet;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||||
|
using Color = System.Windows.Media.Color;
|
||||||
|
using Colors = System.Windows.Media.Colors;
|
||||||
|
using JsonIgnoreAttribute = Newtonsoft.Json.JsonIgnoreAttribute;
|
||||||
|
|
||||||
|
namespace CtrEditor.ObjetosSim
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ucFramePlate.xaml
|
||||||
|
/// </summary>
|
||||||
|
///
|
||||||
|
|
||||||
|
public partial class osFramePlate : osBase, IosBase
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public float offsetY;
|
||||||
|
[JsonIgnore]
|
||||||
|
public float offsetX;
|
||||||
|
|
||||||
|
public static string NombreClase()
|
||||||
|
{
|
||||||
|
return "Frame Plate";
|
||||||
|
}
|
||||||
|
private string nombre = NombreClase();
|
||||||
|
public override string Nombre
|
||||||
|
{
|
||||||
|
get => nombre;
|
||||||
|
set => SetProperty(ref nombre, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Layer index to add to Objects on the Frame")]
|
||||||
|
[property: Category("Layer:")]
|
||||||
|
int zindex_FramePlate;
|
||||||
|
|
||||||
|
partial void OnZindex_FramePlateChanged(int value)
|
||||||
|
{
|
||||||
|
UpdateZIndex(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
Color color;
|
||||||
|
[ObservableProperty]
|
||||||
|
Color color_Titulo;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
string titulo;
|
||||||
|
[ObservableProperty]
|
||||||
|
public float alto_Titulo;
|
||||||
|
|
||||||
|
// Encoder X
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("This is a link to a Encoder for X.")]
|
||||||
|
[property: Category("Encoders:")]
|
||||||
|
[property: ItemsSource(typeof(osBaseItemsSource<osEncoderMotorLineal>))]
|
||||||
|
private string encoder_X;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("K Pulses per meter for Moving")]
|
||||||
|
[property: Category("Encoders:")]
|
||||||
|
public float k_encoder_X;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("X in meter offset Left. Position when the encoder is 0")]
|
||||||
|
[property: Category("Encoders:")]
|
||||||
|
public float offset_encoder_X;
|
||||||
|
|
||||||
|
// Encoder Y
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("This is a link to a Encoder for Y.")]
|
||||||
|
[property: Category("Encoders:")]
|
||||||
|
[property: ItemsSource(typeof(osBaseItemsSource<osEncoderMotorLineal>))]
|
||||||
|
private string encoder_Y;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("K Pulses per meter for Moving")]
|
||||||
|
[property: Category("Encoders:")]
|
||||||
|
public float k_encoder_Y;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Y in meter offset Top. Position when the encoder is 0")]
|
||||||
|
[property: Category("Encoders:")]
|
||||||
|
public float offset_encoder_Y;
|
||||||
|
|
||||||
|
partial void OnK_encoder_YChanged(float value)
|
||||||
|
{
|
||||||
|
UpdatePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnOffset_encoder_YChanged(float value)
|
||||||
|
{
|
||||||
|
UpdatePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnK_encoder_XChanged(float value)
|
||||||
|
{
|
||||||
|
UpdatePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnOffset_encoder_XChanged(float value)
|
||||||
|
{
|
||||||
|
UpdatePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
private osEncoderMotorLineal EncoderX;
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
private osEncoderMotorLineal EncoderY;
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
private bool isUpdatingFromEncoderX = false;
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
private bool isUpdatingFromEncoderY = false;
|
||||||
|
|
||||||
|
partial void OnEncoder_XChanged(string value)
|
||||||
|
{
|
||||||
|
if (EncoderX != null)
|
||||||
|
EncoderX.PropertyChanged -= OnEncoderXPropertyChanged;
|
||||||
|
if (_mainViewModel != null && value != null && value.Length > 0)
|
||||||
|
{
|
||||||
|
EncoderX = (osEncoderMotorLineal)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osEncoderMotorLineal && s.Nombre == value), null);
|
||||||
|
if (EncoderX != null)
|
||||||
|
EncoderX.PropertyChanged += OnEncoderXPropertyChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnEncoder_YChanged(string value)
|
||||||
|
{
|
||||||
|
if (EncoderY != null)
|
||||||
|
EncoderY.PropertyChanged -= OnEncoderYPropertyChanged;
|
||||||
|
if (_mainViewModel != null && value != null && value.Length > 0)
|
||||||
|
{
|
||||||
|
EncoderY = (osEncoderMotorLineal)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osEncoderMotorLineal && s.Nombre == value), null);
|
||||||
|
if (EncoderY != null)
|
||||||
|
EncoderY.PropertyChanged += OnEncoderYPropertyChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEncoderXPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (!isUpdatingFromEncoderX)
|
||||||
|
{
|
||||||
|
isUpdatingFromEncoderX = true;
|
||||||
|
// Actualizamos el nombre si este fue modificado
|
||||||
|
if (e.PropertyName == nameof(osEncoderMotorLineal.Nombre))
|
||||||
|
Encoder_X = ((osEncoderMotorLineal)sender).Nombre;
|
||||||
|
|
||||||
|
if (e.PropertyName == nameof(osEncoderMotorLineal.Valor_Actual))
|
||||||
|
{
|
||||||
|
UpdatePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
isUpdatingFromEncoderX = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEncoderYPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (!isUpdatingFromEncoderY)
|
||||||
|
{
|
||||||
|
isUpdatingFromEncoderY = true;
|
||||||
|
// Actualizamos el nombre si este fue modificado
|
||||||
|
if (e.PropertyName == nameof(osEncoderMotorLineal.Nombre))
|
||||||
|
Encoder_Y = ((osEncoderMotorLineal)sender).Nombre;
|
||||||
|
|
||||||
|
if (e.PropertyName == nameof(osEncoderMotorLineal.Valor_Actual))
|
||||||
|
{
|
||||||
|
UpdatePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
isUpdatingFromEncoderY = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdatePosition()
|
||||||
|
{
|
||||||
|
// Update X position if encoder is available
|
||||||
|
if (EncoderX != null && K_encoder_X != 0)
|
||||||
|
Left = (EncoderX.Valor_Actual / k_encoder_X) + offset_encoder_X;
|
||||||
|
|
||||||
|
// Update Y position if encoder is available
|
||||||
|
if (EncoderY != null && K_encoder_Y != 0)
|
||||||
|
Top = (EncoderY.Valor_Actual / k_encoder_Y) + offset_encoder_Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void TopChanging(float oldValue, float newValue)
|
||||||
|
{
|
||||||
|
offsetY = newValue - oldValue;
|
||||||
|
}
|
||||||
|
public override void LeftChanging(float oldValue, float newValue)
|
||||||
|
{
|
||||||
|
offsetX = newValue - oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Show/Hide the plate background")]
|
||||||
|
[property: Category("Appearance:")]
|
||||||
|
private bool showPlate;
|
||||||
|
|
||||||
|
public osFramePlate()
|
||||||
|
{
|
||||||
|
Ancho = 0.5f;
|
||||||
|
Alto = 0.5f;
|
||||||
|
Alto_Titulo = 0.2f;
|
||||||
|
Color = Colors.WhiteSmoke;
|
||||||
|
Titulo = "Frame";
|
||||||
|
Zindex_FramePlate = 0;
|
||||||
|
ShowPlate = true; // Default value
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ucLoaded()
|
||||||
|
{
|
||||||
|
base.ucLoaded();
|
||||||
|
// El UserControl se ha cargado
|
||||||
|
OnEncoder_XChanged(Encoder_X);
|
||||||
|
OnEncoder_YChanged(Encoder_Y);
|
||||||
|
UpdateZIndex(Zindex_FramePlate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ucUnLoaded()
|
||||||
|
{
|
||||||
|
base.ucUnLoaded();
|
||||||
|
// El UserControl se esta eliminando
|
||||||
|
// eliminar el objeto de simulacion
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class ucFramePlate : UserControl, IDataContainer
|
||||||
|
{
|
||||||
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
|
public ucFramePlate()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.Loaded += OnLoaded;
|
||||||
|
this.Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucLoaded();
|
||||||
|
}
|
||||||
|
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucUnLoaded();
|
||||||
|
}
|
||||||
|
public void Highlight(bool State) { }
|
||||||
|
public ZIndexEnum ZIndex_Base()
|
||||||
|
{
|
||||||
|
return ZIndexEnum.Decorativos;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
<UserControl x:Class="CtrEditor.ObjetosSim.ucTextPlate"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||||
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<UserControl.DataContext>
|
||||||
|
<vm:osTextPlate Color_Titulo="Black" Alto_Titulo="0.1"/>
|
||||||
|
</UserControl.DataContext>
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Viewbox Grid.Row="0" Height="{Binding Alto_Titulo, Converter={StaticResource MeterToPixelConverter}}" >
|
||||||
|
<Label Content="{Binding Titulo}"
|
||||||
|
VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold"
|
||||||
|
Foreground="{Binding Color_Titulo, Converter={StaticResource ColorToBrushConverter}}"/>
|
||||||
|
</Viewbox>
|
||||||
|
<Rectangle Grid.Row="1" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Fill="{Binding Color, Converter={StaticResource ColorToBrushConverter}}" />
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,99 @@
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
|
||||||
|
namespace CtrEditor.ObjetosSim
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ucTextPlate.xaml
|
||||||
|
/// </summary>
|
||||||
|
///
|
||||||
|
|
||||||
|
public partial class osTextPlate : osBase, IosBase
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public float offsetY;
|
||||||
|
[JsonIgnore]
|
||||||
|
public float offsetX;
|
||||||
|
|
||||||
|
public static string NombreClase()
|
||||||
|
{
|
||||||
|
return "Plate";
|
||||||
|
}
|
||||||
|
private string nombre = NombreClase();
|
||||||
|
public override string Nombre
|
||||||
|
{
|
||||||
|
get => nombre;
|
||||||
|
set => SetProperty(ref nombre, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
Color color;
|
||||||
|
[ObservableProperty]
|
||||||
|
Color color_Titulo;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
string titulo;
|
||||||
|
[ObservableProperty]
|
||||||
|
public float alto_Titulo;
|
||||||
|
|
||||||
|
|
||||||
|
public override void TopChanging(float oldValue, float newValue) {
|
||||||
|
offsetY = newValue - oldValue;
|
||||||
|
}
|
||||||
|
public override void LeftChanging(float oldValue, float newValue)
|
||||||
|
{
|
||||||
|
offsetX = newValue - oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public osTextPlate()
|
||||||
|
{
|
||||||
|
Ancho = 0.5f;
|
||||||
|
Alto = 0.5f;
|
||||||
|
Alto_Titulo = 0.2f;
|
||||||
|
Color = Colors.Gray;
|
||||||
|
Titulo = "Titulo";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ucUnLoaded()
|
||||||
|
{
|
||||||
|
// El UserControl se esta eliminando
|
||||||
|
// eliminar el objeto de simulacion
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class ucTextPlate : UserControl, IDataContainer
|
||||||
|
{
|
||||||
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
|
public ucTextPlate()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.Loaded += OnLoaded;
|
||||||
|
this.Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucLoaded();
|
||||||
|
}
|
||||||
|
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucUnLoaded();
|
||||||
|
}
|
||||||
|
public void Highlight(bool State) { }
|
||||||
|
public ZIndexEnum ZIndex_Base()
|
||||||
|
{
|
||||||
|
return ZIndexEnum.Decorativos;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
<UserControl x:Class="CtrEditor.ObjetosSim.ucBotella"
|
<UserControl x:Class="CtrEditor.ObjetosSim.ucBotella"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
<UserControl.Resources>
|
>
|
||||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
|
||||||
</UserControl.Resources>
|
<UserControl.DataContext>
|
||||||
|
<vm:osBotella/>
|
||||||
|
</UserControl.DataContext>
|
||||||
|
|
||||||
<Ellipse Height="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}"
|
<Ellipse Height="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
Stroke="red" Fill="Gray"
|
Stroke="{Binding ColorButton_oculto}" Fill="Gray"
|
||||||
Width="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}"/>
|
Width="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}" StrokeThickness="0.5"/>
|
||||||
|
|
||||||
</UserControl>
|
</UserControl>
|
|
@ -1,11 +1,13 @@
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
//using using Microsoft.Xna.Framework;
|
//using using Microsoft.Xna.Framework;
|
||||||
using CtrEditor.Convertidores;
|
|
||||||
using CtrEditor.Siemens;
|
using LibS7Adv;
|
||||||
using CtrEditor.Simulacion;
|
using CtrEditor.Simulacion;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using nkast.Aether.Physics2D.Common;
|
using nkast.Aether.Physics2D.Common;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
|
||||||
namespace CtrEditor.ObjetosSim
|
namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
|
@ -31,6 +33,19 @@ namespace CtrEditor.ObjetosSim
|
||||||
set => SetProperty(ref nombre, value);
|
set => SetProperty(ref nombre, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnMove(float LeftPixels, float TopPixels)
|
||||||
|
{
|
||||||
|
UpdateAfterMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||||
|
{
|
||||||
|
Diametro += Delta_Width;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private Brush colorButton_oculto;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private float diametro;
|
private float diametro;
|
||||||
|
|
||||||
|
@ -39,6 +54,17 @@ namespace CtrEditor.ObjetosSim
|
||||||
SimGeometria?.SetDiameter(Diametro);
|
SimGeometria?.SetDiameter(Diametro);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string velocidad_desde_simulacion;
|
||||||
|
[ObservableProperty]
|
||||||
|
private float inercia_desde_simulacion;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool preserve_Outside_Transport;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private float porcentaje_Traccion;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private float mass;
|
private float mass;
|
||||||
partial void OnMassChanged(float value)
|
partial void OnMassChanged(float value)
|
||||||
|
@ -62,9 +88,8 @@ namespace CtrEditor.ObjetosSim
|
||||||
|
|
||||||
private void ActualizarGeometrias()
|
private void ActualizarGeometrias()
|
||||||
{
|
{
|
||||||
if (SimGeometria != null)
|
if (SimGeometria != null && !RemoverDesdeSimulacion)
|
||||||
{
|
{
|
||||||
SimGeometria.SetDiameter(Diametro);
|
|
||||||
SimGeometria.SetPosition(GetCentro());
|
SimGeometria.SetPosition(GetCentro());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,39 +98,61 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
Diametro = 0.10f;
|
Diametro = 0.10f;
|
||||||
Mass = 1;
|
Mass = 1;
|
||||||
|
ColorButton_oculto = Brushes.Gray;
|
||||||
|
Preserve_Outside_Transport = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateAfterMove()
|
||||||
|
{
|
||||||
|
if (!RemoverDesdeSimulacion)
|
||||||
|
{
|
||||||
|
ActualizarGeometrias();
|
||||||
|
SimGeometria?.SetDiameter(Diametro);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateGeometryStart()
|
public override void UpdateGeometryStart()
|
||||||
{
|
{
|
||||||
// Se llama antes de la simulacion
|
// Se llama antes de la simulacion
|
||||||
ActualizarGeometrias();
|
ActualizarGeometrias();
|
||||||
|
SimGeometria?.SetDiameter(Diametro);
|
||||||
}
|
}
|
||||||
public override void SimulationStop()
|
|
||||||
{
|
|
||||||
// Se llama al detener la simulacion. Util para detener Storyboards
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void UpdateGeometryStep()
|
public override void UpdateGeometryStep()
|
||||||
{
|
{
|
||||||
// Se llama antes de la simulacion
|
// Se llama antes de la simulacion
|
||||||
ActualizarGeometrias();
|
ActualizarGeometrias();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) { }
|
|
||||||
|
|
||||||
public override void UpdateControl(int elapsedMilliseconds)
|
public override void UpdateControl(int elapsedMilliseconds)
|
||||||
{
|
{
|
||||||
SetCentro(SimGeometria.Center);
|
SetCentro(SimGeometria.Center);
|
||||||
|
if (SimGeometria.isRestricted)
|
||||||
|
ColorButton_oculto = Brushes.Yellow;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (SimGeometria.IsOnAnyTransport())
|
||||||
|
ColorButton_oculto = Brushes.Red;
|
||||||
|
else
|
||||||
|
ColorButton_oculto = Brushes.Gray;
|
||||||
|
}
|
||||||
|
|
||||||
if (SimGeometria.Descartar) // Ha sido marcada para remover
|
// Ha sido marcada para remover
|
||||||
|
if (SimGeometria.Descartar)
|
||||||
RemoverDesdeSimulacion = true;
|
RemoverDesdeSimulacion = true;
|
||||||
|
|
||||||
|
// Eliminar la botella si esta fuera de un transporte
|
||||||
|
if (!Preserve_Outside_Transport && !SimGeometria.IsOnAnyTransport())
|
||||||
|
RemoverDesdeSimulacion = true;
|
||||||
|
|
||||||
|
Velocidad_desde_simulacion = SimGeometria.Body.LinearVelocity.ToString();
|
||||||
|
Inercia_desde_simulacion = SimGeometria.Body.Inertia;
|
||||||
|
Porcentaje_Traccion = SimGeometria.OverlapPercentage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ucLoaded()
|
public override void ucLoaded()
|
||||||
{
|
{
|
||||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
// crear el objeto de simulacion
|
// crear el objeto de simulacion
|
||||||
ActualizarLeftTop();
|
base.ucLoaded();
|
||||||
SimGeometria = simulationManager.AddCircle(Diametro, GetCentro(), Mass);
|
SimGeometria = simulationManager.AddCircle(Diametro, GetCentro(), Mass);
|
||||||
}
|
}
|
||||||
public override void ucUnLoaded()
|
public override void ucUnLoaded()
|
||||||
|
@ -120,6 +167,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public partial class ucBotella : UserControl, IDataContainer
|
public partial class ucBotella : UserControl, IDataContainer
|
||||||
{
|
{
|
||||||
public osBase? Datos { get; set; }
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
public ucBotella()
|
public ucBotella()
|
||||||
{
|
{
|
||||||
|
@ -136,20 +184,10 @@ namespace CtrEditor.ObjetosSim
|
||||||
Datos?.ucUnLoaded();
|
Datos?.ucUnLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Resize(float width, float height) { }
|
|
||||||
public void Move(float LeftPixels, float TopPixels)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
{
|
|
||||||
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
|
||||||
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Rotate(float Angle) { }
|
|
||||||
public void Highlight(bool State) { }
|
public void Highlight(bool State) { }
|
||||||
public int ZIndex()
|
public ZIndexEnum ZIndex_Base()
|
||||||
{
|
{
|
||||||
return 10;
|
return ZIndexEnum.Dinamicos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
<UserControl x:Class="CtrEditor.ObjetosSim.ucBotellaCuello"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim">
|
||||||
|
|
||||||
|
<UserControl.DataContext>
|
||||||
|
<vm:osBotellaCuello/>
|
||||||
|
</UserControl.DataContext>
|
||||||
|
|
||||||
|
<Ellipse Height="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Stroke="{Binding ColorButton_oculto}" Fill="Gray"
|
||||||
|
Width="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}" StrokeThickness="0.5"/>
|
||||||
|
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,180 @@
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
//using using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
|
using LibS7Adv;
|
||||||
|
using CtrEditor.Simulacion;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using nkast.Aether.Physics2D.Common;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
|
||||||
|
namespace CtrEditor.ObjetosSim
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ucBotellaCuelloCuello.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class osBotellaCuello : osBase, IosBase
|
||||||
|
{
|
||||||
|
private simBotella SimGeometria;
|
||||||
|
|
||||||
|
// Otros datos y métodos relevantes para la simulación
|
||||||
|
|
||||||
|
public static string NombreClase()
|
||||||
|
{
|
||||||
|
return "Botella con Cuello";
|
||||||
|
}
|
||||||
|
private string nombre = NombreClase();
|
||||||
|
public override string Nombre
|
||||||
|
{
|
||||||
|
get => nombre;
|
||||||
|
set => SetProperty(ref nombre, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void TopChanged(float value)
|
||||||
|
{
|
||||||
|
UpdateAfterMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LeftChanged(float value)
|
||||||
|
{
|
||||||
|
UpdateAfterMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||||
|
{
|
||||||
|
Diametro += Delta_Width;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private Brush colorButton_oculto;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private float diametro;
|
||||||
|
|
||||||
|
partial void OnDiametroChanged(float value)
|
||||||
|
{
|
||||||
|
SimGeometria?.SetDiameter(Diametro);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string velocidad_desde_simulacion;
|
||||||
|
[ObservableProperty]
|
||||||
|
private float inercia_desde_simulacion;
|
||||||
|
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private float mass;
|
||||||
|
partial void OnMassChanged(float value)
|
||||||
|
{
|
||||||
|
SimGeometria?.SetMass(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 GetCentro()
|
||||||
|
{
|
||||||
|
return new Vector2(Left + Diametro / 2, Top + Diametro / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetCentro(float x, float y)
|
||||||
|
{ Left = x; Top = y; }
|
||||||
|
|
||||||
|
public void SetCentro(Vector2 centro)
|
||||||
|
{
|
||||||
|
Left = centro.X - Diametro / 2;
|
||||||
|
Top = centro.Y - Diametro / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ActualizarGeometrias()
|
||||||
|
{
|
||||||
|
if (SimGeometria != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
SimGeometria.SetPosition(GetCentro());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public osBotellaCuello()
|
||||||
|
{
|
||||||
|
Diametro = 0.10f;
|
||||||
|
Mass = 1;
|
||||||
|
ColorButton_oculto = Brushes.Gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateAfterMove()
|
||||||
|
{
|
||||||
|
ActualizarGeometrias();
|
||||||
|
SimGeometria?.SetDiameter(Diametro);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateGeometryStart()
|
||||||
|
{
|
||||||
|
// Se llama antes de la simulacion
|
||||||
|
ActualizarGeometrias();
|
||||||
|
SimGeometria?.SetDiameter(Diametro);
|
||||||
|
}
|
||||||
|
public override void UpdateGeometryStep()
|
||||||
|
{
|
||||||
|
// Se llama antes de la simulacion
|
||||||
|
ActualizarGeometrias();
|
||||||
|
}
|
||||||
|
public override void UpdateControl(int elapsedMilliseconds)
|
||||||
|
{
|
||||||
|
SetCentro(SimGeometria.Center);
|
||||||
|
if (SimGeometria.isRestricted)
|
||||||
|
ColorButton_oculto = Brushes.Yellow;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (SimGeometria.isOnTransports > 0)
|
||||||
|
ColorButton_oculto = Brushes.Red;
|
||||||
|
else
|
||||||
|
ColorButton_oculto = Brushes.Gray;
|
||||||
|
}
|
||||||
|
if (SimGeometria.Descartar) // Ha sido marcada para remover
|
||||||
|
RemoverDesdeSimulacion = true;
|
||||||
|
Velocidad_desde_simulacion = SimGeometria.Body.LinearVelocity.ToString();
|
||||||
|
Inercia_desde_simulacion = SimGeometria.Body.Inertia;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ucLoaded()
|
||||||
|
{
|
||||||
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
|
// crear el objeto de simulacion
|
||||||
|
base.ucLoaded();
|
||||||
|
SimGeometria = simulationManager.AddCircle(Diametro, GetCentro(), Mass);
|
||||||
|
}
|
||||||
|
public override void ucUnLoaded()
|
||||||
|
{
|
||||||
|
// El UserControl se esta eliminando
|
||||||
|
// eliminar el objeto de simulacion
|
||||||
|
simulationManager.Remove(SimGeometria);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class ucBotellaCuello : UserControl, IDataContainer
|
||||||
|
{
|
||||||
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
|
public ucBotellaCuello()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.Loaded += OnLoaded;
|
||||||
|
this.Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucLoaded();
|
||||||
|
}
|
||||||
|
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucUnLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Highlight(bool State) { }
|
||||||
|
public ZIndexEnum ZIndex_Base()
|
||||||
|
{
|
||||||
|
return ZIndexEnum.Dinamicos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<UserControl x:Class="CtrEditor.ObjetosSim.ucBottGenerator"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim">
|
||||||
|
|
||||||
|
|
||||||
|
<UserControl.DataContext>
|
||||||
|
<vm:osFiller/>
|
||||||
|
</UserControl.DataContext>
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Image Source="/imagenes/gear.png"
|
||||||
|
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Stretch="Uniform">
|
||||||
|
<Image.RenderTransform>
|
||||||
|
<RotateTransform Angle="{Binding Angulo}" />
|
||||||
|
</Image.RenderTransform>
|
||||||
|
</Image>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,205 @@
|
||||||
|
using LibS7Adv;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
|
namespace CtrEditor.ObjetosSim
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ucBottGenerator.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class osBottGenerator : osBase, IosBase
|
||||||
|
{
|
||||||
|
TimerTON_TOFF _TON_TOFF = new TimerTON_TOFF();
|
||||||
|
private float TiempoRestante;
|
||||||
|
public static string NombreClase()
|
||||||
|
{
|
||||||
|
return "BottGenerator";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string nombre = NombreClase();
|
||||||
|
public override string Nombre { get => nombre; set => SetProperty(ref nombre, value); }
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private float offsetLeftSalida;
|
||||||
|
[ObservableProperty]
|
||||||
|
private float offsetTopSalida;
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("The bottle will be destroyed if fall outside transport.")]
|
||||||
|
[property: Category("Enable to Run:")]
|
||||||
|
private bool preserve_Outside_Transport;
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("PLC tag for consense to run. 1 => always")]
|
||||||
|
[property: Category("Enable to Run:")]
|
||||||
|
private string tag_consenso;
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Consense to run.")]
|
||||||
|
[property: Category("Enable to Run:")]
|
||||||
|
private bool consenso;
|
||||||
|
partial void OnConsensoChanged(bool value)
|
||||||
|
{
|
||||||
|
_TON_TOFF.Senal = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Consense is Normally close.")]
|
||||||
|
[property: Category("Enable to Run:")]
|
||||||
|
private bool consenso_NC;
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Enable filter.")]
|
||||||
|
[property: Category("Enable to Run:")]
|
||||||
|
private bool consenso_Filtrado;
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Time ON in s.")]
|
||||||
|
[property: Category("Enable to Run:")]
|
||||||
|
float filtro_consenso_ON_s;
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Time OFF in s.")]
|
||||||
|
[property: Category("Enable to Run:")]
|
||||||
|
float filtro_consenso_OFF_s;
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Filter OUT signal.")]
|
||||||
|
[property: Category("Enable to Run:")]
|
||||||
|
bool filter_Output;
|
||||||
|
[ObservableProperty]
|
||||||
|
private float botellas_hora;
|
||||||
|
partial void OnBotellas_horaChanged(float value)
|
||||||
|
{
|
||||||
|
Botellas_segundo = value / 3600;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private float botellas_segundo;
|
||||||
|
partial void OnBotellas_segundoChanged(float value)
|
||||||
|
{
|
||||||
|
Botellas_hora = value * 3600;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private float velocidad_actual_percentual;
|
||||||
|
[ObservableProperty]
|
||||||
|
private float diametro_botella;
|
||||||
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||||
|
{
|
||||||
|
if (Consenso_NC)
|
||||||
|
Consenso = !LeerBitTag(Tag_consenso);
|
||||||
|
else
|
||||||
|
Consenso = LeerBitTag(Tag_consenso);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool HayEspacioParaNuevaBotella(float X, float Y)
|
||||||
|
{
|
||||||
|
float radioMinimo = Diametro_botella / 4; // Distancia mínima entre centros
|
||||||
|
float radioMinimoCuadrado = radioMinimo * radioMinimo;
|
||||||
|
|
||||||
|
// Buscar todas las botellas cercanas
|
||||||
|
foreach (var obj in _mainViewModel.ObjetosSimulables)
|
||||||
|
{
|
||||||
|
if (obj is osBotella)
|
||||||
|
{
|
||||||
|
float distanciaCuadrada = (float)(Math.Pow(obj.Left - X, 2) + Math.Pow(obj.Top - Y, 2));
|
||||||
|
if (distanciaCuadrada < radioMinimoCuadrado)
|
||||||
|
{
|
||||||
|
return false; // Hay una botella demasiado cerca
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true; // No hay botellas cercanas
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateControl(int elapsedMilliseconds)
|
||||||
|
{
|
||||||
|
bool habilitado;
|
||||||
|
_TON_TOFF.Tiempo_ON_s = Filtro_consenso_ON_s;
|
||||||
|
_TON_TOFF.Tiempo_OFF_s = Filtro_consenso_OFF_s;
|
||||||
|
if (Consenso_Filtrado)
|
||||||
|
habilitado = _TON_TOFF.SenalFiltrada();
|
||||||
|
else
|
||||||
|
habilitado = Consenso;
|
||||||
|
Filter_Output = habilitado;
|
||||||
|
|
||||||
|
if (habilitado && Velocidad_actual_percentual > 0)
|
||||||
|
{
|
||||||
|
if (PrimeraActualizacion)
|
||||||
|
{
|
||||||
|
TiempoEntreBotellas = 3600 / (Botellas_hora * (Velocidad_actual_percentual / 100.0f));
|
||||||
|
TiempoRestante = TiempoEntreBotellas;
|
||||||
|
PrimeraActualizacion = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TiempoRestante -= elapsedMilliseconds / 1000.0f;
|
||||||
|
if (TiempoRestante <= 0)
|
||||||
|
{
|
||||||
|
var X = Left + OffsetLeftSalida;
|
||||||
|
var Y = Top + OffsetTopSalida;
|
||||||
|
|
||||||
|
if (HayEspacioParaNuevaBotella(X, Y))
|
||||||
|
{
|
||||||
|
var nuevaBotella = _mainViewModel.CrearObjetoSimulable(typeof(osBotella), X, Y);
|
||||||
|
((osBotella)nuevaBotella).Diametro = Diametro_botella;
|
||||||
|
((osBotella)nuevaBotella).Preserve_Outside_Transport = Preserve_Outside_Transport;
|
||||||
|
nuevaBotella.AutoCreated = true;
|
||||||
|
|
||||||
|
// Recalcular el tiempo entre botellas por si cambió la velocidad
|
||||||
|
TiempoEntreBotellas = 3600 / (Botellas_hora * (Velocidad_actual_percentual / 100.0f));
|
||||||
|
TiempoRestante = TiempoEntreBotellas;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PrimeraActualizacion = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ucLoaded()
|
||||||
|
{
|
||||||
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
|
// crear el objeto de simulacion
|
||||||
|
base.ucLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private float TiempoEntreBotellas; // Nuevo: almacena el intervalo calculado
|
||||||
|
private bool PrimeraActualizacion = true; // Nuevo: flag para la primera actualización
|
||||||
|
public override void SimulationStop()
|
||||||
|
{
|
||||||
|
PrimeraActualizacion = true; // Reset del flag al detener
|
||||||
|
base.SimulationStop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class ucBottGenerator : UserControl, IDataContainer
|
||||||
|
{
|
||||||
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
|
public ucBottGenerator()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.Loaded += OnLoaded;
|
||||||
|
this.Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucUnLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Highlight(bool State)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZIndexEnum ZIndex_Base()
|
||||||
|
{
|
||||||
|
return ZIndexEnum.Generadores;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,14 +3,9 @@
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:CtrEditor.ObjetosSim"
|
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
|
||||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim">
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim">
|
||||||
|
|
||||||
<UserControl.Resources>
|
|
||||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
|
||||||
</UserControl.Resources>
|
|
||||||
|
|
||||||
<UserControl.DataContext>
|
<UserControl.DataContext>
|
||||||
<vm:osFiller/>
|
<vm:osFiller/>
|
||||||
|
@ -20,7 +15,7 @@
|
||||||
<Image Source="/imagenes/filler.png"
|
<Image Source="/imagenes/filler.png"
|
||||||
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
Stretch="Uniform">
|
Stretch="Fill">
|
||||||
<Image.RenderTransform>
|
<Image.RenderTransform>
|
||||||
<RotateTransform Angle="{Binding Angulo}" />
|
<RotateTransform Angle="{Binding Angulo}" />
|
||||||
</Image.RenderTransform>
|
</Image.RenderTransform>
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
using CtrEditor.Convertidores;
|
|
||||||
using CtrEditor.Siemens;
|
using LibS7Adv;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
|
||||||
namespace CtrEditor.ObjetosSim
|
namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
|
@ -11,6 +13,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class osFiller : osBase, IosBase
|
public partial class osFiller : osBase, IosBase
|
||||||
{
|
{
|
||||||
|
TimerTON_TOFF _TON_TOFF = new TimerTON_TOFF();
|
||||||
// Otros datos y métodos relevantes para la simulación
|
// Otros datos y métodos relevantes para la simulación
|
||||||
|
|
||||||
private float TiempoRestante;
|
private float TiempoRestante;
|
||||||
|
@ -31,8 +34,23 @@ namespace CtrEditor.ObjetosSim
|
||||||
private float offsetLeftSalida;
|
private float offsetLeftSalida;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private float offsetTopSalida;
|
private float offsetTopSalida;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string tag_consenso;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private bool consenso;
|
private bool consenso;
|
||||||
|
|
||||||
|
partial void OnConsensoChanged(bool value)
|
||||||
|
{
|
||||||
|
_TON_TOFF.Senal = value;
|
||||||
|
}
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool consenso_NC;
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool consenso_Filtrado;
|
||||||
|
[ObservableProperty]
|
||||||
|
float filtro_consenso_s;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private float botellas_hora;
|
private float botellas_hora;
|
||||||
|
|
||||||
|
@ -53,14 +71,6 @@ namespace CtrEditor.ObjetosSim
|
||||||
private float velocidad_actual_percentual;
|
private float velocidad_actual_percentual;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private float diametro_botella;
|
private float diametro_botella;
|
||||||
[ObservableProperty]
|
|
||||||
private string tag_consenso;
|
|
||||||
[ObservableProperty]
|
|
||||||
private float ancho;
|
|
||||||
[ObservableProperty]
|
|
||||||
private float alto;
|
|
||||||
[ObservableProperty]
|
|
||||||
private float angulo;
|
|
||||||
|
|
||||||
public osFiller()
|
public osFiller()
|
||||||
{
|
{
|
||||||
|
@ -70,16 +80,29 @@ namespace CtrEditor.ObjetosSim
|
||||||
Velocidad_actual_percentual = 0;
|
Velocidad_actual_percentual = 0;
|
||||||
Diametro_botella = 0.1f;
|
Diametro_botella = 0.1f;
|
||||||
Botellas_hora = 10000;
|
Botellas_hora = 10000;
|
||||||
|
Filtro_consenso_s = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||||
{
|
{
|
||||||
Consenso = LeerBitTag(Tag_consenso);
|
if (Consenso_NC)
|
||||||
|
Consenso = !LeerBitTag(Tag_consenso);
|
||||||
|
else
|
||||||
|
Consenso = LeerBitTag(Tag_consenso);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateControl(int elapsedMilliseconds)
|
public override void UpdateControl(int elapsedMilliseconds)
|
||||||
{
|
{
|
||||||
if (Consenso && Velocidad_actual_percentual > 0)
|
bool habilitado;
|
||||||
|
|
||||||
|
_TON_TOFF.Tiempo_ON_s = _TON_TOFF.Tiempo_OFF_s = Filtro_consenso_s;
|
||||||
|
|
||||||
|
if (Consenso_Filtrado)
|
||||||
|
habilitado = _TON_TOFF.SenalFiltrada();
|
||||||
|
else
|
||||||
|
habilitado = Consenso;
|
||||||
|
|
||||||
|
if (habilitado && Velocidad_actual_percentual > 0)
|
||||||
{
|
{
|
||||||
TiempoRestante -= elapsedMilliseconds / 1000.0f;
|
TiempoRestante -= elapsedMilliseconds / 1000.0f;
|
||||||
if (TiempoRestante <= 0)
|
if (TiempoRestante <= 0)
|
||||||
|
@ -108,10 +131,10 @@ namespace CtrEditor.ObjetosSim
|
||||||
|
|
||||||
if (distancia > distanciaMinima)
|
if (distancia > distanciaMinima)
|
||||||
{
|
{
|
||||||
var nuevaBotella = _mainViewModel.CrearObjetoSimulable(typeof(osBotella), X, Y);
|
osBotella nuevaBotella = (osBotella)_mainViewModel.CrearObjetoSimulable(typeof(osBotella), X, Y);
|
||||||
((osBotella)nuevaBotella).Diametro = Diametro_botella;
|
nuevaBotella.Diametro = Diametro_botella;
|
||||||
nuevaBotella.AutoCreated = true;
|
nuevaBotella.AutoCreated = true;
|
||||||
UltimaBotella = (osBotella)nuevaBotella;
|
UltimaBotella = nuevaBotella;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,7 +149,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
// crear el objeto de simulacion
|
// crear el objeto de simulacion
|
||||||
ActualizarLeftTop();
|
base.ucLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -134,6 +157,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public partial class ucFiller : UserControl, IDataContainer
|
public partial class ucFiller : UserControl, IDataContainer
|
||||||
{
|
{
|
||||||
public osBase? Datos { get; set; }
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
public ucFiller()
|
public ucFiller()
|
||||||
{
|
{
|
||||||
|
@ -153,28 +177,14 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
if (Datos is osFiller datos)
|
if (Datos is osFiller datos)
|
||||||
{
|
{
|
||||||
datos.Ancho = PixelToMeter.Instance.calc.PixelsToMeters(width);
|
datos.Ancho += PixelToMeter.Instance.calc.PixelsToMeters(width);
|
||||||
datos.Alto = PixelToMeter.Instance.calc.PixelsToMeters(width);
|
datos.Alto += PixelToMeter.Instance.calc.PixelsToMeters(height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void Move(float LeftPixels, float TopPixels)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
{
|
|
||||||
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
|
||||||
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Rotate(float Angle)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
if (Datos is osFiller datos)
|
|
||||||
datos.Angulo = Angle;
|
|
||||||
}
|
|
||||||
public void Highlight(bool State) { }
|
public void Highlight(bool State) { }
|
||||||
public int ZIndex()
|
public ZIndexEnum ZIndex_Base()
|
||||||
{
|
{
|
||||||
return 10;
|
return ZIndexEnum.Generadores;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,16 +3,8 @@
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:CtrEditor.ObjetosSim"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<UserControl.Resources>
|
|
||||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
|
||||||
<convert:LevelToHeightMultiConverter x:Key="LevelToHeightMultiConverter"/>
|
|
||||||
<convert:WidthPercentageConverter x:Key="WidthPercentageConverter"/>
|
|
||||||
</UserControl.Resources>
|
|
||||||
|
|
||||||
<UserControl.DataContext>
|
<UserControl.DataContext>
|
||||||
<vm:osTanque Alto="1" Ancho="1" Angulo="-4" />
|
<vm:osTanque Alto="1" Ancho="1" Angulo="-4" />
|
||||||
|
@ -21,8 +13,8 @@
|
||||||
<Grid>
|
<Grid>
|
||||||
<Image x:Name="TankImage"
|
<Image x:Name="TankImage"
|
||||||
Source="/imagenes/tank.png"
|
Source="/imagenes/tank.png"
|
||||||
Width="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
Height="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
Stretch="Uniform">
|
Stretch="Uniform">
|
||||||
</Image>
|
</Image>
|
||||||
<Slider
|
<Slider
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CtrEditor.Convertidores;
|
using LibS7Adv;
|
||||||
using CtrEditor.Siemens;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
|
||||||
namespace CtrEditor.ObjetosSim
|
namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
|
@ -46,12 +46,6 @@ namespace CtrEditor.ObjetosSim
|
||||||
public float max_OUT_Scaled;
|
public float max_OUT_Scaled;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float level;
|
public float level;
|
||||||
[ObservableProperty]
|
|
||||||
public float ancho;
|
|
||||||
[ObservableProperty]
|
|
||||||
public float alto;
|
|
||||||
[ObservableProperty]
|
|
||||||
public float angulo;
|
|
||||||
|
|
||||||
public osTanque()
|
public osTanque()
|
||||||
{
|
{
|
||||||
|
@ -61,7 +55,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
Min_OUT_Scaled = 0;
|
Min_OUT_Scaled = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||||
{
|
{
|
||||||
EscribirWordTagScaled(TagNivel_Word, Level, 0, 100, Min_OUT_Scaled, Max_OUT_Scaled);
|
EscribirWordTagScaled(TagNivel_Word, Level, 0, 100, Min_OUT_Scaled, Max_OUT_Scaled);
|
||||||
Ingreso_Abierto = LeerBitTag(TagIngresoAbierto_Bool);
|
Ingreso_Abierto = LeerBitTag(TagIngresoAbierto_Bool);
|
||||||
|
@ -87,7 +81,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
// crear el objeto de simulacion
|
// crear el objeto de simulacion
|
||||||
ActualizarLeftTop();
|
base.ucLoaded();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,6 +89,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public partial class ucTanque : UserControl, IDataContainer
|
public partial class ucTanque : UserControl, IDataContainer
|
||||||
{
|
{
|
||||||
public osBase? Datos { get; set; }
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
public ucTanque()
|
public ucTanque()
|
||||||
{
|
{
|
||||||
|
@ -110,32 +105,10 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
Datos?.ucUnLoaded();
|
Datos?.ucUnLoaded();
|
||||||
}
|
}
|
||||||
public void Resize(float width, float height)
|
|
||||||
{
|
|
||||||
if (Datos is osTanque datos)
|
|
||||||
{
|
|
||||||
datos.Ancho = PixelToMeter.Instance.calc.PixelsToMeters(width);
|
|
||||||
datos.Alto = PixelToMeter.Instance.calc.PixelsToMeters(width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Move(float LeftPixels, float TopPixels)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
{
|
|
||||||
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
|
||||||
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Rotate(float Angle)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
if (Datos is osTanque datos)
|
|
||||||
datos.Angulo = Angle;
|
|
||||||
}
|
|
||||||
public void Highlight(bool State) { }
|
public void Highlight(bool State) { }
|
||||||
public int ZIndex()
|
public ZIndexEnum ZIndex_Base()
|
||||||
{
|
{
|
||||||
return 10;
|
return ZIndexEnum.Generadores;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,10 @@
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:CtrEditor.ObjetosSim"
|
xmlns:local="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
mc:Ignorable="d"
|
|
||||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
|
||||||
<Storyboard x:Key="PulsingStoryboard" RepeatBehavior="Forever">
|
<Storyboard x:Key="PulsingStoryboard" RepeatBehavior="Forever">
|
||||||
<DoubleAnimation
|
<DoubleAnimation
|
||||||
Storyboard.TargetName="AnimatedEllipse"
|
Storyboard.TargetName="AnimatedEllipse"
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
using CtrEditor.Convertidores;
|
|
||||||
using CtrEditor.Siemens;
|
using LibS7Adv;
|
||||||
using CtrEditor.Simulacion;
|
using CtrEditor.Simulacion;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using nkast.Aether.Physics2D.Common;
|
using nkast.Aether.Physics2D.Common;
|
||||||
using System.Windows.Media.Animation;
|
using System.Windows.Media.Animation;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
namespace CtrEditor.ObjetosSim
|
namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -82,7 +83,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public override void UpdateGeometryStep()
|
public override void UpdateGeometryStep()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +95,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
// crear el objeto de simulacion
|
// crear el objeto de simulacion
|
||||||
ActualizarLeftTop();
|
base.ucLoaded();
|
||||||
SimGeometria = simulationManager.AddDescarte(Diametro, GetCentro());
|
SimGeometria = simulationManager.AddDescarte(Diametro, GetCentro());
|
||||||
}
|
}
|
||||||
public override void ucUnLoaded()
|
public override void ucUnLoaded()
|
||||||
|
@ -109,6 +110,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public partial class ucDescarte : UserControl, IDataContainer
|
public partial class ucDescarte : UserControl, IDataContainer
|
||||||
{
|
{
|
||||||
public osBase? Datos { get; set; }
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
public ucDescarte()
|
public ucDescarte()
|
||||||
{
|
{
|
||||||
|
@ -129,28 +131,10 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
Datos?.ucUnLoaded();
|
Datos?.ucUnLoaded();
|
||||||
}
|
}
|
||||||
public void Resize(float width, float height)
|
|
||||||
{
|
|
||||||
if (Datos is osDescarte datos)
|
|
||||||
{
|
|
||||||
datos.Diametro = PixelToMeter.Instance.calc.PixelsToMeters(width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Move(float LeftPixels, float TopPixels)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
{
|
|
||||||
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
|
||||||
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Rotate(float Angle)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public void Highlight(bool State) { }
|
public void Highlight(bool State) { }
|
||||||
public int ZIndex()
|
public ZIndexEnum ZIndex_Base()
|
||||||
{
|
{
|
||||||
return 10;
|
return ZIndexEnum.Descarte;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,7 @@
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim">
|
||||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
|
||||||
|
|
||||||
<UserControl.Resources>
|
|
||||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
|
||||||
</UserControl.Resources>
|
|
||||||
|
|
||||||
<UserControl.DataContext>
|
<UserControl.DataContext>
|
||||||
<vm:osGuia/>
|
<vm:osGuia/>
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CtrEditor.Convertidores;
|
|
||||||
using CtrEditor.Siemens;
|
using LibS7Adv;
|
||||||
using CtrEditor.Simulacion;
|
using CtrEditor.Simulacion;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
|
||||||
namespace CtrEditor.ObjetosSim
|
namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
|
@ -25,21 +26,20 @@ namespace CtrEditor.ObjetosSim
|
||||||
set => SetProperty(ref nombre, value);
|
set => SetProperty(ref nombre, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
public float ancho;
|
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float altoGuia;
|
public float altoGuia;
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
public float angulo;
|
|
||||||
|
|
||||||
private void ActualizarGeometrias()
|
private void ActualizarGeometrias()
|
||||||
{
|
{
|
||||||
if (_visualRepresentation is ucGuia uc)
|
if (_visualRepresentation is ucGuia uc)
|
||||||
UpdateOrCreateLine(SimGeometria, uc.Guia);
|
UpdateOrCreateLine(SimGeometria, uc.Guia);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnMoveResizeRotate()
|
||||||
|
{
|
||||||
|
ActualizarGeometrias();
|
||||||
|
}
|
||||||
|
|
||||||
public osGuia()
|
public osGuia()
|
||||||
{
|
{
|
||||||
Ancho = 1;
|
Ancho = 1;
|
||||||
|
@ -57,12 +57,12 @@ namespace CtrEditor.ObjetosSim
|
||||||
public override void UpdateGeometryStep()
|
public override void UpdateGeometryStep()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) { }
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds) { }
|
||||||
public override void ucLoaded()
|
public override void ucLoaded()
|
||||||
{
|
{
|
||||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
// crear el objeto de simulacion
|
// crear el objeto de simulacion
|
||||||
ActualizarLeftTop();
|
base.ucLoaded();
|
||||||
|
|
||||||
if (_visualRepresentation is ucGuia uc)
|
if (_visualRepresentation is ucGuia uc)
|
||||||
SimGeometria = AddLine(simulationManager, uc.Guia);
|
SimGeometria = AddLine(simulationManager, uc.Guia);
|
||||||
|
@ -80,6 +80,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public partial class ucGuia : UserControl, IDataContainer
|
public partial class ucGuia : UserControl, IDataContainer
|
||||||
{
|
{
|
||||||
public osBase? Datos { get; set; }
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
public ucGuia()
|
public ucGuia()
|
||||||
{
|
{
|
||||||
|
@ -95,29 +96,10 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
Datos?.ucUnLoaded();
|
Datos?.ucUnLoaded();
|
||||||
}
|
}
|
||||||
public void Resize(float width, float height)
|
|
||||||
{
|
|
||||||
if (Datos is osGuia datos)
|
|
||||||
datos.Ancho = PixelToMeter.Instance.calc.PixelsToMeters(width);
|
|
||||||
}
|
|
||||||
public void Move(float LeftPixels, float TopPixels)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
{
|
|
||||||
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
|
||||||
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Rotate(float Angle)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
if (Datos is osGuia datos)
|
|
||||||
datos.Angulo = Angle;
|
|
||||||
}
|
|
||||||
public void Highlight(bool State) { }
|
public void Highlight(bool State) { }
|
||||||
public int ZIndex()
|
public ZIndexEnum ZIndex_Base()
|
||||||
{
|
{
|
||||||
return 1;
|
return ZIndexEnum.Guias;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,9 @@
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:localuc="clr-namespace:CtrEditor.ObjetosSim.UserControls"
|
xmlns:localuc="clr-namespace:CtrEditor.ObjetosSim.UserControls"
|
||||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
|
||||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<UserControl.Resources>
|
|
||||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
|
||||||
</UserControl.Resources>
|
|
||||||
|
|
||||||
<UserControl.DataContext>
|
<UserControl.DataContext>
|
||||||
<vm:osTransporteCurva />
|
<vm:osTransporteCurva />
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
using System.Windows;
|
using System.ComponentModel;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CtrEditor.Convertidores;
|
using LibS7Adv;
|
||||||
using CtrEditor.Siemens;
|
|
||||||
using CtrEditor.Simulacion;
|
using CtrEditor.Simulacion;
|
||||||
|
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CtrEditor.ObjetosSim
|
namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
|
@ -13,16 +15,12 @@ namespace CtrEditor.ObjetosSim
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class osTransporteCurva : osBase, IosBase
|
public partial class osTransporteCurva : osBase, IosBase
|
||||||
{
|
{
|
||||||
private float frictionCoefficient;
|
private osBase Motor = null;
|
||||||
private float velMax50hz; // en metros por minuto
|
|
||||||
private float tiempoRampa;
|
|
||||||
private bool esMarcha;
|
|
||||||
|
|
||||||
private float _velocidadActual;
|
|
||||||
private osBase _osMotor = null;
|
|
||||||
|
|
||||||
private simCurve Simulation_TransporteCurva;
|
private simCurve Simulation_TransporteCurva;
|
||||||
|
|
||||||
|
private float _velocidadActual;
|
||||||
|
|
||||||
public static string NombreClase()
|
public static string NombreClase()
|
||||||
{
|
{
|
||||||
return "Transporte Curva 90";
|
return "Transporte Curva 90";
|
||||||
|
@ -35,15 +33,92 @@ namespace CtrEditor.ObjetosSim
|
||||||
}
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private float radioExterno;
|
public float velocidadActual;
|
||||||
[ObservableProperty]
|
|
||||||
private float radioInterno;
|
partial void OnVelocidadActualChanged(float value)
|
||||||
[ObservableProperty]
|
{
|
||||||
private string motor;
|
SetSpeed();
|
||||||
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
[NotifyPropertyChangedFor(nameof(AnguloFinal))]
|
bool invertirDireccion;
|
||||||
public float angulo;
|
|
||||||
|
partial void OnInvertirDireccionChanged(bool value)
|
||||||
|
{
|
||||||
|
SetSpeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSpeed()
|
||||||
|
{
|
||||||
|
if (InvertirDireccion)
|
||||||
|
Simulation_TransporteCurva?.SetSpeed(-VelocidadActual);
|
||||||
|
else
|
||||||
|
Simulation_TransporteCurva?.SetSpeed(VelocidadActual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private float radioExterno;
|
||||||
|
|
||||||
|
partial void OnRadioExternoChanged(float value)
|
||||||
|
{
|
||||||
|
// Update ancho and alto based on radioExterno
|
||||||
|
Ancho = value * 2;
|
||||||
|
Alto = value * 2;
|
||||||
|
|
||||||
|
// Ensure radioInterno maintains proper proportion if needed
|
||||||
|
if (RadioInterno >= value)
|
||||||
|
{
|
||||||
|
RadioInterno = value * 0.75f; // Default proportion
|
||||||
|
}
|
||||||
|
|
||||||
|
ActualizarGeometrias();
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private float radioInterno;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Bit to enable Link to Motor")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
string tag_ReleActivatedMotor;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Link to Motor")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
[property: ItemsSource(typeof(osBaseItemsSource<osVMmotorSim>))]
|
||||||
|
string id_Motor;
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
private PropertyChangedEventHandler motorPropertyChangedHandler;
|
||||||
|
|
||||||
|
partial void OnId_MotorChanged(string value)
|
||||||
|
{
|
||||||
|
if (Motor != null && motorPropertyChangedHandler != null)
|
||||||
|
Motor.PropertyChanged -= motorPropertyChangedHandler;
|
||||||
|
|
||||||
|
if (_mainViewModel != null && !string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
Motor = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => s is osVMmotorSim motor && motor.Nombre == value);
|
||||||
|
if (Motor != null)
|
||||||
|
{
|
||||||
|
motorPropertyChangedHandler = (sender, e) =>
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(osVMmotorSim.Nombre))
|
||||||
|
{
|
||||||
|
Id_Motor = ((osVMmotorSim)sender).Nombre;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Motor.PropertyChanged += motorPropertyChangedHandler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AnguloChanged(float value)
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(AnguloFinal));
|
||||||
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
[NotifyPropertyChangedFor(nameof(AnguloFinal))]
|
[NotifyPropertyChangedFor(nameof(AnguloFinal))]
|
||||||
|
@ -55,59 +130,103 @@ namespace CtrEditor.ObjetosSim
|
||||||
get => Angulo+Arco_en_grados;
|
get => Angulo+Arco_en_grados;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float VelocidadActual
|
|
||||||
{
|
|
||||||
get => _velocidadActual;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_velocidadActual = value;
|
|
||||||
Simulation_TransporteCurva?.SetSpeed(value);
|
|
||||||
OnPropertyChanged(nameof(VelocidadActual));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ActualizarGeometrias()
|
private void ActualizarGeometrias()
|
||||||
{
|
{
|
||||||
if (_visualRepresentation is ucTransporteCurva uc)
|
if (_visualRepresentation is ucTransporteCurva uc)
|
||||||
{
|
{
|
||||||
UpdateCurve(Simulation_TransporteCurva, RadioInterno, RadioExterno, Angulo, Angulo+Arco_en_grados);
|
UpdateCurve(Simulation_TransporteCurva, RadioInterno, RadioExterno, Angulo, Angulo+Arco_en_grados);
|
||||||
Simulation_TransporteCurva.Speed = VelocidadActual;
|
SetSpeed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public float FrictionCoefficient { get => frictionCoefficient; set => frictionCoefficient = value; }
|
public override void OnMoveResizeRotate()
|
||||||
public float VelMax50hz { get => velMax50hz; set => velMax50hz = value; }
|
{
|
||||||
public float TiempoRampa { get => tiempoRampa; set => tiempoRampa = value; }
|
ActualizarGeometrias();
|
||||||
public bool EsMarcha { get => esMarcha; set => esMarcha = value; }
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public float frictionCoefficient;
|
||||||
|
[ObservableProperty]
|
||||||
|
public float velMax50hz;
|
||||||
|
[ObservableProperty]
|
||||||
|
public float tiempoRampa;
|
||||||
|
[ObservableProperty]
|
||||||
|
public bool esMarcha;
|
||||||
|
|
||||||
|
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||||
|
{
|
||||||
|
// Calculate the proportional change factor
|
||||||
|
float widthChangeFactor = (Ancho + Delta_Width) / Ancho;
|
||||||
|
float heightChangeFactor = (Alto + Delta_Height) / Alto;
|
||||||
|
|
||||||
|
// Use the average or minimum change factor to maintain aspect ratio
|
||||||
|
float changeFactor = Math.Min(widthChangeFactor, heightChangeFactor);
|
||||||
|
|
||||||
|
// Save the original radiuses for calculating position adjustments
|
||||||
|
float originalRadioExterno = RadioExterno;
|
||||||
|
|
||||||
|
// Apply the change factor to both radios
|
||||||
|
RadioExterno *= changeFactor;
|
||||||
|
RadioInterno *= changeFactor;
|
||||||
|
|
||||||
|
// Calculate position adjustment to keep the component centered
|
||||||
|
float radiusDifference = RadioExterno - originalRadioExterno;
|
||||||
|
|
||||||
|
// Adjust Left and Top to maintain center position
|
||||||
|
// We move by negative half the difference because the component expands outward
|
||||||
|
Left -= radiusDifference;
|
||||||
|
Top -= radiusDifference;
|
||||||
|
|
||||||
|
// Ensure minimums
|
||||||
|
if (RadioExterno < 0.1f)
|
||||||
|
RadioExterno = 0.1f;
|
||||||
|
|
||||||
|
if (RadioInterno < 0.05f)
|
||||||
|
RadioInterno = 0.05f;
|
||||||
|
|
||||||
|
// Ensure radioInterno is always less than radioExterno
|
||||||
|
if (RadioInterno >= RadioExterno)
|
||||||
|
RadioInterno = RadioExterno * 0.75f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public osTransporteCurva()
|
public osTransporteCurva()
|
||||||
{
|
{
|
||||||
RadioExterno = 1.3f;
|
RadioExterno = 1.3f;
|
||||||
RadioInterno = 1;
|
RadioInterno = 1f;
|
||||||
|
Ancho = RadioExterno * 2; // Set initial width based on external radius
|
||||||
|
Alto = RadioExterno * 2; // Set initial height based on external radius
|
||||||
Arco_en_grados = 90;
|
Arco_en_grados = 90;
|
||||||
|
Tag_ReleActivatedMotor = "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateGeometryStart()
|
public override void UpdateGeometryStart()
|
||||||
{
|
{
|
||||||
// Se llama antes de la simulacion
|
// Se llama antes de la simulacion
|
||||||
ActualizarGeometrias();
|
ActualizarGeometrias();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||||
{
|
{
|
||||||
if (_osMotor != null)
|
if (Motor != null)
|
||||||
{
|
{
|
||||||
if (_osMotor is osVMmotorSim motor)
|
if (Motor is osVMmotorSim motor)
|
||||||
VelocidadActual = motor.Velocidad;
|
if (LeerBitTag(Tag_ReleActivatedMotor))
|
||||||
|
VelocidadActual = motor.Velocidad;
|
||||||
|
else
|
||||||
|
VelocidadActual = 0;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
_osMotor = ObtenerLink(Motor, typeof(osVMmotorSim));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ucLoaded()
|
public override void ucLoaded()
|
||||||
{
|
{
|
||||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
// crear el objeto de simulacion
|
// crear el objeto de simulacion
|
||||||
ActualizarLeftTop();
|
base.ucLoaded();
|
||||||
|
|
||||||
|
OnId_MotorChanged(Id_Motor); // Link Id_Motor = Motor
|
||||||
|
|
||||||
if (_visualRepresentation is ucTransporteCurva uc)
|
if (_visualRepresentation is ucTransporteCurva uc)
|
||||||
Simulation_TransporteCurva = AddCurve(RadioInterno,RadioExterno, Angulo, Angulo + Arco_en_grados);
|
Simulation_TransporteCurva = AddCurve(RadioInterno,RadioExterno, Angulo, Angulo + Arco_en_grados);
|
||||||
|
@ -126,6 +245,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public partial class ucTransporteCurva : UserControl, IDataContainer
|
public partial class ucTransporteCurva : UserControl, IDataContainer
|
||||||
{
|
{
|
||||||
public osBase? Datos { get; set; }
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
public ucTransporteCurva()
|
public ucTransporteCurva()
|
||||||
{
|
{
|
||||||
|
@ -141,35 +261,10 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
Datos?.ucUnLoaded();
|
Datos?.ucUnLoaded();
|
||||||
}
|
}
|
||||||
public void Resize(float RadioExterno, float RadioInterno)
|
|
||||||
{
|
|
||||||
if (Datos is osTransporteCurva datos)
|
|
||||||
{
|
|
||||||
if (RadioExterno > RadioInterno && RadioExterno > 0 && RadioInterno >= 0)
|
|
||||||
{
|
|
||||||
datos.RadioExterno = PixelToMeter.Instance.calc.PixelsToMeters(RadioExterno);
|
|
||||||
datos.RadioInterno = PixelToMeter.Instance.calc.PixelsToMeters(RadioInterno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Move(float LeftPixels, float TopPixels)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
{
|
|
||||||
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
|
||||||
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Rotate(float Angle)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
if (Datos is osTransporteCurva datos)
|
|
||||||
datos.Angulo = Angle;
|
|
||||||
}
|
|
||||||
public void Highlight(bool State) { }
|
public void Highlight(bool State) { }
|
||||||
public int ZIndex()
|
public ZIndexEnum ZIndex_Base()
|
||||||
{
|
{
|
||||||
return 1;
|
return ZIndexEnum.Estaticos;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,9 @@
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
|
||||||
<convert:DistanceToMarginConverter x:Key="DistanceToMarginConverter"/>
|
|
||||||
|
|
||||||
<!-- Define the VisualBrush for the conveyor belt pattern -->
|
<!-- Define the VisualBrush for the conveyor belt pattern -->
|
||||||
<VisualBrush x:Key="BeltBrush" TileMode="Tile" Viewport="0,0,20,10" ViewportUnits="Absolute" Viewbox="0,0,20,10" ViewboxUnits="Absolute">
|
<VisualBrush x:Key="BeltBrush" TileMode="Tile" Viewport="0,0,20,10" ViewportUnits="Absolute" Viewbox="0,0,20,10" ViewboxUnits="Absolute">
|
||||||
<VisualBrush.Transform>
|
<VisualBrush.Transform>
|
||||||
|
@ -20,8 +16,8 @@
|
||||||
</VisualBrush.Transform>
|
</VisualBrush.Transform>
|
||||||
<VisualBrush.Visual>
|
<VisualBrush.Visual>
|
||||||
<Canvas>
|
<Canvas>
|
||||||
<Rectangle Fill="#FFBFBFBF" Width="10" Height="10"/>
|
<Rectangle Fill="LightGray" Width="10" Height="10" />
|
||||||
<Rectangle Fill="LightGray" Width="10" Height="10" Canvas.Left="10"/>
|
<Rectangle Fill="GhostWhite" Width="10" Height="10" Canvas.Left="10" />
|
||||||
</Canvas>
|
</Canvas>
|
||||||
</VisualBrush.Visual>
|
</VisualBrush.Visual>
|
||||||
</VisualBrush>
|
</VisualBrush>
|
||||||
|
@ -32,18 +28,37 @@
|
||||||
</UserControl.DataContext>
|
</UserControl.DataContext>
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Canvas>
|
<Canvas RenderTransformOrigin="0,0">
|
||||||
<StackPanel x:Name="RectanglesContainer">
|
<Canvas.RenderTransform>
|
||||||
<StackPanel.RenderTransform>
|
<TransformGroup>
|
||||||
|
<ScaleTransform/>
|
||||||
|
<SkewTransform/>
|
||||||
<RotateTransform Angle="{Binding Angulo}"/>
|
<RotateTransform Angle="{Binding Angulo}"/>
|
||||||
</StackPanel.RenderTransform>
|
<TranslateTransform/>
|
||||||
<Rectangle x:Name="GuiaSuperior" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}" Fill="Blue"
|
</TransformGroup>
|
||||||
Margin="{Binding Distance, Converter={StaticResource DistanceToMarginConverter}}"/>
|
</Canvas.RenderTransform>
|
||||||
<Rectangle x:Name="Transporte" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
<StackPanel x:Name="RectanglesContainer">
|
||||||
Margin="{Binding Distance, Converter={StaticResource DistanceToMarginConverter}}"
|
<Rectangle x:Name="GuiaSuperior" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
Fill="{StaticResource BeltBrush}"/>
|
Height="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
<Rectangle x:Name="GuiaInferior" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}" Fill="Blue"/>
|
Fill="{Binding Color, Converter={StaticResource ColorToBrushConverter}}"
|
||||||
|
Margin="{Binding Distance, Converter={StaticResource DistanceToMarginConverter}}"/>
|
||||||
|
<Rectangle x:Name="Transporte" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Margin="{Binding Distance, Converter={StaticResource DistanceToMarginConverter}}"
|
||||||
|
Fill="{StaticResource BeltBrush}"/>
|
||||||
|
<Rectangle x:Name="GuiaInferior" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Height="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Fill="{Binding Color, Converter={StaticResource ColorToBrushConverter}}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
<Viewbox Canvas.Top="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Stretch="Uniform">
|
||||||
|
<Label Content="{Binding Nombre}" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold" FontSize="18" Opacity="0.9"/>
|
||||||
|
</Viewbox>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
using System.Windows;
|
using System.ComponentModel;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CtrEditor.Convertidores;
|
using LibS7Adv;
|
||||||
using CtrEditor.Siemens;
|
|
||||||
using CtrEditor.Simulacion;
|
using CtrEditor.Simulacion;
|
||||||
|
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CtrEditor.ObjetosSim
|
namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
|
@ -12,7 +16,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class osTransporteGuias : osBase, IosBase
|
public partial class osTransporteGuias : osBase, IosBase
|
||||||
{
|
{
|
||||||
private osBase _osMotor = null;
|
private osBase Motor = null;
|
||||||
|
|
||||||
private simTransporte? SimGeometria;
|
private simTransporte? SimGeometria;
|
||||||
private simGuia? Guia_Superior;
|
private simGuia? Guia_Superior;
|
||||||
|
@ -24,6 +28,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
return "Transporte Guias";
|
return "Transporte Guias";
|
||||||
}
|
}
|
||||||
private string nombre = NombreClase();
|
private string nombre = NombreClase();
|
||||||
|
|
||||||
public override string Nombre
|
public override string Nombre
|
||||||
{
|
{
|
||||||
get => nombre;
|
get => nombre;
|
||||||
|
@ -31,34 +36,89 @@ namespace CtrEditor.ObjetosSim
|
||||||
}
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private float velocidadActual;
|
public float velocidadActual;
|
||||||
|
|
||||||
partial void OnVelocidadActualChanged(float value)
|
partial void OnVelocidadActualChanged(float value)
|
||||||
{
|
{
|
||||||
SimGeometria?.SetSpeed(value);
|
SetSpeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
bool invertirDireccion;
|
||||||
|
|
||||||
|
partial void OnInvertirDireccionChanged(bool value)
|
||||||
|
{
|
||||||
|
SetSpeed();
|
||||||
|
if (_visualRepresentation is ucTransporteGuias uc)
|
||||||
|
{
|
||||||
|
CrearAnimacionStoryBoardTrasnporte(uc.Transporte, InvertirDireccion);
|
||||||
|
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSpeed()
|
||||||
|
{
|
||||||
|
if (InvertirDireccion)
|
||||||
|
SimGeometria?.SetSpeed(-VelocidadActual);
|
||||||
|
else
|
||||||
|
SimGeometria?.SetSpeed(VelocidadActual);
|
||||||
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||||
}
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
public string motor;
|
|
||||||
|
|
||||||
partial void OnMotorChanged(string value)
|
[ObservableProperty]
|
||||||
|
Color color = Colors.Blue;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Bit to enable Link to Motor")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
string tag_ReleActivatedMotor;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Link to Motor")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
[property: ItemsSource(typeof(osBaseItemsSource<osVMmotorSim>))]
|
||||||
|
string id_Motor;
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
private PropertyChangedEventHandler motorPropertyChangedHandler;
|
||||||
|
|
||||||
|
partial void OnId_MotorChanged(string value)
|
||||||
{
|
{
|
||||||
_osMotor = ObtenerLink(Motor, typeof(osVMmotorSim));
|
if (Motor != null && motorPropertyChangedHandler != null)
|
||||||
|
Motor.PropertyChanged -= motorPropertyChangedHandler;
|
||||||
|
|
||||||
|
if (_mainViewModel != null && !string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
Motor = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => s is osVMmotorSim motor && motor.Nombre == value);
|
||||||
|
if (Motor != null)
|
||||||
|
{
|
||||||
|
motorPropertyChangedHandler = (sender, e) =>
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(osVMmotorSim.Nombre))
|
||||||
|
{
|
||||||
|
Id_Motor = ((osVMmotorSim)sender).Nombre;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Motor.PropertyChanged += motorPropertyChangedHandler;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
public override void AltoChanged(float value)
|
||||||
public float ancho;
|
|
||||||
[ObservableProperty]
|
|
||||||
public float alto;
|
|
||||||
|
|
||||||
partial void OnAltoChanged(float value)
|
|
||||||
{
|
{
|
||||||
ActualizarGeometrias();
|
ActualizarGeometrias();
|
||||||
}
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float angulo;
|
public bool esFreno;
|
||||||
|
|
||||||
|
partial void OnEsFrenoChanged(bool value)
|
||||||
|
{
|
||||||
|
if (SimGeometria != null)
|
||||||
|
SimGeometria.isBrake = value;
|
||||||
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float frictionCoefficient;
|
public float frictionCoefficient;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
|
@ -78,14 +138,18 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
UpdateRectangle(SimGeometria, uc.Transporte, Alto, Ancho, Angulo);
|
UpdateRectangle(SimGeometria, uc.Transporte, Alto, Ancho, Angulo);
|
||||||
UpdateOrCreateLine(Guia_Superior, uc.GuiaSuperior);
|
UpdateOrCreateLine(Guia_Superior, uc.GuiaSuperior);
|
||||||
UpdateOrCreateLine(Guia_Inferior, uc.GuiaInferior) ;
|
UpdateOrCreateLine(Guia_Inferior, uc.GuiaInferior);
|
||||||
|
|
||||||
SimGeometria.DistanceGuide2Guide = Alto;
|
SimGeometria.DistanceGuide2Guide = Alto;
|
||||||
SimGeometria.Speed = VelocidadActual;
|
SimGeometria.isBrake = esFreno;
|
||||||
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
SetSpeed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnMoveResizeRotate()
|
||||||
|
{
|
||||||
|
ActualizarGeometrias();
|
||||||
|
}
|
||||||
|
|
||||||
public osTransporteGuias()
|
public osTransporteGuias()
|
||||||
{
|
{
|
||||||
|
@ -93,6 +157,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
Alto = 0.10f;
|
Alto = 0.10f;
|
||||||
AltoGuia = 0.03f;
|
AltoGuia = 0.03f;
|
||||||
Distance = 0.01f;
|
Distance = 0.01f;
|
||||||
|
Tag_ReleActivatedMotor = "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateGeometryStart()
|
public override void UpdateGeometryStart()
|
||||||
|
@ -100,26 +165,28 @@ namespace CtrEditor.ObjetosSim
|
||||||
// Se llama antes de la simulacion
|
// Se llama antes de la simulacion
|
||||||
ActualizarGeometrias();
|
ActualizarGeometrias();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SimulationStop()
|
public override void SimulationStop()
|
||||||
{
|
{
|
||||||
// Se llama al detener la simulacion
|
// Se llama al detener la simulacion
|
||||||
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||||
}
|
}
|
||||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
|
||||||
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||||
{
|
{
|
||||||
if (_osMotor != null)
|
if (Motor != null)
|
||||||
{
|
if (Motor is osVMmotorSim id_motor)
|
||||||
if (_osMotor is osVMmotorSim motor)
|
if (LeerBitTag(Tag_ReleActivatedMotor))
|
||||||
VelocidadActual = motor.Velocidad;
|
VelocidadActual = id_motor.Velocidad;
|
||||||
} else if (Motor.Length > 0)
|
else
|
||||||
_osMotor = ObtenerLink(Motor, typeof(osVMmotorSim));
|
VelocidadActual = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ucLoaded()
|
public override void ucLoaded()
|
||||||
{
|
{
|
||||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
// crear el objeto de simulacion
|
// crear el objeto de simulacion
|
||||||
ActualizarLeftTop();
|
base.ucLoaded();
|
||||||
|
|
||||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
// crear el objeto de simulacion
|
// crear el objeto de simulacion
|
||||||
|
@ -131,9 +198,9 @@ namespace CtrEditor.ObjetosSim
|
||||||
Guia_Superior = AddLine(simulationManager, uc.GuiaSuperior);
|
Guia_Superior = AddLine(simulationManager, uc.GuiaSuperior);
|
||||||
Guia_Inferior = AddLine(simulationManager, uc.GuiaInferior);
|
Guia_Inferior = AddLine(simulationManager, uc.GuiaInferior);
|
||||||
|
|
||||||
CrearAnimacionStoryBoardTrasnporte(uc.Transporte);
|
CrearAnimacionStoryBoardTrasnporte(uc.Transporte, InvertirDireccion);
|
||||||
}
|
}
|
||||||
Motor = Motor; // Forzar la busqueda
|
OnId_MotorChanged(Id_Motor); // Link Id_Motor = Motor
|
||||||
}
|
}
|
||||||
public override void ucUnLoaded()
|
public override void ucUnLoaded()
|
||||||
{
|
{
|
||||||
|
@ -150,6 +217,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public partial class ucTransporteGuias : UserControl, IDataContainer
|
public partial class ucTransporteGuias : UserControl, IDataContainer
|
||||||
{
|
{
|
||||||
public osBase? Datos { get; set; }
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
public ucTransporteGuias()
|
public ucTransporteGuias()
|
||||||
{
|
{
|
||||||
|
@ -165,30 +233,12 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
Datos?.ucUnLoaded();
|
Datos?.ucUnLoaded();
|
||||||
}
|
}
|
||||||
public void Resize(float width, float height)
|
|
||||||
{
|
|
||||||
if (Datos is osTransporteGuias datos)
|
|
||||||
datos.Ancho = PixelToMeter.Instance.calc.PixelsToMeters(width);
|
|
||||||
}
|
|
||||||
public void Move(float LeftPixels, float TopPixels)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
{
|
|
||||||
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
|
||||||
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Rotate(float Angle)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
if (Datos is osTransporteGuias datos)
|
|
||||||
datos.Angulo = Angle;
|
|
||||||
}
|
|
||||||
public void Highlight(bool State) { }
|
public void Highlight(bool State) { }
|
||||||
public int ZIndex()
|
public ZIndexEnum ZIndex_Base()
|
||||||
{
|
{
|
||||||
return 1;
|
return ZIndexEnum.Estaticos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
<UserControl x:Class="CtrEditor.ObjetosSim.ucTransporteGuiasUnion"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
|
xmlns:uc="clr-namespace:CtrEditor.ObjetosSim.UserControls"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<UserControl.Resources>
|
||||||
|
<!-- Define the VisualBrush for the conveyor belt pattern -->
|
||||||
|
<VisualBrush x:Key="BeltBrushA" TileMode="Tile" Viewport="0,0,20,10" ViewportUnits="Absolute" Viewbox="0,0,20,10" ViewboxUnits="Absolute">
|
||||||
|
<VisualBrush.Transform>
|
||||||
|
<TransformGroup>
|
||||||
|
<TranslateTransform/>
|
||||||
|
</TransformGroup>
|
||||||
|
</VisualBrush.Transform>
|
||||||
|
<VisualBrush.Visual>
|
||||||
|
<Canvas>
|
||||||
|
<Rectangle Fill="#FFBFBFBF" Width="10" Height="10"/>
|
||||||
|
<Rectangle Fill="LightGray" Width="10" Height="10" Canvas.Left="10"/>
|
||||||
|
</Canvas>
|
||||||
|
</VisualBrush.Visual>
|
||||||
|
</VisualBrush>
|
||||||
|
<VisualBrush x:Key="BeltBrushB" TileMode="Tile" Viewport="0,0,20,10" ViewportUnits="Absolute" Viewbox="0,0,20,10" ViewboxUnits="Absolute">
|
||||||
|
<VisualBrush.Transform>
|
||||||
|
<TransformGroup>
|
||||||
|
<TranslateTransform/>
|
||||||
|
</TransformGroup>
|
||||||
|
</VisualBrush.Transform>
|
||||||
|
<VisualBrush.Visual>
|
||||||
|
<Canvas>
|
||||||
|
<Rectangle Fill="#FFBFBFBF" Width="10" Height="10"/>
|
||||||
|
<Rectangle Fill="LightGray" Width="10" Height="10" Canvas.Left="10"/>
|
||||||
|
</Canvas>
|
||||||
|
</VisualBrush.Visual>
|
||||||
|
</VisualBrush>
|
||||||
|
|
||||||
|
</UserControl.Resources>
|
||||||
|
|
||||||
|
<UserControl.DataContext>
|
||||||
|
<vm:osTransporteGuiasUnion Color="Red"/>
|
||||||
|
</UserControl.DataContext>
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Canvas x:Name="Canvas" RenderTransformOrigin="0,0">
|
||||||
|
<Canvas.RenderTransform>
|
||||||
|
<TransformGroup>
|
||||||
|
<ScaleTransform/>
|
||||||
|
<SkewTransform/>
|
||||||
|
<RotateTransform Angle="{Binding Angulo}"/>
|
||||||
|
<TranslateTransform/>
|
||||||
|
</TransformGroup>
|
||||||
|
</Canvas.RenderTransform>
|
||||||
|
<Rectangle x:Name="TransporteA" Width="{Binding AnchoTransporte_oculto, Converter={StaticResource MeterToPixelConverter},ConverterParameter=1}"
|
||||||
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Fill="{StaticResource BeltBrushA}"
|
||||||
|
/>
|
||||||
|
<Rectangle x:Name="TransporteB" Width="{Binding AnchoTransporte_oculto, Converter={StaticResource MeterToPixelConverter},ConverterParameter=1}"
|
||||||
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Fill="{StaticResource BeltBrushB}"
|
||||||
|
Canvas.Top="{Binding Alto, Converter={StaticResource MeterToPixelConverter},ConverterParameter=1.05}"
|
||||||
|
Canvas.Left="{Binding AnchoRecto, Converter={StaticResource MeterToPixelConverter},ConverterParameter=1}"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<uc:ThreeLinesControl x:Name="GuiaSuperior" AnchoRecto="{Binding AnchoRecto, Converter={StaticResource MeterToPixelConverter},ConverterParameter=1}"
|
||||||
|
AnchoCentro="{Binding AnchoCentral, Converter={StaticResource MeterToPixelConverter},ConverterParameter=1}"
|
||||||
|
Altura="{Binding Alto, Converter={StaticResource MeterToPixelConverter},ConverterParameter=1}"
|
||||||
|
AltoGuia="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter},ConverterParameter=1}"
|
||||||
|
Canvas.Top="{Binding Distance, Converter={StaticResource MeterToPixelConverter},ConverterParameter=-1}" Color="{Binding Color}"/>
|
||||||
|
|
||||||
|
<uc:ThreeLinesControl x:Name="GuiaInferior" AnchoRecto="{Binding AnchoRecto, Converter={StaticResource MeterToPixelConverter},ConverterParameter=1}"
|
||||||
|
AnchoCentro="{Binding AnchoCentral, Converter={StaticResource MeterToPixelConverter},ConverterParameter=1}"
|
||||||
|
Altura="{Binding Alto, Converter={StaticResource MeterToPixelConverter},ConverterParameter=1}"
|
||||||
|
AltoGuia="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter},ConverterParameter=1}"
|
||||||
|
Color="{Binding Color}">
|
||||||
|
|
||||||
|
<Canvas.Top>
|
||||||
|
<MultiBinding Converter="{StaticResource SumConverter}">
|
||||||
|
<Binding Path="Alto" Converter="{StaticResource MeterToPixelConverter}" ConverterParameter="1.0" />
|
||||||
|
<Binding Path="Distance" Converter="{StaticResource MeterToPixelConverter}" ConverterParameter="1.0" />
|
||||||
|
</MultiBinding>
|
||||||
|
</Canvas.Top>
|
||||||
|
</uc:ThreeLinesControl>
|
||||||
|
</Canvas>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,408 @@
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Animation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using LibS7Adv;
|
||||||
|
using CtrEditor.Simulacion;
|
||||||
|
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
|
||||||
|
namespace CtrEditor.ObjetosSim
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ucTransporteGuiasUnion.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class osTransporteGuiasUnion : osBase, IosBase
|
||||||
|
{
|
||||||
|
private osBase _osMotorA = null;
|
||||||
|
private osBase _osMotorB = null;
|
||||||
|
|
||||||
|
Dictionary<Rectangle, simTransporte> SimGeometriaT;
|
||||||
|
Dictionary<Rectangle, simGuia> SimGeometriaG;
|
||||||
|
Dictionary<Rectangle, Storyboard> Storyboards;
|
||||||
|
Dictionary<Rectangle, BoolReference> TransportsDirection;
|
||||||
|
Dictionary<Rectangle, FloatReference> TransportsVelocidad;
|
||||||
|
|
||||||
|
public static string NombreClase()
|
||||||
|
{
|
||||||
|
return "Transporte Guias Union";
|
||||||
|
}
|
||||||
|
private string nombre = NombreClase();
|
||||||
|
|
||||||
|
public override string Nombre
|
||||||
|
{
|
||||||
|
get => nombre;
|
||||||
|
set => SetProperty(ref nombre, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
Color color;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Bit to enable Link to Motor")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
string tag_ReleActivatedMotor;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Link to Motor A")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
[property: ItemsSource(typeof(osBaseItemsSource<osVMmotorSim>))]
|
||||||
|
string id_MotorA;
|
||||||
|
|
||||||
|
partial void OnId_MotorAChanged(string value)
|
||||||
|
{
|
||||||
|
if (_osMotorA != null)
|
||||||
|
_osMotorA.PropertyChanged -= OnMotorPropertyChangedA;
|
||||||
|
if (_mainViewModel != null && value != null && value.Length > 0)
|
||||||
|
{
|
||||||
|
_osMotorA = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osVMmotorSim && s.Nombre == value), null);
|
||||||
|
if (_osMotorA != null)
|
||||||
|
_osMotorA.PropertyChanged += OnMotorPropertyChangedA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMotorPropertyChangedA(object sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(osVMmotorSim.Nombre))
|
||||||
|
{
|
||||||
|
Id_MotorA = ((osVMmotorSim)sender).Nombre;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Link to Motor B")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
[property: ItemsSource(typeof(osBaseItemsSource<osVMmotorSim>))]
|
||||||
|
string id_MotorB;
|
||||||
|
|
||||||
|
partial void OnId_MotorBChanged(string value)
|
||||||
|
{
|
||||||
|
if (_osMotorB != null)
|
||||||
|
_osMotorB.PropertyChanged -= OnMotorPropertyChangedB;
|
||||||
|
if (_mainViewModel != null && value != null && value.Length > 0)
|
||||||
|
{
|
||||||
|
_osMotorB = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osVMmotorSim && s.Nombre == value), null);
|
||||||
|
if (_osMotorB != null)
|
||||||
|
_osMotorB.PropertyChanged += OnMotorPropertyChangedB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMotorPropertyChangedB(object sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(osVMmotorSim.Nombre))
|
||||||
|
{
|
||||||
|
Id_MotorB = ((osVMmotorSim)sender).Nombre;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public float velocidadActualA;
|
||||||
|
|
||||||
|
partial void OnVelocidadActualAChanged(float value)
|
||||||
|
{
|
||||||
|
if (_visualRepresentation is ucTransporteGuiasUnion uc)
|
||||||
|
{
|
||||||
|
var transporte = uc.TransporteA;
|
||||||
|
SetSpeed(transporte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
bool invertirDireccionA;
|
||||||
|
|
||||||
|
partial void OnInvertirDireccionAChanged(bool value)
|
||||||
|
{
|
||||||
|
if (_visualRepresentation is ucTransporteGuiasUnion uc)
|
||||||
|
{
|
||||||
|
var transporte = uc.TransporteA;
|
||||||
|
|
||||||
|
SetSpeed(transporte);
|
||||||
|
ActualizarStoryboards(transporte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public float velocidadActualB;
|
||||||
|
|
||||||
|
partial void OnVelocidadActualBChanged(float value)
|
||||||
|
{
|
||||||
|
if (_visualRepresentation is ucTransporteGuiasUnion uc)
|
||||||
|
{
|
||||||
|
var transporte = uc.TransporteB;
|
||||||
|
SetSpeed(transporte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
bool invertirDireccionB;
|
||||||
|
|
||||||
|
partial void OnInvertirDireccionBChanged(bool value)
|
||||||
|
{
|
||||||
|
if (_visualRepresentation is ucTransporteGuiasUnion uc)
|
||||||
|
{
|
||||||
|
var transporte = uc.TransporteB;
|
||||||
|
|
||||||
|
SetSpeed(transporte);
|
||||||
|
ActualizarStoryboards(transporte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||||
|
{
|
||||||
|
AnchoRecto += Delta_Width;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public float anchoRecto;
|
||||||
|
[ObservableProperty]
|
||||||
|
public float anchoCentral;
|
||||||
|
|
||||||
|
|
||||||
|
partial void OnAnchoRectoChanged(float value)
|
||||||
|
{
|
||||||
|
AnchoTransporte_oculto = anchoRecto + anchoCentral;
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnAnchoCentralChanged(float value)
|
||||||
|
{
|
||||||
|
AnchoTransporte_oculto = anchoRecto + anchoCentral;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public float anchoTransporte_oculto;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public float frictionCoefficient;
|
||||||
|
[ObservableProperty]
|
||||||
|
public float velMax50hz;
|
||||||
|
[ObservableProperty]
|
||||||
|
public float tiempoRampa;
|
||||||
|
[ObservableProperty]
|
||||||
|
public bool esMarcha;
|
||||||
|
[ObservableProperty]
|
||||||
|
private float distance;
|
||||||
|
[ObservableProperty]
|
||||||
|
private float altoGuia;
|
||||||
|
|
||||||
|
void ActualizarStoryboards(Rectangle transporte)
|
||||||
|
{
|
||||||
|
if (!Storyboards.Keys.Contains(transporte)) return;
|
||||||
|
|
||||||
|
var direccion = TransportsDirection[transporte].Value;
|
||||||
|
var velocidad = TransportsVelocidad[transporte].Value;
|
||||||
|
|
||||||
|
Storyboards[transporte] = CrearAnimacionMultiStoryBoardTrasnporte(Storyboards[transporte], transporte, direccion);
|
||||||
|
ActualizarAnimacionMultiStoryBoardTransporte(Storyboards[transporte], velocidad);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSpeed(Rectangle transporte)
|
||||||
|
{
|
||||||
|
if (!Storyboards.Keys.Contains(transporte)) return;
|
||||||
|
|
||||||
|
var invertirDireccion = TransportsDirection[transporte].Value;
|
||||||
|
var velocidad = TransportsVelocidad[transporte].Value;
|
||||||
|
|
||||||
|
if (invertirDireccion)
|
||||||
|
SimGeometriaT[transporte]?.SetSpeed(-velocidad);
|
||||||
|
else
|
||||||
|
SimGeometriaT[transporte]?.SetSpeed(velocidad);
|
||||||
|
|
||||||
|
ActualizarAnimacionMultiStoryBoardTransporte(Storyboards[transporte], velocidad);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ActualizarGeometrias()
|
||||||
|
{
|
||||||
|
if (_visualRepresentation is ucTransporteGuiasUnion uc)
|
||||||
|
{
|
||||||
|
foreach (var transporte in SimGeometriaT)
|
||||||
|
{
|
||||||
|
UpdateRectangle(transporte.Value, transporte.Key, Alto, AnchoTransporte_oculto, Angulo);
|
||||||
|
ActualizarStoryboards(transporte.Key);
|
||||||
|
SetSpeed(transporte.Key);
|
||||||
|
}
|
||||||
|
foreach (var l in SimGeometriaG)
|
||||||
|
UpdateOrCreateLine(l.Value, l.Key);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnMoveResizeRotate()
|
||||||
|
{
|
||||||
|
ActualizarGeometrias();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public osTransporteGuiasUnion()
|
||||||
|
{
|
||||||
|
AnchoRecto = 0.5f;
|
||||||
|
AnchoCentral = 0.5f;
|
||||||
|
Alto = 0.10f;
|
||||||
|
AltoGuia = 0.03f;
|
||||||
|
Distance = 0.02f;
|
||||||
|
SimGeometriaT = new Dictionary<Rectangle, simTransporte>();
|
||||||
|
SimGeometriaG = new Dictionary<Rectangle, simGuia>();
|
||||||
|
Storyboards = new Dictionary<Rectangle, Storyboard>();
|
||||||
|
TransportsDirection = new Dictionary<Rectangle, BoolReference>();
|
||||||
|
TransportsVelocidad = new Dictionary<Rectangle, FloatReference>();
|
||||||
|
Tag_ReleActivatedMotor = "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateGeometryStart()
|
||||||
|
{
|
||||||
|
// Se llama antes de la simulacion
|
||||||
|
ActualizarGeometrias();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SimulationStop()
|
||||||
|
{
|
||||||
|
// Se llama al detener la simulacion
|
||||||
|
if (_visualRepresentation is ucTransporteGuiasUnion uc)
|
||||||
|
{
|
||||||
|
SetSpeed(uc.TransporteB);
|
||||||
|
SetSpeed(uc.TransporteA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||||
|
{
|
||||||
|
if (_osMotorA != null)
|
||||||
|
{
|
||||||
|
if (_osMotorA is osVMmotorSim motor)
|
||||||
|
if (LeerBitTag(Tag_ReleActivatedMotor))
|
||||||
|
VelocidadActualA = motor.Velocidad;
|
||||||
|
else
|
||||||
|
VelocidadActualA = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_osMotorB != null)
|
||||||
|
{
|
||||||
|
if (_osMotorB is osVMmotorSim motor)
|
||||||
|
if (LeerBitTag(Tag_ReleActivatedMotor))
|
||||||
|
VelocidadActualB = motor.Velocidad;
|
||||||
|
else
|
||||||
|
VelocidadActualB = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ucLoaded()
|
||||||
|
{
|
||||||
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
|
// crear el objeto de simulacion
|
||||||
|
base.ucLoaded();
|
||||||
|
|
||||||
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
|
// crear el objeto de simulacion
|
||||||
|
if (_visualRepresentation is ucTransporteGuiasUnion uc)
|
||||||
|
{
|
||||||
|
foreach (var child in uc.Canvas.Children)
|
||||||
|
if (child is Rectangle rect)
|
||||||
|
if (rect.Name.StartsWith("Transporte"))
|
||||||
|
{
|
||||||
|
SimGeometriaT.Add(rect,AddRectangle(simulationManager, rect, Alto, AnchoTransporte_oculto, Angulo));
|
||||||
|
Storyboards.Add(rect,CrearAnimacionMultiStoryBoardTrasnporte(rect,false));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var child in uc.GuiaSuperior.Canvas.Children)
|
||||||
|
if (child is Rectangle rect)
|
||||||
|
SimGeometriaG.Add(rect, AddLine(simulationManager, rect));
|
||||||
|
|
||||||
|
foreach (var child in uc.GuiaInferior.Canvas.Children)
|
||||||
|
if (child is Rectangle rect)
|
||||||
|
SimGeometriaG.Add(rect, AddLine(simulationManager, rect));
|
||||||
|
|
||||||
|
TransportsDirection.Add(uc.TransporteA, new BoolReference(() => InvertirDireccionA, value => InvertirDireccionA = value));
|
||||||
|
TransportsDirection.Add(uc.TransporteB, new BoolReference(() => InvertirDireccionB, value => InvertirDireccionB = value));
|
||||||
|
|
||||||
|
TransportsVelocidad.Add(uc.TransporteA, new FloatReference(() => VelocidadActualA, value => VelocidadActualA = value));
|
||||||
|
TransportsVelocidad.Add(uc.TransporteB, new FloatReference(() => VelocidadActualB, value => VelocidadActualB = value));
|
||||||
|
|
||||||
|
}
|
||||||
|
OnId_MotorAChanged(Id_MotorA); // Link Id_Motor = Motor
|
||||||
|
OnId_MotorBChanged(Id_MotorB); // Link Id_Motor = Motor
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void ucUnLoaded()
|
||||||
|
{
|
||||||
|
// El UserControl se esta eliminando
|
||||||
|
// eliminar el objeto de simulacion
|
||||||
|
foreach (var s in SimGeometriaT)
|
||||||
|
simulationManager.Remove(s.Value);
|
||||||
|
foreach (var s in SimGeometriaG)
|
||||||
|
simulationManager.Remove(s.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BoolReference
|
||||||
|
{
|
||||||
|
private Func<bool> getter;
|
||||||
|
private Action<bool> setter;
|
||||||
|
|
||||||
|
public BoolReference(Func<bool> getter, Action<bool> setter)
|
||||||
|
{
|
||||||
|
this.getter = getter;
|
||||||
|
this.setter = setter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Value
|
||||||
|
{
|
||||||
|
get => getter();
|
||||||
|
set => setter(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FloatReference
|
||||||
|
{
|
||||||
|
private Func<float> getter;
|
||||||
|
private Action<float> setter;
|
||||||
|
|
||||||
|
public FloatReference(Func<float> getter, Action<float> setter)
|
||||||
|
{
|
||||||
|
this.getter = getter;
|
||||||
|
this.setter = setter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Value
|
||||||
|
{
|
||||||
|
get => getter();
|
||||||
|
set => setter(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public partial class ucTransporteGuiasUnion : UserControl, IDataContainer
|
||||||
|
{
|
||||||
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
|
public ucTransporteGuiasUnion()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.Loaded += OnLoaded;
|
||||||
|
this.Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucLoaded();
|
||||||
|
}
|
||||||
|
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucUnLoaded();
|
||||||
|
}
|
||||||
|
public void Highlight(bool State) { }
|
||||||
|
public ZIndexEnum ZIndex_Base()
|
||||||
|
{
|
||||||
|
return ZIndexEnum.Estaticos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,13 +4,10 @@
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||||
mc:Ignorable="d"
|
|
||||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
|
||||||
|
|
||||||
<!-- Define the VisualBrush for the conveyor belt pattern -->
|
<!-- Define the VisualBrush for the conveyor belt pattern -->
|
||||||
<VisualBrush x:Key="BeltBrush" TileMode="Tile" Viewport="0,0,20,10" ViewportUnits="Absolute" Viewbox="0,0,20,10" ViewboxUnits="Absolute">
|
<VisualBrush x:Key="BeltBrush" TileMode="Tile" Viewport="0,0,20,10" ViewportUnits="Absolute" Viewbox="0,0,20,10" ViewboxUnits="Absolute">
|
||||||
<VisualBrush.Transform>
|
<VisualBrush.Transform>
|
||||||
|
@ -20,8 +17,8 @@
|
||||||
</VisualBrush.Transform>
|
</VisualBrush.Transform>
|
||||||
<VisualBrush.Visual>
|
<VisualBrush.Visual>
|
||||||
<Canvas>
|
<Canvas>
|
||||||
<Rectangle Fill="Gray" Width="10" Height="10"/>
|
<Rectangle Fill="LightGray" Width="10" Height="10"/>
|
||||||
<Rectangle Fill="DarkGray" Width="10" Height="10" Canvas.Left="10"/>
|
<Rectangle Fill="GhostWhite" Width="10" Height="10" Canvas.Left="10"/>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
</VisualBrush.Visual>
|
</VisualBrush.Visual>
|
||||||
</VisualBrush>
|
</VisualBrush>
|
||||||
|
@ -31,14 +28,25 @@
|
||||||
<vm:osTransporteTTop Ancho="2"/>
|
<vm:osTransporteTTop Ancho="2"/>
|
||||||
</UserControl.DataContext>
|
</UserControl.DataContext>
|
||||||
|
|
||||||
<Canvas>
|
<Canvas RenderTransformOrigin="0,0">
|
||||||
<Rectangle x:Name="Transporte"
|
<Canvas.RenderTransform>
|
||||||
|
<TransformGroup>
|
||||||
|
<ScaleTransform />
|
||||||
|
<SkewTransform />
|
||||||
|
<RotateTransform Angle="{Binding Angulo}" />
|
||||||
|
<TranslateTransform />
|
||||||
|
</TransformGroup>
|
||||||
|
</Canvas.RenderTransform>
|
||||||
|
<Rectangle x:Name="Transporte"
|
||||||
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
Fill="{StaticResource BeltBrush}">
|
Fill="{StaticResource BeltBrush}">
|
||||||
<Rectangle.RenderTransform>
|
|
||||||
<RotateTransform Angle="{Binding Angulo}"/>
|
|
||||||
</Rectangle.RenderTransform>
|
|
||||||
</Rectangle>
|
</Rectangle>
|
||||||
|
<Viewbox
|
||||||
|
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}" Stretch="Uniform">
|
||||||
|
<Label Content="{Binding Nombre}" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold"
|
||||||
|
FontSize="18" Opacity="0.9" />
|
||||||
|
</Viewbox>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
</UserControl>
|
</UserControl>
|
|
@ -1,13 +1,12 @@
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media.Animation;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CtrEditor.Convertidores;
|
using LibS7Adv;
|
||||||
using CtrEditor.Siemens;
|
|
||||||
using CtrEditor.Simulacion;
|
using CtrEditor.Simulacion;
|
||||||
using System.Windows.Input;
|
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace CtrEditor.ObjetosSim
|
namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
|
@ -18,58 +17,103 @@ namespace CtrEditor.ObjetosSim
|
||||||
|
|
||||||
public partial class osTransporteTTop : osBase, IosBase
|
public partial class osTransporteTTop : osBase, IosBase
|
||||||
{
|
{
|
||||||
private osBase _osMotor = null;
|
|
||||||
|
|
||||||
private simTransporte SimGeometria;
|
private simTransporte SimGeometria;
|
||||||
|
private osVMmotorSim Motor;
|
||||||
|
|
||||||
public static string NombreClase()
|
public static string NombreClase()
|
||||||
{
|
{
|
||||||
return "Transporte";
|
return "Transporte";
|
||||||
}
|
}
|
||||||
private string nombre = "Transporte TTOP";
|
private string nombre = "Transporte TTOP";
|
||||||
|
|
||||||
|
[property: Category("Id:")]
|
||||||
public override string Nombre
|
public override string Nombre
|
||||||
{
|
{
|
||||||
get => nombre;
|
get => nombre;
|
||||||
set => SetProperty(ref nombre, value);
|
set => SetProperty(ref nombre, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private float velocidadActual;
|
[ObservableProperty]
|
||||||
public float VelocidadActual
|
[property: Category("Simulation:")]
|
||||||
|
public float velocidadActual;
|
||||||
|
|
||||||
|
partial void OnVelocidadActualChanged(float value)
|
||||||
{
|
{
|
||||||
get => velocidadActual;
|
SetSpeed();
|
||||||
set
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Simulation:")]
|
||||||
|
bool invertirDireccion;
|
||||||
|
|
||||||
|
partial void OnInvertirDireccionChanged(bool value)
|
||||||
|
{
|
||||||
|
SetSpeed();
|
||||||
|
if (_visualRepresentation is ucTransporteTTop uc)
|
||||||
{
|
{
|
||||||
if (value != velocidadActual)
|
CrearAnimacionStoryBoardTrasnporte(uc.Transporte, InvertirDireccion);
|
||||||
|
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSpeed()
|
||||||
|
{
|
||||||
|
if (InvertirDireccion)
|
||||||
|
SimGeometria?.SetSpeed(-VelocidadActual);
|
||||||
|
else
|
||||||
|
SimGeometria?.SetSpeed(VelocidadActual);
|
||||||
|
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Bit to enable Link to Motor")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
string tag_ReleActivatedMotor;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Link to Motor")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
[property: ItemsSource(typeof(osBaseItemsSource<osVMmotorSim>))]
|
||||||
|
string id_Motor;
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
private PropertyChangedEventHandler motorPropertyChangedHandler;
|
||||||
|
|
||||||
|
partial void OnId_MotorChanged(string value)
|
||||||
|
{
|
||||||
|
if (Motor != null && motorPropertyChangedHandler != null)
|
||||||
|
Motor.PropertyChanged -= motorPropertyChangedHandler;
|
||||||
|
|
||||||
|
if (_mainViewModel != null && !string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
Motor = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => s is osVMmotorSim motor && motor.Nombre == value);
|
||||||
|
if (Motor != null)
|
||||||
{
|
{
|
||||||
velocidadActual = value;
|
motorPropertyChangedHandler = (sender, e) =>
|
||||||
SimGeometria?.SetSpeed(value);
|
{
|
||||||
SetProperty(ref velocidadActual, value);
|
if (e.PropertyName == nameof(osVMmotorSim.Nombre))
|
||||||
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
{
|
||||||
|
Id_Motor = ((osVMmotorSim)sender).Nombre;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Motor.PropertyChanged += motorPropertyChangedHandler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
public string motor;
|
|
||||||
|
|
||||||
partial void OnMotorChanged(string value)
|
|
||||||
{
|
|
||||||
_osMotor = ObtenerLink(Motor, typeof(osVMmotorSim));
|
|
||||||
}
|
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float ancho;
|
[property: Category("Setup:")]
|
||||||
[ObservableProperty]
|
|
||||||
public float alto;
|
|
||||||
[ObservableProperty]
|
|
||||||
public float angulo;
|
|
||||||
[ObservableProperty]
|
|
||||||
public float frictionCoefficient;
|
public float frictionCoefficient;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
|
[property: Category("Setup:")]
|
||||||
public float velMax50hz;
|
public float velMax50hz;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
|
[property: Category("Setup:")]
|
||||||
public float tiempoRampa;
|
public float tiempoRampa;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
|
[property: Category("Setup:")]
|
||||||
public bool esMarcha;
|
public bool esMarcha;
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,16 +121,22 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
if (_visualRepresentation is ucTransporteTTop uc)
|
if (_visualRepresentation is ucTransporteTTop uc)
|
||||||
{
|
{
|
||||||
UpdateRectangle(SimGeometria, uc.Transporte,Alto,Ancho,Angulo);
|
UpdateRectangle(SimGeometria, uc.Transporte, Alto, Ancho, Angulo);
|
||||||
SimGeometria.Speed = VelocidadActual;
|
SetSpeed();
|
||||||
}
|
}
|
||||||
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnMoveResizeRotate()
|
||||||
|
{
|
||||||
|
ActualizarGeometrias();
|
||||||
|
}
|
||||||
|
|
||||||
public osTransporteTTop()
|
public osTransporteTTop()
|
||||||
{
|
{
|
||||||
Ancho = 1;
|
Ancho = 1;
|
||||||
Alto = 0.10f;
|
Alto = 0.10f;
|
||||||
|
Tag_ReleActivatedMotor = "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SimulationStop()
|
public override void SimulationStop()
|
||||||
|
@ -100,27 +150,27 @@ namespace CtrEditor.ObjetosSim
|
||||||
ActualizarGeometrias();
|
ActualizarGeometrias();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||||
{
|
{
|
||||||
if (_osMotor != null)
|
if (Motor != null)
|
||||||
{
|
if (Motor is osVMmotorSim motor)
|
||||||
if (_osMotor is osVMmotorSim motor)
|
if (LeerBitTag(Tag_ReleActivatedMotor))
|
||||||
VelocidadActual = motor.Velocidad;
|
VelocidadActual = motor.Velocidad;
|
||||||
}
|
else
|
||||||
else if (Motor.Length > 0)
|
VelocidadActual = 0;
|
||||||
_osMotor = ObtenerLink(Motor, typeof(osVMmotorSim));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ucLoaded()
|
public override void ucLoaded()
|
||||||
{
|
{
|
||||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
// crear el objeto de simulacion
|
// crear el objeto de simulacion
|
||||||
ActualizarLeftTop();
|
base.ucLoaded();
|
||||||
|
OnId_MotorChanged(Id_Motor); // Link Id_Motor = Motor
|
||||||
|
|
||||||
if (_visualRepresentation is ucTransporteTTop uc)
|
if (_visualRepresentation is ucTransporteTTop uc)
|
||||||
{
|
{
|
||||||
SimGeometria = AddRectangle(simulationManager, uc.Transporte, Alto, Ancho, Angulo);
|
SimGeometria = AddRectangle(simulationManager, uc.Transporte, Alto, Ancho, Angulo);
|
||||||
CrearAnimacionStoryBoardTrasnporte(uc.Transporte);
|
CrearAnimacionStoryBoardTrasnporte(uc.Transporte, InvertirDireccion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override void ucUnLoaded()
|
public override void ucUnLoaded()
|
||||||
|
@ -135,6 +185,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public partial class ucTransporteTTop : UserControl, IDataContainer
|
public partial class ucTransporteTTop : UserControl, IDataContainer
|
||||||
{
|
{
|
||||||
public osBase? Datos { get; set; }
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
public ucTransporteTTop()
|
public ucTransporteTTop()
|
||||||
{
|
{
|
||||||
|
@ -150,31 +201,16 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
Datos?.ucUnLoaded();
|
Datos?.ucUnLoaded();
|
||||||
}
|
}
|
||||||
public void Resize(float width, float height)
|
|
||||||
{
|
|
||||||
if (Datos is osTransporteTTop datos)
|
|
||||||
datos.Ancho = PixelToMeter.Instance.calc.PixelsToMeters(width);
|
|
||||||
}
|
|
||||||
public void Move(float LeftPixels, float TopPixels)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
{
|
|
||||||
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
|
||||||
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Rotate(float Angle) {
|
|
||||||
if (Datos != null)
|
|
||||||
if (Datos is osTransporteTTop datos)
|
|
||||||
datos.Angulo = Angle;
|
|
||||||
}
|
|
||||||
public void Highlight(bool State) { }
|
public void Highlight(bool State) { }
|
||||||
public int ZIndex()
|
public ZIndexEnum ZIndex_Base()
|
||||||
{
|
{
|
||||||
return 1;
|
return ZIndexEnum.Estaticos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
<UserControl x:Class="CtrEditor.ObjetosSim.ucTransporteTTopDualInverter"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:i="http://schemas.microsoft.com/xaml/behaviors" xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<UserControl.Resources>
|
||||||
|
<!-- Define the VisualBrush for the conveyor belt pattern -->
|
||||||
|
<VisualBrush x:Key="BeltBrush" TileMode="Tile" Viewport="0,0,20,10" ViewportUnits="Absolute" Viewbox="0,0,20,10"
|
||||||
|
ViewboxUnits="Absolute">
|
||||||
|
<VisualBrush.Transform>
|
||||||
|
<TransformGroup>
|
||||||
|
<TranslateTransform />
|
||||||
|
</TransformGroup>
|
||||||
|
</VisualBrush.Transform>
|
||||||
|
<VisualBrush.Visual>
|
||||||
|
<Canvas>
|
||||||
|
<Rectangle Fill="LightGray" Width="10" Height="10" />
|
||||||
|
<Rectangle Fill="GhostWhite" Width="10" Height="10" Canvas.Left="10" />
|
||||||
|
</Canvas>
|
||||||
|
</VisualBrush.Visual>
|
||||||
|
</VisualBrush>
|
||||||
|
</UserControl.Resources>
|
||||||
|
|
||||||
|
<UserControl.DataContext>
|
||||||
|
<vm:osTransporteTTop Ancho="2" />
|
||||||
|
</UserControl.DataContext>
|
||||||
|
|
||||||
|
<Canvas RenderTransformOrigin="0,0">
|
||||||
|
<Canvas.RenderTransform>
|
||||||
|
<TransformGroup>
|
||||||
|
<ScaleTransform />
|
||||||
|
<SkewTransform />
|
||||||
|
<RotateTransform Angle="{Binding Angulo}" />
|
||||||
|
<TranslateTransform />
|
||||||
|
</TransformGroup>
|
||||||
|
</Canvas.RenderTransform>
|
||||||
|
<Rectangle x:Name="Transporte" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Fill="{StaticResource BeltBrush}">
|
||||||
|
</Rectangle>
|
||||||
|
<Viewbox Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}" Stretch="Uniform">
|
||||||
|
<Label Content="{Binding Nombre}" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold"
|
||||||
|
FontSize="18" Opacity="0.9" />
|
||||||
|
</Viewbox>
|
||||||
|
</Canvas>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,267 @@
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using LibS7Adv;
|
||||||
|
using CtrEditor.Simulacion;
|
||||||
|
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace CtrEditor.ObjetosSim
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ucTransporteTTop.xaml
|
||||||
|
/// </summary>
|
||||||
|
///
|
||||||
|
|
||||||
|
public partial class osTransporteTTopDualInverter : osBase, IosBase
|
||||||
|
{
|
||||||
|
|
||||||
|
private simTransporte SimGeometria;
|
||||||
|
private osVMmotorSim MotorA;
|
||||||
|
private osVMmotorSim MotorB;
|
||||||
|
|
||||||
|
public static string NombreClase()
|
||||||
|
{
|
||||||
|
return "Transporte Dual Inverter";
|
||||||
|
}
|
||||||
|
private string nombre = "Transporte TTOP Dual Inverter";
|
||||||
|
|
||||||
|
[property: Category("Id:")]
|
||||||
|
public override string Nombre
|
||||||
|
{
|
||||||
|
get => nombre;
|
||||||
|
set => SetProperty(ref nombre, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Simulation:")]
|
||||||
|
public float velocidadActual;
|
||||||
|
|
||||||
|
partial void OnVelocidadActualChanged(float value)
|
||||||
|
{
|
||||||
|
SetSpeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Simulation:")]
|
||||||
|
bool invertirDireccion;
|
||||||
|
|
||||||
|
partial void OnInvertirDireccionChanged(bool value)
|
||||||
|
{
|
||||||
|
SetSpeed();
|
||||||
|
if (_visualRepresentation is ucTransporteTTop uc)
|
||||||
|
{
|
||||||
|
CrearAnimacionStoryBoardTrasnporte(uc.Transporte, InvertirDireccion);
|
||||||
|
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSpeed()
|
||||||
|
{
|
||||||
|
if (InvertirDireccion)
|
||||||
|
SimGeometria?.SetSpeed(-VelocidadActual);
|
||||||
|
else
|
||||||
|
SimGeometria?.SetSpeed(VelocidadActual);
|
||||||
|
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Bit to enable Link to Inverter A")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
string tag_ReleActivatedMotor_A;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Bit to enable Link to Inverter B")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
string tag_ReleActivatedMotor_B;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Link to Inverter A")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
[property: ItemsSource(typeof(osBaseItemsSource<osVMmotorSim>))]
|
||||||
|
string id_Motor_A;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Link to Inverter B")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
[property: ItemsSource(typeof(osBaseItemsSource<osVMmotorSim>))]
|
||||||
|
string id_Motor_B;
|
||||||
|
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
private PropertyChangedEventHandler motorPropertyChangedHandler;
|
||||||
|
|
||||||
|
partial void OnId_Motor_AChanged(string value)
|
||||||
|
{
|
||||||
|
if (MotorA != null && motorPropertyChangedHandler != null)
|
||||||
|
MotorA.PropertyChanged -= motorPropertyChangedHandler;
|
||||||
|
|
||||||
|
if (_mainViewModel != null && !string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
MotorA = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => s is osVMmotorSim motor && motor.Nombre == value);
|
||||||
|
if (MotorA != null)
|
||||||
|
{
|
||||||
|
motorPropertyChangedHandler = (sender, e) =>
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(osVMmotorSim.Nombre))
|
||||||
|
{
|
||||||
|
Id_Motor_A = ((osVMmotorSim)sender).Nombre;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
MotorA.PropertyChanged += motorPropertyChangedHandler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnId_Motor_BChanged(string value)
|
||||||
|
{
|
||||||
|
if (MotorB != null && motorPropertyChangedHandler != null)
|
||||||
|
MotorB.PropertyChanged -= motorPropertyChangedHandler;
|
||||||
|
|
||||||
|
if (_mainViewModel != null && !string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
MotorB = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => s is osVMmotorSim motor && motor.Nombre == value);
|
||||||
|
if (MotorB != null)
|
||||||
|
{
|
||||||
|
motorPropertyChangedHandler = (sender, e) =>
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(osVMmotorSim.Nombre))
|
||||||
|
{
|
||||||
|
Id_Motor_B = ((osVMmotorSim)sender).Nombre;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
MotorB.PropertyChanged += motorPropertyChangedHandler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Setup:")]
|
||||||
|
public float frictionCoefficient;
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Setup:")]
|
||||||
|
public float velMax50hz;
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Setup:")]
|
||||||
|
public float tiempoRampa;
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Setup:")]
|
||||||
|
public bool esMarcha;
|
||||||
|
|
||||||
|
|
||||||
|
private void ActualizarGeometrias()
|
||||||
|
{
|
||||||
|
if (_visualRepresentation is ucTransporteTTop uc)
|
||||||
|
{
|
||||||
|
UpdateRectangle(SimGeometria, uc.Transporte, Alto, Ancho, Angulo);
|
||||||
|
SetSpeed();
|
||||||
|
}
|
||||||
|
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnMoveResizeRotate()
|
||||||
|
{
|
||||||
|
ActualizarGeometrias();
|
||||||
|
}
|
||||||
|
|
||||||
|
public osTransporteTTopDualInverter()
|
||||||
|
{
|
||||||
|
Ancho = 1;
|
||||||
|
Alto = 0.10f;
|
||||||
|
Tag_ReleActivatedMotor_A = "1";
|
||||||
|
Tag_ReleActivatedMotor_B = "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SimulationStop()
|
||||||
|
{
|
||||||
|
// Se llama al detener la simulacion
|
||||||
|
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||||
|
}
|
||||||
|
public override void UpdateGeometryStart()
|
||||||
|
{
|
||||||
|
// Se llama antes de la simulacion
|
||||||
|
ActualizarGeometrias();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||||
|
{
|
||||||
|
if (LeerBitTag(Tag_ReleActivatedMotor_A))
|
||||||
|
{
|
||||||
|
if (MotorA != null)
|
||||||
|
if (MotorA is osVMmotorSim motor)
|
||||||
|
VelocidadActual = motor.Velocidad;
|
||||||
|
else
|
||||||
|
VelocidadActual = 0;
|
||||||
|
}
|
||||||
|
else if (LeerBitTag(Tag_ReleActivatedMotor_B))
|
||||||
|
{
|
||||||
|
if (MotorB != null)
|
||||||
|
if (MotorB is osVMmotorSim motor)
|
||||||
|
VelocidadActual = motor.Velocidad;
|
||||||
|
else
|
||||||
|
VelocidadActual = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ucLoaded()
|
||||||
|
{
|
||||||
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
|
// crear el objeto de simulacion
|
||||||
|
base.ucLoaded();
|
||||||
|
OnId_Motor_AChanged(Id_Motor_A); // Link Id_Motor = Motor
|
||||||
|
OnId_Motor_BChanged(Id_Motor_B); // Link Id_Motor = Motor
|
||||||
|
|
||||||
|
if (_visualRepresentation is ucTransporteTTop uc)
|
||||||
|
{
|
||||||
|
SimGeometria = AddRectangle(simulationManager, uc.Transporte, Alto, Ancho, Angulo);
|
||||||
|
CrearAnimacionStoryBoardTrasnporte(uc.Transporte, InvertirDireccion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override void ucUnLoaded()
|
||||||
|
{
|
||||||
|
// El UserControl se esta eliminando
|
||||||
|
// eliminar el objeto de simulacion
|
||||||
|
simulationManager.Remove(SimGeometria);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class ucTransporteTTopDualInverter : UserControl, IDataContainer
|
||||||
|
{
|
||||||
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
|
public ucTransporteTTopDualInverter()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.Loaded += OnLoaded;
|
||||||
|
this.Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucLoaded();
|
||||||
|
}
|
||||||
|
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucUnLoaded();
|
||||||
|
}
|
||||||
|
public void Highlight(bool State) { }
|
||||||
|
public ZIndexEnum ZIndex_Base()
|
||||||
|
{
|
||||||
|
return ZIndexEnum.Estaticos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,34 +4,40 @@
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:CtrEditor.ObjetosSim"
|
xmlns:local="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
mc:Ignorable="d"
|
|
||||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<UserControl.Resources>
|
|
||||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
|
||||||
</UserControl.Resources>
|
|
||||||
|
|
||||||
<UserControl.DataContext>
|
<UserControl.DataContext>
|
||||||
<vm:osVMmotorSim ImageSource_oculta="/imagenes/motorNegro.png" />
|
<vm:osVMmotorSim ImageSource_oculta="/imagenes/motorNegro.png"/>
|
||||||
</UserControl.DataContext>
|
</UserControl.DataContext>
|
||||||
|
|
||||||
<Grid>
|
<Grid RenderTransformOrigin="0,0">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RenderTransform>
|
||||||
<RowDefinition Height="Auto" />
|
<TransformGroup>
|
||||||
<RowDefinition Height="*" />
|
<RotateTransform Angle="{Binding Angulo}"/>
|
||||||
</Grid.RowDefinitions>
|
</TransformGroup>
|
||||||
|
</Grid.RenderTransform>
|
||||||
|
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<Label Grid.Row="0" Content="{Binding Nombre}"
|
<Image Grid.Column="0" Source="{Binding ImageSource_oculta}"
|
||||||
|
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Stretch="Uniform"/>
|
||||||
|
|
||||||
|
<Viewbox Grid.Column="1" Stretch="Uniform">
|
||||||
|
<Label Content="{Binding Nombre}"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
Foreground="Black"/>
|
Foreground="Black"
|
||||||
|
Opacity="0.5"/>
|
||||||
<Image Grid.Row="1" Source="{Binding ImageSource_oculta}"
|
</Viewbox>
|
||||||
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
|
||||||
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
|
||||||
Stretch="Uniform"/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
using CtrEditor.Convertidores;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CtrEditor.Siemens;
|
using CtrEditor.FuncionesBase;
|
||||||
|
using LibS7Adv;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
|
||||||
|
|
||||||
namespace CtrEditor.ObjetosSim
|
namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
|
@ -17,7 +18,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
|
|
||||||
// Otros datos y métodos relevantes para la simulación
|
// Otros datos y métodos relevantes para la simulación
|
||||||
|
|
||||||
private VMSimMotor motState = new VMSimMotor();
|
private VMSimMotor motState = new VMSimMotor();
|
||||||
|
|
||||||
public static string NombreClase()
|
public static string NombreClase()
|
||||||
|
@ -37,8 +38,23 @@ namespace CtrEditor.ObjetosSim
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float tamano;
|
public float tamano;
|
||||||
|
|
||||||
|
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||||
|
{
|
||||||
|
Tamano += Delta_Width + Delta_Height;
|
||||||
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float maxRatedHz;
|
public float refresh_Time_ms;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public float proporcional_Speed;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public float max_Speed_for_Ramp;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
bool vFD_Trip_NC;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float tiempoRampa;
|
public float tiempoRampa;
|
||||||
|
@ -51,15 +67,32 @@ namespace CtrEditor.ObjetosSim
|
||||||
}
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public bool encendido;
|
bool encendido;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public int pLC_NumeroMotor;
|
int pLC_NumeroMotor;
|
||||||
|
|
||||||
|
partial void OnPLC_NumeroMotorChanged(int value)
|
||||||
|
{
|
||||||
|
if (PLC_DB_Motor == 0)
|
||||||
|
{
|
||||||
|
PLC_DB_Motor = PLC_NumeroMotor - 30 + 300;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
int pLC_DB_Motor;
|
||||||
|
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float ratio;
|
public float ratio;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float velocidad;
|
public float velocidad;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public bool sentido_contrario;
|
||||||
|
|
||||||
|
|
||||||
partial void OnVelocidadChanged(float value)
|
partial void OnVelocidadChanged(float value)
|
||||||
{
|
{
|
||||||
if (value > 0)
|
if (value > 0)
|
||||||
|
@ -72,27 +105,43 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
Tamano = 0.30f;
|
Tamano = 0.30f;
|
||||||
PLC_NumeroMotor = 31;
|
PLC_NumeroMotor = 31;
|
||||||
MaxRatedHz = 100;
|
Proporcional_Speed = 100;
|
||||||
|
Max_Speed_for_Ramp = 100;
|
||||||
TiempoRampa = 3;
|
TiempoRampa = 3;
|
||||||
ImageSource_oculta = ImageFromPath("/imagenes/motor2.png");
|
ImageSource_oculta = ImageFromPath("/imagenes/motor2.png");
|
||||||
}
|
Refresh_Time_ms = 500;
|
||||||
|
}
|
||||||
|
|
||||||
public override void UpdateGeometryStart()
|
public override void UpdateGeometryStart()
|
||||||
{
|
{
|
||||||
// Se llama antes de la simulacion
|
// Se llama antes de la simulacion
|
||||||
|
|
||||||
}
|
}
|
||||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) {
|
|
||||||
|
|
||||||
motState.UpdatePLC(plc,PLC_NumeroMotor,Encendido, elapsedMilliseconds);
|
[JsonIgnore]
|
||||||
Velocidad = motState.STATUS_VFD_ACT_Speed_Hz / 10;
|
private float elapsedTimeAccumulator = 0;
|
||||||
|
|
||||||
|
public override void UpdatePLC(PLCViewModel plc, int TotalMilliseconds)
|
||||||
|
{
|
||||||
|
|
||||||
|
elapsedTimeAccumulator += TotalMilliseconds;
|
||||||
|
float randomFactor = (float)(new Random().NextDouble() * 0.1); // 10% random factor
|
||||||
|
float adjustedRefreshTime = Refresh_Time_ms * (1 + randomFactor);
|
||||||
|
|
||||||
|
if (elapsedTimeAccumulator >= adjustedRefreshTime)
|
||||||
|
{
|
||||||
|
motState.UpdatePLC(plc, this, TotalMilliseconds);
|
||||||
|
elapsedTimeAccumulator = 0;
|
||||||
|
}
|
||||||
|
Velocidad = (Proporcional_Speed / 100) * (motState.STATUS_VFD_ACT_Speed_Hz / 10);
|
||||||
|
Sentido_contrario = motState.OUT_Reversal;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateControl(int elapsedMilliseconds)
|
public override void UpdateControl(int TotalMilliseconds)
|
||||||
{
|
{
|
||||||
// Calculamos la velocidad
|
// Calculamos la velocidad
|
||||||
motState.UpdateSpeed(MaxRatedHz,TiempoRampa, elapsedMilliseconds);
|
motState.UpdateSpeed(Max_Speed_for_Ramp, TiempoRampa, TotalMilliseconds);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +149,8 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
// crear el objeto de simulacion
|
// crear el objeto de simulacion
|
||||||
ActualizarLeftTop();
|
base.ucLoaded();
|
||||||
|
OnVelocidadChanged(Velocidad);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,6 +158,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public partial class ucVMmotorSim : UserControl, IDataContainer
|
public partial class ucVMmotorSim : UserControl, IDataContainer
|
||||||
{
|
{
|
||||||
public osBase? Datos { get; set; }
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
public ucVMmotorSim()
|
public ucVMmotorSim()
|
||||||
{
|
{
|
||||||
|
@ -123,21 +174,12 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
Datos?.ucUnLoaded();
|
Datos?.ucUnLoaded();
|
||||||
}
|
}
|
||||||
public void Resize(float width, float height) { }
|
|
||||||
public void Move(float LeftPixels, float TopPixels)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
{
|
|
||||||
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
|
||||||
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Rotate(float Angle) { }
|
|
||||||
public void Highlight(bool State) { }
|
public void Highlight(bool State) { }
|
||||||
public int ZIndex()
|
public ZIndexEnum ZIndex_Base()
|
||||||
{
|
{
|
||||||
return 10;
|
return ZIndexEnum.Estaticos;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VMSimMotor
|
public class VMSimMotor
|
||||||
|
@ -153,26 +195,33 @@ namespace CtrEditor.ObjetosSim
|
||||||
public bool OUT_Reversal;
|
public bool OUT_Reversal;
|
||||||
public float OUT_OUT_VFD_REQ_Speed_Hz;
|
public float OUT_OUT_VFD_REQ_Speed_Hz;
|
||||||
|
|
||||||
public void UpdatePLC(PLCModel plc, int NumeroMotor, bool Encendido, int elapsedMilliseconds)
|
public void UpdatePLC(PLCViewModel plc, osVMmotorSim Data, int TotalMilliseconds)
|
||||||
{
|
{
|
||||||
var index = 0;
|
var DB_Motor = Data.PLC_DB_Motor;
|
||||||
switch (NumeroMotor)
|
|
||||||
{
|
|
||||||
case < 100:
|
|
||||||
index = (int)NumeroMotor - 30 + 300;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
OUT_Run = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{index}].OUT.Run");
|
if (DB_Motor == 0)
|
||||||
OUT_Reversal = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{index}].OUT.\"Reversal Direction\"");
|
return;
|
||||||
OUT_OUT_VFD_REQ_Speed_Hz = (float)plc.LeerTagInt16($"\"DB MotorSimulate\".Motors[{index}].OUT.OUT_VFD_REQ_Speed_Hz");
|
|
||||||
|
// Add timestamp to trace when the read occurs
|
||||||
|
var timestamp = DateTime.Now;
|
||||||
|
|
||||||
|
// Read ControlWord and track the raw response
|
||||||
|
var rawResponse = plc.LeerTagDInt($"\"DB MotorSimulate\".Motors[{DB_Motor}].ControlWord");
|
||||||
|
int controlWord = rawResponse ?? 0;
|
||||||
|
var control = VMMotorBitPacker.UnpackControlWord(controlWord);
|
||||||
|
|
||||||
|
|
||||||
|
// Update local state from ControlWord
|
||||||
|
OUT_Run = control.run;
|
||||||
|
OUT_Stop = control.stop;
|
||||||
|
OUT_Reversal = control.reversal;
|
||||||
|
OUT_OUT_VFD_REQ_Speed_Hz = control.reqSpeedHz;
|
||||||
|
|
||||||
if (Encendido)
|
// Update motor state based on enable status
|
||||||
|
if (Data.Encendido)
|
||||||
{
|
{
|
||||||
_STATUS_VFD_Ready = true;
|
_STATUS_VFD_Ready = true;
|
||||||
Motor_Running = true;
|
Motor_Running = OUT_Run && !OUT_Stop;
|
||||||
STATUS_VFD_Trip = false;
|
STATUS_VFD_Trip = false;
|
||||||
STATUS_VFD_Warning = false;
|
STATUS_VFD_Warning = false;
|
||||||
STATUS_VFD_Coasting = false;
|
STATUS_VFD_Coasting = false;
|
||||||
|
@ -186,19 +235,27 @@ namespace CtrEditor.ObjetosSim
|
||||||
STATUS_VFD_Coasting = false;
|
STATUS_VFD_Coasting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Ready", _STATUS_VFD_Ready);
|
if (Data.VFD_Trip_NC)
|
||||||
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].Motor_Running", Motor_Running);
|
STATUS_VFD_Trip = !STATUS_VFD_Trip;
|
||||||
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Trip", STATUS_VFD_Trip);
|
|
||||||
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Warning", STATUS_VFD_Warning);
|
|
||||||
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Coasting", STATUS_VFD_Coasting);
|
|
||||||
|
|
||||||
plc.EscribirTagInt16($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_ACT_Speed_Hz", (int)STATUS_VFD_ACT_Speed_Hz);
|
|
||||||
|
|
||||||
|
// Pack all status bits and speed into StatusWord
|
||||||
|
int statusWord = VMMotorBitPacker.PackStatusWord(
|
||||||
|
_STATUS_VFD_Ready,
|
||||||
|
Motor_Running,
|
||||||
|
STATUS_VFD_Trip,
|
||||||
|
STATUS_VFD_Warning,
|
||||||
|
STATUS_VFD_Coasting,
|
||||||
|
(short)STATUS_VFD_ACT_Speed_Hz
|
||||||
|
);
|
||||||
|
|
||||||
|
// Write StatusWord in one operation
|
||||||
|
plc.EscribirTagDInt($"\"DB MotorSimulate\".Motors[{DB_Motor}].StatusWord", statusWord);
|
||||||
}
|
}
|
||||||
|
|
||||||
private float CalcSpeedRamp(float MaxRatedHz, float TiempoRampa, float actual, float expected, int elapsedMilliseconds)
|
private float CalcSpeedRamp(float max_Speed_for_Ramp, float TiempoRampa, float actual, float expected, int TotalMilliseconds)
|
||||||
{
|
{
|
||||||
float hzIncrementsRamp = (MaxRatedHz * 10) / (TiempoRampa * (1000.0f / elapsedMilliseconds));
|
float hzIncrementsRamp = (max_Speed_for_Ramp * 10) / (TiempoRampa * (1000.0f / TotalMilliseconds));
|
||||||
float delta = expected - actual;
|
float delta = expected - actual;
|
||||||
// Conrtolar si la diferencia no es mayor de lo que falta
|
// Conrtolar si la diferencia no es mayor de lo que falta
|
||||||
if (Math.Abs(hzIncrementsRamp) > Math.Abs(delta))
|
if (Math.Abs(hzIncrementsRamp) > Math.Abs(delta))
|
||||||
|
@ -209,12 +266,14 @@ namespace CtrEditor.ObjetosSim
|
||||||
return hzIncrementsRamp;
|
return hzIncrementsRamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateSpeed(float MaxRatedHz, float TiempoRampa, int elapsedMilliseconds)
|
public void UpdateSpeed(float max_Speed_for_Ramp, float TiempoRampa, int TotalMilliseconds)
|
||||||
{
|
{
|
||||||
// Calculamos la velocidad
|
// Calculamos la velocidad
|
||||||
STATUS_VFD_ACT_Speed_Hz += CalcSpeedRamp(MaxRatedHz, TiempoRampa, STATUS_VFD_ACT_Speed_Hz, OUT_OUT_VFD_REQ_Speed_Hz, elapsedMilliseconds);
|
STATUS_VFD_ACT_Speed_Hz += CalcSpeedRamp(max_Speed_for_Ramp, TiempoRampa, STATUS_VFD_ACT_Speed_Hz, OUT_OUT_VFD_REQ_Speed_Hz, TotalMilliseconds);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
<UserControl x:Class="CtrEditor.ObjetosSim.Extraccion_Datos.ucBuscarCoincidencias"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||||
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim.Extraccion_Datos" mc:Ignorable="d"
|
||||||
|
Visibility="{Binding Show_On_This_Page, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||||
|
|
||||||
|
<UserControl.DataContext>
|
||||||
|
<vm:osBuscarCoincidencias />
|
||||||
|
</UserControl.DataContext>
|
||||||
|
|
||||||
|
<Canvas>
|
||||||
|
<Rectangle x:Name="Area" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Opacity="{Binding Opacity_oculto}" Fill="Yellow" Stroke="Black">
|
||||||
|
<Rectangle.RenderTransform>
|
||||||
|
<RotateTransform Angle="{Binding Angulo}" />
|
||||||
|
</Rectangle.RenderTransform>
|
||||||
|
</Rectangle>
|
||||||
|
</Canvas>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,733 @@
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using System.IO;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using Emgu.CV.CvEnum;
|
||||||
|
using Emgu.CV;
|
||||||
|
using System.Drawing;
|
||||||
|
using Image = System.Windows.Controls.Image;
|
||||||
|
using Rectangle = System.Windows.Shapes.Rectangle;
|
||||||
|
using Size = System.Drawing.Size;
|
||||||
|
using Ookii.Dialogs.Wpf;
|
||||||
|
using Rect = System.Windows.Rect;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using ClosedXML.Excel;
|
||||||
|
using Colors = System.Windows.Media.Colors;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using Emgu.CV.Structure;
|
||||||
|
|
||||||
|
namespace CtrEditor.ObjetosSim.Extraccion_Datos
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a template search control that identifies similar patterns in images and creates tag extraction clones.
|
||||||
|
/// This class is designed to work with OCR extraction by finding visual patterns and creating copies of extraction tags
|
||||||
|
/// at each matching location.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Key functionalities:
|
||||||
|
/// - Template matching using OpenCV
|
||||||
|
/// - Automatic tag cloning at found locations
|
||||||
|
/// - OCR text extraction from matched regions
|
||||||
|
/// - Export capabilities to Excel
|
||||||
|
///
|
||||||
|
/// Workflow:
|
||||||
|
/// 1. User creates a search template by positioning and sizing the control over a pattern
|
||||||
|
/// 2. Links extraction tags to this template using Id_Search_Templates
|
||||||
|
/// 3. Activates search_templates to find similar patterns
|
||||||
|
/// 4. The system automatically:
|
||||||
|
/// - Searches for visual matches in the image
|
||||||
|
/// - Creates clones of linked extraction tags at each match
|
||||||
|
/// - Assigns incremental copy_Number to organize rows in exports
|
||||||
|
/// - Performs OCR on each cloned tag location
|
||||||
|
///
|
||||||
|
/// Properties:
|
||||||
|
/// - search_templates: Triggers the pattern search process
|
||||||
|
/// - threshold: Minimum similarity threshold for pattern matching
|
||||||
|
/// - coincidencias: Number of matches found (readonly)
|
||||||
|
/// - show_debug_ocr: Shows debug windows during OCR process
|
||||||
|
/// - export_ocr: Triggers OCR text export for all matches
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
/// 1. Position the search template over a repeating pattern
|
||||||
|
/// 2. Create extraction tags and link them to this template
|
||||||
|
/// 3. Set threshold value (default usually works well)
|
||||||
|
/// 4. Activate search_templates to find matches and create clones
|
||||||
|
/// </remarks>
|
||||||
|
|
||||||
|
public partial class osBuscarCoincidencias : osBase, IosBase
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public float offsetY;
|
||||||
|
[JsonIgnore]
|
||||||
|
public float offsetX;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
List<Rect> search_rectangles;
|
||||||
|
|
||||||
|
public static string NombreClase()
|
||||||
|
{
|
||||||
|
return "Search Templates";
|
||||||
|
}
|
||||||
|
private string nombre = NombreClase();
|
||||||
|
|
||||||
|
public override string Nombre
|
||||||
|
{
|
||||||
|
get => nombre;
|
||||||
|
set => SetProperty(ref nombre, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
bool search_templates;
|
||||||
|
|
||||||
|
partial void OnSearch_templatesChanged(bool oldValue, bool newValue)
|
||||||
|
{
|
||||||
|
if (Search_templates)
|
||||||
|
BuscarCoincidencias();
|
||||||
|
Search_templates = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
bool tomarClip;
|
||||||
|
|
||||||
|
// En lugar de almacenar Mat directamente, guardaremos una representación serializable
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
byte[] capturedRegionData;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
[property: ReadOnly(true)]
|
||||||
|
bool regionCapturada;
|
||||||
|
|
||||||
|
// Para uso interno (no serializado)
|
||||||
|
[JsonIgnore]
|
||||||
|
private Mat _capturedRegion;
|
||||||
|
|
||||||
|
// Propiedades para almacenar las dimensiones de la captura
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
int capturedWidth;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
int capturedHeight;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
bool export_ocr;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
string text_export_ocr;
|
||||||
|
|
||||||
|
|
||||||
|
// Esta propiedad manejará la conversión entre Mat y datos serializables
|
||||||
|
[JsonIgnore]
|
||||||
|
public Mat CapturedRegion
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_capturedRegion == null && CapturedRegionData != null && CapturedRegionData.Length > 0)
|
||||||
|
{
|
||||||
|
// Recrear Mat desde los datos almacenados
|
||||||
|
_capturedRegion = BytesToMat(CapturedRegionData, CapturedWidth, CapturedHeight);
|
||||||
|
}
|
||||||
|
return _capturedRegion;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value != null)
|
||||||
|
{
|
||||||
|
// Convertir Mat a bytes para serialización
|
||||||
|
CapturedRegionData = MatToBytes(value);
|
||||||
|
CapturedWidth = value.Width;
|
||||||
|
CapturedHeight = value.Height;
|
||||||
|
_capturedRegion = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CapturedRegionData = null;
|
||||||
|
CapturedWidth = 0;
|
||||||
|
CapturedHeight = 0;
|
||||||
|
_capturedRegion = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
partial void OnTomarClipChanged(bool oldValue, bool newValue)
|
||||||
|
{
|
||||||
|
if (tomarClip)
|
||||||
|
{
|
||||||
|
CapturarRegionActual();
|
||||||
|
TomarClip = false; // Resetear el flag después de la captura
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Método para capturar la región actual
|
||||||
|
private void CapturarRegionActual()
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
if (_mainViewModel?.MainCanvas.Children[0] is Image imagenDeFondo)
|
||||||
|
{
|
||||||
|
if (imagenDeFondo.Source is BitmapSource bitmapSource)
|
||||||
|
{
|
||||||
|
// Obtener los DPI de la imagen original
|
||||||
|
float originalDpiX = (float)bitmapSource.DpiX;
|
||||||
|
float originalDpiY = (float)bitmapSource.DpiY;
|
||||||
|
|
||||||
|
// Estándar DPI en el que el Canvas renderiza la imagen
|
||||||
|
float canvasDpiX = 96;
|
||||||
|
float canvasDpiY = 96;
|
||||||
|
|
||||||
|
// Calcular el ratio de escala entre el Canvas y la imagen original
|
||||||
|
float scaleFactorX = originalDpiX / canvasDpiX;
|
||||||
|
float scaleFactorY = originalDpiY / canvasDpiY;
|
||||||
|
|
||||||
|
// Ajustar las coordenadas de recorte en función del ratio de escala
|
||||||
|
int x = (int)MeterToPixels(Left * scaleFactorX);
|
||||||
|
int y = (int)MeterToPixels(Top * scaleFactorY);
|
||||||
|
int width = (int)MeterToPixels(Ancho * scaleFactorX);
|
||||||
|
int height = (int)MeterToPixels(Alto * scaleFactorY);
|
||||||
|
|
||||||
|
// Validar y ajustar el tamaño del recorte para que se mantenga dentro de los límites de la imagen
|
||||||
|
if (x < 0) x = 0;
|
||||||
|
if (y < 0) y = 0;
|
||||||
|
if (x + width > bitmapSource.PixelWidth) width = bitmapSource.PixelWidth - x;
|
||||||
|
if (y + height > bitmapSource.PixelHeight) height = bitmapSource.PixelHeight - y;
|
||||||
|
|
||||||
|
// Recortar el área deseada utilizando las coordenadas ajustadas
|
||||||
|
CroppedBitmap croppedBitmap = new CroppedBitmap(bitmapSource, new Int32Rect(x, y, width, height));
|
||||||
|
|
||||||
|
// Capturar la región y almacenarla
|
||||||
|
if (_capturedRegion != null)
|
||||||
|
{
|
||||||
|
_capturedRegion.Dispose(); // Liberar recursos previos
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usar la propiedad que maneja la serialización
|
||||||
|
CapturedRegion = BitmapSourceToMat(croppedBitmap);
|
||||||
|
|
||||||
|
// Actualizar el estado
|
||||||
|
RegionCapturada = true;
|
||||||
|
MessageBox.Show("Región capturada correctamente.", "Información", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Métodos para convertir entre Mat y bytes
|
||||||
|
private byte[] MatToBytes(Mat mat)
|
||||||
|
{
|
||||||
|
if (mat == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Asegurar que tenemos un formato consistente para serialización
|
||||||
|
Mat bgr = new Mat();
|
||||||
|
if (mat.NumberOfChannels != 3)
|
||||||
|
{
|
||||||
|
CvInvoke.CvtColor(mat, bgr, mat.NumberOfChannels == 1 ?
|
||||||
|
ColorConversion.Gray2Bgr : ColorConversion.Bgra2Bgr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bgr = mat.Clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convertir a un formato que pueda ser serializado
|
||||||
|
using (MemoryStream ms = new MemoryStream())
|
||||||
|
{
|
||||||
|
// Convertir Mat a Bitmap
|
||||||
|
Bitmap bitmap = bgr.ToBitmap();
|
||||||
|
|
||||||
|
// Guardar como PNG (sin pérdida de calidad)
|
||||||
|
bitmap.Save(ms, ImageFormat.Png);
|
||||||
|
|
||||||
|
// Liberar recursos
|
||||||
|
bitmap.Dispose();
|
||||||
|
if (bgr != mat)
|
||||||
|
bgr.Dispose();
|
||||||
|
|
||||||
|
return ms.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Mat BytesToMat(byte[] bytes, int width, int height)
|
||||||
|
{
|
||||||
|
if (bytes == null || bytes.Length == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (MemoryStream ms = new MemoryStream(bytes))
|
||||||
|
{
|
||||||
|
// Cargar imagen desde bytes
|
||||||
|
Bitmap bitmap = (Bitmap)System.Drawing.Image.FromStream(ms);
|
||||||
|
|
||||||
|
// Convertir Bitmap a Mat
|
||||||
|
Image<Bgr, byte> img = bitmap.ToImage<Bgr, byte>();
|
||||||
|
|
||||||
|
// Liberar recursos
|
||||||
|
bitmap.Dispose();
|
||||||
|
|
||||||
|
// Si las dimensiones no coinciden, redimensionar
|
||||||
|
if (img.Width != width || img.Height != height)
|
||||||
|
{
|
||||||
|
CvInvoke.Resize(img.Mat, img.Mat, new Size(width, height));
|
||||||
|
}
|
||||||
|
|
||||||
|
return img.Mat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine($"Error al reconstruir Mat: {ex.Message}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sobrescribir los métodos de cambio de tamaño para limpiar la región capturada
|
||||||
|
public override void AnchoChanged(float newValue)
|
||||||
|
{
|
||||||
|
base.AnchoChanged(newValue);
|
||||||
|
//LimpiarRegionCapturada();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AltoChanged(float newValue)
|
||||||
|
{
|
||||||
|
base.AnchoChanged(newValue);
|
||||||
|
// LimpiarRegionCapturada();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LimpiarRegionCapturada()
|
||||||
|
{
|
||||||
|
if (_capturedRegion != null)
|
||||||
|
{
|
||||||
|
_capturedRegion.Dispose();
|
||||||
|
_capturedRegion = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usar la propiedad para manejar la serialización
|
||||||
|
CapturedRegion = null;
|
||||||
|
RegionCapturada = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
partial void OnExport_ocrChanged(bool value)
|
||||||
|
{
|
||||||
|
if (Export_ocr)
|
||||||
|
{
|
||||||
|
Text_export_ocr = "";
|
||||||
|
if (!string.IsNullOrEmpty(Nombre) && _mainViewModel != null)
|
||||||
|
{
|
||||||
|
foreach (var objetoSimulable in _mainViewModel.ObjetosSimulables)
|
||||||
|
{
|
||||||
|
if (objetoSimulable != this && objetoSimulable.Group_Panel == Nombre)
|
||||||
|
{
|
||||||
|
if (objetoSimulable is osExtraccionTag osExtraccionTag)
|
||||||
|
{
|
||||||
|
osExtraccionTag.CaptureImageAreaAndDoOCR();
|
||||||
|
Text_export_ocr += osExtraccionTag.Tag_extract;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Export_ocr = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void TopChanging(float oldValue, float newValue)
|
||||||
|
{
|
||||||
|
offsetY = newValue - oldValue;
|
||||||
|
}
|
||||||
|
public override void LeftChanging(float oldValue, float newValue)
|
||||||
|
{
|
||||||
|
offsetX = newValue - oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
string tag_extract;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
string clase;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
string tag_name;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
float opacity_oculto;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
bool show_debug_ocr;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
float threshold;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
[property: ReadOnly(true)]
|
||||||
|
int coincidencias;
|
||||||
|
|
||||||
|
public osBuscarCoincidencias()
|
||||||
|
{
|
||||||
|
Ancho = 1;
|
||||||
|
Alto = 1;
|
||||||
|
Angulo = 0;
|
||||||
|
Opacity_oculto = 0.1f;
|
||||||
|
Threshold = 0.6f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowPreviewWindow(Stream imageStream)
|
||||||
|
{
|
||||||
|
// Create a new window for preview
|
||||||
|
Window previewWindow = new Window
|
||||||
|
{
|
||||||
|
Title = "Preview Captured Image",
|
||||||
|
Width = 500,
|
||||||
|
Height = 500,
|
||||||
|
Content = new Image
|
||||||
|
{
|
||||||
|
Source = BitmapFrame.Create(imageStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad),
|
||||||
|
Stretch = Stretch.Uniform
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
previewWindow.ShowDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void BuscarCoincidencias()
|
||||||
|
{
|
||||||
|
var progressDialog = new ProgressDialog
|
||||||
|
{
|
||||||
|
WindowTitle = "Procesando",
|
||||||
|
Text = "Buscando coincidencias...",
|
||||||
|
ShowTimeRemaining = true,
|
||||||
|
ShowCancelButton = false
|
||||||
|
};
|
||||||
|
progressDialog.DoWork += (sender, e) => BuscarCoincidenciasAsync(progressDialog);
|
||||||
|
progressDialog.RunWorkerCompleted += (sender, e) =>
|
||||||
|
{
|
||||||
|
if (e.Error != null)
|
||||||
|
{
|
||||||
|
MessageBox.Show(e.Error.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
progressDialog.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modificar el método BuscarCoincidenciasAsync para usar la región capturada si está disponible
|
||||||
|
private void BuscarCoincidenciasAsync(ProgressDialog progressDialog)
|
||||||
|
{
|
||||||
|
// Reset the Canvas children
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
var clearShapes = _mainViewModel.MainCanvas.Children.OfType<System.Windows.Shapes.Shape>().Where(s => s.Tag as string == "BuscarCoincidencias").ToList();
|
||||||
|
foreach (var shape in clearShapes)
|
||||||
|
{
|
||||||
|
_mainViewModel.MainCanvas.Children.Remove(shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_mainViewModel?.MainCanvas.Children[0] is Image imagenDeFondo)
|
||||||
|
{
|
||||||
|
// Asegurarse de que la imagen origen está disponible
|
||||||
|
if (imagenDeFondo.Source is BitmapSource bitmapSource)
|
||||||
|
{
|
||||||
|
progressDialog.ReportProgress(10);
|
||||||
|
|
||||||
|
Mat templateMat;
|
||||||
|
int width, height;
|
||||||
|
float scaleFactorX, scaleFactorY;
|
||||||
|
bool deleteTemplateMat = false;
|
||||||
|
|
||||||
|
// Usar la región capturada si existe, de lo contrario capturar la región actual
|
||||||
|
if (CapturedRegion != null && RegionCapturada)
|
||||||
|
{
|
||||||
|
// Usar la región almacenada (ya deserializada)
|
||||||
|
templateMat = CapturedRegion.Clone();
|
||||||
|
deleteTemplateMat = true;
|
||||||
|
width = templateMat.Width;
|
||||||
|
height = templateMat.Height;
|
||||||
|
|
||||||
|
// Para mantener la relación con la imagen original
|
||||||
|
float originalDpiX = (float)bitmapSource.DpiX;
|
||||||
|
float originalDpiY = (float)bitmapSource.DpiY;
|
||||||
|
float canvasDpiX = 96;
|
||||||
|
float canvasDpiY = 96;
|
||||||
|
scaleFactorX = originalDpiX / canvasDpiX;
|
||||||
|
scaleFactorY = originalDpiY / canvasDpiY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Obtener los DPI de la imagen original
|
||||||
|
float originalDpiX = (float)bitmapSource.DpiX;
|
||||||
|
float originalDpiY = (float)bitmapSource.DpiY;
|
||||||
|
|
||||||
|
// Estándar DPI en el que el Canvas renderiza la imagen
|
||||||
|
float canvasDpiX = 96;
|
||||||
|
float canvasDpiY = 96;
|
||||||
|
|
||||||
|
// Calcular el ratio de escala entre el Canvas y la imagen original
|
||||||
|
scaleFactorX = originalDpiX / canvasDpiX;
|
||||||
|
scaleFactorY = originalDpiY / canvasDpiY;
|
||||||
|
|
||||||
|
// Ajustar las coordenadas de recorte en función del ratio de escala
|
||||||
|
int x = (int)MeterToPixels(Left * scaleFactorX);
|
||||||
|
int y = (int)MeterToPixels(Top * scaleFactorY);
|
||||||
|
width = (int)MeterToPixels(Ancho * scaleFactorX);
|
||||||
|
height = (int)MeterToPixels(Alto * scaleFactorY);
|
||||||
|
|
||||||
|
// Validar y ajustar el tamaño del recorte para que se mantenga dentro de los límites de la imagen
|
||||||
|
if (x < 0) x = 0;
|
||||||
|
if (y < 0) y = 0;
|
||||||
|
if (x + width > bitmapSource.PixelWidth) width = bitmapSource.PixelWidth - x;
|
||||||
|
if (y + height > bitmapSource.PixelHeight) height = bitmapSource.PixelHeight - y;
|
||||||
|
|
||||||
|
// Recortar el área deseada utilizando las coordenadas ajustadas
|
||||||
|
CroppedBitmap croppedBitmap = new CroppedBitmap(bitmapSource, new Int32Rect(x, y, width, height));
|
||||||
|
|
||||||
|
// Convertir CroppedBitmap a Mat directamente
|
||||||
|
templateMat = BitmapSourceToMat(croppedBitmap);
|
||||||
|
deleteTemplateMat = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int scale = 4;
|
||||||
|
|
||||||
|
// Convertir la plantilla a escala de grises y redimensionarla
|
||||||
|
Mat templateGray = new Mat();
|
||||||
|
CvInvoke.CvtColor(templateMat, templateGray, ColorConversion.Bgr2Gray);
|
||||||
|
Mat templateGrayResized = new Mat();
|
||||||
|
CvInvoke.Resize(templateGray, templateGrayResized, new Size(templateGray.Width / scale, templateGray.Height / scale), 0, 0, Inter.Linear);
|
||||||
|
progressDialog.ReportProgress(20);
|
||||||
|
|
||||||
|
// El resto del código permanece igual...
|
||||||
|
|
||||||
|
// Cargar la imagen principal completa en un Mat
|
||||||
|
Mat mainImageMat = BitmapSourceToMat(bitmapSource);
|
||||||
|
|
||||||
|
// Convertir la imagen principal a escala de grises y redimensionarla
|
||||||
|
Mat mainImageGray = new Mat();
|
||||||
|
CvInvoke.CvtColor(mainImageMat, mainImageGray, ColorConversion.Bgr2Gray);
|
||||||
|
Mat mainImageGrayResized = new Mat();
|
||||||
|
CvInvoke.Resize(mainImageGray, mainImageGrayResized, new Size(mainImageGray.Width / scale, mainImageGray.Height / scale), 0, 0, Inter.Linear);
|
||||||
|
|
||||||
|
progressDialog.ReportProgress(50);
|
||||||
|
|
||||||
|
// Realizar la coincidencia de plantillas
|
||||||
|
Mat result = new Mat();
|
||||||
|
CvInvoke.MatchTemplate(mainImageGray, templateGray, result, TemplateMatchingType.CcoeffNormed);
|
||||||
|
|
||||||
|
// Establecer un umbral de coincidencia
|
||||||
|
if (Threshold < 0.4)
|
||||||
|
Threshold = 0.4f;
|
||||||
|
double threshold = Threshold;
|
||||||
|
|
||||||
|
int ConteoPositivos = 0;
|
||||||
|
|
||||||
|
// Lista para mantener áreas ya aceptadas
|
||||||
|
if (search_rectangles != null)
|
||||||
|
search_rectangles.Clear();
|
||||||
|
else
|
||||||
|
search_rectangles = new List<Rect>();
|
||||||
|
|
||||||
|
// Obtener los puntos que superan el umbral
|
||||||
|
float[] resultArray = result.GetData(false) as float[];
|
||||||
|
if (resultArray != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < resultArray.Length; i++)
|
||||||
|
{
|
||||||
|
if (resultArray[i] >= threshold)
|
||||||
|
{
|
||||||
|
int row = i / result.Cols;
|
||||||
|
int col = i % result.Cols;
|
||||||
|
|
||||||
|
Rect newRect = new Rect();
|
||||||
|
newRect.X = col / scaleFactorX;
|
||||||
|
newRect.Y = row / scaleFactorY;
|
||||||
|
newRect.Width = width / scaleFactorX;
|
||||||
|
newRect.Height = height / scaleFactorY;
|
||||||
|
|
||||||
|
// Crear un rectángulo para la coincidencia actual
|
||||||
|
Rectangle matchRect = new Rectangle
|
||||||
|
{
|
||||||
|
Stroke = new SolidColorBrush(Colors.Red),
|
||||||
|
StrokeThickness = 2,
|
||||||
|
Width = newRect.Width,
|
||||||
|
Height = newRect.Height,
|
||||||
|
Tag = "BuscarCoincidencias"
|
||||||
|
};
|
||||||
|
|
||||||
|
Canvas.SetLeft(matchRect, newRect.X);
|
||||||
|
Canvas.SetTop(matchRect, newRect.Y);
|
||||||
|
|
||||||
|
// Verificar si la coincidencia actual está dentro de algún rectángulo aceptado
|
||||||
|
bool isOverlap = search_rectangles.Any(r =>
|
||||||
|
r.IntersectsWith(newRect)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Si no hay superposición, agregar el rectángulo al Canvas y a la lista de aceptados
|
||||||
|
if (!isOverlap)
|
||||||
|
{
|
||||||
|
Canvas.SetZIndex(matchRect, 40);
|
||||||
|
_mainViewModel.MainCanvas.Children.Add(matchRect);
|
||||||
|
search_rectangles.Add(newRect);
|
||||||
|
|
||||||
|
ConteoPositivos++;
|
||||||
|
Coincidencias = ConteoPositivos;
|
||||||
|
progressDialog.ReportProgress(90);
|
||||||
|
if (ConteoPositivos > 20)
|
||||||
|
{
|
||||||
|
// Liberar recursos antes de salir
|
||||||
|
if (deleteTemplateMat) templateMat.Dispose();
|
||||||
|
templateGray.Dispose();
|
||||||
|
templateGrayResized.Dispose();
|
||||||
|
mainImageMat.Dispose();
|
||||||
|
mainImageGray.Dispose();
|
||||||
|
mainImageGrayResized.Dispose();
|
||||||
|
result.Dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PopularTagExtraction();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limpiar recursos
|
||||||
|
if (deleteTemplateMat) templateMat.Dispose();
|
||||||
|
templateGray.Dispose();
|
||||||
|
templateGrayResized.Dispose();
|
||||||
|
mainImageMat.Dispose();
|
||||||
|
mainImageGray.Dispose();
|
||||||
|
mainImageGrayResized.Dispose();
|
||||||
|
result.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PopularTagExtraction()
|
||||||
|
{
|
||||||
|
var objetosSimulablesCopy = new List<osBase>(_mainViewModel.ObjetosSimulables);
|
||||||
|
foreach (var obj in objetosSimulablesCopy)
|
||||||
|
if (obj is osExtraccionTag objExtraccionTag)
|
||||||
|
if (objExtraccionTag.Id_Search_Templates == this.Nombre && objExtraccionTag.Cloned)
|
||||||
|
_mainViewModel.RemoverObjetoSimulable(objExtraccionTag);
|
||||||
|
|
||||||
|
var objetosSimulables2Copy = new List<osBase>(_mainViewModel.ObjetosSimulables);
|
||||||
|
// Saltar el primer rectángulo en el foreach
|
||||||
|
|
||||||
|
int Row = 0;
|
||||||
|
foreach (var rectangle in search_rectangles) //.Skip(1))
|
||||||
|
{
|
||||||
|
float offsetX = PixelsToMeters((float)rectangle.X) - Left;
|
||||||
|
float offsetY = PixelsToMeters((float)rectangle.Y) - Top;
|
||||||
|
|
||||||
|
osExtraccionTag newObj = null;
|
||||||
|
|
||||||
|
foreach (var eTag in objetosSimulables2Copy)
|
||||||
|
{
|
||||||
|
if (eTag is osExtraccionTag objExtraccionTag)
|
||||||
|
{
|
||||||
|
if (objExtraccionTag.Id_Search_Templates == this.Nombre)
|
||||||
|
{
|
||||||
|
newObj = (osExtraccionTag)_mainViewModel.DuplicarObjeto(objExtraccionTag, offsetX, offsetY);
|
||||||
|
if (newObj != null)
|
||||||
|
{
|
||||||
|
newObj.Cloned = true;
|
||||||
|
newObj.Cloned_from = objExtraccionTag.Id;
|
||||||
|
newObj.Copy_Number = Row;
|
||||||
|
newObj.Enable_On_All_Pages = false;
|
||||||
|
if (newObj.Extraer)
|
||||||
|
objExtraccionTag.CaptureImageAreaAndDoOCR();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Row++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int FindFirstEmptyRow(IXLWorksheet worksheet)
|
||||||
|
{
|
||||||
|
var lastRowUsed = worksheet.LastRowUsed();
|
||||||
|
return lastRowUsed == null ? 1 : lastRowUsed.RowNumber() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Método para convertir BitmapSource a Mat
|
||||||
|
private Mat BitmapSourceToMat(BitmapSource bitmapSource)
|
||||||
|
{
|
||||||
|
if (bitmapSource == null)
|
||||||
|
throw new ArgumentNullException(nameof(bitmapSource));
|
||||||
|
|
||||||
|
// Convierte BitmapSource a Bitmap
|
||||||
|
Bitmap bitmap;
|
||||||
|
using (MemoryStream outStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
BitmapEncoder enc = new BmpBitmapEncoder();
|
||||||
|
enc.Frames.Add(BitmapFrame.Create(bitmapSource));
|
||||||
|
enc.Save(outStream);
|
||||||
|
bitmap = new Bitmap(outStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convierte directamente a Mat usando Image<Bgr, byte>
|
||||||
|
Image<Bgr, byte> image = bitmap.ToImage<Bgr, byte>();
|
||||||
|
return image.Mat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ucLoaded()
|
||||||
|
{
|
||||||
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
|
// crear el objeto de simulacion
|
||||||
|
base.ucLoaded();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class ucBuscarCoincidencias : UserControl, IDataContainer
|
||||||
|
{
|
||||||
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
|
public ucBuscarCoincidencias()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.Loaded += OnLoaded;
|
||||||
|
this.Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucLoaded();
|
||||||
|
}
|
||||||
|
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucUnLoaded();
|
||||||
|
}
|
||||||
|
public void Highlight(bool State) { }
|
||||||
|
public ZIndexEnum ZIndex_Base()
|
||||||
|
{
|
||||||
|
return ZIndexEnum.Estaticos;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
<UserControl x:Class="CtrEditor.ObjetosSim.Extraccion_Datos.ucExtraccionTag"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||||
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim.Extraccion_Datos"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Visibility="{Binding Show_On_This_Page, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||||
|
|
||||||
|
<UserControl.DataContext>
|
||||||
|
<vm:osExtraccionTag/>
|
||||||
|
</UserControl.DataContext>
|
||||||
|
|
||||||
|
<Canvas>
|
||||||
|
<Rectangle x:Name="Area" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Opacity="{Binding Opacity_oculto}" Fill="Green" Stroke="Black">
|
||||||
|
</Rectangle>
|
||||||
|
<Viewbox Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}">
|
||||||
|
<Label Content="{Binding Angulo}" VerticalAlignment="Top" HorizontalAlignment="Center"
|
||||||
|
RenderTransformOrigin="0.5,0.5" Opacity="0.1">
|
||||||
|
<Label.RenderTransform>
|
||||||
|
<TransformGroup>
|
||||||
|
<ScaleTransform />
|
||||||
|
<SkewTransform />
|
||||||
|
<RotateTransform Angle="{Binding Angulo}" />
|
||||||
|
<TranslateTransform />
|
||||||
|
</TransformGroup>
|
||||||
|
</Label.RenderTransform>
|
||||||
|
</Label>
|
||||||
|
</Viewbox>
|
||||||
|
</Canvas>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,274 @@
|
||||||
|
using ClosedXML.Excel;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||||
|
|
||||||
|
namespace CtrEditor.ObjetosSim.Extraccion_Datos
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ucExtraccionTag.xaml
|
||||||
|
/// </summary>
|
||||||
|
///
|
||||||
|
|
||||||
|
public partial class osExtraccionTag : osBase, IosBase
|
||||||
|
{
|
||||||
|
public static string NombreClase()
|
||||||
|
{
|
||||||
|
return "Extraccion Tags";
|
||||||
|
}
|
||||||
|
private string nombre = NombreClase();
|
||||||
|
public override string Nombre
|
||||||
|
{
|
||||||
|
get => nombre;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (Collumn_name == null || Collumn_name.Length == 0)
|
||||||
|
Collumn_name = value;
|
||||||
|
SetProperty(ref nombre, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
bool extraer;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
bool eliminar_enters;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
[property: ItemsSource(typeof(IdiomasItemsSource<Idiomas>))]
|
||||||
|
string idioma_Extraccion;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
[property: ItemsSource(typeof(TagPatternItemsSource<TagPattern>))]
|
||||||
|
string pattern_Type;
|
||||||
|
|
||||||
|
public override void TopChanged(float value)
|
||||||
|
{
|
||||||
|
base.TopChanged(value);
|
||||||
|
if (Extraer) ResetTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LeftChanged(float value)
|
||||||
|
{
|
||||||
|
base.LeftChanged(value);
|
||||||
|
if (Extraer) ResetTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnExtraerChanged(bool value)
|
||||||
|
{
|
||||||
|
if (Extraer)
|
||||||
|
ResetTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||||
|
{
|
||||||
|
if (Extraer)
|
||||||
|
ResetTimer();
|
||||||
|
}
|
||||||
|
public override void OnMove(float LeftPixels, float TopPixels)
|
||||||
|
{
|
||||||
|
if (Extraer)
|
||||||
|
ResetTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnRotate(float Angle)
|
||||||
|
{
|
||||||
|
if (Extraer)
|
||||||
|
ResetTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnTimerAfterMovement()
|
||||||
|
{
|
||||||
|
Angulo = (float)Math.Round(Angulo / 90) * 90;
|
||||||
|
|
||||||
|
if (Extraer)
|
||||||
|
CaptureImageAreaAndDoOCR();
|
||||||
|
Extraer = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private osBuscarCoincidencias Search_Templates;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Link to Search Templates")]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
[property: ItemsSource(typeof(osBaseItemsSource<osBuscarCoincidencias>))]
|
||||||
|
string id_Search_Templates;
|
||||||
|
|
||||||
|
partial void OnId_Search_TemplatesChanged(string value)
|
||||||
|
{
|
||||||
|
if (Search_Templates != null)
|
||||||
|
Search_Templates.PropertyChanged -= OnMotorPropertyChanged;
|
||||||
|
if (_mainViewModel != null && value != null && value.Length > 0)
|
||||||
|
{
|
||||||
|
Search_Templates = (osBuscarCoincidencias)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osBuscarCoincidencias && s.Nombre == value), null);
|
||||||
|
if (Search_Templates != null)
|
||||||
|
Search_Templates.PropertyChanged += OnMotorPropertyChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMotorPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(osBuscarCoincidencias.Nombre))
|
||||||
|
{
|
||||||
|
Id_Search_Templates = ((osBuscarCoincidencias)sender).Nombre;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
string tag_extract;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Export:")]
|
||||||
|
string clase;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Export:")]
|
||||||
|
string collumn_name;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Excel collumn.")]
|
||||||
|
[property: Category("Export:")]
|
||||||
|
int collumn_number;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
[property: ReadOnly(true)]
|
||||||
|
int copy_Number;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Tag Extraction:")]
|
||||||
|
bool show_Debug_Window;
|
||||||
|
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
float opacity_oculto;
|
||||||
|
|
||||||
|
public osExtraccionTag()
|
||||||
|
{
|
||||||
|
Ancho = 1;
|
||||||
|
Alto = 1;
|
||||||
|
Angulo = 0;
|
||||||
|
Opacity_oculto = 0.1f;
|
||||||
|
Idioma_Extraccion = Idiomas.DEFAULT_LANGUAGE;
|
||||||
|
Pattern_Type = TagPattern.DEFAULT_PATTERN;
|
||||||
|
Eliminar_enters = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CaptureImageAreaAndDoOCR()
|
||||||
|
{
|
||||||
|
string extractedText = CaptureImageAreaAndDoOCR(Left, Top, Ancho, Alto, Angulo, Show_Debug_Window);
|
||||||
|
|
||||||
|
// Clean up the extracted text if eliminar_enters is true
|
||||||
|
if (Eliminar_enters && !string.IsNullOrEmpty(extractedText))
|
||||||
|
{
|
||||||
|
// Replace all types of line endings with spaces
|
||||||
|
extractedText = extractedText.Replace("\r\n", " ")
|
||||||
|
.Replace("\n", " ")
|
||||||
|
.Replace("\r", " ");
|
||||||
|
|
||||||
|
// Replace multiple consecutive spaces with a single space
|
||||||
|
extractedText = System.Text.RegularExpressions.Regex.Replace(extractedText, @"\s+", " ");
|
||||||
|
|
||||||
|
// Trim spaces at the beginning and end
|
||||||
|
extractedText = extractedText.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the selected pattern
|
||||||
|
extractedText = TagPattern.ApplyPattern(extractedText, Pattern_Type);
|
||||||
|
|
||||||
|
Tag_extract = extractedText;
|
||||||
|
|
||||||
|
// Set default language to English if not set
|
||||||
|
if (string.IsNullOrEmpty(Idioma_Extraccion))
|
||||||
|
{
|
||||||
|
Idioma_Extraccion = Idiomas.DEFAULT_LANGUAGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ExportToExcel(IXLWorksheet worksheet, int row, int colBase)
|
||||||
|
{
|
||||||
|
// Agregar Tag
|
||||||
|
worksheet.Cell(row + 2, Collumn_number + colBase).Value = Tag_extract;
|
||||||
|
return Collumn_number + colBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void ucLoaded()
|
||||||
|
{
|
||||||
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
|
// crear el objeto de simulacion
|
||||||
|
base.ucLoaded();
|
||||||
|
OnId_Search_TemplatesChanged(Id_Search_Templates); // Actualizar Link
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class ucExtraccionTag : UserControl, IDataContainer
|
||||||
|
{
|
||||||
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
|
public ucExtraccionTag()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.Loaded += OnLoaded;
|
||||||
|
this.Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucLoaded();
|
||||||
|
}
|
||||||
|
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucUnLoaded();
|
||||||
|
}
|
||||||
|
public void Resize(float width, float height)
|
||||||
|
{
|
||||||
|
if (Datos is osExtraccionTag datos)
|
||||||
|
{
|
||||||
|
datos.Ancho += PixelToMeter.Instance.calc.PixelsToMeters(width);
|
||||||
|
datos.Alto += PixelToMeter.Instance.calc.PixelsToMeters(height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void Move(float LeftPixels, float TopPixels)
|
||||||
|
{
|
||||||
|
if (Datos != null)
|
||||||
|
{
|
||||||
|
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
||||||
|
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public float Angle()
|
||||||
|
{
|
||||||
|
if (Datos != null)
|
||||||
|
if (Datos is osExtraccionTag datos)
|
||||||
|
return datos.Angulo;
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
public void Rotate(float Angle)
|
||||||
|
{
|
||||||
|
if (Datos != null)
|
||||||
|
if (Datos is osExtraccionTag datos)
|
||||||
|
datos.Angulo += Angle;
|
||||||
|
}
|
||||||
|
public void Highlight(bool State) { }
|
||||||
|
public ZIndexEnum ZIndex_Base()
|
||||||
|
{
|
||||||
|
return ZIndexEnum.ExtraccionTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,20 +4,23 @@
|
||||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||||
xmlns:ei="http://schemas.microsoft.com/xaml/behaviors"
|
xmlns:ei="http://schemas.microsoft.com/xaml/behaviors"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
|
||||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<UserControl.Resources>
|
|
||||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
|
||||||
</UserControl.Resources>
|
|
||||||
|
|
||||||
<UserControl.DataContext>
|
<UserControl.DataContext>
|
||||||
<vm:osBoton Color="#FFADE6C0" ColorButton_oculto="#FFC72323"/>
|
<vm:osBoton Color="#FFADE6C0" ColorButton="#FFC72323" Color_Pressed="#FF9A9A9A" />
|
||||||
</UserControl.DataContext>
|
</UserControl.DataContext>
|
||||||
|
|
||||||
<Grid>
|
<Canvas RenderTransformOrigin="0.5,0.5">
|
||||||
|
<Canvas.RenderTransform>
|
||||||
|
<TransformGroup>
|
||||||
|
<ScaleTransform/>
|
||||||
|
<SkewTransform/>
|
||||||
|
<RotateTransform Angle="{Binding Angulo}"/>
|
||||||
|
<TranslateTransform/>
|
||||||
|
</TransformGroup>
|
||||||
|
</Canvas.RenderTransform>
|
||||||
<Border x:Name="BackgroundRectangle"
|
<Border x:Name="BackgroundRectangle"
|
||||||
BorderBrush="Black"
|
BorderBrush="Black"
|
||||||
BorderThickness="2"
|
BorderThickness="2"
|
||||||
|
@ -26,16 +29,24 @@
|
||||||
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=1.5}"
|
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=1.5}"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Background="Gray"/>
|
Background="{Binding Color_Pressed, Converter={StaticResource ColorToBrushConverter}}"/>
|
||||||
<Ellipse Fill="{Binding ColorButton_oculto}"
|
<Ellipse Fill="{Binding ColorButton, Converter={StaticResource ColorToBrushConverter}}"
|
||||||
Stroke="Black"
|
Stroke="Black"
|
||||||
StrokeThickness="2"
|
StrokeThickness="2"
|
||||||
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Canvas.Top="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=0.5}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Bottom"
|
VerticalAlignment="Bottom"
|
||||||
MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"
|
MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"
|
||||||
MouseLeftButtonUp="Ellipse_MouseLeftButtonUp">
|
MouseLeftButtonUp="Ellipse_MouseLeftButtonUp">
|
||||||
</Ellipse>
|
</Ellipse>
|
||||||
</Grid>
|
<Viewbox Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=0.5}"
|
||||||
|
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}">
|
||||||
|
<Label Content="{Binding Button_Name}"
|
||||||
|
VerticalAlignment="Top" HorizontalAlignment="Center"
|
||||||
|
Foreground="{Binding Color_Titulo, Converter={StaticResource ColorToBrushConverter}}"/>
|
||||||
|
</Viewbox>
|
||||||
|
|
||||||
|
</Canvas>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CtrEditor.Convertidores;
|
|
||||||
using CtrEditor.Siemens;
|
using LibS7Adv;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
|
||||||
namespace CtrEditor.ObjetosSim
|
namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
|
@ -26,24 +27,49 @@ namespace CtrEditor.ObjetosSim
|
||||||
set => SetProperty(ref nombre, value);
|
set => SetProperty(ref nombre, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
string button_Name;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public bool tipo_NC;
|
public bool tipo_NC;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private Brush color;
|
[property: Hidden]
|
||||||
|
Color color_Pressed;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private Brush colorButton_oculto;
|
Color color_Titulo;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
Color color;
|
||||||
|
|
||||||
|
partial void OnColorChanged(Color value)
|
||||||
|
{
|
||||||
|
OnEstadoChanged(Estado);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Hidden]
|
||||||
|
private Color colorButton;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float tamano;
|
public float tamano;
|
||||||
|
|
||||||
|
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||||
|
{
|
||||||
|
Tamano += Delta_Width + Delta_Height;
|
||||||
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public bool estado;
|
public bool estado;
|
||||||
|
|
||||||
partial void OnEstadoChanged(bool value)
|
partial void OnEstadoChanged(bool value)
|
||||||
{
|
{
|
||||||
if (value)
|
if (value)
|
||||||
ColorButton_oculto = Brushes.LightGreen;
|
Color_Pressed = Colors.LightGreen;
|
||||||
else
|
else
|
||||||
ColorButton_oculto = Color;
|
Color_Pressed = Colors.Gray;
|
||||||
if (!tipo_NC)
|
if (!Tipo_NC)
|
||||||
EscribirBitTag(Tag, value);
|
EscribirBitTag(Tag, value);
|
||||||
else
|
else
|
||||||
EscribirBitTag(Tag, !value);
|
EscribirBitTag(Tag, !value);
|
||||||
|
@ -52,6 +78,9 @@ namespace CtrEditor.ObjetosSim
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public string tag;
|
public string tag;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public string tag_Luz;
|
||||||
|
|
||||||
public void ButtonDownCommand()
|
public void ButtonDownCommand()
|
||||||
{
|
{
|
||||||
Estado = true;
|
Estado = true;
|
||||||
|
@ -67,7 +96,10 @@ namespace CtrEditor.ObjetosSim
|
||||||
Estado = false;
|
Estado = false;
|
||||||
Tag = "M50.0";
|
Tag = "M50.0";
|
||||||
// Set initial color
|
// Set initial color
|
||||||
Color = Brushes.LightBlue;
|
Color = Colors.LightBlue;
|
||||||
|
color_Titulo = Colors.Black;
|
||||||
|
button_Name = "TAG";
|
||||||
|
Color_Pressed = Colors.Gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateGeometryStart()
|
public override void UpdateGeometryStart()
|
||||||
|
@ -75,9 +107,18 @@ namespace CtrEditor.ObjetosSim
|
||||||
// Se llama antes de la simulacion
|
// Se llama antes de la simulacion
|
||||||
|
|
||||||
}
|
}
|
||||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||||
{
|
{
|
||||||
|
if (LeerBitTag(Tag_Luz))
|
||||||
|
ColorButton = ObtenerColorMasClaroYSaturado(Color, 0.3, 0.5);
|
||||||
|
else ColorButton = Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdatePLCPrimerCiclo() {
|
||||||
|
// Escribimos el valor actual al iniciar la conexion
|
||||||
|
// Esto es util para NC principalmente
|
||||||
|
|
||||||
|
OnEstadoChanged(Estado);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateControl(int elapsedMilliseconds)
|
public override void UpdateControl(int elapsedMilliseconds)
|
||||||
|
@ -88,7 +129,8 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
// crear el objeto de simulacion
|
// crear el objeto de simulacion
|
||||||
ActualizarLeftTop();
|
base.ucLoaded();
|
||||||
|
ColorButton = Color;
|
||||||
}
|
}
|
||||||
public override void ucUnLoaded()
|
public override void ucUnLoaded()
|
||||||
{
|
{
|
||||||
|
@ -101,6 +143,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public partial class ucBoton : UserControl, IDataContainer
|
public partial class ucBoton : UserControl, IDataContainer
|
||||||
{
|
{
|
||||||
public osBase? Datos { get; set; }
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
public ucBoton()
|
public ucBoton()
|
||||||
{
|
{
|
||||||
|
@ -140,21 +183,11 @@ namespace CtrEditor.ObjetosSim
|
||||||
e.Handled = true; // Evita que el evento se propague
|
e.Handled = true; // Evita que el evento se propague
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Resize(float width, float height) { }
|
|
||||||
public void Move(float LeftPixels, float TopPixels)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
{
|
|
||||||
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
|
||||||
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Rotate(float Angle) { }
|
|
||||||
public void Highlight(bool State) { }
|
public void Highlight(bool State) { }
|
||||||
public int ZIndex()
|
public ZIndexEnum ZIndex_Base()
|
||||||
{
|
{
|
||||||
return 10;
|
return ZIndexEnum.Estaticos;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<UserControl x:Class="CtrEditor.ObjetosSim.ucEncoderMotor"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<UserControl.DataContext>
|
||||||
|
<vm:osEncoderMotor />
|
||||||
|
</UserControl.DataContext>
|
||||||
|
|
||||||
|
<Grid Width="50" Height="50">
|
||||||
|
<Ellipse Fill="{Binding Color_oculto}" Stroke="DarkGray" StrokeThickness="2" Width="30" Height="30" />
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,161 @@
|
||||||
|
// EncoderMotorViewModel.cs
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using LibS7Adv;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace CtrEditor.ObjetosSim
|
||||||
|
{
|
||||||
|
public partial class osEncoderMotor : osBase, IosBase
|
||||||
|
{
|
||||||
|
private osBase Motor = null;
|
||||||
|
private Stopwatch Stopwatch = new Stopwatch();
|
||||||
|
private double stopwatch_last = 0;
|
||||||
|
|
||||||
|
public static string NombreClase()
|
||||||
|
{
|
||||||
|
return "Encoder Motor";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string nombre = NombreClase();
|
||||||
|
public override string Nombre
|
||||||
|
{
|
||||||
|
get => nombre;
|
||||||
|
set => SetProperty(ref nombre, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private Brush color_oculto;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public float velocidadActual;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Pulsos por vuelta del encoder")]
|
||||||
|
[property: Category("Encoder Config:")]
|
||||||
|
public float pulsos_Por_Vuelta;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Ratio de giros por 50Hz")]
|
||||||
|
[property: Category("Encoder Config:")]
|
||||||
|
public float ratio_Giros_50hz;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Valor actual del encoder")]
|
||||||
|
[property: Category("Encoder Status:")]
|
||||||
|
public float valor_Actual;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Link to Motor")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
[property: ItemsSource(typeof(osBaseItemsSource<osVMmotorSim>))]
|
||||||
|
string id_Motor;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Tag para escribir el valor del encoder")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
string tag_Valor;
|
||||||
|
|
||||||
|
partial void OnId_MotorChanged(string value)
|
||||||
|
{
|
||||||
|
if (Motor != null)
|
||||||
|
Motor.PropertyChanged -= OnMotorPropertyChanged;
|
||||||
|
if (_mainViewModel != null && value != null && value.Length > 0)
|
||||||
|
{
|
||||||
|
Motor = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osVMmotorSim && s.Nombre == value), null);
|
||||||
|
if (Motor != null)
|
||||||
|
Motor.PropertyChanged += OnMotorPropertyChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMotorPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(osVMmotorSim.Nombre))
|
||||||
|
{
|
||||||
|
Id_Motor = ((osVMmotorSim)sender).Nombre;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public osEncoderMotor()
|
||||||
|
{
|
||||||
|
Pulsos_Por_Vuelta = 360; // Por defecto, un pulso por grado
|
||||||
|
Ratio_Giros_50hz = 1; // Por defecto, 1 giro por cada 50Hz
|
||||||
|
Color_oculto = Brushes.Gray;
|
||||||
|
Stopwatch.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||||
|
{
|
||||||
|
if (Motor != null && Motor is osVMmotorSim motor)
|
||||||
|
{
|
||||||
|
VelocidadActual = motor.Velocidad;
|
||||||
|
|
||||||
|
// Calcular giros por segundo basado en la velocidad actual
|
||||||
|
// velocidad * ratio_giros_50hz / 100 nos da los giros por segundo a esa velocidad
|
||||||
|
float girosPorSegundo = (VelocidadActual * Ratio_Giros_50hz) / 100f;
|
||||||
|
|
||||||
|
// Considerar el sentido de giro
|
||||||
|
if (motor.Sentido_contrario)
|
||||||
|
girosPorSegundo = -girosPorSegundo;
|
||||||
|
|
||||||
|
// Calcular incremento de pulsos para este ciclo
|
||||||
|
float segundosTranscurridos = elapsedMilliseconds / 1000f;
|
||||||
|
float incrementoPulsos = girosPorSegundo * Pulsos_Por_Vuelta * segundosTranscurridos;
|
||||||
|
|
||||||
|
// Actualizar valor del encoder
|
||||||
|
Valor_Actual = (Valor_Actual + incrementoPulsos) % Pulsos_Por_Vuelta;
|
||||||
|
if (Valor_Actual < 0) Valor_Actual += Pulsos_Por_Vuelta;
|
||||||
|
|
||||||
|
// Actualizar color basado en si está girando
|
||||||
|
Color_oculto = Math.Abs(girosPorSegundo) > 0.01f ? Brushes.LightGreen : Brushes.Gray;
|
||||||
|
|
||||||
|
// Escribir valor al PLC si hay tag configurado
|
||||||
|
if (!string.IsNullOrEmpty(Tag_Valor))
|
||||||
|
{
|
||||||
|
EscribirWordTagScaled(Tag_Valor, Valor_Actual, 0, Pulsos_Por_Vuelta, 0, 27648);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ucLoaded()
|
||||||
|
{
|
||||||
|
base.ucLoaded();
|
||||||
|
OnId_MotorChanged(Id_Motor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class ucEncoderMotor : UserControl, IDataContainer
|
||||||
|
{
|
||||||
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
|
public ucEncoderMotor()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.Loaded += OnLoaded;
|
||||||
|
this.Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucUnLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Highlight(bool State) { }
|
||||||
|
|
||||||
|
public ZIndexEnum ZIndex_Base()
|
||||||
|
{
|
||||||
|
return ZIndexEnum.Estaticos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
<UserControl x:Class="CtrEditor.ObjetosSim.ucEncoderMotorLineal"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<UserControl.DataContext>
|
||||||
|
<vm:osEncoderMotorLineal />
|
||||||
|
</UserControl.DataContext>
|
||||||
|
|
||||||
|
<Grid Width="50" Height="50">
|
||||||
|
<Ellipse Fill="{Binding Color_oculto}" Stroke="DarkGray" StrokeThickness="2" Width="30" Height="30" />
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,153 @@
|
||||||
|
// EncoderMotorLinealViewModel.cs
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using LibS7Adv;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace CtrEditor.ObjetosSim
|
||||||
|
{
|
||||||
|
public partial class osEncoderMotorLineal : osBase, IosBase
|
||||||
|
{
|
||||||
|
private osBase Motor = null;
|
||||||
|
private Stopwatch Stopwatch = new Stopwatch();
|
||||||
|
private double stopwatch_last = 0;
|
||||||
|
|
||||||
|
public static string NombreClase()
|
||||||
|
{
|
||||||
|
return "Encoder Motor Lineal";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string nombre = NombreClase();
|
||||||
|
public override string Nombre
|
||||||
|
{
|
||||||
|
get => nombre;
|
||||||
|
set => SetProperty(ref nombre, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private Brush color_oculto;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public float velocidadActual;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Pulsos por Hz por segundo : K")]
|
||||||
|
[property: Category("Encoder Config:")]
|
||||||
|
public float pulsos_Por_Hz;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Valor actual del encoder")]
|
||||||
|
[property: Category("Encoder Status:")]
|
||||||
|
public float valor_Actual;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Link to Motor")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
[property: ItemsSource(typeof(osBaseItemsSource<osVMmotorSim>))]
|
||||||
|
string id_Motor;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Tag para escribir el valor del encoder")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
string tag_Valor;
|
||||||
|
|
||||||
|
partial void OnId_MotorChanged(string value)
|
||||||
|
{
|
||||||
|
if (Motor != null)
|
||||||
|
Motor.PropertyChanged -= OnMotorPropertyChanged;
|
||||||
|
if (_mainViewModel != null && value != null && value.Length > 0)
|
||||||
|
{
|
||||||
|
Motor = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osVMmotorSim && s.Nombre == value), null);
|
||||||
|
if (Motor != null)
|
||||||
|
Motor.PropertyChanged += OnMotorPropertyChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMotorPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(osVMmotorSim.Nombre))
|
||||||
|
{
|
||||||
|
Id_Motor = ((osVMmotorSim)sender).Nombre;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public osEncoderMotorLineal()
|
||||||
|
{
|
||||||
|
Pulsos_Por_Hz = 3000; // Por defecto, un pulso por grado
|
||||||
|
Color_oculto = Brushes.Gray;
|
||||||
|
Stopwatch.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||||
|
{
|
||||||
|
if (Motor != null && Motor is osVMmotorSim motor)
|
||||||
|
{
|
||||||
|
VelocidadActual = motor.Velocidad;
|
||||||
|
|
||||||
|
// Calcular giros por segundo basado en la velocidad actual
|
||||||
|
float pulsosPorHz = (VelocidadActual * Pulsos_Por_Hz) / 100f;
|
||||||
|
|
||||||
|
// Considerar el sentido de giro
|
||||||
|
if (motor.Sentido_contrario)
|
||||||
|
pulsosPorHz = -pulsosPorHz;
|
||||||
|
|
||||||
|
// Calcular incremento de pulsos para este ciclo
|
||||||
|
float segundosTranscurridos = elapsedMilliseconds / 1000f;
|
||||||
|
float incrementoPulsos = pulsosPorHz * segundosTranscurridos;
|
||||||
|
|
||||||
|
// Actualizar valor del encoder
|
||||||
|
Valor_Actual = (Valor_Actual + incrementoPulsos);
|
||||||
|
|
||||||
|
// Actualizar color basado en si está girando
|
||||||
|
Color_oculto = Math.Abs(pulsosPorHz) > 0.01f ? Brushes.LightGreen : Brushes.Gray;
|
||||||
|
|
||||||
|
// Escribir valor al PLC si hay tag configurado
|
||||||
|
if (!string.IsNullOrEmpty(Tag_Valor))
|
||||||
|
{
|
||||||
|
EscribirDINTTag(tag_Valor, (int)Valor_Actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ucLoaded()
|
||||||
|
{
|
||||||
|
base.ucLoaded();
|
||||||
|
OnId_MotorChanged(Id_Motor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class ucEncoderMotorLineal : UserControl, IDataContainer
|
||||||
|
{
|
||||||
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
|
public ucEncoderMotorLineal()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.Loaded += OnLoaded;
|
||||||
|
this.Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucUnLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Highlight(bool State) { }
|
||||||
|
|
||||||
|
public ZIndexEnum ZIndex_Base()
|
||||||
|
{
|
||||||
|
return ZIndexEnum.Estaticos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,13 +4,8 @@
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:CtrEditor.ObjetosSim.UserControls"
|
xmlns:local="clr-namespace:CtrEditor.ObjetosSim.UserControls"
|
||||||
mc:Ignorable="d"
|
|
||||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<UserControl.Resources>
|
|
||||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
|
||||||
</UserControl.Resources>
|
|
||||||
|
|
||||||
<UserControl.DataContext>
|
<UserControl.DataContext>
|
||||||
<vm:osGearEncoder Dientes="9"/>
|
<vm:osGearEncoder Dientes="9"/>
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
using CtrEditor.Convertidores;
|
|
||||||
using CtrEditor.Siemens;
|
using LibS7Adv;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
|
||||||
namespace CtrEditor.ObjetosSim
|
namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
|
@ -14,7 +16,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class osGearEncoder : osBase, IosBase
|
public partial class osGearEncoder : osBase, IosBase
|
||||||
{
|
{
|
||||||
private osBase _osMotor = null;
|
private osBase Motor = null;
|
||||||
private Stopwatch Stopwatch = new Stopwatch();
|
private Stopwatch Stopwatch = new Stopwatch();
|
||||||
private double stopwatch_last = 0;
|
private double stopwatch_last = 0;
|
||||||
|
|
||||||
|
@ -41,8 +43,8 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
var dTime = Stopwatch.ElapsedMilliseconds - stopwatch_last;
|
var dTime = Stopwatch.Elapsed.TotalMilliseconds - stopwatch_last;
|
||||||
stopwatch_last = Stopwatch.ElapsedMilliseconds;
|
stopwatch_last = Stopwatch.Elapsed.TotalMilliseconds;
|
||||||
Tiempo_Pulso = (float)dTime;
|
Tiempo_Pulso = (float)dTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,10 +59,8 @@ namespace CtrEditor.ObjetosSim
|
||||||
private Brush color_oculto;
|
private Brush color_oculto;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float velocidadActual;
|
public float velocidadActual;
|
||||||
[ObservableProperty]
|
|
||||||
public double angulo;
|
|
||||||
|
|
||||||
partial void OnAnguloChanged(double value)
|
public override void AnguloChanged(float value)
|
||||||
{
|
{
|
||||||
// Generar pulsos cuadrados en función del ángulo
|
// Generar pulsos cuadrados en función del ángulo
|
||||||
Pulso = DetectarDiente();
|
Pulso = DetectarDiente();
|
||||||
|
@ -96,12 +96,37 @@ namespace CtrEditor.ObjetosSim
|
||||||
public float ancho_Dientes;
|
public float ancho_Dientes;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float giros_segundo_a_100;
|
public float giros_segundo_a_100;
|
||||||
[ObservableProperty]
|
|
||||||
public string motor;
|
|
||||||
|
|
||||||
partial void OnMotorChanged(string value)
|
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||||
{
|
{
|
||||||
_osMotor = ObtenerLink(Motor, typeof(osVMmotorSim));
|
Radio_Externo += Delta_Width;
|
||||||
|
Radio_Interno += Delta_Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Link to Motor")]
|
||||||
|
[property: Category("PLC link:")]
|
||||||
|
[property: ItemsSource(typeof(osBaseItemsSource<osVMmotorSim>))]
|
||||||
|
string id_Motor;
|
||||||
|
|
||||||
|
partial void OnId_MotorChanged(string value)
|
||||||
|
{
|
||||||
|
if (Motor != null)
|
||||||
|
Motor.PropertyChanged -= OnMotorPropertyChanged;
|
||||||
|
if (_mainViewModel != null && value != null && value.Length > 0)
|
||||||
|
{
|
||||||
|
Motor = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osVMmotorSim && s.Nombre == value), null);
|
||||||
|
if (Motor != null)
|
||||||
|
Motor.PropertyChanged += OnMotorPropertyChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMotorPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.PropertyName == nameof(osVMmotorSim.Nombre))
|
||||||
|
{
|
||||||
|
Id_Motor = ((osVMmotorSim)sender).Nombre;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public osGearEncoder()
|
public osGearEncoder()
|
||||||
|
@ -119,28 +144,9 @@ namespace CtrEditor.ObjetosSim
|
||||||
// Se llama antes de la simulacion
|
// Se llama antes de la simulacion
|
||||||
|
|
||||||
}
|
}
|
||||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||||
{
|
{
|
||||||
if (_osMotor != null)
|
|
||||||
{
|
|
||||||
if (_osMotor is osVMmotorSim motor)
|
|
||||||
{
|
|
||||||
VelocidadActual = motor.Velocidad;
|
|
||||||
|
|
||||||
// Calcular la cantidad de giros por segundo
|
|
||||||
double girosPorSegundo = (VelocidadActual / 100.0) * Giros_segundo_a_100;
|
|
||||||
|
|
||||||
// Calcular la fracción del segundo que ha pasado
|
|
||||||
double segundosTranscurridos = elapsedMilliseconds / 1000.0;
|
|
||||||
|
|
||||||
// Calcular el incremento de ángulo
|
|
||||||
double incrementoAngulo = (girosPorSegundo * 360.0) * segundosTranscurridos;
|
|
||||||
|
|
||||||
// Actualizar el ángulo
|
|
||||||
Angulo = (Angulo + incrementoAngulo) % 360;
|
|
||||||
}
|
|
||||||
} else if (Motor.Length>0)
|
|
||||||
_osMotor = ObtenerLink(Motor, typeof(osVMmotorSim));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DetectarDiente()
|
public bool DetectarDiente()
|
||||||
|
@ -183,21 +189,43 @@ namespace CtrEditor.ObjetosSim
|
||||||
public override void UpdateControl(int elapsedMilliseconds)
|
public override void UpdateControl(int elapsedMilliseconds)
|
||||||
{
|
{
|
||||||
// Calculamos la velocidad
|
// Calculamos la velocidad
|
||||||
|
if (Motor != null)
|
||||||
|
{
|
||||||
|
if (Motor is osVMmotorSim motor)
|
||||||
|
{
|
||||||
|
if (motor.Sentido_contrario)
|
||||||
|
VelocidadActual = -motor.Velocidad;
|
||||||
|
else
|
||||||
|
VelocidadActual = motor.Velocidad;
|
||||||
|
|
||||||
|
// Calcular la cantidad de giros por segundo
|
||||||
|
double girosPorSegundo = (VelocidadActual / 100.0) * Giros_segundo_a_100;
|
||||||
|
|
||||||
|
// Calcular la fracción del segundo que ha pasado
|
||||||
|
double segundosTranscurridos = elapsedMilliseconds / 1000.0;
|
||||||
|
|
||||||
|
// Calcular el incremento de ángulo
|
||||||
|
double incrementoAngulo = (girosPorSegundo * 360.0) * segundosTranscurridos;
|
||||||
|
|
||||||
|
// Actualizar el ángulo
|
||||||
|
Angulo = (float)(Angulo + incrementoAngulo) % 360;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ucLoaded()
|
public override void ucLoaded()
|
||||||
{
|
{
|
||||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
// crear el objeto de simulacion
|
// crear el objeto de simulacion
|
||||||
ActualizarLeftTop();
|
base.ucLoaded();
|
||||||
|
OnId_MotorChanged(Id_Motor); // Link Id_Motor = Motor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class ucGearEncoder : UserControl, IDataContainer
|
public partial class ucGearEncoder : UserControl, IDataContainer
|
||||||
{
|
{
|
||||||
public osBase? Datos { get; set; }
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
public ucGearEncoder()
|
public ucGearEncoder()
|
||||||
{
|
{
|
||||||
|
@ -213,21 +241,12 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
Datos?.ucUnLoaded();
|
Datos?.ucUnLoaded();
|
||||||
}
|
}
|
||||||
public void Resize(float width, float height) { }
|
|
||||||
public void Move(float LeftPixels, float TopPixels)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
{
|
|
||||||
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
|
||||||
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Rotate(float Angle) { }
|
|
||||||
public void Highlight(bool State) { }
|
public void Highlight(bool State) { }
|
||||||
public int ZIndex()
|
public ZIndexEnum ZIndex_Base()
|
||||||
{
|
{
|
||||||
return 10;
|
return ZIndexEnum.Estaticos;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,54 +4,55 @@
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:CtrEditor.ObjetosSim.UserControls"
|
xmlns:local="clr-namespace:CtrEditor.ObjetosSim.UserControls"
|
||||||
mc:Ignorable="d"
|
|
||||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<UserControl.Resources>
|
|
||||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
|
||||||
</UserControl.Resources>
|
|
||||||
|
|
||||||
<UserControl.DataContext>
|
<UserControl.DataContext>
|
||||||
<vm:osPhotocell Color="#FFCA1C1C"/>
|
<vm:osPhotocell Color="#FFCA1C1C" Ancho="0.8" Nombre="PTH" Alto="0.04" />
|
||||||
</UserControl.DataContext>
|
</UserControl.DataContext>
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition
|
||||||
|
Width="{Binding Alto, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=5}" />
|
||||||
<!-- Columna para el Label -->
|
<!-- Columna para el Label -->
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<!-- Columna para la Image -->
|
<!-- Columna para la Image -->
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<!-- Columna para el Rectangle -->
|
<!-- Columna para el Rectangle -->
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<Grid.RenderTransform>
|
<Grid.RenderTransform>
|
||||||
<RotateTransform Angle="{Binding Angulo}" CenterX="0" CenterY="0"/>
|
<RotateTransform Angle="{Binding Angulo}" CenterX="0" CenterY="0"/>
|
||||||
</Grid.RenderTransform>
|
</Grid.RenderTransform>
|
||||||
|
|
||||||
<!-- Label en la primera columna -->
|
<!-- Label en la primera columna -->
|
||||||
<Label Content="{Binding Nombre}" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Column="0" Foreground="{Binding Color}" >
|
<Viewbox Grid.Column="0" Stretch="UniformToFill">
|
||||||
|
<Label Content="{Binding Nombre}"
|
||||||
|
VerticalAlignment="Center" HorizontalAlignment="Center" Opacity="0.8" FontWeight="Bold" Foreground="{Binding Color}"/>
|
||||||
|
</Viewbox>
|
||||||
|
|
||||||
</Label>
|
<Image Source="/Icons/fotocelula.png"
|
||||||
|
Width="{Binding Alto, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=2}"
|
||||||
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=2}"
|
||||||
|
VerticalAlignment="Center" HorizontalAlignment="Left" Margin="2,2,2,2" Grid.Column="1"/>
|
||||||
|
|
||||||
<Image Source="/Icons/fotocelula.png"
|
<Rectangle x:Name="Photocell" Grid.Column="2" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=0.9}"
|
||||||
Width="{Binding Alto, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=3}"
|
Height="{Binding Ancho_Haz_De_Luz, Converter={StaticResource MeterToPixelConverter}}">
|
||||||
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=3}"
|
|
||||||
VerticalAlignment="Center" HorizontalAlignment="Left" Margin="0,0,0,0" Grid.Column="1"/>
|
|
||||||
|
|
||||||
<Rectangle x:Name="Photocell" Grid.Column="2" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}">
|
|
||||||
<Rectangle.Fill>
|
<Rectangle.Fill>
|
||||||
<VisualBrush x:Name="MovingPattern" TileMode="Tile" Viewport="0,0,3,3" ViewportUnits="Absolute" Viewbox="0,0,3,3" ViewboxUnits="Absolute">
|
<VisualBrush x:Name="MovingPattern" TileMode="Tile" Viewport="0,0,3,3" ViewportUnits="Absolute" Viewbox="0,0,3,3" ViewboxUnits="Absolute">
|
||||||
<VisualBrush.Visual>
|
<VisualBrush.Visual>
|
||||||
<Canvas>
|
<Canvas>
|
||||||
<Ellipse Width="2" Height="2" Fill="{Binding Color}"/>
|
<Ellipse
|
||||||
|
Width="1"
|
||||||
|
Height="1" Fill="{Binding Color}"/>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
</VisualBrush.Visual>
|
</VisualBrush.Visual>
|
||||||
</VisualBrush>
|
</VisualBrush>
|
||||||
</Rectangle.Fill>
|
</Rectangle.Fill>
|
||||||
<!-- No se aplica la transformación aquí -->
|
|
||||||
</Rectangle>
|
</Rectangle>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|
||||||
</UserControl>
|
</UserControl>
|
|
@ -1,11 +1,15 @@
|
||||||
using CtrEditor.Convertidores;
|
|
||||||
using CtrEditor.Simulacion;
|
using CtrEditor.Simulacion;
|
||||||
using CtrEditor.Siemens;
|
using LibS7Adv;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||||
|
using JsonIgnoreAttribute = Newtonsoft.Json.JsonIgnoreAttribute;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace CtrEditor.ObjetosSim
|
namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
|
@ -15,7 +19,10 @@ namespace CtrEditor.ObjetosSim
|
||||||
public partial class osPhotocell : osBase, IosBase
|
public partial class osPhotocell : osBase, IosBase
|
||||||
{
|
{
|
||||||
private simBarrera Simulation_Photocell;
|
private simBarrera Simulation_Photocell;
|
||||||
|
Stopwatch timer;
|
||||||
|
double timer_lastPositive;
|
||||||
|
double timer_lastNegative;
|
||||||
|
|
||||||
public static string NombreClase()
|
public static string NombreClase()
|
||||||
{
|
{
|
||||||
return "Photocell";
|
return "Photocell";
|
||||||
|
@ -27,10 +34,15 @@ namespace CtrEditor.ObjetosSim
|
||||||
set => SetProperty(ref nombre, value);
|
set => SetProperty(ref nombre, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Color")]
|
||||||
|
[property: Category("Layout:")]
|
||||||
|
Brush color;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public Brush color;
|
[property: Description("Light cut")]
|
||||||
[ObservableProperty]
|
[property: Category("Debug:")]
|
||||||
public bool luzCortada;
|
bool luzCortada;
|
||||||
|
|
||||||
partial void OnLuzCortadaChanged(bool value)
|
partial void OnLuzCortadaChanged(bool value)
|
||||||
{
|
{
|
||||||
|
@ -42,12 +54,85 @@ namespace CtrEditor.ObjetosSim
|
||||||
EscribirBitTag(TagPhotocell_OUT, !LuzCortada);
|
EscribirBitTag(TagPhotocell_OUT, !LuzCortada);
|
||||||
else
|
else
|
||||||
EscribirBitTag(TagPhotocell_OUT, LuzCortada);
|
EscribirBitTag(TagPhotocell_OUT, LuzCortada);
|
||||||
|
if (Filter_Frecuency < 1)
|
||||||
|
{
|
||||||
|
Filter_Frecuency = 1;
|
||||||
|
Frecuency = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
Lenght_positive_pulse = (float) (timer.Elapsed.TotalMilliseconds - timer_lastPositive);
|
||||||
|
timer_lastNegative = timer.Elapsed.TotalMilliseconds;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
Lenght_negative_pulse = (float)(timer.Elapsed.TotalMilliseconds - timer_lastNegative);
|
||||||
|
timer_lastPositive = timer.Elapsed.TotalMilliseconds;
|
||||||
|
Lenght_FP_to_FP = Lenght_positive_pulse + Lenght_negative_pulse;
|
||||||
|
Frecuency = (Frecuency * (filter_Frecuency - 1) + (1000 / Lenght_FP_to_FP)) / filter_Frecuency;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
|
[property: Description("Size of the Light.")]
|
||||||
|
[property: Category("Setup:")]
|
||||||
|
float ancho_Haz_De_Luz;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Distance to the neck.")]
|
||||||
|
[property: Category("Debug:")]
|
||||||
|
float distancia_cuello;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Type of detection: Neck of the bottle or Complete bottle.")]
|
||||||
|
[property: Category("Setup:")]
|
||||||
|
bool detectarCuello;
|
||||||
|
|
||||||
|
partial void OnDetectarCuelloChanged(bool value)
|
||||||
|
{
|
||||||
|
if (Simulation_Photocell == null) return;
|
||||||
|
|
||||||
|
Simulation_Photocell.DetectNeck = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Filter signal.")]
|
||||||
|
[property: Category("Setup:")]
|
||||||
|
float filter_Frecuency;
|
||||||
|
|
||||||
|
partial void OnFilter_FrecuencyChanged(float value)
|
||||||
|
{
|
||||||
|
if (value<=0)
|
||||||
|
Filter_Frecuency = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Debug:")]
|
||||||
|
float frecuency;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Debug:")]
|
||||||
|
float lenght_positive_pulse;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Debug:")]
|
||||||
|
float lenght_negative_pulse;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Category("Debug:")]
|
||||||
|
float lenght_FP_to_FP;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
[property: Description("Type Filter signal.")]
|
||||||
|
[property: Category("Setup:")]
|
||||||
public bool tipo_NC;
|
public bool tipo_NC;
|
||||||
|
|
||||||
|
partial void OnTipo_NCChanged(bool value)
|
||||||
|
{
|
||||||
|
OnLuzCortadaChanged(LuzCortada);
|
||||||
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public string tagPhotocell_OUT;
|
public string tagPhotocell_OUT;
|
||||||
|
|
||||||
|
@ -62,40 +147,36 @@ namespace CtrEditor.ObjetosSim
|
||||||
ActualizarGeometrias();
|
ActualizarGeometrias();
|
||||||
}
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
public override void AnguloChanged(float value)
|
||||||
public float ancho;
|
|
||||||
|
|
||||||
partial void OnAnchoChanged(float value)
|
|
||||||
{
|
{
|
||||||
ActualizarGeometrias();
|
ActualizarGeometrias();
|
||||||
}
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
public override void AltoChanged(float value)
|
||||||
public float alto;
|
|
||||||
|
|
||||||
partial void OnAltoChanged(float value)
|
|
||||||
{
|
{
|
||||||
ActualizarGeometrias();
|
ActualizarGeometrias();
|
||||||
}
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
public override void AnchoChanged(float value)
|
||||||
public float angulo;
|
|
||||||
|
|
||||||
partial void OnAnguloChanged(float value)
|
|
||||||
{
|
{
|
||||||
ActualizarGeometrias();
|
ActualizarGeometrias();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void ActualizarGeometrias()
|
private void ActualizarGeometrias()
|
||||||
{
|
{
|
||||||
if (_visualRepresentation is ucPhotocell uc)
|
if (_visualRepresentation is ucPhotocell uc)
|
||||||
UpdateRectangle(Simulation_Photocell, uc.Photocell, Alto, Ancho, Angulo);
|
UpdateRectangle(Simulation_Photocell, uc.Photocell, Ancho_Haz_De_Luz, Ancho, Angulo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public osPhotocell()
|
public osPhotocell()
|
||||||
{
|
{
|
||||||
Ancho = 1;
|
Ancho = 1;
|
||||||
Alto = 0.03f;
|
Alto = 0.03f;
|
||||||
|
Ancho_Haz_De_Luz = 0.01f;
|
||||||
|
Frecuency = 0;
|
||||||
|
timer = new Stopwatch();
|
||||||
|
timer.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateGeometryStart()
|
public override void UpdateGeometryStart()
|
||||||
|
@ -105,22 +186,29 @@ namespace CtrEditor.ObjetosSim
|
||||||
}
|
}
|
||||||
public override void UpdateControl(int elapsedMilliseconds)
|
public override void UpdateControl(int elapsedMilliseconds)
|
||||||
{
|
{
|
||||||
LuzCortada = Simulation_Photocell.LuzCortada;
|
Distancia_cuello = Simulation_Photocell.Distancia;
|
||||||
|
if (DetectarCuello)
|
||||||
|
LuzCortada = Simulation_Photocell.LuzCortadaNeck;
|
||||||
|
else
|
||||||
|
LuzCortada = Simulation_Photocell.LuzCortada > 0;
|
||||||
}
|
}
|
||||||
public override void UpdateGeometryStep()
|
public override void UpdatePLCPrimerCiclo()
|
||||||
{
|
{
|
||||||
Simulation_Photocell.LuzCortada = false;
|
// Escribimos el valor actual al iniciar la conexion
|
||||||
|
// Esto es util para NC principalmente
|
||||||
|
|
||||||
|
OnLuzCortadaChanged(LuzCortada);
|
||||||
}
|
}
|
||||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) {
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds) {
|
||||||
}
|
}
|
||||||
public override void ucLoaded()
|
public override void ucLoaded()
|
||||||
{
|
{
|
||||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
// crear el objeto de simulacion
|
// crear el objeto de simulacion
|
||||||
ActualizarLeftTop();
|
base.ucLoaded();
|
||||||
|
|
||||||
if (_visualRepresentation is ucPhotocell uc)
|
if (_visualRepresentation is ucPhotocell uc)
|
||||||
Simulation_Photocell = AddBarrera(simulationManager, uc.Photocell, Alto, Ancho, Angulo);
|
Simulation_Photocell = AddBarrera(simulationManager, uc.Photocell, Alto, Ancho, Angulo, DetectarCuello);
|
||||||
}
|
}
|
||||||
public override void ucUnLoaded()
|
public override void ucUnLoaded()
|
||||||
{
|
{
|
||||||
|
@ -135,6 +223,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public partial class ucPhotocell : UserControl, IDataContainer
|
public partial class ucPhotocell : UserControl, IDataContainer
|
||||||
{
|
{
|
||||||
public osBase? Datos { get; set; }
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
public ucPhotocell()
|
public ucPhotocell()
|
||||||
{
|
{
|
||||||
|
@ -150,31 +239,12 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
Datos?.ucUnLoaded();
|
Datos?.ucUnLoaded();
|
||||||
}
|
}
|
||||||
public void Resize(float width, float height)
|
|
||||||
{
|
|
||||||
if (width == 0) return;
|
|
||||||
if (Datos is osPhotocell datos)
|
|
||||||
datos.Ancho = PixelToMeter.Instance.calc.PixelsToMeters(width);
|
|
||||||
}
|
|
||||||
public void Move(float LeftPixels, float TopPixels)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
{
|
|
||||||
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
|
||||||
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Rotate(float Angle)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
if (Datos is osPhotocell datos)
|
|
||||||
datos.Angulo = Angle;
|
|
||||||
}
|
|
||||||
public void Highlight(bool State) { }
|
public void Highlight(bool State) { }
|
||||||
public int ZIndex()
|
public ZIndexEnum ZIndex_Base()
|
||||||
{
|
{
|
||||||
return 16;
|
return ZIndexEnum.Fotocelula;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,8 @@
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:CtrEditor.ObjetosSim"
|
xmlns:local="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
mc:Ignorable="d"
|
|
||||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<UserControl.Resources>
|
|
||||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
|
||||||
</UserControl.Resources>
|
|
||||||
|
|
||||||
<UserControl.DataContext>
|
<UserControl.DataContext>
|
||||||
<vm:osSensTemperatura />
|
<vm:osSensTemperatura />
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CtrEditor.Convertidores;
|
|
||||||
using CtrEditor.Siemens;
|
using LibS7Adv;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
|
||||||
namespace CtrEditor.ObjetosSim
|
namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
|
@ -30,6 +32,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public float min_OUT_Scaled;
|
public float min_OUT_Scaled;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float max_OUT_Scaled;
|
public float max_OUT_Scaled;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float value;
|
public float value;
|
||||||
|
|
||||||
|
@ -38,13 +41,6 @@ namespace CtrEditor.ObjetosSim
|
||||||
EscribirWordTagScaled(Tag, value, 0, 100, Min_OUT_Scaled, Max_OUT_Scaled);
|
EscribirWordTagScaled(Tag, value, 0, 100, Min_OUT_Scaled, Max_OUT_Scaled);
|
||||||
}
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
public float ancho;
|
|
||||||
[ObservableProperty]
|
|
||||||
public float alto;
|
|
||||||
[ObservableProperty]
|
|
||||||
public float angulo;
|
|
||||||
|
|
||||||
public osSensTemperatura()
|
public osSensTemperatura()
|
||||||
{
|
{
|
||||||
Ancho = 0.4f;
|
Ancho = 0.4f;
|
||||||
|
@ -53,16 +49,21 @@ namespace CtrEditor.ObjetosSim
|
||||||
Min_OUT_Scaled = 0;
|
Min_OUT_Scaled = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
public override void UpdatePLCPrimerCiclo()
|
||||||
|
{
|
||||||
|
// Escribimos el valor actual al iniciar la conexion
|
||||||
|
OnValueChanged(Value);
|
||||||
|
}
|
||||||
|
|
||||||
public override void ucLoaded()
|
public override void ucLoaded()
|
||||||
{
|
{
|
||||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
// crear el objeto de simulacion
|
// crear el objeto de simulacion
|
||||||
ActualizarLeftTop();
|
base.ucLoaded();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +72,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public partial class ucSensTemperatura : UserControl, IDataContainer
|
public partial class ucSensTemperatura : UserControl, IDataContainer
|
||||||
{
|
{
|
||||||
public osBase? Datos { get; set; }
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
public ucSensTemperatura()
|
public ucSensTemperatura()
|
||||||
{
|
{
|
||||||
|
@ -86,32 +88,11 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
Datos?.ucUnLoaded();
|
Datos?.ucUnLoaded();
|
||||||
}
|
}
|
||||||
public void Resize(float width, float height)
|
|
||||||
{
|
|
||||||
if (Datos is osSensTemperatura datos)
|
|
||||||
{
|
|
||||||
datos.Ancho = PixelToMeter.Instance.calc.PixelsToMeters(width);
|
|
||||||
datos.Alto = PixelToMeter.Instance.calc.PixelsToMeters(width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Move(float LeftPixels, float TopPixels)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
{
|
|
||||||
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
|
||||||
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Rotate(float Angle)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
if (Datos is osSensTemperatura datos)
|
|
||||||
datos.Angulo = Angle;
|
|
||||||
}
|
|
||||||
public void Highlight(bool State) { }
|
public void Highlight(bool State) { }
|
||||||
public int ZIndex()
|
public ZIndexEnum ZIndex_Base()
|
||||||
{
|
{
|
||||||
return 10;
|
return ZIndexEnum.Estaticos;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,15 +4,10 @@
|
||||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||||
xmlns:ei="http://schemas.microsoft.com/xaml/behaviors"
|
xmlns:ei="http://schemas.microsoft.com/xaml/behaviors"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
|
||||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<UserControl.Resources>
|
|
||||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
|
||||||
</UserControl.Resources>
|
|
||||||
|
|
||||||
<UserControl.DataContext>
|
<UserControl.DataContext>
|
||||||
<vm:osAnalogTag/>
|
<vm:osAnalogTag/>
|
||||||
</UserControl.DataContext>
|
</UserControl.DataContext>
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
using CtrEditor.Convertidores;
|
|
||||||
using CtrEditor.Siemens;
|
using LibS7Adv;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
|
||||||
namespace CtrEditor.ObjetosSim
|
namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
|
@ -31,6 +32,12 @@ namespace CtrEditor.ObjetosSim
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float tamano;
|
public float tamano;
|
||||||
|
|
||||||
|
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||||
|
{
|
||||||
|
Tamano += Delta_Width + Delta_Height;
|
||||||
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
[NotifyPropertyChangedFor(nameof(Value))]
|
[NotifyPropertyChangedFor(nameof(Value))]
|
||||||
public string tag;
|
public string tag;
|
||||||
|
@ -74,10 +81,16 @@ namespace CtrEditor.ObjetosSim
|
||||||
// Se llama antes de la simulacion
|
// Se llama antes de la simulacion
|
||||||
|
|
||||||
}
|
}
|
||||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void UpdatePLCPrimerCiclo()
|
||||||
|
{
|
||||||
|
// Escribimos el valor actual al iniciar la conexion
|
||||||
|
OnValueChanged(Value);
|
||||||
|
}
|
||||||
|
|
||||||
public override void UpdateControl(int elapsedMilliseconds)
|
public override void UpdateControl(int elapsedMilliseconds)
|
||||||
{
|
{
|
||||||
// Calculamos la velocidad
|
// Calculamos la velocidad
|
||||||
|
@ -88,7 +101,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
// crear el objeto de simulacion
|
// crear el objeto de simulacion
|
||||||
ActualizarLeftTop();
|
base.ucLoaded();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,6 +109,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public partial class ucAnalogTag : UserControl, IDataContainer
|
public partial class ucAnalogTag : UserControl, IDataContainer
|
||||||
{
|
{
|
||||||
public osBase? Datos { get; set; }
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
public ucAnalogTag()
|
public ucAnalogTag()
|
||||||
{
|
{
|
||||||
|
@ -111,20 +125,10 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
Datos?.ucUnLoaded();
|
Datos?.ucUnLoaded();
|
||||||
}
|
}
|
||||||
public void Resize(float width, float height) { }
|
|
||||||
public void Move(float LeftPixels, float TopPixels)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
{
|
|
||||||
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
|
||||||
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Rotate(float Angle) { }
|
|
||||||
public void Highlight(bool State) { }
|
public void Highlight(bool State) { }
|
||||||
public int ZIndex()
|
public ZIndexEnum ZIndex_Base()
|
||||||
{
|
{
|
||||||
return 10;
|
return ZIndexEnum.Estaticos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,18 +4,22 @@
|
||||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||||
xmlns:ei="http://schemas.microsoft.com/xaml/behaviors"
|
xmlns:ei="http://schemas.microsoft.com/xaml/behaviors"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
|
||||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<UserControl.Resources>
|
|
||||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
|
||||||
</UserControl.Resources>
|
|
||||||
|
|
||||||
<UserControl.DataContext>
|
<UserControl.DataContext>
|
||||||
<vm:osBoolTag/>
|
<vm:osBoolTag/>
|
||||||
</UserControl.DataContext>
|
</UserControl.DataContext>
|
||||||
|
<Canvas RenderTransformOrigin="0.5,0.5">
|
||||||
|
<Canvas.RenderTransform>
|
||||||
|
<TransformGroup>
|
||||||
|
<ScaleTransform />
|
||||||
|
<SkewTransform />
|
||||||
|
<RotateTransform Angle="{Binding Angulo}" />
|
||||||
|
<TranslateTransform />
|
||||||
|
</TransformGroup>
|
||||||
|
</Canvas.RenderTransform>
|
||||||
<Grid Margin="10">
|
<Grid Margin="10">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
|
@ -30,8 +34,10 @@
|
||||||
Height="40"
|
Height="40"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Background="Gray"/>
|
Background="{Binding Color, Converter={StaticResource ColorToBrushConverter}}"/>
|
||||||
<Label Content="{Binding Descripcion}" Grid.Column="1" VerticalAlignment="Center" Background="{Binding Color}" />
|
<Label Content="{Binding Descripcion}" Grid.Column="1" VerticalAlignment="Center" Background="{Binding Color}" />
|
||||||
<CheckBox Grid.Column="2" VerticalAlignment="Center" IsChecked="{Binding Estado}" />
|
<CheckBox Grid.Column="2" VerticalAlignment="Center" IsChecked="{Binding Estado}"
|
||||||
|
Background="{Binding Color_oculto}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
</Canvas>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
using CtrEditor.Convertidores;
|
|
||||||
using CtrEditor.Siemens;
|
using LibS7Adv;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
|
||||||
namespace CtrEditor.ObjetosSim
|
namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
|
@ -32,6 +33,9 @@ namespace CtrEditor.ObjetosSim
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private Brush color_oculto;
|
private Brush color_oculto;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
Color color;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public bool estado;
|
public bool estado;
|
||||||
|
|
||||||
|
@ -43,9 +47,15 @@ namespace CtrEditor.ObjetosSim
|
||||||
else
|
else
|
||||||
Color_oculto = Brushes.Transparent;
|
Color_oculto = Brushes.Transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float tamano;
|
public float tamano;
|
||||||
|
|
||||||
|
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||||
|
{
|
||||||
|
Tamano += Delta_Width + Delta_Height;
|
||||||
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
[NotifyPropertyChangedFor(nameof(Estado))]
|
[NotifyPropertyChangedFor(nameof(Estado))]
|
||||||
public string tag;
|
public string tag;
|
||||||
|
@ -58,13 +68,20 @@ namespace CtrEditor.ObjetosSim
|
||||||
Tamano = 0.30f;
|
Tamano = 0.30f;
|
||||||
tag = "%M50.0";
|
tag = "%M50.0";
|
||||||
Descripcion = "Nombre del Tag";
|
Descripcion = "Nombre del Tag";
|
||||||
|
Color = Colors.LightBlue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdatePLCPrimerCiclo()
|
||||||
|
{
|
||||||
|
// Escribimos el valor actual al iniciar la conexion
|
||||||
|
OnEstadoChanged(Estado);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ucLoaded()
|
public override void ucLoaded()
|
||||||
{
|
{
|
||||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
// crear el objeto de simulacion
|
// crear el objeto de simulacion
|
||||||
ActualizarLeftTop();
|
base.ucLoaded();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +89,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public partial class ucBoolTag : UserControl, IDataContainer
|
public partial class ucBoolTag : UserControl, IDataContainer
|
||||||
{
|
{
|
||||||
public osBase? Datos { get; set; }
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
public ucBoolTag()
|
public ucBoolTag()
|
||||||
{
|
{
|
||||||
|
@ -87,20 +105,11 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
Datos?.ucUnLoaded();
|
Datos?.ucUnLoaded();
|
||||||
}
|
}
|
||||||
public void Resize(float width, float height) { }
|
|
||||||
public void Move(float LeftPixels, float TopPixels)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
{
|
|
||||||
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
|
||||||
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Rotate(float Angle) { }
|
|
||||||
public void Highlight(bool State) { }
|
public void Highlight(bool State) { }
|
||||||
public int ZIndex()
|
public ZIndexEnum ZIndex_Base()
|
||||||
{
|
{
|
||||||
return 10;
|
return ZIndexEnum.Estaticos;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,9 @@
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
mc:Ignorable="d"
|
Background="LightGray"
|
||||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
mc:Ignorable="d">
|
||||||
Background="LightGray">
|
|
||||||
|
|
||||||
<UserControl.DataContext>
|
<UserControl.DataContext>
|
||||||
<vm:osConsensGeneric />
|
<vm:osConsensGeneric />
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CtrEditor.Convertidores;
|
|
||||||
using CtrEditor.Siemens;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
|
||||||
|
|
||||||
namespace CtrEditor.ObjetosSim
|
namespace CtrEditor.ObjetosSim
|
||||||
|
@ -34,14 +33,19 @@ namespace CtrEditor.ObjetosSim
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public float tamano;
|
public float tamano;
|
||||||
|
|
||||||
|
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||||
|
{
|
||||||
|
Tamano += Delta_Width + Delta_Height;
|
||||||
|
}
|
||||||
|
|
||||||
public override void ucLoaded()
|
public override void ucLoaded()
|
||||||
{
|
{
|
||||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
// crear el objeto de simulacion
|
// crear el objeto de simulacion
|
||||||
ActualizarLeftTop();
|
base.ucLoaded();
|
||||||
|
|
||||||
if (_visualRepresentation is ucConsensGeneric uc)
|
//if (_visualRepresentation is ucConsensGeneric uc)
|
||||||
Tags = UserControlFactory.CargarPropiedadesosDatosTags(Consensos, uc.PanelEdicion, null);
|
// Tags = UserControlFactory.CargarPropiedadesosDatosTags(Consensos, uc.PanelEdicion, null);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +53,7 @@ namespace CtrEditor.ObjetosSim
|
||||||
public partial class ucConsensGeneric : UserControl, IDataContainer
|
public partial class ucConsensGeneric : UserControl, IDataContainer
|
||||||
{
|
{
|
||||||
public osBase? Datos { get; set; }
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
public ucConsensGeneric()
|
public ucConsensGeneric()
|
||||||
{
|
{
|
||||||
|
@ -64,21 +69,12 @@ namespace CtrEditor.ObjetosSim
|
||||||
{
|
{
|
||||||
Datos?.ucUnLoaded();
|
Datos?.ucUnLoaded();
|
||||||
}
|
}
|
||||||
public void Resize(float width, float height) { }
|
|
||||||
public void Move(float LeftPixels, float TopPixels)
|
|
||||||
{
|
|
||||||
if (Datos != null)
|
|
||||||
{
|
|
||||||
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
|
||||||
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Rotate(float Angle) { }
|
|
||||||
public void Highlight(bool State) { }
|
public void Highlight(bool State) { }
|
||||||
public int ZIndex()
|
public ZIndexEnum ZIndex_Base()
|
||||||
{
|
{
|
||||||
return 10;
|
return ZIndexEnum.Estaticos;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TagsConsensos
|
public class TagsConsensos
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
<UserControl x:Class="CtrEditor.ObjetosSim.ucTrace3"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||||
|
xmlns:ei="http://schemas.microsoft.com/xaml/behaviors"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
Background="#FFECECEC"
|
||||||
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
|
||||||
|
<UserControl.DataContext>
|
||||||
|
<vm:osTrace3 Descripcion_Serie_1="Serie 1" Max_Cantidad_Elementos="100"/>
|
||||||
|
</UserControl.DataContext>
|
||||||
|
|
||||||
|
|
||||||
|
<Grid Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<!-- Title -->
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<!-- Chart Area -->
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<!-- Descriptions -->
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="0" Text="{Binding Titulo}" FontSize="10" HorizontalAlignment="Center"/>
|
||||||
|
|
||||||
|
<Canvas Grid.Row="1" x:Name="ChartCanvas" Background="White" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" />
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center" >
|
||||||
|
<TextBlock Text="{Binding Descripcion_Serie_1}" Margin="1" FontSize="8" Foreground="{Binding Color_Serie_1}"/>
|
||||||
|
<TextBlock Text="{Binding Descripcion_Serie_2}" Margin="1" FontSize="8" Foreground="{Binding Color_Serie_2}"/>
|
||||||
|
<TextBlock Text="{Binding Descripcion_Serie_3}" Margin="1" FontSize="8" Foreground="{Binding Color_Serie_3}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,305 @@
|
||||||
|
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
using LibS7Adv;
|
||||||
|
using System.Runtime.Intrinsics;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
|
||||||
|
namespace CtrEditor.ObjetosSim
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ucTrace3.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class osTrace3 : osBase, IosBase
|
||||||
|
{
|
||||||
|
private List<float> _series1 = new List<float>();
|
||||||
|
private List<float> _series2 = new List<float>();
|
||||||
|
private List<float> _series3 = new List<float>();
|
||||||
|
|
||||||
|
// Otros datos y métodos relevantes para la simulación
|
||||||
|
|
||||||
|
public static string NombreClase()
|
||||||
|
{
|
||||||
|
return "Trace3";
|
||||||
|
}
|
||||||
|
private string nombre = NombreClase();
|
||||||
|
public override string Nombre
|
||||||
|
{
|
||||||
|
get => nombre;
|
||||||
|
set => SetProperty(ref nombre, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private Brush color_Serie_1;
|
||||||
|
[ObservableProperty]
|
||||||
|
private Brush color_Serie_2;
|
||||||
|
[ObservableProperty]
|
||||||
|
private Brush color_Serie_3;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
float alto;
|
||||||
|
[ObservableProperty]
|
||||||
|
float ancho;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
bool serie1_Tipo_Bool;
|
||||||
|
[ObservableProperty]
|
||||||
|
string tag_Serie1;
|
||||||
|
[ObservableProperty]
|
||||||
|
bool serie2_Tipo_Bool;
|
||||||
|
[ObservableProperty]
|
||||||
|
string tag_Serie2;
|
||||||
|
[ObservableProperty]
|
||||||
|
bool serie3_Tipo_Bool;
|
||||||
|
[ObservableProperty]
|
||||||
|
string tag_Serie3;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
string titulo;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
string descripcion_Serie_1;
|
||||||
|
[ObservableProperty]
|
||||||
|
string descripcion_Serie_2;
|
||||||
|
[ObservableProperty]
|
||||||
|
string descripcion_Serie_3;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
float min_Serie_1;
|
||||||
|
[ObservableProperty]
|
||||||
|
float max_Serie_1;
|
||||||
|
[ObservableProperty]
|
||||||
|
float min_Serie_2;
|
||||||
|
[ObservableProperty]
|
||||||
|
float max_Serie_2;
|
||||||
|
[ObservableProperty]
|
||||||
|
float min_Serie_3;
|
||||||
|
[ObservableProperty]
|
||||||
|
float max_Serie_3;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
float y_offset_1;
|
||||||
|
[ObservableProperty]
|
||||||
|
float y_offset_2;
|
||||||
|
[ObservableProperty]
|
||||||
|
float y_offset_3;
|
||||||
|
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
float max_Cantidad_Elementos;
|
||||||
|
|
||||||
|
public osTrace3()
|
||||||
|
{
|
||||||
|
Alto = 3;
|
||||||
|
Ancho = 5;
|
||||||
|
Titulo = "Datos";
|
||||||
|
Max_Cantidad_Elementos = 10;
|
||||||
|
Color_Serie_1 = Brushes.Black;
|
||||||
|
Color_Serie_2 = Brushes.Red;
|
||||||
|
Color_Serie_3 = Brushes.Blue;
|
||||||
|
Max_Serie_1 = 2;
|
||||||
|
Max_Serie_2 = 2;
|
||||||
|
Max_Serie_3 = 2;
|
||||||
|
Serie1_Tipo_Bool = true;
|
||||||
|
Serie2_Tipo_Bool = true;
|
||||||
|
Serie3_Tipo_Bool = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdatePLCPrimerCiclo()
|
||||||
|
{
|
||||||
|
// Escribimos el valor actual al iniciar la conexion
|
||||||
|
}
|
||||||
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||||
|
{
|
||||||
|
float v1, v2, v3;
|
||||||
|
|
||||||
|
base.UpdatePLC(plc, elapsedMilliseconds);
|
||||||
|
|
||||||
|
if (Serie1_Tipo_Bool)
|
||||||
|
v1 = LeerBitTag(Tag_Serie1) ? 0 : 1;
|
||||||
|
else
|
||||||
|
v1 = LeerWordTag(Tag_Serie1);
|
||||||
|
|
||||||
|
if (Serie2_Tipo_Bool)
|
||||||
|
v2 = LeerBitTag(Tag_Serie2) ? 0 : 1;
|
||||||
|
else
|
||||||
|
v2 = LeerWordTag(Tag_Serie2);
|
||||||
|
|
||||||
|
if (Serie3_Tipo_Bool)
|
||||||
|
v3 = LeerBitTag(Tag_Serie3) ? 0 : 1;
|
||||||
|
else
|
||||||
|
v3 = LeerWordTag(Tag_Serie3);
|
||||||
|
|
||||||
|
AddData(v1, v2, v3);
|
||||||
|
}
|
||||||
|
public override void ucLoaded()
|
||||||
|
{
|
||||||
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
|
// crear el objeto de simulacion
|
||||||
|
base.ucLoaded();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddData(float series1Value, float series2Value, float series3Value)
|
||||||
|
{
|
||||||
|
if (_series1.Count >= Max_Cantidad_Elementos)
|
||||||
|
{
|
||||||
|
_series1.RemoveAt(0);
|
||||||
|
_series2.RemoveAt(0);
|
||||||
|
_series3.RemoveAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
_series1.Add(series1Value);
|
||||||
|
_series2.Add(series2Value);
|
||||||
|
_series3.Add(series3Value);
|
||||||
|
|
||||||
|
DrawChart();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawChart()
|
||||||
|
{
|
||||||
|
if (VisualRepresentation != null)
|
||||||
|
if (VisualRepresentation is ucTrace3 uc)
|
||||||
|
{
|
||||||
|
uc.ChartCanvas.Children.Clear();
|
||||||
|
|
||||||
|
DrawSeries(uc.ChartCanvas, _series1, Brushes.Red, Min_Serie_1, Max_Serie_1, Y_offset_1);
|
||||||
|
DrawSeries(uc.ChartCanvas, _series2, Brushes.Green, Min_Serie_2, Max_Serie_2, Y_offset_2);
|
||||||
|
DrawSeries(uc.ChartCanvas, _series3, Brushes.Blue, Min_Serie_3, Max_Serie_3, Y_offset_3);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void DrawSeries(Canvas ChartCanvas, List<float> series, Brush color, float minY, float maxY, float yoffset)
|
||||||
|
{
|
||||||
|
if (series.Count < 2) return;
|
||||||
|
|
||||||
|
foreach (var value in series)
|
||||||
|
{
|
||||||
|
if (value < minY) minY = value;
|
||||||
|
if (value > maxY) maxY = value;
|
||||||
|
}
|
||||||
|
if (minY == maxY) return;
|
||||||
|
|
||||||
|
float canvasHeight = (float)ChartCanvas.ActualHeight;
|
||||||
|
float canvasWidth = (float)ChartCanvas.ActualWidth;
|
||||||
|
float scaleX = canvasWidth / Max_Cantidad_Elementos;
|
||||||
|
float scaleY = canvasHeight / (maxY - minY + yoffset);
|
||||||
|
|
||||||
|
int startIndex = 0;
|
||||||
|
float lastX = 0;
|
||||||
|
float lastY = canvasHeight - (series[startIndex] - minY + yoffset) * scaleY;
|
||||||
|
|
||||||
|
while (startIndex < series.Count - 1)
|
||||||
|
{
|
||||||
|
// Buscar el próximo cambio en la serie
|
||||||
|
int endIndex = startIndex + 1;
|
||||||
|
while (endIndex < series.Count && series[endIndex] == series[startIndex])
|
||||||
|
{
|
||||||
|
endIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dibujar la línea horizontal desde startIndex hasta endIndex - 1
|
||||||
|
float x1 = lastX;
|
||||||
|
float y1 = lastY;
|
||||||
|
float x2 = (endIndex - 1) * scaleX;
|
||||||
|
float y2 = y1;
|
||||||
|
|
||||||
|
var horizontalLine = new Line
|
||||||
|
{
|
||||||
|
Stroke = color,
|
||||||
|
StrokeThickness = 0.4,
|
||||||
|
X1 = x1,
|
||||||
|
Y1 = y1,
|
||||||
|
X2 = x2,
|
||||||
|
Y2 = y2
|
||||||
|
};
|
||||||
|
|
||||||
|
ChartCanvas.Children.Add(horizontalLine);
|
||||||
|
|
||||||
|
// Dibujar la línea vertical en endIndex - 1 si no es el último punto
|
||||||
|
if (endIndex < series.Count)
|
||||||
|
{
|
||||||
|
float xVertical = x2;
|
||||||
|
float yVerticalStart = y2;
|
||||||
|
float yVerticalEnd = canvasHeight - (series[endIndex] - minY + yoffset) * scaleY;
|
||||||
|
|
||||||
|
var verticalLine = new Line
|
||||||
|
{
|
||||||
|
Stroke = color,
|
||||||
|
StrokeThickness = 0.4,
|
||||||
|
X1 = xVertical,
|
||||||
|
Y1 = yVerticalStart,
|
||||||
|
X2 = xVertical,
|
||||||
|
Y2 = yVerticalEnd
|
||||||
|
};
|
||||||
|
|
||||||
|
ChartCanvas.Children.Add(verticalLine);
|
||||||
|
|
||||||
|
// Actualizar la última posición dibujada
|
||||||
|
lastX = xVertical;
|
||||||
|
lastY = yVerticalEnd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Actualizar la última posición dibujada para la última línea horizontal
|
||||||
|
lastX = x2;
|
||||||
|
lastY = y2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actualizar startIndex
|
||||||
|
startIndex = endIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class ucTrace3 : UserControl, IDataContainer
|
||||||
|
{
|
||||||
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
|
public ucTrace3()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.Loaded += OnLoaded;
|
||||||
|
this.Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucLoaded();
|
||||||
|
}
|
||||||
|
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucUnLoaded();
|
||||||
|
}
|
||||||
|
public void Resize(float width, float height) {
|
||||||
|
if (Datos is osTrace3 datos)
|
||||||
|
{
|
||||||
|
datos.Ancho += PixelToMeter.Instance.calc.PixelsToMeters(width);
|
||||||
|
datos.Alto += PixelToMeter.Instance.calc.PixelsToMeters(height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void Move(float LeftPixels, float TopPixels)
|
||||||
|
{
|
||||||
|
if (Datos != null)
|
||||||
|
{
|
||||||
|
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
||||||
|
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public float Angle() { return 0; } public void Rotate(float Angle) { }
|
||||||
|
public void Highlight(bool State) { }
|
||||||
|
public ZIndexEnum ZIndex_Base()
|
||||||
|
{
|
||||||
|
return ZIndexEnum.Trace;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
<UserControl x:Class="CtrEditor.ObjetosSim.ucTraceSimple"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:lvc="clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF"
|
||||||
|
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<UserControl.DataContext>
|
||||||
|
<vm:osTraceSimple Alto="3" Ancho="6"/>
|
||||||
|
</UserControl.DataContext>
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<lvc:CartesianChart Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||||
|
Name="SignalChart" Series="{Binding Series}">
|
||||||
|
</lvc:CartesianChart>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,171 @@
|
||||||
|
|
||||||
|
using LibS7Adv;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using LiveChartsCore;
|
||||||
|
using LiveChartsCore.SkiaSharpView;
|
||||||
|
using LiveChartsCore.Defaults;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using CtrEditor.FuncionesBase;
|
||||||
|
|
||||||
|
namespace CtrEditor.ObjetosSim
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ucTraceSimple.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class osTraceSimple : osBase, IosBase
|
||||||
|
{
|
||||||
|
|
||||||
|
private List<float> data;
|
||||||
|
Stopwatch stopwatch;
|
||||||
|
private double YScale { get; set; }
|
||||||
|
|
||||||
|
// Otros datos y métodos relevantes para la simulación
|
||||||
|
|
||||||
|
public static string NombreClase()
|
||||||
|
{
|
||||||
|
return "Trace";
|
||||||
|
}
|
||||||
|
private string nombre = NombreClase();
|
||||||
|
public override string Nombre
|
||||||
|
{
|
||||||
|
get => nombre;
|
||||||
|
set => SetProperty(ref nombre, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
float alto;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
float ancho;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
string tag_serie;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
string x_Series_Name;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
string y_Series_Name;
|
||||||
|
|
||||||
|
private readonly ObservableCollection<ObservableValue> _observableValues;
|
||||||
|
|
||||||
|
|
||||||
|
public ObservableCollection<ISeries> Series { get; set; }
|
||||||
|
|
||||||
|
public osTraceSimple()
|
||||||
|
{
|
||||||
|
// Use ObservableCollections to let the chart listen for changes (or any INotifyCollectionChanged).
|
||||||
|
_observableValues = new ObservableCollection<ObservableValue>();
|
||||||
|
Series = new ObservableCollection<ISeries>
|
||||||
|
{
|
||||||
|
new LineSeries<ObservableValue>
|
||||||
|
{
|
||||||
|
Values = _observableValues,
|
||||||
|
Fill = null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
data = new List<float>();
|
||||||
|
stopwatch = new Stopwatch();
|
||||||
|
|
||||||
|
YScale = 2.0;
|
||||||
|
Alto = 1;
|
||||||
|
Ancho = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateGeometryStart()
|
||||||
|
{
|
||||||
|
// Se llama antes de la simulacion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdatePLCPrimerCiclo()
|
||||||
|
{
|
||||||
|
stopwatch.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||||
|
{
|
||||||
|
if (Tag_serie != null && Tag_serie.Length > 0) {
|
||||||
|
var value = LeerBitTag(Tag_serie) == false ? 0 : 1;
|
||||||
|
data.Add(value);
|
||||||
|
}
|
||||||
|
if (data.Count > 50)
|
||||||
|
data.RemoveAt(0);
|
||||||
|
if (stopwatch.Elapsed.TotalMilliseconds > 1000)
|
||||||
|
{
|
||||||
|
stopwatch.Reset();
|
||||||
|
stopwatch.Start();
|
||||||
|
foreach (var v in data)
|
||||||
|
{
|
||||||
|
_observableValues.Add(new(v));
|
||||||
|
if (_observableValues.Count > 50)
|
||||||
|
_observableValues.RemoveAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateControl(int elapsedMilliseconds)
|
||||||
|
{
|
||||||
|
// Calculamos la velocidad
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ucLoaded()
|
||||||
|
{
|
||||||
|
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||||
|
// crear el objeto de simulacion
|
||||||
|
base.ucLoaded();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class ucTraceSimple : UserControl, IDataContainer
|
||||||
|
{
|
||||||
|
public osBase? Datos { get; set; }
|
||||||
|
public int zIndex_fromFrames { get; set; }
|
||||||
|
|
||||||
|
public ucTraceSimple()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.Loaded += OnLoaded;
|
||||||
|
this.Unloaded += OnUnloaded;
|
||||||
|
}
|
||||||
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucLoaded();
|
||||||
|
}
|
||||||
|
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Datos?.ucUnLoaded();
|
||||||
|
}
|
||||||
|
public void Resize(float width, float height) {
|
||||||
|
if (Datos is osTraceSimple datos)
|
||||||
|
{
|
||||||
|
datos.Ancho += PixelToMeter.Instance.calc.PixelsToMeters(width);
|
||||||
|
datos.Alto += PixelToMeter.Instance.calc.PixelsToMeters(height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void Move(float LeftPixels, float TopPixels)
|
||||||
|
{
|
||||||
|
if (Datos != null)
|
||||||
|
{
|
||||||
|
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
|
||||||
|
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public float Angle() { return 0; } public void Rotate(float Angle) { }
|
||||||
|
public void Highlight(bool State) { }
|
||||||
|
public ZIndexEnum ZIndex_Base()
|
||||||
|
{
|
||||||
|
return ZIndexEnum.Trace;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|