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"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:CtrEditor"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application x:Class="CtrEditor.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:CtrEditor"
|
||||
xmlns:osExtraccion="clr-namespace:CtrEditor.ObjetosSim.Extraccion_Datos"
|
||||
xmlns:os="clr-namespace:CtrEditor.ObjetosSim" StartupUri="MainWindow.xaml">
|
||||
|
||||
<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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<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>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="ObjetosSim\ucBasicExample.xaml.cs" />
|
||||
<Compile Remove="ObjetosSim\ucTransporteCurva.xaml.cs" />
|
||||
<Compile Remove="Simulacion\FPhysics.cs" />
|
||||
<Compile Remove="Simulacion\GeometrySimulator.cs" />
|
||||
|
@ -17,45 +27,74 @@
|
|||
<ItemGroup>
|
||||
<None Remove="app2.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.png" />
|
||||
<None Remove="Icons\app2.128x128.ico" />
|
||||
<None Remove="Icons\app2.256x256.ico" />
|
||||
<None Remove="Icons\app2.png" />
|
||||
<None Remove="Icons\borrar.png" />
|
||||
<None Remove="Icons\choose.png" />
|
||||
<None Remove="Icons\connect.png" />
|
||||
<None Remove="Icons\CtrEditorA.png" />
|
||||
<None Remove="Icons\CtrEditorC.png" />
|
||||
<None Remove="Icons\CtrEditorE.png" />
|
||||
<None Remove="Icons\disconnect.png" />
|
||||
<None Remove="Icons\duplicate.png" />
|
||||
<None Remove="Icons\extract.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\start.png" />
|
||||
<None Remove="Icons\stop.png" />
|
||||
<None Remove="Icons\unselect.png" />
|
||||
<None Remove="imagenes\filler.png" />
|
||||
<None Remove="imagenes\gear.png" />
|
||||
<None Remove="imagenes\motorNegro.png" />
|
||||
<None Remove="imagenes\motorVerde.png" />
|
||||
<None Remove="Images\base.png" />
|
||||
<None Remove="motor2.png" />
|
||||
<None Remove="tank.png" />
|
||||
<None Remove="IA\appsettings.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Remove="ObjetosSim\ucBasicExample.xaml" />
|
||||
<Page Remove="ObjetosSim\ucTransporteCurva.xaml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="ObjetosSim\ucBasicExample.xaml" />
|
||||
<None Include="ObjetosSim\ucBasicExample.xaml.cs" />
|
||||
<None Include="Simulacion\FPhysics.cs" />
|
||||
<None Include="Simulacion\GeometrySimulator.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aether.Physics2D" Version="2.1.0" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
||||
<PackageReference Include="FarseerPhysics" Version="3.5.0" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.77" />
|
||||
<PackageReference Include="ClosedXML" Version="0.104.2" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<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="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>
|
||||
|
@ -68,23 +107,69 @@
|
|||
<ItemGroup>
|
||||
<Resource Include="app2.png" />
|
||||
<Resource Include="CtrEditorE.png" />
|
||||
<Resource Include="Icons\allselect.png" />
|
||||
<Resource Include="Icons\analyze.png" />
|
||||
<Resource Include="Icons\app.png" />
|
||||
<Resource Include="Icons\app2.png" />
|
||||
<Resource Include="Icons\borrar.png" />
|
||||
<Resource Include="Icons\choose.png" />
|
||||
<Resource Include="Icons\connect.png" />
|
||||
<Resource Include="Icons\CtrEditorA.png" />
|
||||
<Resource Include="Icons\CtrEditorC.png" />
|
||||
<Resource Include="Icons\CtrEditorE.png" />
|
||||
<Resource Include="Icons\disconnect.png" />
|
||||
<Resource Include="Icons\duplicate.png" />
|
||||
<Resource Include="Icons\extract.png">
|
||||
<CopyToOutputDirectory></CopyToOutputDirectory>
|
||||
</Resource>
|
||||
<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\start.png" />
|
||||
<Resource Include="Icons\stop.png" />
|
||||
<Resource Include="Icons\unselect.png" />
|
||||
<Resource Include="imagenes\filler.png" />
|
||||
<Resource Include="imagenes\gear.png" />
|
||||
<Resource Include="imagenes\motorNegro.png" />
|
||||
<Resource Include="imagenes\motorVerde.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>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.9.34723.18
|
||||
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
|
||||
Global
|
||||
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}.Release|Any CPU.ActiveCfg = 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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
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;
|
||||
}
|
||||
|
||||
public string? ObtenerPathAllPages(string extension)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(EstadoPersistente.Instance.directorio))
|
||||
return Path.Combine(EstadoPersistente.Instance.directorio, "AllPages" + extension);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void CargarImagenes()
|
||||
{
|
||||
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 |
730
MainViewModel.cs
270
MainWindow.xaml
|
@ -1,42 +1,53 @@
|
|||
<Window
|
||||
xmlns:ctreditor="clr-namespace:CtrEditor"
|
||||
<Window xmlns:ctreditor="clr-namespace:CtrEditor"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:Siemens="clr-namespace:CtrEditor.Siemens"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
||||
xmlns:ObjetosSim="clr-namespace:CtrEditor.ObjetosSim" x:Class="CtrEditor.MainWindow"
|
||||
Height="900" Width="1600" WindowState="Maximized"
|
||||
ResizeMode="CanResize" Title="{Binding directorioTrabajo}" Icon="/app2.png">
|
||||
xmlns:Siemens="clr-namespace:LibS7Adv;assembly=LibS7Adv"
|
||||
xmlns:local="clr-namespace:CtrEditor"
|
||||
xmlns:controls="clr-namespace:CtrEditor.Controls"
|
||||
xmlns:uc="clr-namespace:CtrEditor.ObjetosSim.UserControls"
|
||||
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>
|
||||
<ctreditor:MainViewModel/>
|
||||
<ctreditor:MainViewModel />
|
||||
</Window.DataContext>
|
||||
|
||||
<Window.Resources>
|
||||
<convert:FloatToFormattedStringConverter x:Key="floatFormatter"/>
|
||||
<convert:DoubleToFormattedStringConverter x:Key="doubleFormatter"/>
|
||||
<convert:BrushToColorNameConverter x:Key="BrushToColorNameConverter"/>
|
||||
|
||||
<!-- Style for Start/Stop Button -->
|
||||
<Style x:Key="StartStopButtonStyle" TargetType="Button">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsSimulationRunning}" Value="True">
|
||||
<Setter Property="Background" Value="LightGreen"/>
|
||||
<Setter Property="Background" Value="LightGreen" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!-- Style for Connect/Disconnect 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>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Background" Value="LightGreen"/>
|
||||
<Setter Property="Background" Value="#90EE90" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</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>
|
||||
|
||||
<Grid>
|
||||
|
@ -44,8 +55,17 @@
|
|||
<Menu VerticalAlignment="Top" HorizontalAlignment="Stretch">
|
||||
<MenuItem Header="Projecto">
|
||||
<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="Detenet Simulacion" Command="{Binding StopSimulationCommand}" />
|
||||
<MenuItem Header="Debug Window" Command="{Binding DebugWindowCommand}" />
|
||||
<MenuItem Header="Guardar" Command="{Binding SaveCommand}" />
|
||||
<MenuItem Header="Salir" Command="{Binding ExitCommand}" />
|
||||
</MenuItem>
|
||||
|
@ -54,27 +74,31 @@
|
|||
<Grid Margin="0,20,0,0">
|
||||
<!-- Margen superior para el menú -->
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" MinWidth="100"/>
|
||||
<ColumnDefinition Width="8*" MinWidth="200"/>
|
||||
<ColumnDefinition Width="2*" MinWidth="100"/>
|
||||
<ColumnDefinition Width="1*" MinWidth="200" />
|
||||
<ColumnDefinition Width="8*" MinWidth="200" />
|
||||
<ColumnDefinition Width="2*" MinWidth="100" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Primera Columna -->
|
||||
<Grid Grid.Column="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="2*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="2*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ListBox x:Name="ListaImagenes" Grid.Row="0" Margin="5" ItemsSource="{Binding ListaImagenes}" SelectedItem="{Binding SelectedImage}" />
|
||||
<ListBox x:Name="ListaFunciones" Grid.Row="1" Margin="5" ItemsSource="{Binding ListaOsBase}" DisplayMemberPath="Nombre" SelectedItem="{Binding SelectedItem}">
|
||||
<ListBox x:Name="ListaImagenes" Grid.Row="0" Margin="5" ItemsSource="{Binding ListaImagenes}"
|
||||
SelectedItem="{Binding SelectedImage}" />
|
||||
<ListBox x:Name="ListaFunciones" Grid.Row="1" Margin="5" ItemsSource="{Binding ListaOsBase}"
|
||||
DisplayMemberPath="Nombre" SelectedItem="{Binding SelectedItem}">
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="MouseDoubleClick">
|
||||
<i:InvokeCommandAction Command="{Binding ItemDoubleClickCommand}" CommandParameter="{Binding SelectedItem}"/>
|
||||
<i:InvokeCommandAction Command="{Binding ItemDoubleClickCommand}"
|
||||
CommandParameter="{Binding SelectedItem}" />
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
</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>
|
||||
<!-- GridSplitter -->
|
||||
<GridSplitter Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right" Width="5" Background="LightGray" />
|
||||
|
@ -88,45 +112,100 @@
|
|||
|
||||
<ToolBarTray Grid.Row="0">
|
||||
<ToolBar>
|
||||
<Button Command="{Binding TBStartSimulationCommand}" ToolTip="Iniciar Simulación" Style="{StaticResource StartStopButtonStyle}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Command="{Binding TBStartSimulationCommand}" ToolTip="Iniciar Simulación"
|
||||
Style="{StaticResource StartStopButtonStyle}">
|
||||
<StackPanel>
|
||||
<Image Source="Icons/start.png" Width="16" Height="16"/>
|
||||
<TextBlock Text="Iniciar"/>
|
||||
<Image Source="Icons/start.png" Width="24" Height="24" />
|
||||
<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">
|
||||
<StackPanel>
|
||||
<Image Source="Icons/stop.png" Width="16" Height="16"/>
|
||||
<TextBlock Text="Detener"/>
|
||||
<Image Source="Icons/stop.png" Width="24" Height="24" />
|
||||
<TextBlock Text="Detener" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{Binding TBSaveCommand}" ToolTip="Guardar">
|
||||
<StackPanel>
|
||||
<Image Source="Icons/save.png" Width="16" Height="16"/>
|
||||
<TextBlock Text="Guardar"/>
|
||||
<Image Source="Icons/save.png" Width="24" Height="24" />
|
||||
<TextBlock Text="Guardar" />
|
||||
</StackPanel>
|
||||
</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="Icons/connect.png" Width="16" Height="16"/>
|
||||
<TextBlock Text="Conectar"/>
|
||||
<Image Source="{Binding IsConnected, Converter={StaticResource ConnectStateToImageConverter}}"
|
||||
Width="24" Height="24" />
|
||||
<TextBlock Text="{Binding IsConnected, Converter={StaticResource ConnectStateToBtnTextConverter}}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{Binding TBDisconnectPLCCommand}" ToolTip="Desconectar PLC">
|
||||
|
||||
<!-- 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>
|
||||
<Image Source="Icons/disconnect.png" Width="16" Height="16"/>
|
||||
<TextBlock Text="Desconectar"/>
|
||||
<Image Source="Icons/match.png" Width="24" Height="24" />
|
||||
<TextBlock Text="Multi Page Analyze" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button Command="{Binding TBMultiPageMatrixCommand}" ToolTip="Analyze Matrix (Multiple Pages)">
|
||||
<StackPanel>
|
||||
<Image Source="Icons/ocr.png" Width="24" Height="24" />
|
||||
<TextBlock Text="Exportar Tags a Excel" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
</ToolBar>
|
||||
</ToolBarTray>
|
||||
|
||||
<ScrollViewer Grid.Row="1" x:Name="ImagenEnTrabajoScrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" PanningMode="Both">
|
||||
<Canvas x:Name="ImagenEnTrabajoCanvas" Margin="400">
|
||||
<!-- El Margin puede ser ajustado según el espacio adicional que quieras proporcionar -->
|
||||
<Canvas.LayoutTransform>
|
||||
<ScaleTransform ScaleX="1" ScaleY="1"/>
|
||||
</Canvas.LayoutTransform>
|
||||
<ScrollViewer Grid.Row="1" x:Name="ImagenEnTrabajoScrollViewer"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
PanningMode="Both"
|
||||
PreviewKeyDown="ScrollViewer_PreviewKeyDown">
|
||||
<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>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
@ -137,51 +216,114 @@
|
|||
<!-- Tercera Columna -->
|
||||
<Grid Grid.Column="2">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<!-- Altura ajustable para el ListBox -->
|
||||
<RowDefinition Height="Auto" />
|
||||
<!-- Espacio para el GridSplitter -->
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<!-- Altura ajustable para el PanelEdicion -->
|
||||
<RowDefinition Height="Auto" />
|
||||
</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 -->
|
||||
<Expander Grid.Row="2" Header="Objects List" IsExpanded="False">
|
||||
<ListBox x:Name="ListaOs"
|
||||
Grid.Row="0"
|
||||
Margin="5"
|
||||
MinHeight="100"
|
||||
MaxHeight="300"
|
||||
ItemsSource="{Binding ObjetosSimulables}"
|
||||
DisplayMemberPath="Nombre"
|
||||
SelectedItem="{Binding SelectedItemOsList, Mode=TwoWay}"
|
||||
SelectionChanged="ListaOs_SelectionChanged"/>
|
||||
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 Grid.Row="1"
|
||||
Height="5"
|
||||
<GridSplitter Grid.Row="4" Height="5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="Gray"
|
||||
ResizeDirection="Rows"
|
||||
VerticalAlignment="Center"/>
|
||||
VerticalAlignment="Center" />
|
||||
|
||||
<!-- PanelEdicion -->
|
||||
<ScrollViewer Grid.Row="2" Margin="5" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel x:Name="PanelEdicion">
|
||||
<!-- Aquí puedes agregar los controles para editar propiedades -->
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
<controls:PanelEdicionControl Grid.Row="5"
|
||||
x:Name="PanelEdicion"
|
||||
Margin="5"/>
|
||||
|
||||
<ToolBarTray Grid.Row="3">
|
||||
<ToolBarTray Grid.Row="6">
|
||||
<ToolBar>
|
||||
<Button Command="{Binding TBEliminarUserControlCommand}" ToolTip="Eliminar Control">
|
||||
<StackPanel>
|
||||
<Image Source="Icons/borrar.png" Width="16" Height="16"/>
|
||||
<TextBlock Text="Eliminar"/>
|
||||
<Image Source="Icons/borrar.png" Width="16" Height="16" />
|
||||
<TextBlock Text="Eliminar" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{Binding TBDuplicarUserControlCommand}" ToolTip="Duplicar Control">
|
||||
<StackPanel>
|
||||
<Image Source="Icons/duplicate.png" Width="16" Height="16"/>
|
||||
<TextBlock Text="Duplicar"/>
|
||||
<Image Source="Icons/duplicate.png" Width="16" Height="16" />
|
||||
<TextBlock Text="Duplicar" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</ToolBar>
|
||||
|
|
|
@ -1,35 +1,22 @@
|
|||
using System.Globalization;
|
||||
using System.Text;
|
||||
using CtrEditor.ObjetosSim;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
using Binding = System.Windows.Data.Binding;
|
||||
using Label = System.Windows.Controls.Label;
|
||||
using System.Windows.Threading;
|
||||
using MouseEventArgs = System.Windows.Input.MouseEventArgs;
|
||||
using TextBox = System.Windows.Controls.TextBox;
|
||||
using UserControl = System.Windows.Controls.UserControl;
|
||||
using CheckBox = System.Windows.Controls.CheckBox;
|
||||
using Orientation = System.Windows.Controls.Orientation;
|
||||
using ListBox = System.Windows.Controls.ListBox;
|
||||
using CtrEditor.ObjetosSim;
|
||||
|
||||
using CtrEditor.Controls; // Add this using statement
|
||||
|
||||
namespace CtrEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
///
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
// Para el Canvas
|
||||
|
@ -37,73 +24,79 @@ namespace CtrEditor
|
|||
private bool _isDrawingCanvas = false;
|
||||
private bool _isDraggingCanvas = false;
|
||||
private Image imagenDeFondo;
|
||||
internal ObjectManipulationManager _objectManager;
|
||||
private Rectangle _panningArea;
|
||||
|
||||
// Para los UserControl
|
||||
private Point _startPointUserControl;
|
||||
private UserControl _currentDraggingControl;
|
||||
private bool _isRotatingUserControl = false;
|
||||
private bool _isResizingUserControl = false;
|
||||
private bool _isDraggingUserControl = false;
|
||||
private bool _isMovingUserControl = false;
|
||||
private double _initialAngleUserControl;
|
||||
private TextBlock _angleDisplayTextBlock;
|
||||
// Temporizadores y animación
|
||||
private DispatcherTimer _zoomTimer;
|
||||
private double _targetZoomFactor;
|
||||
private double _initialZoomFactor;
|
||||
private double _currentZoomStep;
|
||||
private Point _zoomCursorPosition;
|
||||
private const int ZoomDuration = 500; // Duración del zoom en milisegundos
|
||||
private int _ZoomDuration;
|
||||
private const double MinZoomScale = 0.1; // Límite mínimo de zoom
|
||||
private Stopwatch _stopwatch;
|
||||
|
||||
private dataDebug dataDebug = new dataDebug();
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_objectManager = new ObjectManipulationManager(this, ImagenEnTrabajoCanvas);
|
||||
|
||||
_panningArea = new Rectangle
|
||||
{
|
||||
Fill = Brushes.Transparent,
|
||||
IsHitTestVisible = true
|
||||
};
|
||||
|
||||
// Inicializar temporizador de zoom
|
||||
_zoomTimer = new DispatcherTimer();
|
||||
_zoomTimer.Interval = TimeSpan.FromMilliseconds(1);
|
||||
_zoomTimer.Tick += ZoomTimer_Tick;
|
||||
_stopwatch = new Stopwatch();
|
||||
|
||||
// Suscribir eventos
|
||||
this.Loaded += MainWindow_Loaded;
|
||||
ImagenEnTrabajoScrollViewer.PreviewMouseWheel += ImagenEnTrabajoCanvas_MouseWheel;
|
||||
|
||||
ImagenEnTrabajoCanvas.MouseDown += Canvas_MouseDown_Panning;
|
||||
ImagenEnTrabajoCanvas.MouseMove += Canvas_MouseMove_Panning;
|
||||
ImagenEnTrabajoCanvas.MouseUp += Canvas_MouseUp_Panning;
|
||||
|
||||
_panningArea.MouseDown += Canvas_MouseDown_Panning;
|
||||
_panningArea.MouseRightButtonDown += Canvas_MouseRightButtonDown;
|
||||
this.KeyDown += MainWindow_KeyDown;
|
||||
ImagenEnTrabajoCanvas.MouseEnter += Canvas_MouseEnter;
|
||||
this.Closed += MainWindow_Closed;
|
||||
|
||||
// Importante: Agregar el evento para el menú contextual
|
||||
ImagenEnTrabajoCanvas.MouseRightButtonDown += Canvas_MouseRightButtonDown;
|
||||
|
||||
// Asegurarse de que estos eventos estén conectados
|
||||
ImagenEnTrabajoCanvas.MouseUp += Canvas_MouseUp_Panning;
|
||||
}
|
||||
|
||||
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is MainViewModel viewModel)
|
||||
{
|
||||
viewModel.MainWindow = this;
|
||||
viewModel.ImageSelected += ViewModel_ImageSelected;
|
||||
viewModel?.LoadInitialData(); // Carga la primera imagen por defecto una vez cargada la ventana principal
|
||||
viewModel?.LoadInitialData();
|
||||
viewModel.simulationManager.DebugCanvas = ImagenEnTrabajoCanvas;
|
||||
viewModel.MainCanvas = ImagenEnTrabajoCanvas;
|
||||
|
||||
// Inicializar ObjectHierarchyView
|
||||
ObjectHierarchy.Initialize(viewModel);
|
||||
}
|
||||
}
|
||||
|
||||
public (float X, float Y) ObtenerCentroCanvasPixels()
|
||||
{
|
||||
var scaleTransform = ImagenEnTrabajoCanvas.LayoutTransform as ScaleTransform;
|
||||
float scaleX = (float)(scaleTransform?.ScaleX ?? 1.0);
|
||||
float scaleY = (float)(scaleTransform?.ScaleY ?? 1.0);
|
||||
|
||||
// Obtiene el área visible del ScrollViewer
|
||||
float visibleWidth = (float)ImagenEnTrabajoScrollViewer.ViewportWidth;
|
||||
float visibleHeight = (float)ImagenEnTrabajoScrollViewer.ViewportHeight;
|
||||
|
||||
// Obtiene la posición actual del desplazamiento ajustada por el zoom
|
||||
float offsetX = (float)ImagenEnTrabajoScrollViewer.HorizontalOffset / scaleX;
|
||||
float offsetY = (float)ImagenEnTrabajoScrollViewer.VerticalOffset / scaleY;
|
||||
|
||||
// Calcula el centro visible ajustado
|
||||
float centerX = offsetX + (visibleWidth / scaleX) / 2;
|
||||
float centerY = offsetY + (visibleHeight / scaleY) / 2;
|
||||
|
||||
return (centerX, centerY);
|
||||
}
|
||||
|
||||
public (float X, float Y) ObtenerCentroCanvasMeters()
|
||||
{
|
||||
var c = ObtenerCentroCanvasPixels();
|
||||
return (PixelToMeter.Instance.calc.PixelsToMeters(c.X), PixelToMeter.Instance.calc.PixelsToMeters(c.Y));
|
||||
}
|
||||
|
||||
public void SuscribirEventos(UserControl userControl)
|
||||
{
|
||||
userControl.MouseEnter += UserControl_MouseEnter;
|
||||
userControl.MouseLeave += UserControl_MouseLeave;
|
||||
|
||||
// Suscribir a eventos de mouse para panning
|
||||
userControl.MouseLeftButtonDown += UserControl_MouseLeftButtonDown;
|
||||
userControl.MouseLeftButtonUp += UserControl_MouseLeftButtonUp;
|
||||
userControl.MouseMove += UserControl_MouseMove;
|
||||
_objectManager.SuscribirEventos(userControl);
|
||||
}
|
||||
|
||||
public void AgregarRegistrarUserControlCanvas(UserControl userControl)
|
||||
|
@ -111,9 +104,7 @@ namespace CtrEditor
|
|||
if (userControl is IDataContainer dataContainer)
|
||||
{
|
||||
SuscribirEventos(userControl);
|
||||
|
||||
// Añade el UserControl al Canvas
|
||||
Canvas.SetZIndex(userControl, dataContainer.ZIndex());
|
||||
Canvas.SetZIndex(userControl, ((int)dataContainer.ZIndex_Base() + dataContainer.zIndex_fromFrames));
|
||||
ImagenEnTrabajoCanvas.Children.Add(userControl);
|
||||
}
|
||||
}
|
||||
|
@ -126,198 +117,6 @@ namespace CtrEditor
|
|||
}
|
||||
}
|
||||
|
||||
private void UserControl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (!_isDrawingCanvas)
|
||||
{
|
||||
var userControl = sender as UserControl;
|
||||
_currentDraggingControl = userControl;
|
||||
userControl.CaptureMouse(); // Importante para recibir eventos de movimiento incluso fuera del control
|
||||
_isMovingUserControl = true;
|
||||
|
||||
if (sender is UserControl control && control.DataContext is osBase datos)
|
||||
{
|
||||
var viewModel = DataContext as MainViewModel;
|
||||
if (viewModel != null)
|
||||
{
|
||||
viewModel.SelectedItemOsList = datos; // Esto desencadenará ListaOs_SelectionChanged
|
||||
}
|
||||
}
|
||||
|
||||
// ROTACION
|
||||
if (Keyboard.IsKeyDown(Key.LeftShift))
|
||||
{
|
||||
// Inicializar la rotación
|
||||
_isRotatingUserControl = true;
|
||||
RotateTransform rotateTransform = userControl.RenderTransform as RotateTransform;
|
||||
if (rotateTransform == null)
|
||||
{
|
||||
rotateTransform = new RotateTransform();
|
||||
userControl.RenderTransform = rotateTransform;
|
||||
}
|
||||
_initialAngleUserControl = rotateTransform.Angle;
|
||||
|
||||
// Establecer el punto inicial de referencia para el cálculo de rotación
|
||||
_startPointUserControl = new Point(rotateTransform.CenterX, rotateTransform.CenterY);
|
||||
|
||||
// Ajusta el punto inicial al espacio del Canvas
|
||||
_startPointUserControl = userControl.TranslatePoint(_startPointUserControl, ImagenEnTrabajoCanvas);
|
||||
|
||||
// Crear y configurar el TextBlock si no existe
|
||||
if (_angleDisplayTextBlock == null)
|
||||
{
|
||||
_angleDisplayTextBlock = new TextBlock
|
||||
{
|
||||
Foreground = Brushes.Black,
|
||||
Background = Brushes.White,
|
||||
Opacity = 0.8,
|
||||
Padding = new Thickness(5)
|
||||
};
|
||||
ImagenEnTrabajoCanvas.Children.Add(_angleDisplayTextBlock);
|
||||
}
|
||||
|
||||
PositionAngleDisplay(userControl);
|
||||
_angleDisplayTextBlock.Visibility = Visibility.Visible;
|
||||
Canvas.SetZIndex(_angleDisplayTextBlock, 15);
|
||||
}
|
||||
// TAMANO
|
||||
else if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
||||
{
|
||||
// Inicializar el cambio de tamaño
|
||||
_isResizingUserControl = true;
|
||||
}
|
||||
// MOVIMIENTO
|
||||
else
|
||||
{
|
||||
// Inicializar el movimiento/panning
|
||||
_isDraggingUserControl = true;
|
||||
_startPointUserControl = e.GetPosition(ImagenEnTrabajoCanvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UserControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (_isMovingUserControl)
|
||||
{
|
||||
var userControl = sender as UserControl;
|
||||
|
||||
userControl.ReleaseMouseCapture();
|
||||
_currentDraggingControl = null;
|
||||
_isResizingUserControl = _isRotatingUserControl = _isDraggingUserControl = false ;
|
||||
_isMovingUserControl = false;
|
||||
// Ocultar el TextBlock de ángulo
|
||||
if (_angleDisplayTextBlock != null)
|
||||
{
|
||||
_angleDisplayTextBlock.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UserControl_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (_isMovingUserControl && _currentDraggingControl != null)
|
||||
{
|
||||
var currentPosition = e.GetPosition(ImagenEnTrabajoCanvas);
|
||||
|
||||
if (_isDraggingUserControl)
|
||||
{
|
||||
// Código para mover el control
|
||||
var dx = currentPosition.X - _startPointUserControl.X;
|
||||
var dy = currentPosition.Y - _startPointUserControl.Y;
|
||||
var newX = Canvas.GetLeft(_currentDraggingControl) + dx;
|
||||
var newY = Canvas.GetTop(_currentDraggingControl) + dy;
|
||||
|
||||
if (_currentDraggingControl is IDataContainer dataContainer)
|
||||
dataContainer.Move((float)newX,(float) newY);
|
||||
|
||||
_startPointUserControl = currentPosition; // Actualiza el punto inicial para el siguiente movimiento
|
||||
}
|
||||
else if (_isRotatingUserControl)
|
||||
{
|
||||
// Código para rotar el control
|
||||
RotateControl(_currentDraggingControl, currentPosition);
|
||||
}
|
||||
else if (_isResizingUserControl)
|
||||
{
|
||||
// Código para cambiar el tamaño del control
|
||||
ResizeControl(_currentDraggingControl, currentPosition);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void RotateControl(UserControl control, Point currentPosition)
|
||||
{
|
||||
double deltaX = currentPosition.X - _startPointUserControl.X;
|
||||
double deltaY = currentPosition.Y - _startPointUserControl.Y;
|
||||
double angle = Math.Atan2(deltaY, deltaX) * (180 / Math.PI);
|
||||
|
||||
//RotateTransform rotateTransform = control.RenderTransform as RotateTransform;
|
||||
//rotateTransform.Angle = angle; // - _initialAngleUserControl; // Asegúrate de ajustar esta parte según cómo calcules el ángulo inicial
|
||||
|
||||
if (control is IDataContainer dataContainer)
|
||||
dataContainer.Rotate((float)angle);
|
||||
|
||||
// Actualizar el ángulo mostrado
|
||||
_angleDisplayTextBlock.Text = $"Ángulo: {angle:F2}°";
|
||||
PositionAngleDisplay(control);
|
||||
}
|
||||
|
||||
private void PositionAngleDisplay(UserControl control)
|
||||
{
|
||||
// Posicionar el TextBlock sobre el control
|
||||
Canvas.SetLeft(_angleDisplayTextBlock, Canvas.GetLeft(control));
|
||||
Canvas.SetTop(_angleDisplayTextBlock, Canvas.GetTop(control));
|
||||
}
|
||||
|
||||
private void ResizeControl(UserControl control, Point currentPosition)
|
||||
{
|
||||
// Calcular la diferencia en la posición X desde el punto de inicio
|
||||
double widthChange = currentPosition.X - _startPointUserControl.X;
|
||||
|
||||
// Calcular la diferencia en la posición Y desde el punto de inicio
|
||||
double heightChange = currentPosition.Y - _startPointUserControl.Y;
|
||||
|
||||
// Actualizar el ancho del control
|
||||
double newWidth = Math.Max(control.ActualWidth + widthChange, control.MinWidth);
|
||||
|
||||
// Actualizar la altura del control
|
||||
double newHeight = Math.Max(control.ActualHeight + heightChange, control.MinHeight);
|
||||
|
||||
// Asegurar que el nuevo tamaño no sea menor que los mínimos
|
||||
control.Width = newWidth;
|
||||
control.Height = newHeight;
|
||||
|
||||
if (control is IDataContainer dataContainer)
|
||||
{
|
||||
dataContainer.Resize((float)newWidth, (float)newHeight);
|
||||
}
|
||||
|
||||
// Actualizar el punto de inicio para el próximo evento de movimiento
|
||||
_startPointUserControl = currentPosition;
|
||||
}
|
||||
|
||||
|
||||
private void UserControl_MouseEnter(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (sender is UserControl userControl)
|
||||
if (userControl is IDataContainer dataContainer)
|
||||
dataContainer.Highlight(true);
|
||||
}
|
||||
|
||||
private void UserControl_MouseLeave(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (sender is UserControl userControl)
|
||||
if (userControl is IDataContainer dataContainer)
|
||||
dataContainer.Highlight(false);
|
||||
}
|
||||
|
||||
private void ViewModel_ImageSelected(object sender, string imagePath)
|
||||
{
|
||||
LoadImageToCanvas(imagePath);
|
||||
}
|
||||
|
||||
private void LoadImageToCanvas(string imagePath)
|
||||
{
|
||||
BitmapImage bitmap = new BitmapImage(new Uri(imagePath, UriKind.Absolute));
|
||||
|
@ -330,24 +129,38 @@ namespace CtrEditor
|
|||
imagenDeFondo.Source = bitmap;
|
||||
RenderOptions.SetBitmapScalingMode(imagenDeFondo, BitmapScalingMode.HighQuality);
|
||||
|
||||
// Actualizar dimensiones del canvas
|
||||
ImagenEnTrabajoCanvas.Width = bitmap.Width;
|
||||
ImagenEnTrabajoCanvas.Height = bitmap.Height;
|
||||
|
||||
// Elimina solo los ROIs, no la imagen de fondo
|
||||
// Configurar el área de panning
|
||||
_panningArea.Width = bitmap.Width * 4;
|
||||
_panningArea.Height = bitmap.Height * 4;
|
||||
|
||||
// Posicionar el área de panning centrada respecto a la imagen
|
||||
Canvas.SetLeft(_panningArea, -bitmap.Width / 4);
|
||||
Canvas.SetTop(_panningArea, -bitmap.Height / 4);
|
||||
Canvas.SetZIndex(_panningArea, -1); // Asegurar que está detrás de todo
|
||||
|
||||
// Asegurarse de que el área de panning está en el canvas
|
||||
if (!ImagenEnTrabajoCanvas.Children.Contains(_panningArea))
|
||||
{
|
||||
ImagenEnTrabajoCanvas.Children.Add(_panningArea);
|
||||
}
|
||||
|
||||
// Posicionar la imagen
|
||||
Canvas.SetLeft(imagenDeFondo, 0);
|
||||
Canvas.SetTop(imagenDeFondo, 0);
|
||||
|
||||
// Eliminar solo los ROIs, no la imagen de fondo ni el área de panning
|
||||
for (int i = ImagenEnTrabajoCanvas.Children.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (ImagenEnTrabajoCanvas.Children[i] is not Image)
|
||||
var child = ImagenEnTrabajoCanvas.Children[i];
|
||||
if (child != imagenDeFondo && child != _panningArea)
|
||||
{
|
||||
ImagenEnTrabajoCanvas.Children.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Ajusta el tamaño del Canvas a la imagen, si es necesario
|
||||
ImagenEnTrabajoCanvas.Width = bitmap.Width;
|
||||
ImagenEnTrabajoCanvas.Height = bitmap.Height;
|
||||
|
||||
// Posiciona la imagen correctamente dentro del Canvas
|
||||
Canvas.SetLeft(imagenDeFondo, 0);
|
||||
Canvas.SetTop(imagenDeFondo, 0);
|
||||
|
||||
}
|
||||
|
||||
private void Canvas_MouseUp_Panning(object sender, MouseButtonEventArgs e)
|
||||
|
@ -355,78 +168,268 @@ namespace CtrEditor
|
|||
if (_isDraggingCanvas)
|
||||
{
|
||||
_isDraggingCanvas = false;
|
||||
ImagenEnTrabajoScrollViewer.ReleaseMouseCapture(); // Finaliza la captura del ratón
|
||||
ImagenEnTrabajoCanvas.ReleaseMouseCapture();
|
||||
Mouse.OverrideCursor = null;
|
||||
|
||||
if (_objectManager.SelectedObjects.Count > 0)
|
||||
{
|
||||
_objectManager.MakeResizeRectanglesNormal();
|
||||
_objectManager.UpdateSelectionVisuals(); // Agregar esta línea
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void Canvas_MouseDown_Panning(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed && !_isDrawingCanvas && !_isMovingUserControl)
|
||||
if (e.LeftButton == MouseButtonState.Pressed && !_isDrawingCanvas)
|
||||
{
|
||||
// Permitir el panning cuando se hace clic en el área de panning o en la imagen
|
||||
if (e.Source == _panningArea ||
|
||||
e.Source == imagenDeFondo ||
|
||||
e.Source == ImagenEnTrabajoCanvas ||
|
||||
(e.Source is Rectangle rect && rect == _objectManager._selectionRectangle))
|
||||
{
|
||||
ImagenEnTrabajoCanvas.Focus();
|
||||
|
||||
if (_objectManager.IsRectangleSelectionActive)
|
||||
{
|
||||
if (!_objectManager.HasActiveSelectionRectangle)
|
||||
{
|
||||
_objectManager.StartRectangleSelection(e.GetPosition(ImagenEnTrabajoCanvas));
|
||||
}
|
||||
else
|
||||
{
|
||||
_objectManager.FinishRectangleSelection(e.GetPosition(ImagenEnTrabajoCanvas));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Indica que se inicia el panning
|
||||
_isDraggingCanvas = true;
|
||||
// Guarda la posición actual del ratón
|
||||
_lastMousePosition = e.GetPosition(ImagenEnTrabajoScrollViewer);
|
||||
//ImagenEnTrabajoScrollViewer.CaptureMouse(); // Importante para capturar el movimiento
|
||||
ImagenEnTrabajoCanvas.CaptureMouse(); // Importante: siempre capturar en el Canvas principal
|
||||
Mouse.OverrideCursor = Cursors.Hand;
|
||||
|
||||
if (DataContext is MainViewModel viewModel)
|
||||
{
|
||||
viewModel.SelectedItemOsList = null;
|
||||
_objectManager.RemoveResizeRectangles();
|
||||
}
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Canvas_MouseMove_Panning(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (_isDraggingCanvas && !_isDrawingCanvas)
|
||||
if (_objectManager.IsRectangleSelectionActive && _objectManager.HasActiveSelectionRectangle)
|
||||
{
|
||||
var currentPoint = e.GetPosition(ImagenEnTrabajoCanvas);
|
||||
_objectManager.UpdateRectangleSelection(currentPoint);
|
||||
}
|
||||
else if (_isDraggingCanvas && e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
// Calcula el nuevo desplazamiento basado en el movimiento del ratón
|
||||
var currentPosition = e.GetPosition(ImagenEnTrabajoScrollViewer);
|
||||
var dx = currentPosition.X - _lastMousePosition.X;
|
||||
var dy = currentPosition.Y - _lastMousePosition.Y;
|
||||
|
||||
// Ajusta el desplazamiento del ScrollViewer
|
||||
ImagenEnTrabajoScrollViewer.ScrollToHorizontalOffset(ImagenEnTrabajoScrollViewer.HorizontalOffset - dx);
|
||||
ImagenEnTrabajoScrollViewer.ScrollToVerticalOffset(ImagenEnTrabajoScrollViewer.VerticalOffset - dy);
|
||||
_objectManager.MakeResizeRectanglesTransparent();
|
||||
_objectManager.RemoveHighlightRectangles();
|
||||
|
||||
var transform = (TranslateTransform)((TransformGroup)ImagenEnTrabajoCanvas.RenderTransform)
|
||||
.Children.First(t => t is TranslateTransform);
|
||||
transform.X += dx;
|
||||
transform.Y += dy;
|
||||
|
||||
// Actualiza la posición del ratón para el próximo movimiento
|
||||
_lastMousePosition = currentPosition;
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void ImagenEnTrabajoCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
|
||||
{
|
||||
var st = (ScaleTransform)ImagenEnTrabajoCanvas.LayoutTransform;
|
||||
double zoomFactor = e.Delta > 0 ? 1.1 : 0.9;
|
||||
Point cursorPosition = e.GetPosition(ImagenEnTrabajoScrollViewer);
|
||||
_objectManager.MakeResizeRectanglesTransparent();
|
||||
_objectManager.RemoveHighlightRectangles();
|
||||
|
||||
// Calcular el punto focal del zoom relativo al contenido del ScrollViewer
|
||||
var absoluteX = ImagenEnTrabajoScrollViewer.HorizontalOffset + cursorPosition.X;
|
||||
var absoluteY = ImagenEnTrabajoScrollViewer.VerticalOffset + cursorPosition.Y;
|
||||
_initialZoomFactor = ((ScaleTransform)((TransformGroup)ImagenEnTrabajoCanvas.RenderTransform)
|
||||
.Children.First(t => t is ScaleTransform)).ScaleX;
|
||||
|
||||
// Aplicar el zoom
|
||||
st.ScaleX *= zoomFactor;
|
||||
st.ScaleY *= zoomFactor;
|
||||
double minZoomFactor = Math.Min(
|
||||
ImagenEnTrabajoScrollViewer.ViewportWidth / ImagenEnTrabajoCanvas.ActualWidth,
|
||||
ImagenEnTrabajoScrollViewer.ViewportHeight / ImagenEnTrabajoCanvas.ActualHeight) / 1.5;
|
||||
|
||||
// Calcular el nuevo desplazamiento para que el zoom se centre en la posición del cursor
|
||||
ImagenEnTrabajoScrollViewer.UpdateLayout(); // Asegurarse de que el layout del ScrollViewer esté actualizado
|
||||
var newHorizontalOffset = absoluteX * zoomFactor - cursorPosition.X;
|
||||
var newVerticalOffset = absoluteY * zoomFactor - cursorPosition.Y;
|
||||
_targetZoomFactor = e.Delta > 0 ?
|
||||
_initialZoomFactor * 1.4 :
|
||||
Math.Max(_initialZoomFactor * 0.75, minZoomFactor);
|
||||
|
||||
// Aplicar el nuevo desplazamiento
|
||||
ImagenEnTrabajoScrollViewer.ScrollToHorizontalOffset(newHorizontalOffset);
|
||||
ImagenEnTrabajoScrollViewer.ScrollToVerticalOffset(newVerticalOffset);
|
||||
_zoomCursorPosition = e.GetPosition(ImagenEnTrabajoCanvas);
|
||||
|
||||
e.Handled = true; // Evita el procesamiento adicional del evento
|
||||
RenderOptions.SetBitmapScalingMode(ImagenEnTrabajoCanvas, BitmapScalingMode.LowQuality);
|
||||
|
||||
_ZoomDuration = !_zoomTimer.IsEnabled ? ZoomDuration : ZoomDuration / 3;
|
||||
|
||||
_stopwatch.Restart();
|
||||
_zoomTimer.Start();
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void ListaOs_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
private void ZoomTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
double elapsedMilliseconds = _stopwatch.Elapsed.TotalMilliseconds;
|
||||
|
||||
if (elapsedMilliseconds >= _ZoomDuration)
|
||||
{
|
||||
_zoomTimer.Stop();
|
||||
_stopwatch.Stop();
|
||||
|
||||
RenderOptions.SetBitmapScalingMode(ImagenEnTrabajoCanvas, BitmapScalingMode.HighQuality);
|
||||
|
||||
if (_objectManager.SelectedObjects.Count > 0)
|
||||
{
|
||||
_objectManager.MakeResizeRectanglesNormal();
|
||||
_objectManager.UpdateSelectionVisuals(); // Agregar esta línea
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var tg = (TransformGroup)ImagenEnTrabajoCanvas.RenderTransform;
|
||||
var st = (ScaleTransform)tg.Children.First(t => t is ScaleTransform);
|
||||
var tt = (TranslateTransform)tg.Children.First(t => t is TranslateTransform);
|
||||
|
||||
double t = elapsedMilliseconds / _ZoomDuration;
|
||||
double easeOutT = t * (2 - t);
|
||||
double zoomFactor = _initialZoomFactor + (_targetZoomFactor - _initialZoomFactor) * easeOutT;
|
||||
|
||||
zoomFactor = Math.Max(zoomFactor, MinZoomScale);
|
||||
|
||||
Point cursorPosition = _zoomCursorPosition;
|
||||
|
||||
var relativeX = cursorPosition.X * st.ScaleX + tt.X;
|
||||
var relativeY = cursorPosition.Y * st.ScaleY + tt.Y;
|
||||
|
||||
st.ScaleX = zoomFactor;
|
||||
st.ScaleY = zoomFactor;
|
||||
|
||||
tt.X = relativeX - cursorPosition.X * st.ScaleX;
|
||||
tt.Y = relativeY - cursorPosition.Y * st.ScaleY;
|
||||
}
|
||||
|
||||
private void ListaOs_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||
{
|
||||
PanelEdicion.Children.Clear(); // Limpiar el panel existente
|
||||
|
||||
if (e.AddedItems.Count > 0 && e.AddedItems[0] is osBase selectedObject)
|
||||
{
|
||||
// Siempre trabajar con selección única para las propiedades
|
||||
CargarPropiedadesosDatos(selectedObject);
|
||||
|
||||
_objectManager.SelectObject(selectedObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
_objectManager.RemoveResizeRectangles();
|
||||
}
|
||||
}
|
||||
|
||||
private void CargarPropiedadesosDatos(osBase selectedObject)
|
||||
private void ImagePathButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dlg = new Ookii.Dialogs.Wpf.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 Xceed.Wpf.Toolkit.PropertyGrid.PropertyItem propertyItem)
|
||||
{
|
||||
propertyItem.Value = dlg.FileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void MainWindow_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
// Only force canvas focus if PanelEdicion doesn't have focus
|
||||
if (!PanelEdicion.IsKeyboardFocusWithin)
|
||||
{
|
||||
if (!ImagenEnTrabajoCanvas.IsFocused)
|
||||
{
|
||||
ImagenEnTrabajoCanvas.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
if (DataContext is MainViewModel viewModel)
|
||||
viewModel.CargarPropiedadesosDatos(selectedObject, PanelEdicion, Resources);
|
||||
{
|
||||
if (e.Key == Key.Delete)
|
||||
{
|
||||
_objectManager.EliminarObjetosSeleccionados();
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (e.Key == Key.Escape)
|
||||
{
|
||||
viewModel.SelectedItemOsList = null;
|
||||
_objectManager.ClearSelection();
|
||||
_objectManager.RemoveResizeRectangles();
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (_objectManager.SelectedObjects.Any())
|
||||
{
|
||||
const float moveDistance = 0.1f;
|
||||
switch (e.Key)
|
||||
{
|
||||
case Key.Left:
|
||||
MoveSelectedObjects(-moveDistance, 0);
|
||||
e.Handled = true;
|
||||
break;
|
||||
case Key.Right:
|
||||
MoveSelectedObjects(moveDistance, 0);
|
||||
e.Handled = true;
|
||||
break;
|
||||
case Key.Up:
|
||||
MoveSelectedObjects(0, -moveDistance);
|
||||
e.Handled = true;
|
||||
break;
|
||||
case Key.Down:
|
||||
MoveSelectedObjects(0, moveDistance);
|
||||
e.Handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MoveSelectedObjects(float deltaX, float deltaY)
|
||||
{
|
||||
// Mover todos los objetos primero
|
||||
foreach (var obj in _objectManager.SelectedObjects)
|
||||
{
|
||||
obj.Left += deltaX;
|
||||
obj.Top += deltaY;
|
||||
}
|
||||
|
||||
// Forzar una actualización del layout antes de actualizar los visuales
|
||||
ImagenEnTrabajoCanvas.UpdateLayout();
|
||||
|
||||
// Ahora actualizar los visuales de selección
|
||||
_objectManager.UpdateSelectionVisuals();
|
||||
|
||||
if (DataContext is MainViewModel viewModel)
|
||||
{
|
||||
viewModel.HasUnsavedChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void Canvas_MouseEnter(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource == ImagenEnTrabajoCanvas)
|
||||
{
|
||||
//_objectManager.RemoveResizeRectangles();
|
||||
}
|
||||
}
|
||||
|
||||
private void MainWindow_Closed(object sender, EventArgs e)
|
||||
|
@ -437,22 +440,268 @@ namespace CtrEditor
|
|||
}
|
||||
}
|
||||
|
||||
private void CargarPropiedadesosDatos(osBase selectedObject)
|
||||
{
|
||||
if (DataContext is MainViewModel viewModel)
|
||||
viewModel.CargarPropiedadesosDatos(selectedObject, PanelEdicion, Resources);
|
||||
}
|
||||
|
||||
public (float X, float Y) ObtenerCentroCanvasMeters()
|
||||
{
|
||||
var c = ObtenerCentroCanvasPixels();
|
||||
return (PixelToMeter.Instance.calc.PixelsToMeters(c.X),
|
||||
PixelToMeter.Instance.calc.PixelsToMeters(c.Y));
|
||||
}
|
||||
|
||||
public (float X, float Y) ObtenerCentroCanvasPixels()
|
||||
{
|
||||
var tg = (TransformGroup)ImagenEnTrabajoCanvas.RenderTransform;
|
||||
var st = (ScaleTransform)tg.Children.First(t => t is ScaleTransform);
|
||||
var tt = (TranslateTransform)tg.Children.First(t => t is TranslateTransform);
|
||||
|
||||
double visibleWidth = ImagenEnTrabajoScrollViewer.ViewportWidth;
|
||||
double visibleHeight = ImagenEnTrabajoScrollViewer.ViewportHeight;
|
||||
|
||||
double offsetX = ImagenEnTrabajoScrollViewer.HorizontalOffset;
|
||||
double offsetY = ImagenEnTrabajoScrollViewer.VerticalOffset;
|
||||
|
||||
double centerX = offsetX + (visibleWidth / 2);
|
||||
double centerY = offsetY + (visibleHeight / 2);
|
||||
|
||||
double canvasCenterX = (centerX - tt.X) / st.ScaleX;
|
||||
double canvasCenterY = (centerY - tt.Y) / st.ScaleY;
|
||||
|
||||
return ((float)canvasCenterX, (float)canvasCenterY);
|
||||
}
|
||||
|
||||
private void ViewModel_ImageSelected(object sender, string imagePath)
|
||||
{
|
||||
LoadImageToCanvas(imagePath);
|
||||
}
|
||||
|
||||
public void DebugWindow()
|
||||
{
|
||||
var debugWindow = new wDebug
|
||||
{
|
||||
Data = dataDebug
|
||||
};
|
||||
debugWindow.Show();
|
||||
}
|
||||
|
||||
private void Canvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
// Aceptar el evento si viene del canvas o de la imagen de fondo
|
||||
if ((e.Source == ImagenEnTrabajoCanvas || e.Source == imagenDeFondo || e.Source is UserControl) &&
|
||||
DataContext is MainViewModel viewModel)
|
||||
{
|
||||
ImagenEnTrabajoCanvas.Focus(); // Asegurar que el canvas tiene el foco
|
||||
e.Handled = true;
|
||||
ShowContextMenu(e.GetPosition(ImagenEnTrabajoCanvas));
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowContextMenu(Point position)
|
||||
{
|
||||
var contextMenu = new ContextMenu();
|
||||
|
||||
if (DataContext is MainViewModel viewModel)
|
||||
{
|
||||
// Multi-selection checkbox
|
||||
var multiSelectMenuItem = new MenuItem
|
||||
{
|
||||
Header = "Modo Multi-Selección",
|
||||
IsCheckable = true,
|
||||
StaysOpenOnClick = false,
|
||||
IsChecked = viewModel.IsMultiSelectionActive
|
||||
};
|
||||
|
||||
multiSelectMenuItem.Click += (s, e) =>
|
||||
{
|
||||
viewModel.IsMultiSelectionActive = multiSelectMenuItem.IsChecked;
|
||||
|
||||
// Si se desactiva la multi-selección, desactivar también la selección por rectángulo
|
||||
if (!multiSelectMenuItem.IsChecked)
|
||||
_objectManager.IsRectangleSelectionActive = false;
|
||||
};
|
||||
|
||||
contextMenu.Items.Add(multiSelectMenuItem);
|
||||
|
||||
// Mostrar opción de selección por rectángulo solo cuando multi-selección está activa
|
||||
if (viewModel.IsMultiSelectionActive)
|
||||
{
|
||||
var rectangleSelectMenuItem = new MenuItem
|
||||
{
|
||||
Header = "Selección por Rectángulo",
|
||||
IsCheckable = true,
|
||||
IsChecked = _objectManager.IsRectangleSelectionActive,
|
||||
StaysOpenOnClick = false
|
||||
};
|
||||
|
||||
rectangleSelectMenuItem.Click += (s, e) =>
|
||||
{
|
||||
_objectManager.IsRectangleSelectionActive = rectangleSelectMenuItem.IsChecked;
|
||||
_objectManager.IsDraggingCanvas = false; // Desactivar panning cuando se activa la selección por rectángulo
|
||||
};
|
||||
|
||||
contextMenu.Items.Add(rectangleSelectMenuItem);
|
||||
}
|
||||
|
||||
// Si hay objetos seleccionados, agregar opciones de alineación
|
||||
if (_objectManager.SelectedObjects.Count > 1)
|
||||
{
|
||||
contextMenu.Items.Add(new Separator());
|
||||
|
||||
var alignSubmenu = new MenuItem { Header = "Alinear" };
|
||||
|
||||
// Alineación horizontal
|
||||
var alignLeftItem = new MenuItem { Header = "Izquierda" };
|
||||
alignLeftItem.Click += (s, e) => _objectManager.AlignObjects(AlignmentType.Left);
|
||||
alignSubmenu.Items.Add(alignLeftItem);
|
||||
|
||||
var alignRightItem = new MenuItem { Header = "Derecha" };
|
||||
alignRightItem.Click += (s, e) => _objectManager.AlignObjects(AlignmentType.Right);
|
||||
alignSubmenu.Items.Add(alignRightItem);
|
||||
|
||||
var alignCenterHItem = new MenuItem { Header = "Centro Horizontal" };
|
||||
alignCenterHItem.Click += (s, e) => _objectManager.AlignObjects(AlignmentType.CenterHorizontally);
|
||||
alignSubmenu.Items.Add(alignCenterHItem);
|
||||
|
||||
// Alineación vertical
|
||||
alignSubmenu.Items.Add(new Separator());
|
||||
|
||||
var alignTopItem = new MenuItem { Header = "Arriba" };
|
||||
alignTopItem.Click += (s, e) => _objectManager.AlignObjects(AlignmentType.Top);
|
||||
alignSubmenu.Items.Add(alignTopItem);
|
||||
|
||||
var alignBottomItem = new MenuItem { Header = "Abajo" };
|
||||
alignBottomItem.Click += (s, e) => _objectManager.AlignObjects(AlignmentType.Bottom);
|
||||
alignSubmenu.Items.Add(alignBottomItem);
|
||||
|
||||
var alignCenterVItem = new MenuItem { Header = "Centro Vertical" };
|
||||
alignCenterVItem.Click += (s, e) => _objectManager.AlignObjects(AlignmentType.CenterVertically);
|
||||
alignSubmenu.Items.Add(alignCenterVItem);
|
||||
|
||||
// Distribución
|
||||
alignSubmenu.Items.Add(new Separator());
|
||||
|
||||
var distributeHItem = new MenuItem { Header = "Distribuir Horizontalmente" };
|
||||
distributeHItem.Click += (s, e) => _objectManager.AlignObjects(AlignmentType.DistributeHorizontally);
|
||||
alignSubmenu.Items.Add(distributeHItem);
|
||||
|
||||
var distributeVItem = new MenuItem { Header = "Distribuir Verticalmente" };
|
||||
distributeVItem.Click += (s, e) => _objectManager.AlignObjects(AlignmentType.DistributeVertically);
|
||||
alignSubmenu.Items.Add(distributeVItem);
|
||||
|
||||
// Igualar tamaños
|
||||
alignSubmenu.Items.Add(new Separator());
|
||||
|
||||
var equalWidthItem = new MenuItem { Header = "Igualar Ancho" };
|
||||
equalWidthItem.Click += (s, e) => _objectManager.AlignObjects(AlignmentType.EqualWidth);
|
||||
alignSubmenu.Items.Add(equalWidthItem);
|
||||
|
||||
var equalHeightItem = new MenuItem { Header = "Igualar Alto" };
|
||||
equalHeightItem.Click += (s, e) => _objectManager.AlignObjects(AlignmentType.EqualHeight);
|
||||
alignSubmenu.Items.Add(equalHeightItem);
|
||||
|
||||
var equalAngleItem = new MenuItem { Header = "Igualar Ángulo" };
|
||||
equalAngleItem.Click += (s, e) => _objectManager.AlignObjects(AlignmentType.EqualAngle);
|
||||
alignSubmenu.Items.Add(equalAngleItem);
|
||||
|
||||
contextMenu.Items.Add(alignSubmenu);
|
||||
}
|
||||
|
||||
// Add Edit Properties option when objects are selected
|
||||
if (_objectManager.SelectedObjects.Count > 0)
|
||||
{
|
||||
var editPropertiesItem = new MenuItem { Header = "Edit Properties" };
|
||||
editPropertiesItem.Click += (s, e) => viewModel.ShowMultiPropertyEditor(_objectManager.SelectedObjects);
|
||||
contextMenu.Items.Add(editPropertiesItem);
|
||||
|
||||
contextMenu.Items.Add(new Separator());
|
||||
}
|
||||
|
||||
contextMenu.IsOpen = true;
|
||||
contextMenu.PlacementTarget = ImagenEnTrabajoCanvas;
|
||||
contextMenu.Placement = System.Windows.Controls.Primitives.PlacementMode.MousePoint;
|
||||
}
|
||||
}
|
||||
|
||||
private void Canvas_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
// Only handle if PanelEdicion doesn't have focus
|
||||
if (!PanelEdicion.IsKeyboardFocusWithin)
|
||||
{
|
||||
HandleKeyDown(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void ScrollViewer_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
// Only handle if PanelEdicion doesn't have focus
|
||||
if (!PanelEdicion.IsKeyboardFocusWithin &&
|
||||
(e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Up || e.Key == Key.Down))
|
||||
{
|
||||
HandleKeyDown(e);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleKeyDown(KeyEventArgs e)
|
||||
{
|
||||
if (DataContext is MainViewModel viewModel)
|
||||
{
|
||||
if (e.Key == Key.Delete)
|
||||
{
|
||||
_objectManager.EliminarObjetosSeleccionados(); // Cambiar aquí
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (e.Key == Key.Escape)
|
||||
{
|
||||
viewModel.SelectedItemOsList = null;
|
||||
_objectManager.ClearSelection();
|
||||
_objectManager.RemoveResizeRectangles();
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (_objectManager.SelectedObjects.Any())
|
||||
{
|
||||
const float moveDistance = 0.01f;
|
||||
switch (e.Key)
|
||||
{
|
||||
case Key.Left:
|
||||
MoveSelectedObjects(-moveDistance, 0);
|
||||
e.Handled = true;
|
||||
break;
|
||||
case Key.Right:
|
||||
MoveSelectedObjects(moveDistance, 0);
|
||||
e.Handled = true;
|
||||
break;
|
||||
case Key.Up:
|
||||
MoveSelectedObjects(0, -moveDistance);
|
||||
e.Handled = true;
|
||||
break;
|
||||
case Key.Down:
|
||||
MoveSelectedObjects(0, moveDistance);
|
||||
e.Handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Image ImagenDeFondo => imagenDeFondo;
|
||||
}
|
||||
|
||||
public class FloatValidationRule : ValidationRule
|
||||
{
|
||||
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
|
||||
{
|
||||
// Comprobamos si el valor es nulo o está vacío
|
||||
if (string.IsNullOrEmpty(value?.ToString()))
|
||||
return new ValidationResult(false, "El campo no puede estar vacío.");
|
||||
|
||||
// Intentamos convertir el valor a un tipo float
|
||||
if (float.TryParse(value.ToString(), NumberStyles.Float, cultureInfo, out float result))
|
||||
return ValidationResult.ValidResult; // La validación es exitosa
|
||||
return ValidationResult.ValidResult;
|
||||
else
|
||||
return new ValidationResult(false, "Ingrese un número válido.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
||||
<UserControl.Resources>
|
||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
||||
</UserControl.Resources>
|
||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||
>
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osBotella/>
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Ellipse Height="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Stroke="red" Fill="Gray"
|
||||
Width="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}"/>
|
||||
Stroke="{Binding ColorButton_oculto}" Fill="Gray"
|
||||
Width="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}" StrokeThickness="0.5"/>
|
||||
|
||||
</UserControl>
|
|
@ -1,11 +1,13 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
//using using Microsoft.Xna.Framework;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
|
||||
using LibS7Adv;
|
||||
using CtrEditor.Simulacion;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using nkast.Aether.Physics2D.Common;
|
||||
using System.Windows.Media;
|
||||
using CtrEditor.FuncionesBase;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
|
@ -31,6 +33,19 @@ namespace CtrEditor.ObjetosSim
|
|||
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]
|
||||
private float diametro;
|
||||
|
||||
|
@ -39,6 +54,17 @@ namespace CtrEditor.ObjetosSim
|
|||
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]
|
||||
private float mass;
|
||||
partial void OnMassChanged(float value)
|
||||
|
@ -62,9 +88,8 @@ namespace CtrEditor.ObjetosSim
|
|||
|
||||
private void ActualizarGeometrias()
|
||||
{
|
||||
if (SimGeometria != null)
|
||||
if (SimGeometria != null && !RemoverDesdeSimulacion)
|
||||
{
|
||||
SimGeometria.SetDiameter(Diametro);
|
||||
SimGeometria.SetPosition(GetCentro());
|
||||
}
|
||||
}
|
||||
|
@ -73,39 +98,61 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
Diametro = 0.10f;
|
||||
Mass = 1;
|
||||
ColorButton_oculto = Brushes.Gray;
|
||||
Preserve_Outside_Transport = true;
|
||||
}
|
||||
|
||||
public void UpdateAfterMove()
|
||||
{
|
||||
if (!RemoverDesdeSimulacion)
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
SimGeometria?.SetDiameter(Diametro);
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
ActualizarGeometrias();
|
||||
SimGeometria?.SetDiameter(Diametro);
|
||||
}
|
||||
public override void SimulationStop()
|
||||
{
|
||||
// Se llama al detener la simulacion. Util para detener Storyboards
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStep()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) { }
|
||||
|
||||
public override void UpdateControl(int elapsedMilliseconds)
|
||||
{
|
||||
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;
|
||||
|
||||
// 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()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
base.ucLoaded();
|
||||
SimGeometria = simulationManager.AddCircle(Diametro, GetCentro(), Mass);
|
||||
}
|
||||
public override void ucUnLoaded()
|
||||
|
@ -120,6 +167,7 @@ namespace CtrEditor.ObjetosSim
|
|||
public partial class ucBotella : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
public int zIndex_fromFrames { get; set; }
|
||||
|
||||
public ucBotella()
|
||||
{
|
||||
|
@ -136,20 +184,10 @@ namespace CtrEditor.ObjetosSim
|
|||
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 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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:CtrEditor.ObjetosSim"
|
||||
mc:Ignorable="d"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim">
|
||||
|
||||
<UserControl.Resources>
|
||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osFiller/>
|
||||
|
@ -20,7 +15,7 @@
|
|||
<Image Source="/imagenes/filler.png"
|
||||
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Stretch="Uniform">
|
||||
Stretch="Fill">
|
||||
<Image.RenderTransform>
|
||||
<RotateTransform Angle="{Binding Angulo}" />
|
||||
</Image.RenderTransform>
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
|
||||
using LibS7Adv;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using CtrEditor.FuncionesBase;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
|
@ -11,6 +13,7 @@ namespace CtrEditor.ObjetosSim
|
|||
/// </summary>
|
||||
public partial class osFiller : osBase, IosBase
|
||||
{
|
||||
TimerTON_TOFF _TON_TOFF = new TimerTON_TOFF();
|
||||
// Otros datos y métodos relevantes para la simulación
|
||||
|
||||
private float TiempoRestante;
|
||||
|
@ -31,8 +34,23 @@ namespace CtrEditor.ObjetosSim
|
|||
private float offsetLeftSalida;
|
||||
[ObservableProperty]
|
||||
private float offsetTopSalida;
|
||||
|
||||
[ObservableProperty]
|
||||
private string tag_consenso;
|
||||
[ObservableProperty]
|
||||
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]
|
||||
private float botellas_hora;
|
||||
|
||||
|
@ -53,14 +71,6 @@ namespace CtrEditor.ObjetosSim
|
|||
private float velocidad_actual_percentual;
|
||||
[ObservableProperty]
|
||||
private float diametro_botella;
|
||||
[ObservableProperty]
|
||||
private string tag_consenso;
|
||||
[ObservableProperty]
|
||||
private float ancho;
|
||||
[ObservableProperty]
|
||||
private float alto;
|
||||
[ObservableProperty]
|
||||
private float angulo;
|
||||
|
||||
public osFiller()
|
||||
{
|
||||
|
@ -70,16 +80,29 @@ namespace CtrEditor.ObjetosSim
|
|||
Velocidad_actual_percentual = 0;
|
||||
Diametro_botella = 0.1f;
|
||||
Botellas_hora = 10000;
|
||||
Filtro_consenso_s = 1;
|
||||
}
|
||||
|
||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
||||
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||
{
|
||||
if (Consenso_NC)
|
||||
Consenso = !LeerBitTag(Tag_consenso);
|
||||
else
|
||||
Consenso = LeerBitTag(Tag_consenso);
|
||||
}
|
||||
|
||||
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;
|
||||
if (TiempoRestante <= 0)
|
||||
|
@ -108,10 +131,10 @@ namespace CtrEditor.ObjetosSim
|
|||
|
||||
if (distancia > distanciaMinima)
|
||||
{
|
||||
var nuevaBotella = _mainViewModel.CrearObjetoSimulable(typeof(osBotella), X, Y);
|
||||
((osBotella)nuevaBotella).Diametro = Diametro_botella;
|
||||
osBotella nuevaBotella = (osBotella)_mainViewModel.CrearObjetoSimulable(typeof(osBotella), X, Y);
|
||||
nuevaBotella.Diametro = Diametro_botella;
|
||||
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
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
base.ucLoaded();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -134,6 +157,7 @@ namespace CtrEditor.ObjetosSim
|
|||
public partial class ucFiller : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
public int zIndex_fromFrames { get; set; }
|
||||
|
||||
public ucFiller()
|
||||
{
|
||||
|
@ -153,28 +177,14 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
if (Datos is osFiller datos)
|
||||
{
|
||||
datos.Ancho = PixelToMeter.Instance.calc.PixelsToMeters(width);
|
||||
datos.Alto = PixelToMeter.Instance.calc.PixelsToMeters(width);
|
||||
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 void Rotate(float Angle)
|
||||
{
|
||||
if (Datos != null)
|
||||
if (Datos is osFiller datos)
|
||||
datos.Angulo = Angle;
|
||||
}
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
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:convert="clr-namespace:CtrEditor.Convertidores">
|
||||
|
||||
<UserControl.Resources>
|
||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
||||
<convert:LevelToHeightMultiConverter x:Key="LevelToHeightMultiConverter"/>
|
||||
<convert:WidthPercentageConverter x:Key="WidthPercentageConverter"/>
|
||||
</UserControl.Resources>
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osTanque Alto="1" Ancho="1" Angulo="-4" />
|
||||
|
@ -21,8 +13,8 @@
|
|||
<Grid>
|
||||
<Image x:Name="TankImage"
|
||||
Source="/imagenes/tank.png"
|
||||
Width="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Stretch="Uniform">
|
||||
</Image>
|
||||
<Slider
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using LibS7Adv;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using CtrEditor.FuncionesBase;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
|
@ -46,12 +46,6 @@ namespace CtrEditor.ObjetosSim
|
|||
public float max_OUT_Scaled;
|
||||
[ObservableProperty]
|
||||
public float level;
|
||||
[ObservableProperty]
|
||||
public float ancho;
|
||||
[ObservableProperty]
|
||||
public float alto;
|
||||
[ObservableProperty]
|
||||
public float angulo;
|
||||
|
||||
public osTanque()
|
||||
{
|
||||
|
@ -61,7 +55,7 @@ namespace CtrEditor.ObjetosSim
|
|||
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);
|
||||
Ingreso_Abierto = LeerBitTag(TagIngresoAbierto_Bool);
|
||||
|
@ -87,7 +81,7 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
base.ucLoaded();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -95,6 +89,7 @@ namespace CtrEditor.ObjetosSim
|
|||
public partial class ucTanque : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
public int zIndex_fromFrames { get; set; }
|
||||
|
||||
public ucTanque()
|
||||
{
|
||||
|
@ -110,32 +105,10 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
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 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:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:CtrEditor.ObjetosSim"
|
||||
mc:Ignorable="d"
|
||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
||||
<Storyboard x:Key="PulsingStoryboard" RepeatBehavior="Forever">
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="AnimatedEllipse"
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
|
||||
using LibS7Adv;
|
||||
using CtrEditor.Simulacion;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using nkast.Aether.Physics2D.Common;
|
||||
using System.Windows.Media.Animation;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.FuncionesBase;
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -82,7 +83,7 @@ namespace CtrEditor.ObjetosSim
|
|||
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
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
base.ucLoaded();
|
||||
SimGeometria = simulationManager.AddDescarte(Diametro, GetCentro());
|
||||
}
|
||||
public override void ucUnLoaded()
|
||||
|
@ -109,6 +110,7 @@ namespace CtrEditor.ObjetosSim
|
|||
public partial class ucDescarte : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
public int zIndex_fromFrames { get; set; }
|
||||
|
||||
public ucDescarte()
|
||||
{
|
||||
|
@ -129,28 +131,10 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
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 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:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d"
|
||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
||||
|
||||
<UserControl.Resources>
|
||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
||||
</UserControl.Resources>
|
||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim">
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osGuia/>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
|
||||
using LibS7Adv;
|
||||
using CtrEditor.Simulacion;
|
||||
using CtrEditor.FuncionesBase;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
|
@ -25,21 +26,20 @@ namespace CtrEditor.ObjetosSim
|
|||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float ancho;
|
||||
|
||||
[ObservableProperty]
|
||||
public float altoGuia;
|
||||
|
||||
[ObservableProperty]
|
||||
public float angulo;
|
||||
|
||||
private void ActualizarGeometrias()
|
||||
{
|
||||
if (_visualRepresentation is ucGuia uc)
|
||||
UpdateOrCreateLine(SimGeometria, uc.Guia);
|
||||
}
|
||||
|
||||
public override void OnMoveResizeRotate()
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
public osGuia()
|
||||
{
|
||||
Ancho = 1;
|
||||
|
@ -57,12 +57,12 @@ namespace CtrEditor.ObjetosSim
|
|||
public override void UpdateGeometryStep()
|
||||
{
|
||||
}
|
||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) { }
|
||||
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds) { }
|
||||
public override void ucLoaded()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
base.ucLoaded();
|
||||
|
||||
if (_visualRepresentation is ucGuia uc)
|
||||
SimGeometria = AddLine(simulationManager, uc.Guia);
|
||||
|
@ -80,6 +80,7 @@ namespace CtrEditor.ObjetosSim
|
|||
public partial class ucGuia : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
public int zIndex_fromFrames { get; set; }
|
||||
|
||||
public ucGuia()
|
||||
{
|
||||
|
@ -95,29 +96,10 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
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 int ZIndex()
|
||||
public ZIndexEnum ZIndex_Base()
|
||||
{
|
||||
return 1;
|
||||
return ZIndexEnum.Guias;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,12 +4,8 @@
|
|||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:localuc="clr-namespace:CtrEditor.ObjetosSim.UserControls"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osTransporteCurva />
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
using System.Windows;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using LibS7Adv;
|
||||
using CtrEditor.Simulacion;
|
||||
|
||||
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||
using CtrEditor.FuncionesBase;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
|
@ -13,16 +15,12 @@ namespace CtrEditor.ObjetosSim
|
|||
/// </summary>
|
||||
public partial class osTransporteCurva : osBase, IosBase
|
||||
{
|
||||
private float frictionCoefficient;
|
||||
private float velMax50hz; // en metros por minuto
|
||||
private float tiempoRampa;
|
||||
private bool esMarcha;
|
||||
|
||||
private float _velocidadActual;
|
||||
private osBase _osMotor = null;
|
||||
private osBase Motor = null;
|
||||
|
||||
private simCurve Simulation_TransporteCurva;
|
||||
|
||||
private float _velocidadActual;
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Transporte Curva 90";
|
||||
|
@ -35,15 +33,92 @@ namespace CtrEditor.ObjetosSim
|
|||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private float radioExterno;
|
||||
[ObservableProperty]
|
||||
private float radioInterno;
|
||||
[ObservableProperty]
|
||||
private string motor;
|
||||
public float velocidadActual;
|
||||
|
||||
partial void OnVelocidadActualChanged(float value)
|
||||
{
|
||||
SetSpeed();
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(AnguloFinal))]
|
||||
public float angulo;
|
||||
bool invertirDireccion;
|
||||
|
||||
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]
|
||||
[NotifyPropertyChangedFor(nameof(AnguloFinal))]
|
||||
|
@ -55,59 +130,103 @@ namespace CtrEditor.ObjetosSim
|
|||
get => Angulo+Arco_en_grados;
|
||||
}
|
||||
|
||||
public float VelocidadActual
|
||||
{
|
||||
get => _velocidadActual;
|
||||
set
|
||||
{
|
||||
_velocidadActual = value;
|
||||
Simulation_TransporteCurva?.SetSpeed(value);
|
||||
OnPropertyChanged(nameof(VelocidadActual));
|
||||
}
|
||||
}
|
||||
|
||||
private void ActualizarGeometrias()
|
||||
{
|
||||
if (_visualRepresentation is ucTransporteCurva uc)
|
||||
{
|
||||
UpdateCurve(Simulation_TransporteCurva, RadioInterno, RadioExterno, Angulo, Angulo+Arco_en_grados);
|
||||
Simulation_TransporteCurva.Speed = VelocidadActual;
|
||||
SetSpeed();
|
||||
}
|
||||
}
|
||||
|
||||
public float FrictionCoefficient { get => frictionCoefficient; set => frictionCoefficient = value; }
|
||||
public float VelMax50hz { get => velMax50hz; set => velMax50hz = value; }
|
||||
public float TiempoRampa { get => tiempoRampa; set => tiempoRampa = value; }
|
||||
public bool EsMarcha { get => esMarcha; set => esMarcha = value; }
|
||||
public override void OnMoveResizeRotate()
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
[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()
|
||||
{
|
||||
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;
|
||||
Tag_ReleActivatedMotor = "1";
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
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)
|
||||
if (LeerBitTag(Tag_ReleActivatedMotor))
|
||||
VelocidadActual = motor.Velocidad;
|
||||
}
|
||||
else
|
||||
_osMotor = ObtenerLink(Motor, typeof(osVMmotorSim));
|
||||
VelocidadActual = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ucLoaded()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
base.ucLoaded();
|
||||
|
||||
OnId_MotorChanged(Id_Motor); // Link Id_Motor = Motor
|
||||
|
||||
if (_visualRepresentation is ucTransporteCurva uc)
|
||||
Simulation_TransporteCurva = AddCurve(RadioInterno,RadioExterno, Angulo, Angulo + Arco_en_grados);
|
||||
|
@ -126,6 +245,7 @@ namespace CtrEditor.ObjetosSim
|
|||
public partial class ucTransporteCurva : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
public int zIndex_fromFrames { get; set; }
|
||||
|
||||
public ucTransporteCurva()
|
||||
{
|
||||
|
@ -141,35 +261,10 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
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 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:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
||||
<convert:DistanceToMarginConverter x:Key="DistanceToMarginConverter"/>
|
||||
|
||||
<!-- 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>
|
||||
|
@ -20,8 +16,8 @@
|
|||
</VisualBrush.Transform>
|
||||
<VisualBrush.Visual>
|
||||
<Canvas>
|
||||
<Rectangle Fill="#FFBFBFBF" Width="10" Height="10"/>
|
||||
<Rectangle Fill="LightGray" Width="10" Height="10" Canvas.Left="10"/>
|
||||
<Rectangle Fill="LightGray" Width="10" Height="10" />
|
||||
<Rectangle Fill="GhostWhite" Width="10" Height="10" Canvas.Left="10" />
|
||||
</Canvas>
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
|
@ -32,18 +28,37 @@
|
|||
</UserControl.DataContext>
|
||||
|
||||
<Grid>
|
||||
<Canvas>
|
||||
<StackPanel x:Name="RectanglesContainer">
|
||||
<StackPanel.RenderTransform>
|
||||
<Canvas RenderTransformOrigin="0,0">
|
||||
<Canvas.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform/>
|
||||
<SkewTransform/>
|
||||
<RotateTransform Angle="{Binding Angulo}"/>
|
||||
</StackPanel.RenderTransform>
|
||||
<Rectangle x:Name="GuiaSuperior" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}" Fill="Blue"
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</Canvas.RenderTransform>
|
||||
<StackPanel x:Name="RectanglesContainer">
|
||||
<Rectangle x:Name="GuiaSuperior" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}"
|
||||
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}}"
|
||||
<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="Blue"/>
|
||||
<Rectangle x:Name="GuiaInferior" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Fill="{Binding Color, Converter={StaticResource ColorToBrushConverter}}"/>
|
||||
</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>
|
||||
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
using System.Windows;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using LibS7Adv;
|
||||
using CtrEditor.Simulacion;
|
||||
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||
using CtrEditor.FuncionesBase;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
|
@ -12,7 +16,7 @@ namespace CtrEditor.ObjetosSim
|
|||
/// </summary>
|
||||
public partial class osTransporteGuias : osBase, IosBase
|
||||
{
|
||||
private osBase _osMotor = null;
|
||||
private osBase Motor = null;
|
||||
|
||||
private simTransporte? SimGeometria;
|
||||
private simGuia? Guia_Superior;
|
||||
|
@ -24,6 +28,7 @@ namespace CtrEditor.ObjetosSim
|
|||
return "Transporte Guias";
|
||||
}
|
||||
private string nombre = NombreClase();
|
||||
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
|
@ -31,34 +36,89 @@ namespace CtrEditor.ObjetosSim
|
|||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private float velocidadActual;
|
||||
public float velocidadActual;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
[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 float ancho;
|
||||
[ObservableProperty]
|
||||
public float alto;
|
||||
|
||||
partial void OnAltoChanged(float value)
|
||||
public override void AltoChanged(float value)
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float angulo;
|
||||
public bool esFreno;
|
||||
|
||||
partial void OnEsFrenoChanged(bool value)
|
||||
{
|
||||
if (SimGeometria != null)
|
||||
SimGeometria.isBrake = value;
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float frictionCoefficient;
|
||||
[ObservableProperty]
|
||||
|
@ -78,14 +138,18 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
UpdateRectangle(SimGeometria, uc.Transporte, Alto, Ancho, Angulo);
|
||||
UpdateOrCreateLine(Guia_Superior, uc.GuiaSuperior);
|
||||
UpdateOrCreateLine(Guia_Inferior, uc.GuiaInferior) ;
|
||||
UpdateOrCreateLine(Guia_Inferior, uc.GuiaInferior);
|
||||
|
||||
SimGeometria.DistanceGuide2Guide = Alto;
|
||||
SimGeometria.Speed = VelocidadActual;
|
||||
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||
SimGeometria.isBrake = esFreno;
|
||||
SetSpeed();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMoveResizeRotate()
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
public osTransporteGuias()
|
||||
{
|
||||
|
@ -93,6 +157,7 @@ namespace CtrEditor.ObjetosSim
|
|||
Alto = 0.10f;
|
||||
AltoGuia = 0.03f;
|
||||
Distance = 0.01f;
|
||||
Tag_ReleActivatedMotor = "1";
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
|
@ -100,26 +165,28 @@ namespace CtrEditor.ObjetosSim
|
|||
// Se llama antes de la simulacion
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
public override void SimulationStop()
|
||||
{
|
||||
// Se llama al detener la simulacion
|
||||
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||
}
|
||||
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;
|
||||
} else if (Motor.Length > 0)
|
||||
_osMotor = ObtenerLink(Motor, typeof(osVMmotorSim));
|
||||
if (Motor != null)
|
||||
if (Motor is osVMmotorSim id_motor)
|
||||
if (LeerBitTag(Tag_ReleActivatedMotor))
|
||||
VelocidadActual = id_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
|
||||
ActualizarLeftTop();
|
||||
base.ucLoaded();
|
||||
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
|
@ -131,9 +198,9 @@ namespace CtrEditor.ObjetosSim
|
|||
Guia_Superior = AddLine(simulationManager, uc.GuiaSuperior);
|
||||
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()
|
||||
{
|
||||
|
@ -150,6 +217,7 @@ namespace CtrEditor.ObjetosSim
|
|||
public partial class ucTransporteGuias : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
public int zIndex_fromFrames { get; set; }
|
||||
|
||||
public ucTransporteGuias()
|
||||
{
|
||||
|
@ -165,30 +233,12 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
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 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:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
mc:Ignorable="d"
|
||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
||||
|
||||
<!-- 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>
|
||||
|
@ -20,8 +17,8 @@
|
|||
</VisualBrush.Transform>
|
||||
<VisualBrush.Visual>
|
||||
<Canvas>
|
||||
<Rectangle Fill="Gray" Width="10" Height="10"/>
|
||||
<Rectangle Fill="DarkGray" Width="10" Height="10" Canvas.Left="10"/>
|
||||
<Rectangle Fill="LightGray" Width="10" Height="10"/>
|
||||
<Rectangle Fill="GhostWhite" Width="10" Height="10" Canvas.Left="10"/>
|
||||
</Canvas>
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
|
@ -31,14 +28,25 @@
|
|||
<vm:osTransporteTTop Ancho="2"/>
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Canvas>
|
||||
<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.RenderTransform>
|
||||
<RotateTransform Angle="{Binding Angulo}"/>
|
||||
</Rectangle.RenderTransform>
|
||||
</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>
|
|
@ -1,13 +1,12 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media.Animation;
|
||||
using System.Windows.Media;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using LibS7Adv;
|
||||
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
|
||||
{
|
||||
|
@ -18,58 +17,103 @@ namespace CtrEditor.ObjetosSim
|
|||
|
||||
public partial class osTransporteTTop : osBase, IosBase
|
||||
{
|
||||
private osBase _osMotor = null;
|
||||
|
||||
private simTransporte SimGeometria;
|
||||
private osVMmotorSim Motor;
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Transporte";
|
||||
}
|
||||
private string nombre = "Transporte TTOP";
|
||||
|
||||
[property: Category("Id:")]
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
private float velocidadActual;
|
||||
public float VelocidadActual
|
||||
[ObservableProperty]
|
||||
[property: Category("Simulation:")]
|
||||
public float velocidadActual;
|
||||
|
||||
partial void OnVelocidadActualChanged(float value)
|
||||
{
|
||||
get => velocidadActual;
|
||||
set
|
||||
SetSpeed();
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
[property: Category("Simulation:")]
|
||||
bool invertirDireccion;
|
||||
|
||||
partial void OnInvertirDireccionChanged(bool value)
|
||||
{
|
||||
if (value != velocidadActual)
|
||||
SetSpeed();
|
||||
if (_visualRepresentation is ucTransporteTTop uc)
|
||||
{
|
||||
velocidadActual = value;
|
||||
SimGeometria?.SetSpeed(value);
|
||||
SetProperty(ref velocidadActual, value);
|
||||
CrearAnimacionStoryBoardTrasnporte(uc.Transporte, InvertirDireccion);
|
||||
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public string motor;
|
||||
|
||||
partial void OnMotorChanged(string value)
|
||||
void SetSpeed()
|
||||
{
|
||||
_osMotor = ObtenerLink(Motor, typeof(osVMmotorSim));
|
||||
if (InvertirDireccion)
|
||||
SimGeometria?.SetSpeed(-VelocidadActual);
|
||||
else
|
||||
SimGeometria?.SetSpeed(VelocidadActual);
|
||||
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float ancho;
|
||||
[property: Description("Bit to enable Link to Motor")]
|
||||
[property: Category("PLC link:")]
|
||||
string tag_ReleActivatedMotor;
|
||||
|
||||
[ObservableProperty]
|
||||
public float alto;
|
||||
[ObservableProperty]
|
||||
public float angulo;
|
||||
[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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[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;
|
||||
|
||||
|
||||
|
@ -77,16 +121,22 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
if (_visualRepresentation is ucTransporteTTop uc)
|
||||
{
|
||||
UpdateRectangle(SimGeometria, uc.Transporte,Alto,Ancho,Angulo);
|
||||
SimGeometria.Speed = VelocidadActual;
|
||||
UpdateRectangle(SimGeometria, uc.Transporte, Alto, Ancho, Angulo);
|
||||
SetSpeed();
|
||||
}
|
||||
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||
}
|
||||
|
||||
public override void OnMoveResizeRotate()
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
public osTransporteTTop()
|
||||
{
|
||||
Ancho = 1;
|
||||
Alto = 0.10f;
|
||||
Tag_ReleActivatedMotor = "1";
|
||||
}
|
||||
|
||||
public override void SimulationStop()
|
||||
|
@ -100,27 +150,27 @@ namespace CtrEditor.ObjetosSim
|
|||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
||||
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
|
||||
{
|
||||
if (_osMotor != null)
|
||||
{
|
||||
if (_osMotor is osVMmotorSim motor)
|
||||
if (Motor != null)
|
||||
if (Motor is osVMmotorSim motor)
|
||||
if (LeerBitTag(Tag_ReleActivatedMotor))
|
||||
VelocidadActual = motor.Velocidad;
|
||||
}
|
||||
else if (Motor.Length > 0)
|
||||
_osMotor = ObtenerLink(Motor, typeof(osVMmotorSim));
|
||||
else
|
||||
VelocidadActual = 0;
|
||||
}
|
||||
|
||||
public override void ucLoaded()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
base.ucLoaded();
|
||||
OnId_MotorChanged(Id_Motor); // Link Id_Motor = Motor
|
||||
|
||||
if (_visualRepresentation is ucTransporteTTop uc)
|
||||
{
|
||||
SimGeometria = AddRectangle(simulationManager, uc.Transporte, Alto, Ancho, Angulo);
|
||||
CrearAnimacionStoryBoardTrasnporte(uc.Transporte);
|
||||
CrearAnimacionStoryBoardTrasnporte(uc.Transporte, InvertirDireccion);
|
||||
}
|
||||
}
|
||||
public override void ucUnLoaded()
|
||||
|
@ -135,6 +185,7 @@ namespace CtrEditor.ObjetosSim
|
|||
public partial class ucTransporteTTop : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
public int zIndex_fromFrames { get; set; }
|
||||
|
||||
public ucTransporteTTop()
|
||||
{
|
||||
|
@ -150,31 +201,16 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
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 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:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:CtrEditor.ObjetosSim"
|
||||
mc:Ignorable="d"
|
||||
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>
|
||||
<vm:osVMmotorSim ImageSource_oculta="/imagenes/motorNegro.png" />
|
||||
<vm:osVMmotorSim ImageSource_oculta="/imagenes/motorNegro.png"/>
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid RenderTransformOrigin="0,0">
|
||||
<Grid.RenderTransform>
|
||||
<TransformGroup>
|
||||
<RotateTransform Angle="{Binding Angulo}"/>
|
||||
</TransformGroup>
|
||||
</Grid.RenderTransform>
|
||||
|
||||
<Label Grid.Row="0" Content="{Binding Nombre}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Background="Transparent"
|
||||
Foreground="Black"/>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Image Grid.Row="1" Source="{Binding ImageSource_oculta}"
|
||||
<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"
|
||||
VerticalAlignment="Center"
|
||||
Background="Transparent"
|
||||
Foreground="Black"
|
||||
Opacity="0.5"/>
|
||||
</Viewbox>
|
||||
</Grid>
|
||||
|
||||
|
||||
</UserControl>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.FuncionesBase;
|
||||
using LibS7Adv;
|
||||
using Newtonsoft.Json;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using Newtonsoft.Json;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
|
@ -37,8 +38,23 @@ namespace CtrEditor.ObjetosSim
|
|||
|
||||
[ObservableProperty]
|
||||
public float tamano;
|
||||
|
||||
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||
{
|
||||
Tamano += Delta_Width + Delta_Height;
|
||||
}
|
||||
|
||||
[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]
|
||||
public float tiempoRampa;
|
||||
|
@ -51,15 +67,32 @@ namespace CtrEditor.ObjetosSim
|
|||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public bool encendido;
|
||||
bool encendido;
|
||||
[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]
|
||||
public float ratio;
|
||||
|
||||
[ObservableProperty]
|
||||
public float velocidad;
|
||||
|
||||
[ObservableProperty]
|
||||
public bool sentido_contrario;
|
||||
|
||||
|
||||
partial void OnVelocidadChanged(float value)
|
||||
{
|
||||
if (value > 0)
|
||||
|
@ -72,9 +105,11 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
Tamano = 0.30f;
|
||||
PLC_NumeroMotor = 31;
|
||||
MaxRatedHz = 100;
|
||||
Proporcional_Speed = 100;
|
||||
Max_Speed_for_Ramp = 100;
|
||||
TiempoRampa = 3;
|
||||
ImageSource_oculta = ImageFromPath("/imagenes/motor2.png");
|
||||
Refresh_Time_ms = 500;
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
|
@ -82,17 +117,31 @@ namespace CtrEditor.ObjetosSim
|
|||
// Se llama antes de la simulacion
|
||||
|
||||
}
|
||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds) {
|
||||
|
||||
motState.UpdatePLC(plc,PLC_NumeroMotor,Encendido, elapsedMilliseconds);
|
||||
Velocidad = motState.STATUS_VFD_ACT_Speed_Hz / 10;
|
||||
[JsonIgnore]
|
||||
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
|
||||
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
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
base.ucLoaded();
|
||||
OnVelocidadChanged(Velocidad);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -108,6 +158,7 @@ namespace CtrEditor.ObjetosSim
|
|||
public partial class ucVMmotorSim : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
public int zIndex_fromFrames { get; set; }
|
||||
|
||||
public ucVMmotorSim()
|
||||
{
|
||||
|
@ -123,21 +174,12 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
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 int ZIndex()
|
||||
public ZIndexEnum ZIndex_Base()
|
||||
{
|
||||
return 10;
|
||||
return ZIndexEnum.Estaticos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class VMSimMotor
|
||||
|
@ -153,26 +195,33 @@ namespace CtrEditor.ObjetosSim
|
|||
public bool OUT_Reversal;
|
||||
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;
|
||||
switch (NumeroMotor)
|
||||
{
|
||||
case < 100:
|
||||
index = (int)NumeroMotor - 30 + 300;
|
||||
break;
|
||||
}
|
||||
var DB_Motor = Data.PLC_DB_Motor;
|
||||
|
||||
OUT_Run = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{index}].OUT.Run");
|
||||
OUT_Reversal = plc.LeerTagBool($"\"DB MotorSimulate\".Motors[{index}].OUT.\"Reversal Direction\"");
|
||||
OUT_OUT_VFD_REQ_Speed_Hz = (float)plc.LeerTagInt16($"\"DB MotorSimulate\".Motors[{index}].OUT.OUT_VFD_REQ_Speed_Hz");
|
||||
if (DB_Motor == 0)
|
||||
return;
|
||||
|
||||
// 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;
|
||||
Motor_Running = true;
|
||||
Motor_Running = OUT_Run && !OUT_Stop;
|
||||
STATUS_VFD_Trip = false;
|
||||
STATUS_VFD_Warning = false;
|
||||
STATUS_VFD_Coasting = false;
|
||||
|
@ -186,19 +235,27 @@ namespace CtrEditor.ObjetosSim
|
|||
STATUS_VFD_Coasting = false;
|
||||
}
|
||||
|
||||
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_Ready", _STATUS_VFD_Ready);
|
||||
plc.EscribirTagBool($"\"DB MotorSimulate\".Motors[{index}].Motor_Running", Motor_Running);
|
||||
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);
|
||||
if (Data.VFD_Trip_NC)
|
||||
STATUS_VFD_Trip = !STATUS_VFD_Trip;
|
||||
|
||||
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;
|
||||
// Conrtolar si la diferencia no es mayor de lo que falta
|
||||
if (Math.Abs(hzIncrementsRamp) > Math.Abs(delta))
|
||||
|
@ -209,12 +266,14 @@ namespace CtrEditor.ObjetosSim
|
|||
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
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -5,19 +5,22 @@
|
|||
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"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osBoton Color="#FFADE6C0" ColorButton_oculto="#FFC72323"/>
|
||||
<vm:osBoton Color="#FFADE6C0" ColorButton="#FFC72323" Color_Pressed="#FF9A9A9A" />
|
||||
</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"
|
||||
BorderBrush="Black"
|
||||
BorderThickness="2"
|
||||
|
@ -26,16 +29,24 @@
|
|||
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=1.5}"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Left"
|
||||
Background="Gray"/>
|
||||
<Ellipse Fill="{Binding ColorButton_oculto}"
|
||||
Background="{Binding Color_Pressed, Converter={StaticResource ColorToBrushConverter}}"/>
|
||||
<Ellipse Fill="{Binding ColorButton, Converter={StaticResource ColorToBrushConverter}}"
|
||||
Stroke="Black"
|
||||
StrokeThickness="2"
|
||||
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Canvas.Top="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=0.5}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Bottom"
|
||||
MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"
|
||||
MouseLeftButtonUp="Ellipse_MouseLeftButtonUp">
|
||||
</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>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
|
||||
using LibS7Adv;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using CtrEditor.FuncionesBase;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
|
@ -26,24 +27,49 @@ namespace CtrEditor.ObjetosSim
|
|||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
string button_Name;
|
||||
|
||||
[ObservableProperty]
|
||||
public bool tipo_NC;
|
||||
|
||||
[ObservableProperty]
|
||||
private Brush color;
|
||||
[property: Hidden]
|
||||
Color color_Pressed;
|
||||
|
||||
[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]
|
||||
public float tamano;
|
||||
|
||||
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||
{
|
||||
Tamano += Delta_Width + Delta_Height;
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public bool estado;
|
||||
|
||||
partial void OnEstadoChanged(bool value)
|
||||
{
|
||||
if (value)
|
||||
ColorButton_oculto = Brushes.LightGreen;
|
||||
Color_Pressed = Colors.LightGreen;
|
||||
else
|
||||
ColorButton_oculto = Color;
|
||||
if (!tipo_NC)
|
||||
Color_Pressed = Colors.Gray;
|
||||
if (!Tipo_NC)
|
||||
EscribirBitTag(Tag, value);
|
||||
else
|
||||
EscribirBitTag(Tag, !value);
|
||||
|
@ -52,6 +78,9 @@ namespace CtrEditor.ObjetosSim
|
|||
[ObservableProperty]
|
||||
public string tag;
|
||||
|
||||
[ObservableProperty]
|
||||
public string tag_Luz;
|
||||
|
||||
public void ButtonDownCommand()
|
||||
{
|
||||
Estado = true;
|
||||
|
@ -67,7 +96,10 @@ namespace CtrEditor.ObjetosSim
|
|||
Estado = false;
|
||||
Tag = "M50.0";
|
||||
// Set initial color
|
||||
Color = Brushes.LightBlue;
|
||||
Color = Colors.LightBlue;
|
||||
color_Titulo = Colors.Black;
|
||||
button_Name = "TAG";
|
||||
Color_Pressed = Colors.Gray;
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
|
@ -75,9 +107,18 @@ namespace CtrEditor.ObjetosSim
|
|||
// 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)
|
||||
|
@ -88,7 +129,8 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
base.ucLoaded();
|
||||
ColorButton = Color;
|
||||
}
|
||||
public override void ucUnLoaded()
|
||||
{
|
||||
|
@ -101,6 +143,7 @@ namespace CtrEditor.ObjetosSim
|
|||
public partial class ucBoton : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
public int zIndex_fromFrames { get; set; }
|
||||
|
||||
public ucBoton()
|
||||
{
|
||||
|
@ -140,21 +183,11 @@ namespace CtrEditor.ObjetosSim
|
|||
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 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:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:CtrEditor.ObjetosSim.UserControls"
|
||||
mc:Ignorable="d"
|
||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
||||
|
||||
<UserControl.Resources>
|
||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
||||
</UserControl.Resources>
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osGearEncoder Dientes="9"/>
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
|
||||
using LibS7Adv;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using Newtonsoft.Json;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||
using System.ComponentModel;
|
||||
using CtrEditor.FuncionesBase;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
|
@ -14,7 +16,7 @@ namespace CtrEditor.ObjetosSim
|
|||
/// </summary>
|
||||
public partial class osGearEncoder : osBase, IosBase
|
||||
{
|
||||
private osBase _osMotor = null;
|
||||
private osBase Motor = null;
|
||||
private Stopwatch Stopwatch = new Stopwatch();
|
||||
private double stopwatch_last = 0;
|
||||
|
||||
|
@ -41,8 +43,8 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
if (value)
|
||||
{
|
||||
var dTime = Stopwatch.ElapsedMilliseconds - stopwatch_last;
|
||||
stopwatch_last = Stopwatch.ElapsedMilliseconds;
|
||||
var dTime = Stopwatch.Elapsed.TotalMilliseconds - stopwatch_last;
|
||||
stopwatch_last = Stopwatch.Elapsed.TotalMilliseconds;
|
||||
Tiempo_Pulso = (float)dTime;
|
||||
}
|
||||
|
||||
|
@ -57,10 +59,8 @@ namespace CtrEditor.ObjetosSim
|
|||
private Brush color_oculto;
|
||||
[ObservableProperty]
|
||||
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
|
||||
Pulso = DetectarDiente();
|
||||
|
@ -96,12 +96,37 @@ namespace CtrEditor.ObjetosSim
|
|||
public float ancho_Dientes;
|
||||
[ObservableProperty]
|
||||
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()
|
||||
|
@ -119,28 +144,9 @@ namespace CtrEditor.ObjetosSim
|
|||
// 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()
|
||||
|
@ -183,21 +189,43 @@ namespace CtrEditor.ObjetosSim
|
|||
public override void UpdateControl(int elapsedMilliseconds)
|
||||
{
|
||||
// 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()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
|
||||
base.ucLoaded();
|
||||
OnId_MotorChanged(Id_Motor); // Link Id_Motor = Motor
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ucGearEncoder : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
public int zIndex_fromFrames { get; set; }
|
||||
|
||||
public ucGearEncoder()
|
||||
{
|
||||
|
@ -213,21 +241,12 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
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 int ZIndex()
|
||||
public ZIndexEnum ZIndex_Base()
|
||||
{
|
||||
return 10;
|
||||
return ZIndexEnum.Estaticos;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,25 +4,22 @@
|
|||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:CtrEditor.ObjetosSim.UserControls"
|
||||
mc:Ignorable="d"
|
||||
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>
|
||||
<vm:osPhotocell Color="#FFCA1C1C"/>
|
||||
<vm:osPhotocell Color="#FFCA1C1C" Ancho="0.8" Nombre="PTH" Alto="0.04" />
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition
|
||||
Width="{Binding Alto, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=5}" />
|
||||
<!-- Columna para el Label -->
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<!-- Columna para la Image -->
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<!-- Columna para el Rectangle -->
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
|
@ -31,27 +28,31 @@
|
|||
</Grid.RenderTransform>
|
||||
|
||||
<!-- Label en la primera columna -->
|
||||
<Label Content="{Binding Nombre}" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Column="0" Foreground="{Binding Color}" >
|
||||
|
||||
</Label>
|
||||
<Viewbox Grid.Column="0" Stretch="UniformToFill">
|
||||
<Label Content="{Binding Nombre}"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Center" Opacity="0.8" FontWeight="Bold" Foreground="{Binding Color}"/>
|
||||
</Viewbox>
|
||||
|
||||
<Image Source="/Icons/fotocelula.png"
|
||||
Width="{Binding Alto, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=3}"
|
||||
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=3}"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Left" Margin="0,0,0,0" Grid.Column="1"/>
|
||||
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"/>
|
||||
|
||||
<Rectangle x:Name="Photocell" Grid.Column="2" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}">
|
||||
<Rectangle x:Name="Photocell" Grid.Column="2" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=0.9}"
|
||||
Height="{Binding Ancho_Haz_De_Luz, Converter={StaticResource MeterToPixelConverter}}">
|
||||
<Rectangle.Fill>
|
||||
<VisualBrush x:Name="MovingPattern" TileMode="Tile" Viewport="0,0,3,3" ViewportUnits="Absolute" Viewbox="0,0,3,3" ViewboxUnits="Absolute">
|
||||
<VisualBrush.Visual>
|
||||
<Canvas>
|
||||
<Ellipse Width="2" Height="2" Fill="{Binding Color}"/>
|
||||
<Ellipse
|
||||
Width="1"
|
||||
Height="1" Fill="{Binding Color}"/>
|
||||
</Canvas>
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
</Rectangle.Fill>
|
||||
<!-- No se aplica la transformación aquí -->
|
||||
</Rectangle>
|
||||
</Grid>
|
||||
|
||||
|
||||
</UserControl>
|
|
@ -1,11 +1,15 @@
|
|||
using CtrEditor.Convertidores;
|
||||
|
||||
using CtrEditor.Simulacion;
|
||||
using CtrEditor.Siemens;
|
||||
using LibS7Adv;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
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
|
||||
{
|
||||
|
@ -15,6 +19,9 @@ namespace CtrEditor.ObjetosSim
|
|||
public partial class osPhotocell : osBase, IosBase
|
||||
{
|
||||
private simBarrera Simulation_Photocell;
|
||||
Stopwatch timer;
|
||||
double timer_lastPositive;
|
||||
double timer_lastNegative;
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
|
@ -28,9 +35,14 @@ namespace CtrEditor.ObjetosSim
|
|||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public Brush color;
|
||||
[property: Description("Color")]
|
||||
[property: Category("Layout:")]
|
||||
Brush color;
|
||||
|
||||
[ObservableProperty]
|
||||
public bool luzCortada;
|
||||
[property: Description("Light cut")]
|
||||
[property: Category("Debug:")]
|
||||
bool luzCortada;
|
||||
|
||||
partial void OnLuzCortadaChanged(bool value)
|
||||
{
|
||||
|
@ -42,12 +54,85 @@ namespace CtrEditor.ObjetosSim
|
|||
EscribirBitTag(TagPhotocell_OUT, !LuzCortada);
|
||||
else
|
||||
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]
|
||||
[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;
|
||||
|
||||
partial void OnTipo_NCChanged(bool value)
|
||||
{
|
||||
OnLuzCortadaChanged(LuzCortada);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public string tagPhotocell_OUT;
|
||||
|
||||
|
@ -62,40 +147,36 @@ namespace CtrEditor.ObjetosSim
|
|||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float ancho;
|
||||
|
||||
partial void OnAnchoChanged(float value)
|
||||
public override void AnguloChanged(float value)
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float alto;
|
||||
|
||||
partial void OnAltoChanged(float value)
|
||||
public override void AltoChanged(float value)
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float angulo;
|
||||
|
||||
partial void OnAnguloChanged(float value)
|
||||
public override void AnchoChanged(float value)
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
|
||||
private void ActualizarGeometrias()
|
||||
{
|
||||
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()
|
||||
{
|
||||
Ancho = 1;
|
||||
Alto = 0.03f;
|
||||
Ancho_Haz_De_Luz = 0.01f;
|
||||
Frecuency = 0;
|
||||
timer = new Stopwatch();
|
||||
timer.Start();
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
|
@ -105,22 +186,29 @@ namespace CtrEditor.ObjetosSim
|
|||
}
|
||||
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()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
base.ucLoaded();
|
||||
|
||||
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()
|
||||
{
|
||||
|
@ -135,6 +223,7 @@ namespace CtrEditor.ObjetosSim
|
|||
public partial class ucPhotocell : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
public int zIndex_fromFrames { get; set; }
|
||||
|
||||
public ucPhotocell()
|
||||
{
|
||||
|
@ -150,31 +239,12 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
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 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:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:CtrEditor.ObjetosSim"
|
||||
mc:Ignorable="d"
|
||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
||||
|
||||
<UserControl.Resources>
|
||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
||||
</UserControl.Resources>
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osSensTemperatura />
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
|
||||
using LibS7Adv;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using CtrEditor.FuncionesBase;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
|
@ -30,6 +32,7 @@ namespace CtrEditor.ObjetosSim
|
|||
public float min_OUT_Scaled;
|
||||
[ObservableProperty]
|
||||
public float max_OUT_Scaled;
|
||||
|
||||
[ObservableProperty]
|
||||
public float value;
|
||||
|
||||
|
@ -38,13 +41,6 @@ namespace CtrEditor.ObjetosSim
|
|||
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()
|
||||
{
|
||||
Ancho = 0.4f;
|
||||
|
@ -53,16 +49,21 @@ namespace CtrEditor.ObjetosSim
|
|||
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()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
base.ucLoaded();
|
||||
|
||||
}
|
||||
|
||||
|
@ -71,6 +72,7 @@ namespace CtrEditor.ObjetosSim
|
|||
public partial class ucSensTemperatura : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
public int zIndex_fromFrames { get; set; }
|
||||
|
||||
public ucSensTemperatura()
|
||||
{
|
||||
|
@ -86,32 +88,11 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
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 int ZIndex()
|
||||
public ZIndexEnum ZIndex_Base()
|
||||
{
|
||||
return 10;
|
||||
return ZIndexEnum.Estaticos;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,14 +5,9 @@
|
|||
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"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osAnalogTag/>
|
||||
</UserControl.DataContext>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
|
||||
using LibS7Adv;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using CtrEditor.FuncionesBase;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
|
@ -31,6 +32,12 @@ namespace CtrEditor.ObjetosSim
|
|||
|
||||
[ObservableProperty]
|
||||
public float tamano;
|
||||
|
||||
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||
{
|
||||
Tamano += Delta_Width + Delta_Height;
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(Value))]
|
||||
public string tag;
|
||||
|
@ -74,10 +81,16 @@ namespace CtrEditor.ObjetosSim
|
|||
// 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)
|
||||
{
|
||||
// Calculamos la velocidad
|
||||
|
@ -88,7 +101,7 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
base.ucLoaded();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -96,6 +109,7 @@ namespace CtrEditor.ObjetosSim
|
|||
public partial class ucAnalogTag : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
public int zIndex_fromFrames { get; set; }
|
||||
|
||||
public ucAnalogTag()
|
||||
{
|
||||
|
@ -111,20 +125,10 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
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 int ZIndex()
|
||||
public ZIndexEnum ZIndex_Base()
|
||||
{
|
||||
return 10;
|
||||
return ZIndexEnum.Estaticos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,17 +5,21 @@
|
|||
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"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osBoolTag/>
|
||||
</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.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
|
@ -30,8 +34,10 @@
|
|||
Height="40"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Left"
|
||||
Background="Gray"/>
|
||||
Background="{Binding Color, Converter={StaticResource ColorToBrushConverter}}"/>
|
||||
<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>
|
||||
</Canvas>
|
||||
</UserControl>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
|
||||
using LibS7Adv;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using CtrEditor.FuncionesBase;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
|
@ -32,6 +33,9 @@ namespace CtrEditor.ObjetosSim
|
|||
[ObservableProperty]
|
||||
private Brush color_oculto;
|
||||
|
||||
[ObservableProperty]
|
||||
Color color;
|
||||
|
||||
[ObservableProperty]
|
||||
public bool estado;
|
||||
|
||||
|
@ -46,6 +50,12 @@ namespace CtrEditor.ObjetosSim
|
|||
|
||||
[ObservableProperty]
|
||||
public float tamano;
|
||||
|
||||
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||
{
|
||||
Tamano += Delta_Width + Delta_Height;
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(Estado))]
|
||||
public string tag;
|
||||
|
@ -58,13 +68,20 @@ namespace CtrEditor.ObjetosSim
|
|||
Tamano = 0.30f;
|
||||
tag = "%M50.0";
|
||||
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()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
base.ucLoaded();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +89,7 @@ namespace CtrEditor.ObjetosSim
|
|||
public partial class ucBoolTag : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
public int zIndex_fromFrames { get; set; }
|
||||
|
||||
public ucBoolTag()
|
||||
{
|
||||
|
@ -87,20 +105,11 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
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 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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d"
|
||||
Background="LightGray"
|
||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
||||
Background="LightGray">
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osConsensGeneric />
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using CtrEditor.FuncionesBase;
|
||||
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
|
@ -34,14 +33,19 @@ namespace CtrEditor.ObjetosSim
|
|||
[ObservableProperty]
|
||||
public float tamano;
|
||||
|
||||
public override void OnResize(float Delta_Width, float Delta_Height)
|
||||
{
|
||||
Tamano += Delta_Width + Delta_Height;
|
||||
}
|
||||
|
||||
public override void ucLoaded()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
base.ucLoaded();
|
||||
|
||||
if (_visualRepresentation is ucConsensGeneric uc)
|
||||
Tags = UserControlFactory.CargarPropiedadesosDatosTags(Consensos, uc.PanelEdicion, null);
|
||||
//if (_visualRepresentation is ucConsensGeneric uc)
|
||||
// Tags = UserControlFactory.CargarPropiedadesosDatosTags(Consensos, uc.PanelEdicion, null);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +53,7 @@ namespace CtrEditor.ObjetosSim
|
|||
public partial class ucConsensGeneric : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
public int zIndex_fromFrames { get; set; }
|
||||
|
||||
public ucConsensGeneric()
|
||||
{
|
||||
|
@ -64,21 +69,12 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
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 int ZIndex()
|
||||
public ZIndexEnum ZIndex_Base()
|
||||
{
|
||||
return 10;
|
||||
return ZIndexEnum.Estaticos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|