Compare commits
26 Commits
master
...
FarseerPhy
Author | SHA1 | Date |
---|---|---|
Miguel | 288635b9bf | |
Miguel | e54dba175a | |
Miguel | 25da24d042 | |
Miguel | ecf433cecc | |
Miguel | 0e174fc308 | |
Miguel | 260362dc24 | |
Miguel | f090722de0 | |
Miguel | 334b1a2fd8 | |
Miguel | 0d18cae40a | |
Miguel | 1bccd5d33b | |
Miguel | 6155f8475e | |
Miguel | f458a031c5 | |
Miguel | 2e8c3b7d83 | |
Miguel | 9cf86d001e | |
Miguel | 9ed8a0b7bd | |
Miguel | ebe7986142 | |
Miguel | 664d325de8 | |
Miguel | 77ff643642 | |
Miguel | f3e5992433 | |
Miguel | 794a5898c5 | |
Miguel | 494f960628 | |
Miguel | 6da98e621b | |
Miguel | b224070690 | |
Miguel | 9c8eb0b348 | |
Miguel | 56a2e994a2 | |
Miguel | 2bfd83ef3b |
|
@ -6,9 +6,100 @@ 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
|
||||
|
@ -33,22 +124,55 @@ namespace CtrEditor.Convertidores
|
|||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
float meters = (float)value;
|
||||
float factor = 1;
|
||||
if (parameter != null)
|
||||
if (parameter.ToString() == "0.5") factor = 0.5f;
|
||||
else if (parameter.ToString() == "-0.5") factor = -0.5f;
|
||||
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)
|
||||
{
|
||||
float pixels = (float)value;
|
||||
float factor = 1;
|
||||
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)
|
||||
if (parameter.ToString() == "0.5") factor = 0.5f;
|
||||
else if (parameter.ToString() == "-0.5") factor = -0.5f;
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -92,6 +216,28 @@ namespace CtrEditor.Convertidores
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -9,14 +9,53 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="motor2.png" />
|
||||
<Compile Remove="ObjetosSim\ucTransporteCurva.xaml.cs" />
|
||||
<Compile Remove="Simulacion\FPhysics.cs" />
|
||||
<Compile Remove="Simulacion\GeometrySimulator.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="app2.png" />
|
||||
<None Remove="CtrEditorE.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\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\fotocelula.png" />
|
||||
<None Remove="Icons\save.png" />
|
||||
<None Remove="Icons\start.png" />
|
||||
<None Remove="Icons\stop.png" />
|
||||
<None Remove="imagenes\filler.png" />
|
||||
<None Remove="imagenes\motorNegro.png" />
|
||||
<None Remove="imagenes\motorVerde.png" />
|
||||
<None Remove="motor2.png" />
|
||||
<None Remove="tank.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Remove="ObjetosSim\ucTransporteCurva.xaml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<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="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
|
||||
<PackageReference Include="OpenCvSharp4.Windows" Version="4.9.0.20240103" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -27,7 +66,25 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="motor2.png" />
|
||||
<Resource Include="app2.png" />
|
||||
<Resource Include="CtrEditorE.png" />
|
||||
<Resource Include="Icons\app.png" />
|
||||
<Resource Include="Icons\app2.png" />
|
||||
<Resource Include="Icons\borrar.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\fotocelula.png" />
|
||||
<Resource Include="Icons\save.png" />
|
||||
<Resource Include="Icons\start.png" />
|
||||
<Resource Include="Icons\stop.png" />
|
||||
<Resource Include="imagenes\filler.png" />
|
||||
<Resource Include="imagenes\motorNegro.png" />
|
||||
<Resource Include="imagenes\motorVerde.png" />
|
||||
<Resource Include="imagenes\tank.png" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
After Width: | Height: | Size: 655 KiB |
After Width: | Height: | Size: 453 KiB |
After Width: | Height: | Size: 298 KiB |
After Width: | Height: | Size: 316 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 75 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 8.4 KiB |
After Width: | Height: | Size: 9.1 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 14 KiB |
602
MainViewModel.cs
|
@ -1,154 +1,98 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using Ookii.Dialogs.Wpf;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
using System.Windows.Threading;
|
||||
using CtrEditor.ObjetosSim;
|
||||
using CtrEditor.Siemens;
|
||||
using System.IO;
|
||||
// using System.Windows.Forms;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json;
|
||||
using Newtonsoft.Json;
|
||||
using System.Windows.Data;
|
||||
using System.Windows;
|
||||
using static System.Resources.ResXFileRef;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Simulacion;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
|
||||
namespace CtrEditor
|
||||
{
|
||||
|
||||
public class MainViewModel : INotifyPropertyChanged
|
||||
public partial class MainViewModel : ObservableObject
|
||||
{
|
||||
public DatosDeTrabajo datosDeTrabajo { get; }
|
||||
public ObservableCollection<string> listaImagenes { get; private set; } // Publicación de las claves del diccionario
|
||||
public ObservableCollection<TipoSimulable> ListaOsBase { get; } = new ObservableCollection<TipoSimulable>();
|
||||
private ObservableCollection<osBase> _objetosSimulables = new ObservableCollection<osBase>();
|
||||
public PLCViewModel _plcViewModelData;
|
||||
public Stopwatch stopwatch_Sim;
|
||||
|
||||
private SimulationManager simulationManager = new SimulationManager();
|
||||
private double stopwatch_SimPLC_last;
|
||||
private double stopwatch_SimModel_last;
|
||||
|
||||
private float TiempoDesdeStartSimulacion;
|
||||
private bool Debug_SimulacionCreado = false;
|
||||
|
||||
public SimulationManagerFP simulationManager = new SimulationManagerFP();
|
||||
|
||||
private readonly DispatcherTimer _timerSimulacion;
|
||||
|
||||
[ObservableProperty]
|
||||
private DatosDeTrabajo datosDeTrabajo;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<string> listaImagenes; // Publicación de las claves del diccionario
|
||||
|
||||
[ObservableProperty]
|
||||
public ObservableCollection<TipoSimulable> listaOsBase;
|
||||
|
||||
public ICommand StartSimulationCommand { get; }
|
||||
public ICommand StopSimulationCommand { get; }
|
||||
public ICommand ItemDoubleClickCommand { get; private set; }
|
||||
|
||||
public ICommand TBStartSimulationCommand { get; }
|
||||
public ICommand TBStopSimulationCommand { get; }
|
||||
public ICommand TBSaveCommand { get; }
|
||||
public ICommand TBConnectPLCCommand { get; }
|
||||
public ICommand TBDisconnectPLCCommand { get; }
|
||||
|
||||
public ICommand TBEliminarUserControlCommand { get; }
|
||||
public ICommand TBDuplicarUserControlCommand { get; }
|
||||
|
||||
public ICommand OpenWorkDirectoryCommand { get; }
|
||||
|
||||
// Evento que se dispara cuando se selecciona una nueva imagen
|
||||
public event EventHandler<string> ImageSelected;
|
||||
public event EventHandler<TickSimulacionEventArgs> TickSimulacion;
|
||||
public event Action<UserControl> OnUserControlSelected;
|
||||
|
||||
public MainViewModel()
|
||||
// Propiedades
|
||||
|
||||
private bool habilitarEliminarUserControl;
|
||||
|
||||
private MainWindow mainWindow;
|
||||
|
||||
public MainWindow MainWindow { get => mainWindow; set => mainWindow = value; }
|
||||
|
||||
|
||||
[ObservableProperty]
|
||||
private float canvasLeft;
|
||||
|
||||
[ObservableProperty]
|
||||
private float canvasTop;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool isSimulationRunning;
|
||||
|
||||
partial void OnIsSimulationRunningChanged(bool value)
|
||||
{
|
||||
OpenWorkDirectoryCommand = new RelayCommand(OpenWorkDirectory);
|
||||
datosDeTrabajo = new DatosDeTrabajo();
|
||||
|
||||
// Inicializa el PLCViewModel
|
||||
_plcViewModelData = new PLCViewModel();
|
||||
|
||||
InitializeTipoSimulableList();
|
||||
|
||||
ItemDoubleClickCommand = new ParameterizedRelayCommand(ExecuteDoubleClick);
|
||||
|
||||
_timerSimulacion = new DispatcherTimer();
|
||||
_timerSimulacion.Interval = TimeSpan.FromMilliseconds(20); // ajusta el intervalo según sea necesario
|
||||
_timerSimulacion.Tick += OnTickSimulacion;
|
||||
|
||||
StartSimulationCommand = new RelayCommand(StartSimulation);
|
||||
StopSimulationCommand = new RelayCommand(StopSimulation);
|
||||
CommandManager.InvalidateRequerySuggested(); // Notificar que el estado de los comandos ha cambiado
|
||||
}
|
||||
|
||||
public void LoadInitialData()
|
||||
[ObservableProperty]
|
||||
private bool isConnected;
|
||||
|
||||
partial void OnIsConnectedChanged(bool value)
|
||||
{
|
||||
// Suponiendo que "SelectedImage" es una propiedad que al establecerse dispara "ImageSelected"
|
||||
directorioTrabajo = EstadoPersistente.Instance.directorio;
|
||||
CommandManager.InvalidateRequerySuggested();
|
||||
}
|
||||
|
||||
|
||||
private TipoSimulable _selectedItem = null;
|
||||
public TipoSimulable SelectedItem
|
||||
{
|
||||
get => _selectedItem;
|
||||
set
|
||||
{
|
||||
if (_selectedItem != value)
|
||||
{
|
||||
_selectedItem = value;
|
||||
OnPropertyChanged(nameof(SelectedItem)); // Notificar que la propiedad ha cambiado
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ExecuteDoubleClick(object parameter)
|
||||
{
|
||||
if (parameter is TipoSimulable tipoSimulable)
|
||||
{
|
||||
// Crear una nueva instancia del osBase correspondiente
|
||||
osBase? newosBase = UserControlFactory.GetInstanceForType(tipoSimulable.Tipo);
|
||||
if (newosBase != null)
|
||||
{
|
||||
if (CrearUsercontrol(newosBase))
|
||||
// Añadir el nuevo osBase a la colección de objetos simulables
|
||||
ObjetosSimulables.Add(newosBase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeTipoSimulableList()
|
||||
{
|
||||
var baseType = typeof(osBase);
|
||||
var types = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(assembly => assembly.GetTypes())
|
||||
.Where(type => type.IsSubclassOf(baseType) && !type.IsAbstract);
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
ListaOsBase.Add(new TipoSimulable { Nombre = type.Name, Tipo = type });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void StartSimulation()
|
||||
{
|
||||
_timerSimulacion.Start();
|
||||
}
|
||||
|
||||
private void StopSimulation()
|
||||
{
|
||||
_timerSimulacion.Stop();
|
||||
}
|
||||
|
||||
private void OnTickSimulacion(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
foreach (var objetoSimulable in ObjetosSimulables)
|
||||
objetoSimulable.UpdateGeometry();
|
||||
|
||||
simulationManager.Step((float)_timerSimulacion.Interval.TotalMilliseconds);
|
||||
|
||||
foreach (var objetoSimulable in ObjetosSimulables)
|
||||
objetoSimulable.UpdateControl();
|
||||
|
||||
}
|
||||
|
||||
//protected virtual void OnTickSimulacion(TickSimulacionEventArgs e)
|
||||
//{
|
||||
// TickSimulacion?.Invoke(this, e);
|
||||
//}
|
||||
|
||||
public string directorioTrabajo
|
||||
{
|
||||
get => EstadoPersistente.Instance.directorio;
|
||||
|
@ -158,62 +102,316 @@ namespace CtrEditor
|
|||
{
|
||||
EstadoPersistente.Instance.directorio = value; // Actualizar el estado persistente
|
||||
EstadoPersistente.Instance.GuardarEstado(); // Guardar el estado actualizado
|
||||
datosDeTrabajo.CargarImagenes();
|
||||
listaImagenes = new ObservableCollection<string>(datosDeTrabajo.Imagenes.Keys); // Actualizar claves
|
||||
DatosDeTrabajo.CargarImagenes();
|
||||
ListaImagenes = new ObservableCollection<string>(DatosDeTrabajo.Imagenes.Keys); // Actualizar claves
|
||||
SelectedImage = null;
|
||||
if (listaImagenes.FirstOrDefault() != null)
|
||||
SelectedImage = listaImagenes.FirstOrDefault();
|
||||
if (ListaImagenes.FirstOrDefault() != null)
|
||||
SelectedImage = ListaImagenes.FirstOrDefault();
|
||||
OnPropertyChanged(nameof(directorioTrabajo)); // Notificar el cambio de propiedad
|
||||
OnPropertyChanged(nameof(listaImagenes)); // Notificar que la lista de imágenes ha cambiado
|
||||
OnPropertyChanged(nameof(ListaImagenes)); // Notificar que la lista de imágenes ha cambiado
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private PLCViewModel pLCViewModel;
|
||||
|
||||
public PLCViewModel PLCViewModel
|
||||
[ObservableProperty]
|
||||
private string selectedImage;
|
||||
|
||||
partial void OnSelectedImageChanged(string value)
|
||||
{
|
||||
get { return _plcViewModelData; }
|
||||
set
|
||||
if (value != null)
|
||||
{
|
||||
_plcViewModelData = value;
|
||||
OnPropertyChanged(nameof(PLCViewModel));
|
||||
StopSimulation();
|
||||
// SaveStateObjetosSimulables(); // Guarda el estado antes de cambiar la imagen
|
||||
ImageSelected?.Invoke(this, datosDeTrabajo.Imagenes[value]); // Dispara el evento con la nueva ruta de imagen
|
||||
LoadStateObjetosSimulables();
|
||||
}
|
||||
}
|
||||
|
||||
private string _selectedImage = null;
|
||||
public string SelectedImage
|
||||
[ObservableProperty]
|
||||
private osBase selectedItemOsList;
|
||||
|
||||
partial void OnSelectedItemOsListChanged(osBase value)
|
||||
{
|
||||
get => _selectedImage;
|
||||
set
|
||||
if (value != null)
|
||||
habilitarEliminarUserControl = true;
|
||||
else
|
||||
habilitarEliminarUserControl = false;
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private TipoSimulable selectedItem;
|
||||
|
||||
[ObservableProperty]
|
||||
public ObservableCollection<osBase> objetosSimulables;
|
||||
|
||||
//
|
||||
// Constructor
|
||||
//
|
||||
|
||||
public MainViewModel()
|
||||
{
|
||||
OpenWorkDirectoryCommand = new RelayCommand(OpenWorkDirectory);
|
||||
datosDeTrabajo = new DatosDeTrabajo();
|
||||
|
||||
ObjetosSimulables = new ObservableCollection<osBase>();
|
||||
ListaOsBase = new ObservableCollection<TipoSimulable>();
|
||||
|
||||
// Inicializa el PLCViewModel
|
||||
PLCViewModel = new PLCViewModel();
|
||||
PLCViewModel.RefreshEvent += OnRefreshEvent;
|
||||
|
||||
InitializeTipoSimulableList();
|
||||
|
||||
ItemDoubleClickCommand = new ParameterizedRelayCommand(ExecuteDoubleClick);
|
||||
|
||||
_timerSimulacion = new DispatcherTimer();
|
||||
_timerSimulacion.Interval = TimeSpan.FromMilliseconds(1); // ajusta el intervalo según sea necesario
|
||||
_timerSimulacion.Tick += OnTickSimulacion;
|
||||
|
||||
StartSimulationCommand = new RelayCommand(StartSimulation);
|
||||
StopSimulationCommand = new RelayCommand(StopSimulation);
|
||||
|
||||
TBStartSimulationCommand = new RelayCommand(StartSimulation, () => !IsSimulationRunning);
|
||||
TBStopSimulationCommand = new RelayCommand(StopSimulation, () => IsSimulationRunning);
|
||||
TBSaveCommand = new RelayCommand(Save);
|
||||
TBConnectPLCCommand = new RelayCommand(ConnectPLC, () => !IsConnected);
|
||||
TBDisconnectPLCCommand = new RelayCommand(DisconnectPLC, () => IsConnected);
|
||||
|
||||
TBEliminarUserControlCommand = new RelayCommand(EliminarUserControl, () => habilitarEliminarUserControl);
|
||||
TBDuplicarUserControlCommand = new RelayCommand(DuplicarUserControl, () => habilitarEliminarUserControl);
|
||||
|
||||
stopwatch_Sim = new Stopwatch();
|
||||
stopwatch_Sim.Start();
|
||||
}
|
||||
|
||||
public void LoadInitialData()
|
||||
{
|
||||
// Suponiendo que "SelectedImage" es una propiedad que al establecerse dispara "ImageSelected"
|
||||
directorioTrabajo = EstadoPersistente.Instance.directorio;
|
||||
}
|
||||
|
||||
// Crear un nuevo Objeto
|
||||
private void ExecuteDoubleClick(object parameter)
|
||||
{
|
||||
if (parameter is TipoSimulable tipoSimulable)
|
||||
{
|
||||
if (_selectedImage != value && value != null)
|
||||
CrearObjetoSimulableEnCentroCanvas(tipoSimulable.Tipo);
|
||||
}
|
||||
}
|
||||
|
||||
public void CrearObjetoSimulableEnCentroCanvas(Type tipoSimulable)
|
||||
{
|
||||
var CentroCanvas = MainWindow.ObtenerCentroCanvasMeters();
|
||||
CrearObjetoSimulable(tipoSimulable,CentroCanvas.X,CentroCanvas.Y);
|
||||
}
|
||||
|
||||
public osBase CrearObjetoSimulable(Type tipoSimulable,float Left,float Top)
|
||||
{
|
||||
// Crear una nueva instancia del osBase correspondiente
|
||||
osBase? NuevoOsBase = UserControlFactory.GetInstanceForType(tipoSimulable);
|
||||
|
||||
NuevoOsBase.Left = Left;
|
||||
NuevoOsBase.Top = Top;
|
||||
|
||||
if (NuevoOsBase != null)
|
||||
{
|
||||
if (CrearUserControlDesdeObjetoSimulable(NuevoOsBase))
|
||||
// Añadir el nuevo osBase a la colección de objetos simulables
|
||||
ObjetosSimulables.Add(NuevoOsBase);
|
||||
}
|
||||
return NuevoOsBase;
|
||||
}
|
||||
|
||||
// Crear UserControl desde osBase : Nuevo o desde Deserealizacion
|
||||
private bool CrearUserControlDesdeObjetoSimulable(osBase osObjeto)
|
||||
{
|
||||
Type tipoObjeto = osObjeto.GetType();
|
||||
|
||||
// Obtén el UserControl correspondiente para el tipo de objeto
|
||||
UserControl? userControl = UserControlFactory.GetControlForType(tipoObjeto);
|
||||
|
||||
if (userControl != null)
|
||||
{
|
||||
// Asignar los datos al UserControl
|
||||
UserControlFactory.AssignDatos(userControl, osObjeto, simulationManager);
|
||||
osObjeto._mainViewModel = this;
|
||||
|
||||
MainWindow.AgregarRegistrarUserControlCanvas(userControl);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void RemoverObjetoSimulable(osBase osObjeto)
|
||||
{
|
||||
if (osObjeto != null && ObjetosSimulables.Contains(osObjeto))
|
||||
{
|
||||
ObjetosSimulables.Remove(osObjeto);
|
||||
if (osObjeto.VisualRepresentation != null)
|
||||
MainWindow.EliminarUserControlDelCanvas(osObjeto.VisualRepresentation);
|
||||
}
|
||||
}
|
||||
|
||||
private void DuplicarUserControl()
|
||||
{
|
||||
if (SelectedItemOsList is osBase objDuplicar)
|
||||
{
|
||||
StopSimulation();
|
||||
DisconnectPLC();
|
||||
|
||||
objDuplicar.SalvarDatosNoSerializables();
|
||||
|
||||
var settings = new JsonSerializerSettings
|
||||
{
|
||||
StopSimulation();
|
||||
SaveStateObjetosSimulables(); // Guarda el estado antes de cambiar la imagen
|
||||
_selectedImage = value;
|
||||
ImageSelected?.Invoke(this, datosDeTrabajo.Imagenes[value]); // Dispara el evento con la nueva ruta de imagen
|
||||
LoadStateObjetosSimulables();
|
||||
}
|
||||
_selectedImage = value;
|
||||
OnPropertyChanged(nameof(SelectedImage));
|
||||
}
|
||||
}
|
||||
Formatting = Formatting.Indented,
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
TypeNameHandling = TypeNameHandling.All
|
||||
};
|
||||
|
||||
private osBase _selectedItemOsList;
|
||||
public osBase SelectedItemOsList
|
||||
{
|
||||
get => _selectedItemOsList;
|
||||
set
|
||||
{
|
||||
if (_selectedItemOsList != value)
|
||||
try
|
||||
{
|
||||
_selectedItemOsList = value;
|
||||
OnPropertyChanged(nameof(SelectedItemOsList));
|
||||
// Serializar
|
||||
var serializedData = JsonConvert.SerializeObject(objDuplicar, settings);
|
||||
// Duplicar
|
||||
var NuevoObjetoDuplicado = JsonConvert.DeserializeObject<osBase>(serializedData, settings);
|
||||
if (NuevoObjetoDuplicado != null)
|
||||
{
|
||||
NuevoObjetoDuplicado.Nombre += "_Duplicado";
|
||||
NuevoObjetoDuplicado.Left += 0.5f;
|
||||
NuevoObjetoDuplicado.Top += 0.5f;
|
||||
ObjetosSimulables.Add(NuevoObjetoDuplicado);
|
||||
CrearUserControlDesdeObjetoSimulable(NuevoObjetoDuplicado);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Log error or handle it accordingly
|
||||
}
|
||||
finally {
|
||||
objDuplicar.RestaurarDatosNoSerializables();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand OpenWorkDirectoryCommand { get; }
|
||||
private void EliminarUserControl()
|
||||
{
|
||||
if (SelectedItemOsList is osBase objEliminar)
|
||||
RemoverObjetoSimulable(objEliminar);
|
||||
}
|
||||
|
||||
private void InitializeTipoSimulableList()
|
||||
{
|
||||
var baseType = typeof(osBase);
|
||||
var types = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(assembly => assembly.GetTypes())
|
||||
.Where(type => type.IsSubclassOf(baseType) && !type.IsAbstract && typeof(IosBase).IsAssignableFrom(type));
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
var methodInfo = type.GetMethod("NombreClase", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
|
||||
string nombre = methodInfo != null ? methodInfo.Invoke(null, null)?.ToString() : "Nombre no encontrado";
|
||||
|
||||
ListaOsBase.Add(new TipoSimulable { Nombre = nombre, Tipo = type });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void StartSimulation()
|
||||
{
|
||||
IsSimulationRunning = true;
|
||||
|
||||
foreach (var objetoSimulable in ObjetosSimulables)
|
||||
objetoSimulable.UpdateGeometryStart();
|
||||
|
||||
simulationManager.Debug_DrawInitialBodies();
|
||||
TiempoDesdeStartSimulacion = 0;
|
||||
Debug_SimulacionCreado = true;
|
||||
|
||||
_timerSimulacion.Start();
|
||||
}
|
||||
|
||||
private void StopSimulation()
|
||||
{
|
||||
IsSimulationRunning = false;
|
||||
|
||||
foreach (var objetoSimulable in ObjetosSimulables)
|
||||
objetoSimulable.SimulationStop();
|
||||
|
||||
if (Debug_SimulacionCreado)
|
||||
{
|
||||
simulationManager.Debug_ClearSimulationShapes();
|
||||
Debug_SimulacionCreado = false;
|
||||
}
|
||||
_timerSimulacion.Stop();
|
||||
}
|
||||
|
||||
private void OnTickSimulacion(object sender, EventArgs e)
|
||||
{
|
||||
// Detener el cronómetro y obtener el tiempo transcurrido en milisegundos
|
||||
var elapsedMilliseconds = stopwatch_Sim.Elapsed.TotalMilliseconds - stopwatch_SimModel_last;
|
||||
stopwatch_SimModel_last = stopwatch_Sim.Elapsed.TotalMilliseconds;
|
||||
|
||||
// Eliminar el diseño de Debug luego de 2 segundos
|
||||
if (TiempoDesdeStartSimulacion > 2000)
|
||||
simulationManager.Debug_ClearSimulationShapes();
|
||||
else
|
||||
TiempoDesdeStartSimulacion += (float)elapsedMilliseconds;
|
||||
|
||||
foreach (var objetoSimulable in ObjetosSimulables)
|
||||
objetoSimulable.UpdateGeometryStep();
|
||||
|
||||
simulationManager.Step();
|
||||
|
||||
var objetosSimulablesCopy = new List<osBase>(ObjetosSimulables);
|
||||
|
||||
foreach (var objetoSimulable in objetosSimulablesCopy)
|
||||
{
|
||||
if (!objetoSimulable.RemoverDesdeSimulacion)
|
||||
objetoSimulable.UpdateControl((int)elapsedMilliseconds);
|
||||
else
|
||||
RemoverObjetoSimulable(objetoSimulable);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void ConnectPLC()
|
||||
{
|
||||
PLCViewModel.Connect();
|
||||
}
|
||||
|
||||
private void DisconnectPLC()
|
||||
{
|
||||
PLCViewModel.Disconnect();
|
||||
IsConnected = false;
|
||||
foreach (var objetoSimulable in ObjetosSimulables)
|
||||
objetoSimulable.SetPLC(null);
|
||||
|
||||
}
|
||||
|
||||
private void OnRefreshEvent(object sender, EventArgs e)
|
||||
{
|
||||
if (PLCViewModel.IsConnected)
|
||||
{
|
||||
if (!isConnected)
|
||||
{
|
||||
IsConnected = true;
|
||||
foreach (var objetoSimulable in ObjetosSimulables)
|
||||
objetoSimulable.SetPLC(PLCViewModel.PLCInterface);
|
||||
}
|
||||
// Detener el cronómetro y obtener el tiempo transcurrido en milisegundos
|
||||
var elapsedMilliseconds = stopwatch_Sim.Elapsed.TotalMilliseconds - stopwatch_SimPLC_last;
|
||||
stopwatch_SimPLC_last = stopwatch_Sim.Elapsed.TotalMilliseconds;
|
||||
|
||||
|
||||
// Reiniciar el cronómetro para la próxima medición
|
||||
foreach (var objetoSimulable in ObjetosSimulables)
|
||||
objetoSimulable.UpdatePLC(PLCViewModel.PLCInterface, (int) elapsedMilliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenWorkDirectory()
|
||||
{
|
||||
|
@ -228,35 +426,40 @@ namespace CtrEditor
|
|||
// Lista de osBase
|
||||
//
|
||||
|
||||
|
||||
public ObservableCollection<osBase> ObjetosSimulables
|
||||
public void Save()
|
||||
{
|
||||
get => _objetosSimulables;
|
||||
set
|
||||
{
|
||||
if (_objetosSimulables != value)
|
||||
{
|
||||
_objetosSimulables = value;
|
||||
OnPropertyChanged(nameof(ObjetosSimulables));
|
||||
}
|
||||
}
|
||||
SaveStateObjetosSimulables();
|
||||
}
|
||||
|
||||
public void SaveStateObjetosSimulables()
|
||||
{
|
||||
if (_selectedImage != null)
|
||||
if (SelectedImage != null)
|
||||
{
|
||||
StopSimulation();
|
||||
DisconnectPLC();
|
||||
|
||||
// Ruta del archivo a ser guardado
|
||||
var path = DatosDeTrabajo.ObtenerPathImagenConExtension(SelectedImage, ".json");
|
||||
|
||||
// Verificar si el archivo ya existe y crear un respaldo
|
||||
if (File.Exists(path))
|
||||
{
|
||||
var backupPath = Path.ChangeExtension(path, ".bak");
|
||||
File.Copy(path, backupPath, true); // Copia el archivo existente a un nuevo archivo .bak, sobrescribiendo si es necesario
|
||||
}
|
||||
|
||||
foreach (var obj in ObjetosSimulables)
|
||||
// Guardar referencias temporales
|
||||
obj.SalvarDatosNoSerializables();
|
||||
|
||||
var settings = new JsonSerializerSettings
|
||||
{
|
||||
Formatting = Formatting.Indented,
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
TypeNameHandling = TypeNameHandling.Auto
|
||||
};
|
||||
foreach (var obj in ObjetosSimulables)
|
||||
{
|
||||
obj.VisualRepresentation = null;
|
||||
}
|
||||
// Crear un objeto que incluya tanto los ObjetosSimulables como el UnitConverter
|
||||
|
||||
// Crear un objeto que incluya tanto los ObjetosSimulables como el UnitConverter y PLC_ConnectionData
|
||||
var dataToSerialize = new SimulationData
|
||||
{
|
||||
ObjetosSimulables = ObjetosSimulables,
|
||||
|
@ -264,8 +467,13 @@ namespace CtrEditor
|
|||
PLC_ConnectionData = PLCViewModel
|
||||
};
|
||||
|
||||
// Serializar
|
||||
var serializedData = JsonConvert.SerializeObject(dataToSerialize, settings);
|
||||
File.WriteAllText(datosDeTrabajo.ObtenerPathImagenConExtension(_selectedImage, ".json"), serializedData);
|
||||
File.WriteAllText(path, serializedData); // Escribir el nuevo archivo JSON
|
||||
|
||||
// Restaurar las propiedades originales de los objetos
|
||||
foreach (var obj in ObjetosSimulables)
|
||||
obj.RestaurarDatosNoSerializables();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,10 +481,13 @@ namespace CtrEditor
|
|||
{
|
||||
try
|
||||
{
|
||||
StopSimulation();
|
||||
DisconnectPLC();
|
||||
ObjetosSimulables.Clear();
|
||||
if (_selectedImage != null)
|
||||
simulationManager.Clear();
|
||||
if (SelectedImage != null)
|
||||
{
|
||||
string jsonPath = datosDeTrabajo.ObtenerPathImagenConExtension(_selectedImage, ".json");
|
||||
string jsonPath = datosDeTrabajo.ObtenerPathImagenConExtension(SelectedImage, ".json");
|
||||
if (File.Exists(jsonPath))
|
||||
{
|
||||
string jsonString = File.ReadAllText(jsonPath);
|
||||
|
@ -301,9 +512,12 @@ namespace CtrEditor
|
|||
|
||||
PixelToMeter.Instance.calc = simulationData.UnitConverter;
|
||||
|
||||
// Re-register to the events
|
||||
PLCViewModel.RefreshEvent += OnRefreshEvent;
|
||||
|
||||
// Recorrer la colección de objetos simulables
|
||||
foreach (var objetoSimulable in ObjetosSimulables)
|
||||
CrearUsercontrol(objetoSimulable);
|
||||
CrearUserControlDesdeObjetoSimulable(objetoSimulable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -311,49 +525,39 @@ namespace CtrEditor
|
|||
catch { /* Consider logging the error or handling it appropriately */ }
|
||||
}
|
||||
|
||||
|
||||
private bool CrearUsercontrol(osBase osObjeto)
|
||||
// Se cargan los datos de cada UserControl en el StackPanel
|
||||
public void CargarPropiedadesosDatos(osBase selectedObject, StackPanel PanelEdicion, ResourceDictionary Resources)
|
||||
{
|
||||
Type tipoObjeto = osObjeto.GetType();
|
||||
|
||||
// Obtén el UserControl correspondiente para el tipo de objeto
|
||||
UserControl? userControl = UserControlFactory.GetControlForType(tipoObjeto);
|
||||
|
||||
if (userControl != null)
|
||||
{
|
||||
// Asignar los datos al UserControl
|
||||
UserControlFactory.AssignDatos(userControl, osObjeto, simulationManager);
|
||||
|
||||
OnUserControlSelected?.Invoke(userControl);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
UserControlFactory.CargarPropiedadesosDatos(selectedObject,PanelEdicion, Resources);
|
||||
}
|
||||
|
||||
private RelayCommand saveCommand;
|
||||
public ICommand SaveCommand => saveCommand ??= new RelayCommand(Save);
|
||||
|
||||
|
||||
|
||||
// Implementación de INotifyPropertyChanged...
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
private void Save(object commandParameter)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
private RelayCommand exitCommand;
|
||||
public ICommand ExitCommand => exitCommand ??= new RelayCommand(Exit);
|
||||
|
||||
private void Exit()
|
||||
{
|
||||
Save();
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
}
|
||||
public class SimulationData
|
||||
{
|
||||
public ObservableCollection<osBase> ObjetosSimulables { get; set; }
|
||||
public UnitConverter UnitConverter { get; set; }
|
||||
public PLCViewModel PLC_ConnectionData { get; set; }
|
||||
public ObservableCollection<osBase>? ObjetosSimulables { get; set; }
|
||||
public UnitConverter? UnitConverter { get; set; }
|
||||
public PLCViewModel? PLC_ConnectionData { get; set; }
|
||||
}
|
||||
|
||||
public class TipoSimulable
|
||||
{
|
||||
public string Nombre { get; set; }
|
||||
public Type Tipo { get; set; }
|
||||
public string? Nombre { get; set; }
|
||||
public Type? Tipo { get; set; }
|
||||
}
|
||||
|
||||
public class TickSimulacionEventArgs : EventArgs
|
||||
|
|
106
MainWindow.xaml
|
@ -3,19 +3,42 @@
|
|||
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" x:Class="CtrEditor.MainWindow"
|
||||
xmlns:Siemens="clr-namespace:CtrEditor.Siemens"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
||||
Height="900" Width="1600"
|
||||
ResizeMode="CanResize" Title="{Binding directorioTrabajo}">
|
||||
|
||||
<Window.Resources>
|
||||
<convert:FloatToFormattedStringConverter x:Key="floatFormatter"/>
|
||||
</Window.Resources>
|
||||
xmlns:ObjetosSim="clr-namespace:CtrEditor.ObjetosSim" x:Class="CtrEditor.MainWindow"
|
||||
Height="900" Width="1600" WindowState="Maximized"
|
||||
ResizeMode="CanResize" Title="{Binding directorioTrabajo}" Icon="/app2.png">
|
||||
|
||||
<Window.DataContext>
|
||||
<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"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsSimulationRunning}" Value="True">
|
||||
<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"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Background" Value="LightGreen"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<!-- Menú Principal sobre toda la ventana -->
|
||||
<Menu VerticalAlignment="Top" HorizontalAlignment="Stretch">
|
||||
|
@ -32,8 +55,8 @@
|
|||
<!-- Margen superior para el menú -->
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" MinWidth="100"/>
|
||||
<ColumnDefinition Width="4*" MinWidth="200"/>
|
||||
<ColumnDefinition Width="1*" MinWidth="100"/>
|
||||
<ColumnDefinition Width="8*" MinWidth="200"/>
|
||||
<ColumnDefinition Width="2*" MinWidth="100"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Primera Columna -->
|
||||
|
@ -43,7 +66,7 @@
|
|||
<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="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">
|
||||
|
@ -58,8 +81,48 @@
|
|||
|
||||
<!-- Segunda Columna -->
|
||||
<Grid Grid.Column="1">
|
||||
<ScrollViewer x:Name="ImagenEnTrabajoScrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" PanningMode="Both">
|
||||
<Canvas x:Name="ImagenEnTrabajoCanvas" Margin="20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ToolBarTray Grid.Row="0">
|
||||
<ToolBar>
|
||||
<Button Command="{Binding TBStartSimulationCommand}" ToolTip="Iniciar Simulación" Style="{StaticResource StartStopButtonStyle}">
|
||||
<StackPanel>
|
||||
<Image Source="Icons/start.png" Width="16" Height="16"/>
|
||||
<TextBlock Text="Iniciar"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{Binding TBStopSimulationCommand}" ToolTip="Detener Simulación">
|
||||
<StackPanel>
|
||||
<Image Source="Icons/stop.png" Width="16" Height="16"/>
|
||||
<TextBlock Text="Detener"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{Binding TBSaveCommand}" ToolTip="Guardar">
|
||||
<StackPanel>
|
||||
<Image Source="Icons/save.png" Width="16" Height="16"/>
|
||||
<TextBlock Text="Guardar"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{Binding TBConnectPLCCommand}" ToolTip="Conectar PLC" Style="{StaticResource ConnectDisconnectButtonStyle}">
|
||||
<StackPanel>
|
||||
<Image Source="Icons/connect.png" Width="16" Height="16"/>
|
||||
<TextBlock Text="Conectar"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{Binding TBDisconnectPLCCommand}" ToolTip="Desconectar PLC">
|
||||
<StackPanel>
|
||||
<Image Source="Icons/disconnect.png" Width="16" Height="16"/>
|
||||
<TextBlock Text="Desconectar"/>
|
||||
</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"/>
|
||||
|
@ -80,6 +143,7 @@
|
|||
<!-- Espacio para el GridSplitter -->
|
||||
<RowDefinition Height="*" />
|
||||
<!-- Altura ajustable para el PanelEdicion -->
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- ListBox -->
|
||||
|
@ -105,6 +169,24 @@
|
|||
<!-- Aquí puedes agregar los controles para editar propiedades -->
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<ToolBarTray Grid.Row="3">
|
||||
<ToolBar>
|
||||
<Button Command="{Binding TBEliminarUserControlCommand}" ToolTip="Eliminar Control">
|
||||
<StackPanel>
|
||||
<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"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</ToolBar>
|
||||
</ToolBarTray>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
|
|
@ -10,7 +10,6 @@ using System.Windows.Media;
|
|||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using CtrEditor.ObjetosSim;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
|
@ -19,6 +18,10 @@ using Label = System.Windows.Controls.Label;
|
|||
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;
|
||||
|
||||
|
||||
namespace CtrEditor
|
||||
|
@ -58,66 +61,68 @@ namespace CtrEditor
|
|||
{
|
||||
if (DataContext is MainViewModel viewModel)
|
||||
{
|
||||
viewModel.ImageSelected += ViewModel_ImageSelected;
|
||||
//viewModel.TickSimulacion += MainViewModel_TickSimulacion;
|
||||
viewModel.OnUserControlSelected += AgregarUserControl;
|
||||
viewModel.MainWindow = this;
|
||||
viewModel.ImageSelected += ViewModel_ImageSelected;
|
||||
viewModel?.LoadInitialData(); // Carga la primera imagen por defecto una vez cargada la ventana principal
|
||||
viewModel.simulationManager.DebugCanvas = ImagenEnTrabajoCanvas;
|
||||
}
|
||||
}
|
||||
|
||||
private void AgregarUserControl(UserControl userControl)
|
||||
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;
|
||||
}
|
||||
|
||||
public void AgregarRegistrarUserControlCanvas(UserControl userControl)
|
||||
{
|
||||
if (userControl is IDataContainer dataContainer)
|
||||
{
|
||||
var NuevoOS = dataContainer.Datos;
|
||||
if (!NuevoOS.Inicializado) // Aun no fue inicializado
|
||||
{
|
||||
// Obtiene el factor de escala
|
||||
var scaleTransform = ImagenEnTrabajoCanvas.LayoutTransform as ScaleTransform;
|
||||
double scaleX = scaleTransform?.ScaleX ?? 1.0;
|
||||
double scaleY = scaleTransform?.ScaleY ?? 1.0;
|
||||
|
||||
// Obtiene el área visible del ScrollViewer
|
||||
double visibleWidth = ImagenEnTrabajoScrollViewer.ViewportWidth;
|
||||
double visibleHeight = ImagenEnTrabajoScrollViewer.ViewportHeight;
|
||||
|
||||
// Obtiene la posición actual del desplazamiento ajustada por el zoom
|
||||
double offsetX = ImagenEnTrabajoScrollViewer.HorizontalOffset / scaleX;
|
||||
double offsetY = ImagenEnTrabajoScrollViewer.VerticalOffset / scaleY;
|
||||
|
||||
// Calcula el centro visible ajustado
|
||||
double centerX = offsetX + (visibleWidth / scaleX) / 2;
|
||||
double centerY = offsetY + (visibleHeight / scaleY) / 2;
|
||||
|
||||
// Ajusta la posición del UserControl para que esté centrado en el área visible
|
||||
double leftPixels = centerX - (userControl.ActualWidth / 2);
|
||||
double topPixels = centerY - (userControl.ActualHeight / 2);
|
||||
|
||||
// Establece la posición del UserControl
|
||||
NuevoOS.Left = PixelToMeter.Instance.calc.PixelsToMeters((float)leftPixels);
|
||||
NuevoOS.Top = PixelToMeter.Instance.calc.PixelsToMeters((float)topPixels);
|
||||
|
||||
NuevoOS.Inicializado = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fuerza a Establecer la posición del UserControl
|
||||
NuevoOS.Left = NuevoOS.Left;
|
||||
NuevoOS.Top = NuevoOS.Top;
|
||||
}
|
||||
|
||||
// Suscribirse a eventos de mouse para marcar el Control
|
||||
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;
|
||||
SuscribirEventos(userControl);
|
||||
|
||||
// Añade el UserControl al Canvas
|
||||
Canvas.SetZIndex(userControl, dataContainer.ZIndex());
|
||||
ImagenEnTrabajoCanvas.Children.Add(userControl);
|
||||
ImagenEnTrabajoCanvas.Children.Add(userControl);
|
||||
}
|
||||
}
|
||||
|
||||
public void EliminarUserControlDelCanvas(UserControl userControl)
|
||||
{
|
||||
if (ImagenEnTrabajoCanvas.Children.Contains(userControl))
|
||||
{
|
||||
ImagenEnTrabajoCanvas.Children.Remove(userControl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -271,17 +276,29 @@ namespace CtrEditor
|
|||
// 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);
|
||||
control.Width = newWidth; // Asegurar que no sea menor que el mínimo
|
||||
|
||||
// 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, 0);
|
||||
{
|
||||
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)
|
||||
|
@ -408,46 +425,10 @@ namespace CtrEditor
|
|||
|
||||
private void CargarPropiedadesosDatos(osBase selectedObject)
|
||||
{
|
||||
PanelEdicion.Children.Clear();
|
||||
var properties = selectedObject.GetType().GetProperties();
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
if (property.PropertyType == typeof(float) || property.PropertyType == typeof(string))
|
||||
{
|
||||
var label = new Label { Content = property.Name };
|
||||
var textBox = new TextBox { Width = 200, Margin = new Thickness(0) };
|
||||
|
||||
var binding = new Binding(property.Name)
|
||||
{
|
||||
Source = selectedObject,
|
||||
Mode = BindingMode.TwoWay,
|
||||
UpdateSourceTrigger = UpdateSourceTrigger.LostFocus, // Actualizar solo al perder el foco
|
||||
Converter = (FloatToFormattedStringConverter)Resources["floatFormatter"] // Usar el convertidor
|
||||
};
|
||||
|
||||
// Aplicar el convertidor solo a propiedades float
|
||||
if (property.PropertyType == typeof(float))
|
||||
{
|
||||
textBox.SetBinding(TextBox.TextProperty, binding);
|
||||
}
|
||||
else
|
||||
{
|
||||
textBox.SetBinding(TextBox.TextProperty, new Binding(property.Name)
|
||||
{
|
||||
Source = selectedObject,
|
||||
Mode = BindingMode.TwoWay,
|
||||
UpdateSourceTrigger = UpdateSourceTrigger.LostFocus
|
||||
});
|
||||
}
|
||||
|
||||
PanelEdicion.Children.Add(label);
|
||||
PanelEdicion.Children.Add(textBox);
|
||||
}
|
||||
}
|
||||
if (DataContext is MainViewModel viewModel)
|
||||
viewModel.CargarPropiedadesosDatos(selectedObject, PanelEdicion, Resources);
|
||||
}
|
||||
|
||||
|
||||
private void MainWindow_Closed(object sender, EventArgs e)
|
||||
{
|
||||
if (DataContext is MainViewModel viewModel)
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
//using using Microsoft.Xna.Framework;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using CtrEditor.Simulacion;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using nkast.Aether.Physics2D.Common;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucBotella.xaml
|
||||
/// </summary>
|
||||
///
|
||||
|
||||
public partial class osBotella : osBase, IosBase
|
||||
{
|
||||
private simBotella SimGeometria;
|
||||
|
||||
// Otros datos y métodos relevantes para la simulación
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Botella";
|
||||
}
|
||||
private string nombre = NombreClase();
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private float diametro;
|
||||
|
||||
partial void OnDiametroChanged(float value)
|
||||
{
|
||||
SimGeometria?.SetDiameter(Diametro);
|
||||
}
|
||||
|
||||
[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.SetDiameter(Diametro);
|
||||
SimGeometria.SetPosition(GetCentro());
|
||||
}
|
||||
}
|
||||
|
||||
public osBotella()
|
||||
{
|
||||
Diametro = 0.10f;
|
||||
Mass = 1;
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
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.Descartar) // Ha sido marcada para remover
|
||||
RemoverDesdeSimulacion = true;
|
||||
}
|
||||
|
||||
public override void ucLoaded()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
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 ucBotella : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucBotella()
|
||||
{
|
||||
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) { }
|
||||
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()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucFiller"
|
||||
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.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/>
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Grid>
|
||||
<Image Source="/imagenes/filler.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,181 @@
|
|||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucFiller.xaml
|
||||
/// </summary>
|
||||
public partial class osFiller : osBase, IosBase
|
||||
{
|
||||
// Otros datos y métodos relevantes para la simulación
|
||||
|
||||
private float TiempoRestante;
|
||||
private osBotella UltimaBotella;
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Filler";
|
||||
}
|
||||
private string nombre = NombreClase();
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private float offsetLeftSalida;
|
||||
[ObservableProperty]
|
||||
private float offsetTopSalida;
|
||||
[ObservableProperty]
|
||||
private bool consenso;
|
||||
[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;
|
||||
[ObservableProperty]
|
||||
private string tag_consenso;
|
||||
[ObservableProperty]
|
||||
private float ancho;
|
||||
[ObservableProperty]
|
||||
private float alto;
|
||||
[ObservableProperty]
|
||||
private float angulo;
|
||||
|
||||
public osFiller()
|
||||
{
|
||||
Ancho = 0.30f;
|
||||
Alto = 0.30f;
|
||||
Angulo = 0;
|
||||
Velocidad_actual_percentual = 0;
|
||||
Diametro_botella = 0.1f;
|
||||
Botellas_hora = 10000;
|
||||
}
|
||||
|
||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
||||
{
|
||||
Consenso = LeerBitTag(Tag_consenso);
|
||||
}
|
||||
|
||||
public override void UpdateControl(int elapsedMilliseconds)
|
||||
{
|
||||
if (Consenso && Velocidad_actual_percentual > 0)
|
||||
{
|
||||
TiempoRestante -= elapsedMilliseconds / 1000.0f;
|
||||
if (TiempoRestante <= 0)
|
||||
{
|
||||
TiempoRestante += 3600 / (Botellas_hora * (Velocidad_actual_percentual / 100.0f));
|
||||
|
||||
var X = Left + OffsetLeftSalida;
|
||||
var Y = Top + OffsetTopSalida;
|
||||
|
||||
if (UltimaBotella != null && UltimaBotella.RemoverDesdeSimulacion)
|
||||
UltimaBotella = null;
|
||||
|
||||
if (UltimaBotella == null)
|
||||
{
|
||||
// No hay botellas, se puede crear una nueva directamente
|
||||
var nuevaBotella = _mainViewModel.CrearObjetoSimulable(typeof(osBotella), X, Y);
|
||||
((osBotella)nuevaBotella).Diametro = Diametro_botella;
|
||||
nuevaBotella.AutoCreated = true;
|
||||
UltimaBotella = (osBotella)nuevaBotella;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calcular la distancia entre el centro de la última botella y la nueva posición
|
||||
float distancia = (float)Math.Sqrt(Math.Pow(UltimaBotella.Left - X, 2) + Math.Pow(UltimaBotella.Top - Y, 2));
|
||||
float distanciaMinima = Diametro_botella / 2; // Asumiendo que el diámetro de la nueva botella es similar
|
||||
|
||||
if (distancia > distanciaMinima)
|
||||
{
|
||||
var nuevaBotella = _mainViewModel.CrearObjetoSimulable(typeof(osBotella), X, Y);
|
||||
((osBotella)nuevaBotella).Diametro = Diametro_botella;
|
||||
nuevaBotella.AutoCreated = true;
|
||||
UltimaBotella = (osBotella)nuevaBotella;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TiempoRestante = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ucLoaded()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public partial class ucFiller : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucFiller()
|
||||
{
|
||||
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 osFiller 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 osFiller datos)
|
||||
datos.Angulo = Angle;
|
||||
}
|
||||
public void Highlight(bool State) { }
|
||||
public int ZIndex()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucTanque"
|
||||
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.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>
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osTanque Alto="1" Ancho="1" Angulo="-4" />
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Grid>
|
||||
<Image x:Name="TankImage"
|
||||
Source="/imagenes/tank.png"
|
||||
Width="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Stretch="Uniform">
|
||||
</Image>
|
||||
<Slider
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Orientation="Vertical"
|
||||
Value="{Binding Level}"
|
||||
Maximum="100"/>
|
||||
|
||||
<Rectangle x:Name="WaterLevel"
|
||||
Fill="Blue"
|
||||
VerticalAlignment="Bottom"
|
||||
HorizontalAlignment="Center">
|
||||
<Rectangle.Width>
|
||||
<Binding ElementName="TankImage" Path="ActualWidth" Converter="{StaticResource WidthPercentageConverter}" />
|
||||
</Rectangle.Width>
|
||||
<Rectangle.Height>
|
||||
<MultiBinding Converter="{StaticResource LevelToHeightMultiConverter}">
|
||||
<Binding Path="Level" />
|
||||
<Binding ElementName="TankImage" Path="ActualHeight" />
|
||||
</MultiBinding>
|
||||
</Rectangle.Height>
|
||||
</Rectangle>
|
||||
|
||||
<Label Content="{Binding Level}" HorizontalAlignment="Center" Margin="10,10,0,0" VerticalAlignment="Top"/>
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -0,0 +1,141 @@
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucTanque.xaml
|
||||
/// </summary>
|
||||
public partial class osTanque : osBase, IosBase
|
||||
{
|
||||
// Otros datos y métodos relevantes para la simulación
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Tanque";
|
||||
}
|
||||
private string nombre = NombreClase();
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float capacidad_Litros;
|
||||
[ObservableProperty]
|
||||
public bool ingreso_Abierto;
|
||||
[ObservableProperty]
|
||||
public bool salida_Abierta;
|
||||
[ObservableProperty]
|
||||
public string tagNivel_Word;
|
||||
[ObservableProperty]
|
||||
public string tagIngresoAbierto_Bool;
|
||||
[ObservableProperty]
|
||||
public string tagSalidaAbierta_Bool;
|
||||
[ObservableProperty]
|
||||
public float velocidad_Ingreso;
|
||||
[ObservableProperty]
|
||||
public float velocidad_Salida;
|
||||
[ObservableProperty]
|
||||
public float min_OUT_Scaled;
|
||||
[ObservableProperty]
|
||||
public float max_OUT_Scaled;
|
||||
[ObservableProperty]
|
||||
public float level;
|
||||
[ObservableProperty]
|
||||
public float ancho;
|
||||
[ObservableProperty]
|
||||
public float alto;
|
||||
[ObservableProperty]
|
||||
public float angulo;
|
||||
|
||||
public osTanque()
|
||||
{
|
||||
Ancho = 0.30f;
|
||||
Alto = 0.30f;
|
||||
Max_OUT_Scaled = 27648;
|
||||
Min_OUT_Scaled = 0;
|
||||
}
|
||||
|
||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
||||
{
|
||||
EscribirWordTagScaled(TagNivel_Word, Level, 0, 100, Min_OUT_Scaled, Max_OUT_Scaled);
|
||||
Ingreso_Abierto = LeerBitTag(TagIngresoAbierto_Bool);
|
||||
Salida_Abierta = LeerBitTag(TagSalidaAbierta_Bool);
|
||||
}
|
||||
|
||||
public override void UpdateControl(int elapsedMilliseconds)
|
||||
{
|
||||
if (Salida_Abierta && Level > 0)
|
||||
{
|
||||
var l_por_milisegundo = Velocidad_Salida / 60000.0f;
|
||||
Level -= l_por_milisegundo * elapsedMilliseconds;
|
||||
if (Level < 0) Level = 0;
|
||||
}
|
||||
if (Ingreso_Abierto && Level < 100)
|
||||
{
|
||||
var l_por_milisegundo = Velocidad_Ingreso / 60000.0f;
|
||||
Level += l_por_milisegundo * elapsedMilliseconds;
|
||||
if (Level > 100) Level = 100;
|
||||
}
|
||||
}
|
||||
public override void ucLoaded()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ucTanque : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucTanque()
|
||||
{
|
||||
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 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()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucDescarte"
|
||||
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.ObjetosSim"
|
||||
mc:Ignorable="d"
|
||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
||||
<UserControl.Resources>
|
||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
||||
<Storyboard x:Key="PulsingStoryboard" RepeatBehavior="Forever">
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="AnimatedEllipse"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
|
||||
From="1" To="0.5" Duration="0:0:1" AutoReverse="True" />
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="AnimatedEllipse"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
|
||||
From="1" To="0.5" Duration="0:0:1" AutoReverse="True" />
|
||||
</Storyboard>
|
||||
</UserControl.Resources>
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osDescarte/>
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Grid>
|
||||
<Ellipse
|
||||
Height="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Width="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Stroke="Yellow"
|
||||
Fill="Black"
|
||||
Opacity="0.5"/>
|
||||
<Ellipse x:Name="AnimatedEllipse"
|
||||
Height="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Width="{Binding Diametro, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Stroke="Blue"
|
||||
Fill="Transparent"
|
||||
RenderTransformOrigin="0.5,0.5">
|
||||
<Ellipse.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform />
|
||||
</TransformGroup>
|
||||
</Ellipse.RenderTransform>
|
||||
</Ellipse>
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -0,0 +1,157 @@
|
|||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using CtrEditor.Simulacion;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using nkast.Aether.Physics2D.Common;
|
||||
using System.Windows.Media.Animation;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucDescarte.xaml
|
||||
/// </summary>
|
||||
public partial class osDescarte : osBase, IosBase
|
||||
{
|
||||
// Otros datos y métodos relevantes para la simulación
|
||||
private simDescarte SimGeometria;
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Descarte";
|
||||
}
|
||||
private string nombre = NombreClase();
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private float diametro;
|
||||
|
||||
partial void OnDiametroChanged(float value)
|
||||
{
|
||||
SimGeometria?.SetDiameter(Diametro);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public override void LeftChanged(float value)
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
public override void TopChanged(float value)
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
|
||||
private void ActualizarGeometrias()
|
||||
{
|
||||
if (SimGeometria != null)
|
||||
{
|
||||
SimGeometria.SetDiameter(Diametro);
|
||||
SimGeometria.SetPosition(GetCentro());
|
||||
}
|
||||
}
|
||||
|
||||
public osDescarte()
|
||||
{
|
||||
Diametro = 1f;
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
public override void UpdateGeometryStep()
|
||||
{
|
||||
}
|
||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
||||
{
|
||||
}
|
||||
|
||||
public override void UpdateControl(int elapsedMilliseconds)
|
||||
{
|
||||
|
||||
}
|
||||
public override void ucLoaded()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
SimGeometria = simulationManager.AddDescarte(Diametro, GetCentro());
|
||||
}
|
||||
public override void ucUnLoaded()
|
||||
{
|
||||
// El UserControl se esta eliminando
|
||||
// eliminar el objeto de simulacion
|
||||
simulationManager.Remove(SimGeometria);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public partial class ucDescarte : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucDescarte()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Loaded += OnLoaded;
|
||||
this.Unloaded += OnUnloaded;
|
||||
}
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Datos?.ucLoaded();
|
||||
Storyboard storyboard = this.Resources["PulsingStoryboard"] as Storyboard;
|
||||
if (storyboard != null)
|
||||
{
|
||||
storyboard.Begin();
|
||||
}
|
||||
}
|
||||
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
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()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -4,14 +4,19 @@
|
|||
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>
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osGuia/>
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Canvas>
|
||||
<Rectangle Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}" Fill="Blue">
|
||||
<Rectangle x:Name="Guia" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}" Fill="Blue">
|
||||
<Rectangle.RenderTransform>
|
||||
<RotateTransform Angle="{Binding Angulo}"/>
|
||||
</Rectangle.RenderTransform>
|
|
@ -0,0 +1,124 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using CtrEditor.Simulacion;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucGuia.xaml
|
||||
/// </summary>
|
||||
public partial class osGuia : osBase, IosBase
|
||||
{
|
||||
private simGuia SimGeometria;
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Guia";
|
||||
}
|
||||
private string nombre = "Guia";
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
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 osGuia()
|
||||
{
|
||||
Ancho = 1;
|
||||
AltoGuia = 0.03f;
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
public override void UpdateControl(int elapsedMilliseconds)
|
||||
{
|
||||
}
|
||||
public override void UpdateGeometryStep()
|
||||
{
|
||||
}
|
||||
public override void UpdatePLC(PLCModel 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();
|
||||
|
||||
if (_visualRepresentation is ucGuia uc)
|
||||
SimGeometria = AddLine(simulationManager, uc.Guia);
|
||||
}
|
||||
public override void ucUnLoaded()
|
||||
{
|
||||
// El UserControl se esta eliminando
|
||||
// eliminar el objeto de simulacion
|
||||
simulationManager?.Remove(SimGeometria);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public partial class ucGuia : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucGuia()
|
||||
{
|
||||
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 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()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -5,12 +5,19 @@
|
|||
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>
|
||||
<Canvas>
|
||||
<localuc:CircularSegment Angle="{Binding Angulo}" OuterRadius="{Binding RadioExterno, Converter={StaticResource MeterToPixelConverter}}" InnerRadius="{Binding RadioInterno, Converter={StaticResource MeterToPixelConverter}}"
|
||||
StartAngle="0" EndAngle="90" />
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osTransporteCurva />
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Canvas x:Name="MainCanvas">
|
||||
|
||||
<localuc:CircularSegment x:Name="Transporte" Angle="0" OuterRadius="{Binding RadioExterno, Converter={StaticResource MeterToPixelConverter}}" InnerRadius="{Binding RadioInterno, Converter={StaticResource MeterToPixelConverter}}"
|
||||
StartAngle="{Binding Angulo}" EndAngle="{Binding AnguloFinal}" />
|
||||
</Canvas>
|
||||
</UserControl>
|
|
@ -0,0 +1,177 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using CtrEditor.Simulacion;
|
||||
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucTransporteCurva.xaml
|
||||
/// </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 simCurve Simulation_TransporteCurva;
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Transporte Curva 90";
|
||||
}
|
||||
private string nombre = "Transporte Curva 90";
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private float radioExterno;
|
||||
[ObservableProperty]
|
||||
private float radioInterno;
|
||||
[ObservableProperty]
|
||||
private string motor;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(AnguloFinal))]
|
||||
public float angulo;
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(AnguloFinal))]
|
||||
private float arco_en_grados;
|
||||
|
||||
[Hidden]
|
||||
public float AnguloFinal
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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 osTransporteCurva()
|
||||
{
|
||||
RadioExterno = 1.3f;
|
||||
RadioInterno = 1;
|
||||
Arco_en_grados = 90;
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
||||
{
|
||||
if (_osMotor != null)
|
||||
{
|
||||
if (_osMotor is osVMmotorSim motor)
|
||||
VelocidadActual = motor.Velocidad;
|
||||
}
|
||||
else
|
||||
_osMotor = ObtenerLink(Motor, typeof(osVMmotorSim));
|
||||
}
|
||||
|
||||
public override void ucLoaded()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
|
||||
if (_visualRepresentation is ucTransporteCurva uc)
|
||||
Simulation_TransporteCurva = AddCurve(RadioInterno,RadioExterno, Angulo, Angulo + Arco_en_grados);
|
||||
|
||||
// AddCurve(float innerRadius, float outerRadius, float startAngle, float endAngle, Vector2 position)
|
||||
}
|
||||
public override void ucUnLoaded()
|
||||
{
|
||||
// El UserControl se esta eliminando
|
||||
// eliminar el objeto de simulacion
|
||||
simulationManager?.Remove(Simulation_TransporteCurva);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public partial class ucTransporteCurva : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucTransporteCurva()
|
||||
{
|
||||
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 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()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -3,14 +3,34 @@
|
|||
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: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>
|
||||
<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:osTransporteGuias/>
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Grid>
|
||||
<Canvas>
|
||||
<StackPanel x:Name="RectanglesContainer">
|
||||
|
@ -19,8 +39,9 @@
|
|||
</StackPanel.RenderTransform>
|
||||
<Rectangle x:Name="GuiaSuperior" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}" Fill="Blue"
|
||||
Margin="{Binding Distance, Converter={StaticResource DistanceToMarginConverter}}"/>
|
||||
<Rectangle x:Name="Transporte" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}" Fill="Gray"
|
||||
Margin="{Binding Distance, Converter={StaticResource DistanceToMarginConverter}}"/>
|
||||
<Rectangle x:Name="Transporte" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Margin="{Binding Distance, Converter={StaticResource DistanceToMarginConverter}}"
|
||||
Fill="{StaticResource BeltBrush}"/>
|
||||
<Rectangle x:Name="GuiaInferior" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}" Fill="Blue"/>
|
||||
</StackPanel>
|
||||
</Canvas>
|
|
@ -0,0 +1,194 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using CtrEditor.Simulacion;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucTransporteGuias.xaml
|
||||
/// </summary>
|
||||
public partial class osTransporteGuias : osBase, IosBase
|
||||
{
|
||||
private osBase _osMotor = null;
|
||||
|
||||
private simTransporte? SimGeometria;
|
||||
private simGuia? Guia_Superior;
|
||||
private simGuia? Guia_Inferior;
|
||||
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Transporte Guias";
|
||||
}
|
||||
private string nombre = NombreClase();
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private float velocidadActual;
|
||||
|
||||
partial void OnVelocidadActualChanged(float value)
|
||||
{
|
||||
SimGeometria?.SetSpeed(value);
|
||||
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public string motor;
|
||||
|
||||
partial void OnMotorChanged(string value)
|
||||
{
|
||||
_osMotor = ObtenerLink(Motor, typeof(osVMmotorSim));
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float ancho;
|
||||
[ObservableProperty]
|
||||
public float alto;
|
||||
|
||||
partial void OnAltoChanged(float value)
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float angulo;
|
||||
[ObservableProperty]
|
||||
public float frictionCoefficient;
|
||||
[ObservableProperty]
|
||||
public float velMax50hz;
|
||||
[ObservableProperty]
|
||||
public float tiempoRampa;
|
||||
[ObservableProperty]
|
||||
public bool esMarcha;
|
||||
[ObservableProperty]
|
||||
private float distance;
|
||||
[ObservableProperty]
|
||||
private float altoGuia;
|
||||
|
||||
private void ActualizarGeometrias()
|
||||
{
|
||||
if (_visualRepresentation is ucTransporteGuias uc)
|
||||
{
|
||||
UpdateRectangle(SimGeometria, uc.Transporte, Alto, Ancho, Angulo);
|
||||
UpdateOrCreateLine(Guia_Superior, uc.GuiaSuperior);
|
||||
UpdateOrCreateLine(Guia_Inferior, uc.GuiaInferior) ;
|
||||
|
||||
SimGeometria.DistanceGuide2Guide = Alto;
|
||||
SimGeometria.Speed = VelocidadActual;
|
||||
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public osTransporteGuias()
|
||||
{
|
||||
Ancho = 1;
|
||||
Alto = 0.10f;
|
||||
AltoGuia = 0.03f;
|
||||
Distance = 0.01f;
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
if (_osMotor != null)
|
||||
{
|
||||
if (_osMotor is osVMmotorSim motor)
|
||||
VelocidadActual = motor.Velocidad;
|
||||
} else if (Motor.Length > 0)
|
||||
_osMotor = ObtenerLink(Motor, typeof(osVMmotorSim));
|
||||
}
|
||||
|
||||
public override void ucLoaded()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
if (_visualRepresentation is ucTransporteGuias uc)
|
||||
{
|
||||
SimGeometria = AddRectangle(simulationManager, uc.Transporte, Alto, Ancho, Angulo);
|
||||
SimGeometria.TransportWithGuides = true;
|
||||
SimGeometria.DistanceGuide2Guide = Alto;
|
||||
Guia_Superior = AddLine(simulationManager, uc.GuiaSuperior);
|
||||
Guia_Inferior = AddLine(simulationManager, uc.GuiaInferior);
|
||||
|
||||
CrearAnimacionStoryBoardTrasnporte(uc.Transporte);
|
||||
}
|
||||
Motor = Motor; // Forzar la busqueda
|
||||
}
|
||||
public override void ucUnLoaded()
|
||||
{
|
||||
// El UserControl se esta eliminando
|
||||
// eliminar el objeto de simulacion
|
||||
simulationManager.Remove(SimGeometria);
|
||||
simulationManager.Remove(Guia_Superior);
|
||||
simulationManager.Remove(Guia_Inferior);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public partial class ucTransporteGuias : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucTransporteGuias()
|
||||
{
|
||||
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 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()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucTransporteTTop"
|
||||
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"
|
||||
mc:Ignorable="d"
|
||||
xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
||||
|
||||
<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>
|
||||
<TransformGroup>
|
||||
<TranslateTransform/>
|
||||
</TransformGroup>
|
||||
</VisualBrush.Transform>
|
||||
<VisualBrush.Visual>
|
||||
<Canvas>
|
||||
<Rectangle Fill="Gray" Width="10" Height="10"/>
|
||||
<Rectangle Fill="DarkGray" Width="10" Height="10" Canvas.Left="10"/>
|
||||
</Canvas>
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
</UserControl.Resources>
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osTransporteTTop Ancho="2"/>
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Canvas>
|
||||
<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>
|
||||
</Canvas>
|
||||
</UserControl>
|
|
@ -0,0 +1,181 @@
|
|||
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 CtrEditor.Simulacion;
|
||||
using System.Windows.Input;
|
||||
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucTransporteTTop.xaml
|
||||
/// </summary>
|
||||
///
|
||||
|
||||
public partial class osTransporteTTop : osBase, IosBase
|
||||
{
|
||||
private osBase _osMotor = null;
|
||||
|
||||
private simTransporte SimGeometria;
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Transporte";
|
||||
}
|
||||
private string nombre = "Transporte TTOP";
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
private float velocidadActual;
|
||||
public float VelocidadActual
|
||||
{
|
||||
get => velocidadActual;
|
||||
set
|
||||
{
|
||||
if (value != velocidadActual)
|
||||
{
|
||||
velocidadActual = value;
|
||||
SimGeometria?.SetSpeed(value);
|
||||
SetProperty(ref velocidadActual, value);
|
||||
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public string motor;
|
||||
|
||||
partial void OnMotorChanged(string value)
|
||||
{
|
||||
_osMotor = ObtenerLink(Motor, typeof(osVMmotorSim));
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float ancho;
|
||||
[ObservableProperty]
|
||||
public float alto;
|
||||
[ObservableProperty]
|
||||
public float angulo;
|
||||
[ObservableProperty]
|
||||
public float frictionCoefficient;
|
||||
[ObservableProperty]
|
||||
public float velMax50hz;
|
||||
[ObservableProperty]
|
||||
public float tiempoRampa;
|
||||
[ObservableProperty]
|
||||
public bool esMarcha;
|
||||
|
||||
|
||||
private void ActualizarGeometrias()
|
||||
{
|
||||
if (_visualRepresentation is ucTransporteTTop uc)
|
||||
{
|
||||
UpdateRectangle(SimGeometria, uc.Transporte,Alto,Ancho,Angulo);
|
||||
SimGeometria.Speed = VelocidadActual;
|
||||
}
|
||||
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
|
||||
}
|
||||
|
||||
public osTransporteTTop()
|
||||
{
|
||||
Ancho = 1;
|
||||
Alto = 0.10f;
|
||||
}
|
||||
|
||||
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(PLCModel plc, int elapsedMilliseconds)
|
||||
{
|
||||
if (_osMotor != null)
|
||||
{
|
||||
if (_osMotor is osVMmotorSim motor)
|
||||
VelocidadActual = motor.Velocidad;
|
||||
}
|
||||
else if (Motor.Length > 0)
|
||||
_osMotor = ObtenerLink(Motor, typeof(osVMmotorSim));
|
||||
}
|
||||
|
||||
public override void ucLoaded()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
|
||||
if (_visualRepresentation is ucTransporteTTop uc)
|
||||
{
|
||||
SimGeometria = AddRectangle(simulationManager, uc.Transporte, Alto, Ancho, Angulo);
|
||||
CrearAnimacionStoryBoardTrasnporte(uc.Transporte);
|
||||
}
|
||||
}
|
||||
public override void ucUnLoaded()
|
||||
{
|
||||
// El UserControl se esta eliminando
|
||||
// eliminar el objeto de simulacion
|
||||
simulationManager.Remove(SimGeometria);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public partial class ucTransporteTTop : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucTransporteTTop()
|
||||
{
|
||||
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 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()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucVMmotorSim"
|
||||
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.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>
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osVMmotorSim ImageSource_oculta="/imagenes/motorNegro.png" />
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Content="{Binding Nombre}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Background="Transparent"
|
||||
Foreground="Black"/>
|
||||
|
||||
<Image Grid.Row="1" Source="{Binding ImageSource_oculta}"
|
||||
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Stretch="Uniform"/>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
|
@ -0,0 +1,220 @@
|
|||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using Newtonsoft.Json;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucVMmotorSim.xaml
|
||||
/// </summary>
|
||||
///
|
||||
|
||||
public partial class osVMmotorSim : osBase, IosBase
|
||||
{
|
||||
|
||||
// Otros datos y métodos relevantes para la simulación
|
||||
|
||||
private VMSimMotor motState = new VMSimMotor();
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "VetroMeccanica Motor";
|
||||
}
|
||||
private string nombre = NombreClase();
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
[ObservableProperty]
|
||||
public ImageSource imageSource_oculta;
|
||||
|
||||
[ObservableProperty]
|
||||
public float tamano;
|
||||
[ObservableProperty]
|
||||
public float maxRatedHz;
|
||||
|
||||
[ObservableProperty]
|
||||
public float tiempoRampa;
|
||||
|
||||
partial void OnTiempoRampaChanged(float value)
|
||||
{
|
||||
if (value < 0.1f)
|
||||
value = 0.1f;
|
||||
tiempoRampa = value;
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public bool encendido;
|
||||
[ObservableProperty]
|
||||
public int pLC_NumeroMotor;
|
||||
[ObservableProperty]
|
||||
public float ratio;
|
||||
|
||||
[ObservableProperty]
|
||||
public float velocidad;
|
||||
|
||||
partial void OnVelocidadChanged(float value)
|
||||
{
|
||||
if (value > 0)
|
||||
ImageSource_oculta = ImageFromPath("/imagenes/motorVerde.png");
|
||||
else
|
||||
ImageSource_oculta = ImageFromPath("/imagenes/motorNegro.png");
|
||||
}
|
||||
|
||||
public osVMmotorSim()
|
||||
{
|
||||
Tamano = 0.30f;
|
||||
PLC_NumeroMotor = 31;
|
||||
MaxRatedHz = 100;
|
||||
TiempoRampa = 3;
|
||||
ImageSource_oculta = ImageFromPath("/imagenes/motor2.png");
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
{
|
||||
// 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;
|
||||
|
||||
}
|
||||
|
||||
public override void UpdateControl(int elapsedMilliseconds)
|
||||
{
|
||||
// Calculamos la velocidad
|
||||
motState.UpdateSpeed(MaxRatedHz,TiempoRampa, elapsedMilliseconds);
|
||||
|
||||
}
|
||||
|
||||
public override void ucLoaded()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ucVMmotorSim : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucVMmotorSim()
|
||||
{
|
||||
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) { }
|
||||
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()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
public class VMSimMotor
|
||||
{
|
||||
public bool _STATUS_VFD_Ready;
|
||||
public float STATUS_VFD_ACT_Speed_Hz;
|
||||
public bool Motor_Running;
|
||||
public bool STATUS_VFD_Trip;
|
||||
public bool STATUS_VFD_Warning;
|
||||
public bool STATUS_VFD_Coasting;
|
||||
public bool OUT_Run;
|
||||
public bool OUT_Stop;
|
||||
public bool OUT_Reversal;
|
||||
public float OUT_OUT_VFD_REQ_Speed_Hz;
|
||||
|
||||
public void UpdatePLC(PLCModel plc, int NumeroMotor, bool Encendido, int elapsedMilliseconds)
|
||||
{
|
||||
var index = 0;
|
||||
switch (NumeroMotor)
|
||||
{
|
||||
case < 100:
|
||||
index = (int)NumeroMotor - 30 + 300;
|
||||
break;
|
||||
}
|
||||
|
||||
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 (Encendido)
|
||||
{
|
||||
_STATUS_VFD_Ready = true;
|
||||
Motor_Running = true;
|
||||
STATUS_VFD_Trip = false;
|
||||
STATUS_VFD_Warning = false;
|
||||
STATUS_VFD_Coasting = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_STATUS_VFD_Ready = false;
|
||||
Motor_Running = false;
|
||||
STATUS_VFD_Trip = true;
|
||||
STATUS_VFD_Warning = false;
|
||||
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);
|
||||
|
||||
plc.EscribirTagInt16($"\"DB MotorSimulate\".Motors[{index}].STATUS_VFD_ACT_Speed_Hz", (int)STATUS_VFD_ACT_Speed_Hz);
|
||||
|
||||
}
|
||||
|
||||
private float CalcSpeedRamp(float MaxRatedHz, float TiempoRampa, float actual, float expected, int elapsedMilliseconds)
|
||||
{
|
||||
float hzIncrementsRamp = (MaxRatedHz * 10) / (TiempoRampa * (1000.0f / elapsedMilliseconds));
|
||||
float delta = expected - actual;
|
||||
// Conrtolar si la diferencia no es mayor de lo que falta
|
||||
if (Math.Abs(hzIncrementsRamp) > Math.Abs(delta))
|
||||
hzIncrementsRamp = Math.Abs(delta);
|
||||
if (delta < 0)
|
||||
return -hzIncrementsRamp;
|
||||
else
|
||||
return hzIncrementsRamp;
|
||||
}
|
||||
|
||||
public void UpdateSpeed(float MaxRatedHz, float TiempoRampa, int elapsedMilliseconds)
|
||||
{
|
||||
// Calculamos la velocidad
|
||||
STATUS_VFD_ACT_Speed_Hz += CalcSpeedRamp(MaxRatedHz, TiempoRampa, STATUS_VFD_ACT_Speed_Hz, OUT_OUT_VFD_REQ_Speed_Hz, elapsedMilliseconds);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucBoton"
|
||||
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"
|
||||
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"/>
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Grid>
|
||||
<Border x:Name="BackgroundRectangle"
|
||||
BorderBrush="Black"
|
||||
BorderThickness="2"
|
||||
CornerRadius="0,0,10,10"
|
||||
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=1.5}"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Left"
|
||||
Background="Gray"/>
|
||||
<Ellipse Fill="{Binding ColorButton_oculto}"
|
||||
Stroke="Black"
|
||||
StrokeThickness="2"
|
||||
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Bottom"
|
||||
MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"
|
||||
MouseLeftButtonUp="Ellipse_MouseLeftButtonUp">
|
||||
</Ellipse>
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -0,0 +1,160 @@
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucBoton.xaml
|
||||
/// </summary>
|
||||
public partial class osBoton : osBase, IosBase
|
||||
{
|
||||
// Otros datos y métodos relevantes para la simulación
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Boton";
|
||||
}
|
||||
private string nombre = NombreClase();
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public bool tipo_NC;
|
||||
[ObservableProperty]
|
||||
private Brush color;
|
||||
[ObservableProperty]
|
||||
private Brush colorButton_oculto;
|
||||
[ObservableProperty]
|
||||
public float tamano;
|
||||
[ObservableProperty]
|
||||
public bool estado;
|
||||
|
||||
partial void OnEstadoChanged(bool value)
|
||||
{
|
||||
if (value)
|
||||
ColorButton_oculto = Brushes.LightGreen;
|
||||
else
|
||||
ColorButton_oculto = Color;
|
||||
if (!tipo_NC)
|
||||
EscribirBitTag(Tag, value);
|
||||
else
|
||||
EscribirBitTag(Tag, !value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public string tag;
|
||||
|
||||
public void ButtonDownCommand()
|
||||
{
|
||||
Estado = true;
|
||||
}
|
||||
public void ButtonUpCommand()
|
||||
{
|
||||
Estado = false;
|
||||
}
|
||||
|
||||
public osBoton()
|
||||
{
|
||||
Tamano = 0.30f;
|
||||
Estado = false;
|
||||
Tag = "M50.0";
|
||||
// Set initial color
|
||||
Color = Brushes.LightBlue;
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
|
||||
}
|
||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void UpdateControl(int elapsedMilliseconds)
|
||||
{
|
||||
|
||||
}
|
||||
public override void ucLoaded()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
}
|
||||
public override void ucUnLoaded()
|
||||
{
|
||||
// El UserControl se esta eliminando
|
||||
// eliminar el objeto de simulacion
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public partial class ucBoton : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucBoton()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.DataContextChanged += OnDataContextChanged;
|
||||
this.Loaded += OnLoaded;
|
||||
this.Unloaded += OnUnloaded;
|
||||
}
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Datos?.ucLoaded();
|
||||
}
|
||||
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Datos?.ucUnLoaded();
|
||||
}
|
||||
|
||||
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
Datos = e.NewValue as osBase;
|
||||
}
|
||||
|
||||
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (Datos is osBoton osBotonData)
|
||||
{
|
||||
osBotonData.ButtonDownCommand();
|
||||
e.Handled = true; // Evita que el evento se propague
|
||||
}
|
||||
}
|
||||
|
||||
private void Ellipse_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (Datos is osBoton osBotonData)
|
||||
{
|
||||
osBotonData.ButtonUpCommand();
|
||||
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()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucGearEncoder"
|
||||
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.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>
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osGearEncoder Dientes="9"/>
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="{Binding Radio_Externo, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=1}"/>
|
||||
<ColumnDefinition Width="{Binding Radio_Externo, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=0.02}"/>
|
||||
<!-- Espacio entre el Rectangle y el Canvas -->
|
||||
<ColumnDefinition Width="{Binding Radio_Externo, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=1}"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- StackPanel to contain the Rectangle -->
|
||||
<Canvas Grid.Column="0" HorizontalAlignment="Right">
|
||||
<Rectangle Canvas.Top="{Binding Radio_Externo, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=-0.12}"
|
||||
Grid.Column="0" Width="{Binding Radio_Externo, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=1}"
|
||||
Height="{Binding Radio_Externo, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=0.25}"
|
||||
Fill="{Binding Color_oculto}"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Center"/>
|
||||
</Canvas>
|
||||
<Canvas Grid.Column="0" HorizontalAlignment="Left">
|
||||
<Canvas.RenderTransform>
|
||||
<RotateTransform Angle="{Binding Angulo}" CenterX="0" CenterY="0"/>
|
||||
</Canvas.RenderTransform>
|
||||
|
||||
<local:GearControl ToothWidthRatio="{Binding Ancho_Dientes}" TeethCount="{Binding Dientes}"
|
||||
InnerRadius="{Binding Radio_Interno, Converter={StaticResource MeterToPixelConverter}}"
|
||||
OuterRadius="{Binding Radio_Externo, Converter={StaticResource MeterToPixelConverter}}"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -0,0 +1,233 @@
|
|||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using Newtonsoft.Json;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucGearEncoder.xaml
|
||||
/// </summary>
|
||||
public partial class osGearEncoder : osBase, IosBase
|
||||
{
|
||||
private osBase _osMotor = null;
|
||||
private Stopwatch Stopwatch = new Stopwatch();
|
||||
private double stopwatch_last = 0;
|
||||
|
||||
// Otros datos y métodos relevantes para la simulación
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Ruota Fonica";
|
||||
}
|
||||
|
||||
private string nombre = NombreClase();
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public string tag;
|
||||
[ObservableProperty]
|
||||
public bool pulso;
|
||||
|
||||
partial void OnPulsoChanged(bool value)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
var dTime = Stopwatch.ElapsedMilliseconds - stopwatch_last;
|
||||
stopwatch_last = Stopwatch.ElapsedMilliseconds;
|
||||
Tiempo_Pulso = (float)dTime;
|
||||
}
|
||||
|
||||
EscribirBitTag(Tag, Pulso);
|
||||
if (value)
|
||||
Color_oculto = Brushes.LightGreen;
|
||||
else
|
||||
Color_oculto = Brushes.Gray;
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private Brush color_oculto;
|
||||
[ObservableProperty]
|
||||
public float velocidadActual;
|
||||
[ObservableProperty]
|
||||
public double angulo;
|
||||
|
||||
partial void OnAnguloChanged(double value)
|
||||
{
|
||||
// Generar pulsos cuadrados en función del ángulo
|
||||
Pulso = DetectarDiente();
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float tiempo_Pulso;
|
||||
|
||||
[ObservableProperty]
|
||||
public float pulsos_Por_Segundo;
|
||||
|
||||
partial void OnPulsos_Por_SegundoChanged(float value)
|
||||
{
|
||||
if (VelocidadActual > 0)
|
||||
Giros_segundo_a_100 = (float)((pulsos_Por_Segundo / Dientes) * 100 / VelocidadActual);
|
||||
}
|
||||
[ObservableProperty]
|
||||
private bool homing;
|
||||
|
||||
partial void OnHomingChanged(bool value)
|
||||
{
|
||||
homing = false;
|
||||
Angulo = 0;
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float dientes;
|
||||
[ObservableProperty]
|
||||
public float radio_Interno;
|
||||
[ObservableProperty]
|
||||
public float radio_Externo;
|
||||
[ObservableProperty]
|
||||
public float ancho_Dientes;
|
||||
[ObservableProperty]
|
||||
public float giros_segundo_a_100;
|
||||
[ObservableProperty]
|
||||
public string motor;
|
||||
|
||||
partial void OnMotorChanged(string value)
|
||||
{
|
||||
_osMotor = ObtenerLink(Motor, typeof(osVMmotorSim));
|
||||
}
|
||||
|
||||
public osGearEncoder()
|
||||
{
|
||||
Ancho_Dientes = 0.5f;
|
||||
Dientes = 10;
|
||||
Radio_Interno = 0.5f;
|
||||
Radio_Externo = 0.6f;
|
||||
Color_oculto = Brushes.Gray;
|
||||
Stopwatch.Start();
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
|
||||
}
|
||||
public override void UpdatePLC(PLCModel 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()
|
||||
{
|
||||
double angleStep = 360.0 / Dientes;
|
||||
double halfToothWidthAngle = (angleStep * Ancho_Dientes) / 2;
|
||||
|
||||
// Normalize the Angulo to be within 0-360 degrees
|
||||
double normalizedAngle = Angulo % 360;
|
||||
if (normalizedAngle < 0) normalizedAngle += 360;
|
||||
|
||||
// Calculate the position of the first tooth's center at angle 0
|
||||
double firstToothCenterAngle = 0;
|
||||
|
||||
// Calculate the angular distance from the current angle to the first tooth's center
|
||||
double angularDistance = Math.Abs(firstToothCenterAngle - normalizedAngle);
|
||||
if (angularDistance > 180) angularDistance = 360 - angularDistance;
|
||||
|
||||
// Check if the normalized angle falls within the segment of the first tooth
|
||||
if (angularDistance <= halfToothWidthAngle)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Calculate the number of steps to reach the nearest tooth's center
|
||||
int steps = (int)Math.Round(normalizedAngle / angleStep);
|
||||
|
||||
// Calculate the angular position of the nearest tooth's center
|
||||
double nearestToothCenterAngle = steps * angleStep;
|
||||
|
||||
// Calculate the angular distance from the current angle to the nearest tooth's center
|
||||
angularDistance = Math.Abs(nearestToothCenterAngle - normalizedAngle);
|
||||
if (angularDistance > 180) angularDistance = 360 - angularDistance;
|
||||
|
||||
// Check if the normalized angle falls within the segment of the nearest tooth
|
||||
return angularDistance <= halfToothWidthAngle;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
ActualizarLeftTop();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ucGearEncoder : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucGearEncoder()
|
||||
{
|
||||
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) { }
|
||||
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()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucPhotocell"
|
||||
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.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>
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osPhotocell Color="#FFCA1C1C"/>
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<!-- Columna para el Label -->
|
||||
<ColumnDefinition Width="*"/>
|
||||
<!-- Columna para la Image -->
|
||||
<ColumnDefinition Width="*"/>
|
||||
<!-- Columna para el Rectangle -->
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.RenderTransform>
|
||||
<RotateTransform Angle="{Binding Angulo}" CenterX="0" CenterY="0"/>
|
||||
</Grid.RenderTransform>
|
||||
|
||||
<!-- Label en la primera columna -->
|
||||
<Label Content="{Binding Nombre}" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Column="0" Foreground="{Binding Color}" >
|
||||
|
||||
</Label>
|
||||
|
||||
<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"/>
|
||||
|
||||
<Rectangle x:Name="Photocell" Grid.Column="2" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding Alto, 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}"/>
|
||||
</Canvas>
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
</Rectangle.Fill>
|
||||
<!-- No se aplica la transformación aquí -->
|
||||
</Rectangle>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
|
@ -0,0 +1,180 @@
|
|||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Simulacion;
|
||||
using CtrEditor.Siemens;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucPhotocell.xaml
|
||||
/// </summary>
|
||||
public partial class osPhotocell : osBase, IosBase
|
||||
{
|
||||
private simBarrera Simulation_Photocell;
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Photocell";
|
||||
}
|
||||
private string nombre = NombreClase();
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public Brush color;
|
||||
[ObservableProperty]
|
||||
public bool luzCortada;
|
||||
|
||||
partial void OnLuzCortadaChanged(bool value)
|
||||
{
|
||||
if (LuzCortada)
|
||||
Color = Brushes.Blue;
|
||||
else
|
||||
Color = Brushes.Green;
|
||||
if (Tipo_NC)
|
||||
EscribirBitTag(TagPhotocell_OUT, !LuzCortada);
|
||||
else
|
||||
EscribirBitTag(TagPhotocell_OUT, LuzCortada);
|
||||
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public bool tipo_NC;
|
||||
|
||||
[ObservableProperty]
|
||||
public string tagPhotocell_OUT;
|
||||
|
||||
|
||||
public override void LeftChanged(float value)
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
public override void TopChanged(float value)
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float ancho;
|
||||
|
||||
partial void OnAnchoChanged(float value)
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float alto;
|
||||
|
||||
partial void OnAltoChanged(float value)
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float angulo;
|
||||
|
||||
partial void OnAnguloChanged(float value)
|
||||
{
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
private void ActualizarGeometrias()
|
||||
{
|
||||
if (_visualRepresentation is ucPhotocell uc)
|
||||
UpdateRectangle(Simulation_Photocell, uc.Photocell, Alto, Ancho, Angulo);
|
||||
}
|
||||
|
||||
public osPhotocell()
|
||||
{
|
||||
Ancho = 1;
|
||||
Alto = 0.03f;
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
public override void UpdateControl(int elapsedMilliseconds)
|
||||
{
|
||||
LuzCortada = Simulation_Photocell.LuzCortada;
|
||||
}
|
||||
public override void UpdateGeometryStep()
|
||||
{
|
||||
Simulation_Photocell.LuzCortada = false;
|
||||
}
|
||||
public override void UpdatePLC(PLCModel 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();
|
||||
|
||||
if (_visualRepresentation is ucPhotocell uc)
|
||||
Simulation_Photocell = AddBarrera(simulationManager, uc.Photocell, Alto, Ancho, Angulo);
|
||||
}
|
||||
public override void ucUnLoaded()
|
||||
{
|
||||
// El UserControl se esta eliminando
|
||||
// eliminar el objeto de simulacion
|
||||
simulationManager.Remove(Simulation_Photocell);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public partial class ucPhotocell : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucPhotocell()
|
||||
{
|
||||
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 (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()
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucSensTemperatura"
|
||||
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.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>
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osSensTemperatura />
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Grid>
|
||||
<Border x:Name="BackgroundRectangle"
|
||||
BorderBrush="Black"
|
||||
BorderThickness="2"
|
||||
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}, ConverterParameter=1.5}"
|
||||
VerticalAlignment="Top"
|
||||
Background="Gray"
|
||||
HorizontalAlignment="Center"
|
||||
Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}">
|
||||
<Grid>
|
||||
<Slider
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Orientation="Vertical"
|
||||
Value="{Binding Value}"
|
||||
Maximum="100"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -0,0 +1,117 @@
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucSensTemperatura.xaml
|
||||
/// </summary>
|
||||
public partial class osSensTemperatura : osBase, IosBase
|
||||
{
|
||||
// Otros datos y métodos relevantes para la simulación
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Temperatura";
|
||||
}
|
||||
private string nombre = NombreClase();
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public string tag;
|
||||
[ObservableProperty]
|
||||
public float min_OUT_Scaled;
|
||||
[ObservableProperty]
|
||||
public float max_OUT_Scaled;
|
||||
[ObservableProperty]
|
||||
public float value;
|
||||
|
||||
partial void OnValueChanged(float value)
|
||||
{
|
||||
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;
|
||||
Alto = 1f;
|
||||
Max_OUT_Scaled = 27648;
|
||||
Min_OUT_Scaled = 0;
|
||||
}
|
||||
|
||||
public override void UpdatePLC(PLCModel 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();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public partial class ucSensTemperatura : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucSensTemperatura()
|
||||
{
|
||||
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 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()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucAnalogTag"
|
||||
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"
|
||||
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>
|
||||
|
||||
<Grid Margin="10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border x:Name="BackgroundRectangle"
|
||||
BorderBrush="Black"
|
||||
BorderThickness="2"
|
||||
CornerRadius="10,0,0,10"
|
||||
Width="30"
|
||||
Height="40"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Left"
|
||||
Background="BlueViolet"/>
|
||||
<Label Content="{Binding Descripcion}" Grid.Column="1" VerticalAlignment="Center" Background="{Binding Color}" />
|
||||
<TextBox Grid.Column="2" Text="{Binding Value}" VerticalAlignment="Center" Width="80" TextAlignment="Center" Background="White"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucAnalogTag.xaml
|
||||
/// </summary>
|
||||
///
|
||||
|
||||
public partial class osAnalogTag : osBase, IosBase
|
||||
{
|
||||
|
||||
// Otros datos y métodos relevantes para la simulación
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Analog Tag";
|
||||
}
|
||||
private string nombre = NombreClase();
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float tamano;
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(Value))]
|
||||
public string tag;
|
||||
[ObservableProperty]
|
||||
public string descripcion;
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(Value))]
|
||||
public float min_IN_Scaled;
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(Value))]
|
||||
public float max_IN_Scaled;
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(Value))]
|
||||
public float min_OUT_Scaled;
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(Value))]
|
||||
public float max_OUT_Scaled;
|
||||
|
||||
[ObservableProperty]
|
||||
public float value;
|
||||
|
||||
partial void OnValueChanged(float value)
|
||||
{
|
||||
EscribirWordTagScaled(Tag, Value, Min_IN_Scaled, Max_IN_Scaled, Min_OUT_Scaled, Max_OUT_Scaled);
|
||||
}
|
||||
|
||||
public osAnalogTag()
|
||||
{
|
||||
Tamano = 0.30f;
|
||||
tag = "%MW50.0";
|
||||
Descripcion = "Nombre del Tag:";
|
||||
Max_OUT_Scaled = 27648;
|
||||
Min_OUT_Scaled = 0;
|
||||
min_IN_Scaled = 0;
|
||||
max_IN_Scaled = 100;
|
||||
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
|
||||
}
|
||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
||||
{
|
||||
}
|
||||
|
||||
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
|
||||
ActualizarLeftTop();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ucAnalogTag : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucAnalogTag()
|
||||
{
|
||||
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) { }
|
||||
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()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucBoolTag"
|
||||
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"
|
||||
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>
|
||||
<Grid Margin="10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border x:Name="BackgroundRectangle"
|
||||
BorderBrush="Black"
|
||||
BorderThickness="2"
|
||||
CornerRadius="10,0,0,10"
|
||||
Width="30"
|
||||
Height="40"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Left"
|
||||
Background="Gray"/>
|
||||
<Label Content="{Binding Descripcion}" Grid.Column="1" VerticalAlignment="Center" Background="{Binding Color}" />
|
||||
<CheckBox Grid.Column="2" VerticalAlignment="Center" IsChecked="{Binding Estado}" />
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -0,0 +1,106 @@
|
|||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucBoolTag.xaml
|
||||
/// </summary>
|
||||
///
|
||||
|
||||
public partial class osBoolTag : osBase, IosBase
|
||||
{
|
||||
|
||||
// Otros datos y métodos relevantes para la simulación
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Bool Tag";
|
||||
}
|
||||
private string nombre = NombreClase();
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private Brush color_oculto;
|
||||
|
||||
[ObservableProperty]
|
||||
public bool estado;
|
||||
|
||||
partial void OnEstadoChanged(bool value)
|
||||
{
|
||||
EscribirBitTag(Tag, value);
|
||||
if (value)
|
||||
Color_oculto = Brushes.LightGreen;
|
||||
else
|
||||
Color_oculto = Brushes.Transparent;
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float tamano;
|
||||
[ObservableProperty]
|
||||
[NotifyPropertyChangedFor(nameof(Estado))]
|
||||
public string tag;
|
||||
|
||||
[ObservableProperty]
|
||||
public string descripcion;
|
||||
|
||||
public osBoolTag()
|
||||
{
|
||||
Tamano = 0.30f;
|
||||
tag = "%M50.0";
|
||||
Descripcion = "Nombre del Tag";
|
||||
}
|
||||
|
||||
public override void ucLoaded()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ucBoolTag : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucBoolTag()
|
||||
{
|
||||
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) { }
|
||||
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()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucConsensGeneric"
|
||||
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"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores"
|
||||
Background="LightGray">
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osConsensGeneric />
|
||||
</UserControl.DataContext>
|
||||
|
||||
<!-- PanelEdicion con borde superior -->
|
||||
<Border BorderBrush="LightGreen" BorderThickness="0,10,0,0">
|
||||
<ScrollViewer Margin="5" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel x:Name="PanelEdicion">
|
||||
<!-- Aquí puedes agregar los controles para editar propiedades -->
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</UserControl>
|
|
@ -0,0 +1,92 @@
|
|||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucConsensGeneric.xaml
|
||||
/// </summary>
|
||||
public partial class osConsensGeneric : osBase, IosBase
|
||||
{
|
||||
|
||||
public TagsConsensos Consensos = new TagsConsensos();
|
||||
|
||||
[ObservableProperty]
|
||||
public List<string> tags;
|
||||
|
||||
// Otros datos y métodos relevantes para la simulación
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Consensi";
|
||||
}
|
||||
private string nombre = NombreClase();
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public float tamano;
|
||||
|
||||
public override void ucLoaded()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
|
||||
if (_visualRepresentation is ucConsensGeneric uc)
|
||||
Tags = UserControlFactory.CargarPropiedadesosDatosTags(Consensos, uc.PanelEdicion, null);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ucConsensGeneric : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucConsensGeneric()
|
||||
{
|
||||
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) { }
|
||||
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()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
public class TagsConsensos
|
||||
{
|
||||
public string Tag { get; set; }
|
||||
public bool Consenso_Uscita { get; set; }
|
||||
public string Velocidad { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
using CtrEditor.Simulacion;
|
||||
using System.Reflection;
|
||||
using CtrEditor.Convertidores;
|
||||
using System.Windows.Data;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using CtrEditor.ObjetosSim.UserControls;
|
||||
using System.Collections;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
|
@ -12,43 +15,42 @@ namespace CtrEditor.ObjetosSim
|
|||
{
|
||||
public static UserControl? GetControlForType(Type tipoObjeto)
|
||||
{
|
||||
if (tipoObjeto == typeof(osBotella))
|
||||
return new ucBotella();
|
||||
if (tipoObjeto == typeof(osTransporteTTop))
|
||||
return new ucTransporteTTop();
|
||||
if (tipoObjeto == typeof(osGuia))
|
||||
return new ucGuia();
|
||||
if (tipoObjeto == typeof(osTransporteGuias))
|
||||
return new ucTransporteGuias();
|
||||
if (tipoObjeto == typeof(osTransporteCurva))
|
||||
return new ucTransporteCurva();
|
||||
if (tipoObjeto == typeof(osVMmotorSim ))
|
||||
return new ucVMmotorSim();
|
||||
// Obtener el nombre del tipo de objeto
|
||||
string typeName = tipoObjeto.Name;
|
||||
|
||||
// Puedes añadir más condiciones para otros tipos
|
||||
// Cambiar las primeras dos letras de 'os' a 'uc'
|
||||
if (typeName.StartsWith("os"))
|
||||
{
|
||||
string newTypeName = "uc" + typeName.Substring(2);
|
||||
|
||||
// Obtener el ensamblado donde se encuentra el tipo UserControl
|
||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||
|
||||
// Buscar el tipo en los ensamblados cargados
|
||||
Type? controlType = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(a => a.GetTypes())
|
||||
.FirstOrDefault(t => t.Name == newTypeName);
|
||||
|
||||
if (controlType != null && typeof(UserControl).IsAssignableFrom(controlType))
|
||||
{
|
||||
// Crear una instancia del tipo encontrado
|
||||
return (UserControl?)Activator.CreateInstance(controlType);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static osBase? GetInstanceForType(Type tipoObjeto)
|
||||
{
|
||||
if (tipoObjeto == typeof(osBotella))
|
||||
return new osBotella();
|
||||
if (tipoObjeto == typeof(osTransporteTTop))
|
||||
return new osTransporteTTop();
|
||||
if (tipoObjeto == typeof(osGuia))
|
||||
return new osGuia();
|
||||
if (tipoObjeto == typeof(osTransporteGuias))
|
||||
return new osTransporteGuias();
|
||||
if (tipoObjeto == typeof(osTransporteCurva))
|
||||
return new osTransporteCurva();
|
||||
if (tipoObjeto == typeof(osVMmotorSim))
|
||||
return new osVMmotorSim();
|
||||
// Verifica si el tipo pasado es un subtipo de osBase
|
||||
if (!typeof(osBase).IsAssignableFrom(tipoObjeto))
|
||||
{
|
||||
throw new ArgumentException("El tipo pasado no es un subtipo de osBase", nameof(tipoObjeto));
|
||||
}
|
||||
|
||||
|
||||
// Puedes añadir más condiciones para otros tipos
|
||||
|
||||
return null;
|
||||
// Crear una instancia del tipo especificado
|
||||
return (osBase?)Activator.CreateInstance(tipoObjeto);
|
||||
}
|
||||
|
||||
public static osBase? CreateInstanceAndPopulate(Type tipoObjeto, string jsonString)
|
||||
|
@ -62,17 +64,298 @@ namespace CtrEditor.ObjetosSim
|
|||
return instance;
|
||||
}
|
||||
|
||||
public static void AssignDatos(UserControl userControl, osBase datos, SimulationManager simulationManager)
|
||||
public static void AssignDatos(UserControl userControl, osBase datos, SimulationManagerFP simulationManager)
|
||||
{
|
||||
if (userControl is IDataContainer dataContainer)
|
||||
{
|
||||
dataContainer.Datos = datos;
|
||||
userControl.DataContext = datos;
|
||||
datos.VisualRepresentation = userControl;
|
||||
datos.ConnectSimManager(simulationManager);
|
||||
datos.simulationManager = simulationManager;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void CargarPropiedadesosDatos(Object selectedObject, StackPanel PanelEdicion, ResourceDictionary Resources)
|
||||
{
|
||||
PanelEdicion.Children.Clear();
|
||||
var properties = selectedObject.GetType().GetProperties();
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
if (Attribute.IsDefined(property, typeof(HiddenAttribute)))
|
||||
continue;
|
||||
if (property.Name.EndsWith("_oculto"))
|
||||
continue;
|
||||
|
||||
var grid = new Grid();
|
||||
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
|
||||
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
|
||||
|
||||
var label = new Label
|
||||
{
|
||||
Content = property.Name.Replace("_", " ") + ":",
|
||||
Margin = new Thickness(0, 0, 5, 0),
|
||||
VerticalAlignment = VerticalAlignment.Center
|
||||
};
|
||||
|
||||
Grid.SetColumn(label, 0);
|
||||
grid.Children.Add(label);
|
||||
|
||||
if (property.PropertyType == typeof(double) || property.PropertyType == typeof(float) || property.PropertyType == typeof(string) || property.PropertyType == typeof(int))
|
||||
{
|
||||
var textBox = new TextBox
|
||||
{
|
||||
Margin = new Thickness(0),
|
||||
MinWidth = 200,
|
||||
VerticalContentAlignment = VerticalAlignment.Center
|
||||
};
|
||||
|
||||
var binding = new Binding(property.Name)
|
||||
{
|
||||
Source = selectedObject,
|
||||
Mode = BindingMode.TwoWay,
|
||||
UpdateSourceTrigger = UpdateSourceTrigger.LostFocus
|
||||
};
|
||||
|
||||
if (property.PropertyType == typeof(float))
|
||||
{
|
||||
if (Resources != null)
|
||||
binding.Converter = (FloatToFormattedStringConverter)Resources["floatFormatter"];
|
||||
}
|
||||
if (property.PropertyType == typeof(double))
|
||||
{
|
||||
if (Resources != null)
|
||||
binding.Converter = (DoubleToFormattedStringConverter)Resources["doubleFormatter"];
|
||||
}
|
||||
|
||||
textBox.SetBinding(TextBox.TextProperty, binding);
|
||||
|
||||
Grid.SetColumn(textBox, 1);
|
||||
grid.Children.Add(textBox);
|
||||
}
|
||||
else if (property.PropertyType == typeof(bool))
|
||||
{
|
||||
var checkBox = new CheckBox
|
||||
{
|
||||
Margin = new Thickness(5, 0, 0, 0),
|
||||
VerticalAlignment = VerticalAlignment.Center
|
||||
};
|
||||
|
||||
var binding = new Binding(property.Name)
|
||||
{
|
||||
Source = selectedObject,
|
||||
Mode = BindingMode.TwoWay
|
||||
};
|
||||
|
||||
checkBox.SetBinding(CheckBox.IsCheckedProperty, binding);
|
||||
|
||||
Grid.SetColumn(checkBox, 1);
|
||||
grid.Children.Add(checkBox);
|
||||
}
|
||||
else if (property.PropertyType == typeof(Brush))
|
||||
{
|
||||
var listBox = new ListBox
|
||||
{
|
||||
ItemsSource = new List<string> { "Rojo", "Azul", "Negro", "Verde", "Gris" },
|
||||
Margin = new Thickness(0),
|
||||
MinWidth = 200
|
||||
};
|
||||
|
||||
listBox.SelectionChanged += (sender, e) =>
|
||||
{
|
||||
if (listBox.SelectedItem != null)
|
||||
{
|
||||
switch (listBox.SelectedItem.ToString())
|
||||
{
|
||||
case "Rojo":
|
||||
property.SetValue(selectedObject, Brushes.Red);
|
||||
break;
|
||||
case "Azul":
|
||||
property.SetValue(selectedObject, Brushes.Blue);
|
||||
break;
|
||||
case "Negro":
|
||||
property.SetValue(selectedObject, Brushes.Black);
|
||||
break;
|
||||
case "Verde":
|
||||
property.SetValue(selectedObject, Brushes.Green);
|
||||
break;
|
||||
case "Gris":
|
||||
property.SetValue(selectedObject, Brushes.Gray);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var binding = new Binding(property.Name)
|
||||
{
|
||||
Source = selectedObject,
|
||||
Mode = BindingMode.TwoWay,
|
||||
Converter = new BrushToColorNameConverter()
|
||||
};
|
||||
|
||||
listBox.SetBinding(ListBox.SelectedItemProperty, binding);
|
||||
|
||||
Grid.SetColumn(listBox, 1);
|
||||
grid.Children.Add(listBox);
|
||||
}
|
||||
PanelEdicion.Children.Add(grid);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<string> CargarPropiedadesosDatosTags(Object selectedObject, StackPanel PanelEdicion, ResourceDictionary Resources)
|
||||
{
|
||||
PanelEdicion.Children.Clear();
|
||||
var properties = selectedObject.GetType().GetProperties();
|
||||
List<string> tags = new List<string>();
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
if (Attribute.IsDefined(property, typeof(HiddenAttribute)))
|
||||
continue;
|
||||
if (property.Name.EndsWith("_oculto"))
|
||||
continue;
|
||||
|
||||
var grid = new Grid();
|
||||
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
|
||||
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
|
||||
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
|
||||
|
||||
var label = new Label
|
||||
{
|
||||
Content = property.Name.Replace("_", " ") + ":",
|
||||
Margin = new Thickness(0, 0, 5, 0),
|
||||
VerticalAlignment = VerticalAlignment.Center
|
||||
};
|
||||
|
||||
Grid.SetColumn(label, 0);
|
||||
grid.Children.Add(label);
|
||||
|
||||
if (property.PropertyType == typeof(double) || property.PropertyType == typeof(float) || property.PropertyType == typeof(string) || property.PropertyType == typeof(int))
|
||||
{
|
||||
var textBox = new TextBox
|
||||
{
|
||||
Margin = new Thickness(0),
|
||||
MinWidth = 200,
|
||||
VerticalContentAlignment = VerticalAlignment.Center
|
||||
};
|
||||
|
||||
var binding = new Binding(property.Name)
|
||||
{
|
||||
Source = selectedObject,
|
||||
Mode = BindingMode.TwoWay,
|
||||
UpdateSourceTrigger = UpdateSourceTrigger.LostFocus
|
||||
};
|
||||
|
||||
if (property.PropertyType == typeof(float))
|
||||
{
|
||||
if (Resources != null)
|
||||
binding.Converter = (FloatToFormattedStringConverter)Resources["floatFormatter"];
|
||||
}
|
||||
if (property.PropertyType == typeof(double))
|
||||
{
|
||||
if (Resources != null)
|
||||
binding.Converter = (DoubleToFormattedStringConverter)Resources["doubleFormatter"];
|
||||
}
|
||||
|
||||
textBox.SetBinding(TextBox.TextProperty, binding);
|
||||
|
||||
Grid.SetColumn(textBox, 1);
|
||||
grid.Children.Add(textBox);
|
||||
|
||||
var tagTextBox = new TextBox
|
||||
{
|
||||
Margin = new Thickness(0),
|
||||
MinWidth = 100,
|
||||
VerticalContentAlignment = VerticalAlignment.Center
|
||||
};
|
||||
|
||||
// Add an empty string to the tags list and get the index
|
||||
tags.Add(string.Empty);
|
||||
int tagIndex = tags.Count - 1;
|
||||
|
||||
// Event handler to update the tags list when the text changes
|
||||
tagTextBox.TextChanged += (sender, args) =>
|
||||
{
|
||||
tags[tagIndex] = tagTextBox.Text;
|
||||
};
|
||||
|
||||
Grid.SetColumn(tagTextBox, 2);
|
||||
grid.Children.Add(tagTextBox);
|
||||
}
|
||||
else if (property.PropertyType == typeof(bool))
|
||||
{
|
||||
var checkBox = new CheckBox
|
||||
{
|
||||
Margin = new Thickness(5, 0, 0, 0),
|
||||
VerticalAlignment = VerticalAlignment.Center
|
||||
};
|
||||
|
||||
var binding = new Binding(property.Name)
|
||||
{
|
||||
Source = selectedObject,
|
||||
Mode = BindingMode.TwoWay
|
||||
};
|
||||
|
||||
checkBox.SetBinding(CheckBox.IsCheckedProperty, binding);
|
||||
|
||||
Grid.SetColumn(checkBox, 1);
|
||||
grid.Children.Add(checkBox);
|
||||
}
|
||||
else if (property.PropertyType == typeof(Brush))
|
||||
{
|
||||
var listBox = new ListBox
|
||||
{
|
||||
ItemsSource = new List<string> { "Rojo", "Azul", "Negro", "Verde", "Gris" },
|
||||
Margin = new Thickness(0),
|
||||
MinWidth = 200
|
||||
};
|
||||
|
||||
listBox.SelectionChanged += (sender, e) =>
|
||||
{
|
||||
if (listBox.SelectedItem != null)
|
||||
{
|
||||
switch (listBox.SelectedItem.ToString())
|
||||
{
|
||||
case "Rojo":
|
||||
property.SetValue(selectedObject, Brushes.Red);
|
||||
break;
|
||||
case "Azul":
|
||||
property.SetValue(selectedObject, Brushes.Blue);
|
||||
break;
|
||||
case "Negro":
|
||||
property.SetValue(selectedObject, Brushes.Black);
|
||||
break;
|
||||
case "Verde":
|
||||
property.SetValue(selectedObject, Brushes.Green);
|
||||
break;
|
||||
case "Gris":
|
||||
property.SetValue(selectedObject, Brushes.Gray);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var binding = new Binding(property.Name)
|
||||
{
|
||||
Source = selectedObject,
|
||||
Mode = BindingMode.TwoWay,
|
||||
Converter = new BrushToColorNameConverter()
|
||||
};
|
||||
|
||||
listBox.SetBinding(ListBox.SelectedItemProperty, binding);
|
||||
|
||||
Grid.SetColumn(listBox, 1);
|
||||
grid.Children.Add(listBox);
|
||||
}
|
||||
|
||||
PanelEdicion.Children.Add(grid);
|
||||
}
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace CtrEditor.ObjetosSim.UserControls
|
||||
{
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.UserControls.GearControl"
|
||||
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.ObjetosSim.UserControls"
|
||||
mc:Ignorable="d" Name="circularSegmentControl">
|
||||
<Grid>
|
||||
<Canvas x:Name="GearCanvas" />
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -0,0 +1,129 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace CtrEditor.ObjetosSim.UserControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for GearControl.xaml
|
||||
/// </summary>
|
||||
public partial class GearControl : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty TeethCountProperty =
|
||||
DependencyProperty.Register("TeethCount", typeof(int), typeof(GearControl),
|
||||
new PropertyMetadata(10, OnGearPropertyChanged));
|
||||
|
||||
public static readonly DependencyProperty InnerRadiusProperty =
|
||||
DependencyProperty.Register("InnerRadius", typeof(double), typeof(GearControl),
|
||||
new PropertyMetadata(40.0, OnGearPropertyChanged));
|
||||
|
||||
public static readonly DependencyProperty OuterRadiusProperty =
|
||||
DependencyProperty.Register("OuterRadius", typeof(double), typeof(GearControl),
|
||||
new PropertyMetadata(60.0, OnGearPropertyChanged));
|
||||
|
||||
public static readonly DependencyProperty ToothWidthRatioProperty =
|
||||
DependencyProperty.Register("ToothWidthRatio", typeof(double), typeof(GearControl),
|
||||
new PropertyMetadata(0.5, OnGearPropertyChanged));
|
||||
|
||||
public int TeethCount
|
||||
{
|
||||
get { return (int)GetValue(TeethCountProperty); }
|
||||
set { SetValue(TeethCountProperty, value); }
|
||||
}
|
||||
|
||||
public double InnerRadius
|
||||
{
|
||||
get { return (double)GetValue(InnerRadiusProperty); }
|
||||
set { SetValue(InnerRadiusProperty, value); }
|
||||
}
|
||||
|
||||
public double OuterRadius
|
||||
{
|
||||
get { return (double)GetValue(OuterRadiusProperty); }
|
||||
set { SetValue(OuterRadiusProperty, value); }
|
||||
}
|
||||
|
||||
public double ToothWidthRatio
|
||||
{
|
||||
get { return (double)GetValue(ToothWidthRatioProperty); }
|
||||
set { SetValue(ToothWidthRatioProperty, value); }
|
||||
}
|
||||
|
||||
public GearControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
DrawGear();
|
||||
}
|
||||
|
||||
private static void OnGearPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var control = d as GearControl;
|
||||
control?.DrawGear();
|
||||
}
|
||||
|
||||
private void DrawGear()
|
||||
{
|
||||
GearCanvas.Children.Clear();
|
||||
double centerX = ActualWidth / 2;
|
||||
double centerY = ActualHeight / 2;
|
||||
double angleStep = 360.0 / TeethCount;
|
||||
double toothWidthAngle = angleStep * ToothWidthRatio;
|
||||
|
||||
// Draw inner circle
|
||||
Ellipse innerCircle = new Ellipse
|
||||
{
|
||||
Width = InnerRadius * 2,
|
||||
Height = InnerRadius * 2,
|
||||
Stroke = Brushes.Black,
|
||||
StrokeThickness = 2,
|
||||
Fill = Brushes.Gray
|
||||
};
|
||||
|
||||
Canvas.SetLeft(innerCircle, centerX - InnerRadius);
|
||||
Canvas.SetTop(innerCircle, centerY - InnerRadius);
|
||||
GearCanvas.Children.Add(innerCircle);
|
||||
|
||||
// Draw the zero angle marker
|
||||
double zeroAngle = 0;
|
||||
double radianZero = zeroAngle * Math.PI / 180;
|
||||
double markerLength = InnerRadius * 1.2; // Length of the marker line extending outside the inner circle
|
||||
|
||||
Line zeroAngleMarker = new Line
|
||||
{
|
||||
X1 = centerX,
|
||||
Y1 = centerY,
|
||||
X2 = centerX + markerLength * Math.Cos(radianZero),
|
||||
Y2 = centerY - markerLength * Math.Sin(radianZero),
|
||||
Stroke = Brushes.Red,
|
||||
StrokeThickness = 2
|
||||
};
|
||||
GearCanvas.Children.Add(zeroAngleMarker);
|
||||
|
||||
for (int i = 0; i < TeethCount; i++)
|
||||
{
|
||||
// Offset the angle to center the first tooth on the 0 angle
|
||||
double angle = i * angleStep;
|
||||
double radianStart = (angle - toothWidthAngle / 2) * Math.PI / 180;
|
||||
double radianEnd = (angle + toothWidthAngle / 2) * Math.PI / 180;
|
||||
|
||||
Point p1 = new Point(centerX + InnerRadius * Math.Cos(radianStart), centerY + InnerRadius * Math.Sin(radianStart));
|
||||
Point p2 = new Point(centerX + OuterRadius * Math.Cos(radianStart), centerY + OuterRadius * Math.Sin(radianStart));
|
||||
Point p3 = new Point(centerX + OuterRadius * Math.Cos(radianEnd), centerY + OuterRadius * Math.Sin(radianEnd));
|
||||
Point p4 = new Point(centerX + InnerRadius * Math.Cos(radianEnd), centerY + InnerRadius * Math.Sin(radianEnd));
|
||||
|
||||
Polygon tooth = new Polygon
|
||||
{
|
||||
Fill = Brushes.Black,
|
||||
Points = new PointCollection { p1, p2, p3, p4 }
|
||||
};
|
||||
|
||||
GearCanvas.Children.Add(tooth);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -12,6 +12,16 @@ using System.Windows.Controls;
|
|||
using System.Windows.Data;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using CtrEditor.Simulacion;
|
||||
using System.Windows.Media;
|
||||
using nkast.Aether.Physics2D.Common;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using Siemens.Simatic.Simulation.Runtime;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Input;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
|
@ -20,14 +30,12 @@ namespace CtrEditor.ObjetosSim
|
|||
|
||||
public interface IosBase
|
||||
{
|
||||
string Nombre { get; }
|
||||
|
||||
void ConnectSimManager(SimulationManager simulationManager);
|
||||
void UpdateControl();
|
||||
static abstract string NombreClase();
|
||||
}
|
||||
|
||||
public interface IDataContainer
|
||||
{
|
||||
[JsonIgnore]
|
||||
osBase? Datos { get; set; }
|
||||
void Resize(float width, float height);
|
||||
void Move(float Left, float Top);
|
||||
|
@ -36,20 +44,91 @@ namespace CtrEditor.ObjetosSim
|
|||
int ZIndex();
|
||||
}
|
||||
|
||||
public abstract class osBase : INotifyPropertyChanged, IosBase
|
||||
{
|
||||
public abstract float Left { get; set; }
|
||||
public abstract float Top { get; set; }
|
||||
public class DataSaveToSerialize
|
||||
{
|
||||
private MainViewModel? _mainViewModel;
|
||||
private UserControl? VisualRepresentation;
|
||||
private SimulationManagerFP? simulationManager;
|
||||
|
||||
public DataSaveToSerialize(MainViewModel a, UserControl b, SimulationManagerFP c )
|
||||
{
|
||||
_mainViewModel = a;
|
||||
VisualRepresentation = b;
|
||||
simulationManager = c;
|
||||
}
|
||||
|
||||
public void DataRestoreAfterSerialize(out MainViewModel a, out UserControl b, out SimulationManagerFP c)
|
||||
{
|
||||
a = _mainViewModel;
|
||||
b = VisualRepresentation;
|
||||
c = simulationManager;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public abstract partial class osBase : ObservableObject
|
||||
{
|
||||
public virtual string Nombre { get; set; } = "osBase";
|
||||
[JsonIgnore]
|
||||
private Storyboard _storyboard;
|
||||
|
||||
[ObservableProperty]
|
||||
private float left;
|
||||
|
||||
partial void OnLeftChanged(float value)
|
||||
{
|
||||
CanvasSetLeftinMeter(value);
|
||||
LeftChanged(value);
|
||||
}
|
||||
public virtual void LeftChanged(float value) { }
|
||||
|
||||
[ObservableProperty]
|
||||
private float top;
|
||||
|
||||
partial void OnTopChanged(float value)
|
||||
{
|
||||
CanvasSetTopinMeter(value);
|
||||
TopChanged(value);
|
||||
}
|
||||
|
||||
public virtual void TopChanged(float value) { }
|
||||
|
||||
|
||||
public bool Inicializado = false;
|
||||
|
||||
public bool AutoCreated = false;
|
||||
public bool RemoverDesdeSimulacion = false; // La simulacion indica que se debe remover
|
||||
|
||||
[JsonIgnore]
|
||||
private DataSaveToSerialize DataSave;
|
||||
|
||||
[JsonIgnore]
|
||||
protected UserControl? _visualRepresentation = null;
|
||||
|
||||
public abstract string Nombre { get; set; }
|
||||
[JsonIgnore]
|
||||
protected PLCModel? _plc = null;
|
||||
|
||||
public abstract void ConnectSimManager(SimulationManager simulationManager);
|
||||
public abstract void UpdateControl();
|
||||
public abstract void UpdateGeometry();
|
||||
public virtual void UpdateControl(int elapsedMilliseconds) { }
|
||||
public virtual void UpdateGeometryStart()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
}
|
||||
public virtual void SimulationStop() { }
|
||||
public virtual void UpdateGeometryStep() { }
|
||||
public virtual void UpdatePLC(PLCModel plc, int elapsedMilliseconds) { }
|
||||
public virtual void ucLoaded()
|
||||
{
|
||||
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
|
||||
// crear el objeto de simulacion
|
||||
ActualizarLeftTop();
|
||||
}
|
||||
public virtual void ucUnLoaded()
|
||||
{
|
||||
// El UserControl se esta eliminando
|
||||
// eliminar el objeto de simulacion
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public MainViewModel _mainViewModel;
|
||||
|
||||
[JsonIgnore]
|
||||
public UserControl? VisualRepresentation
|
||||
|
@ -57,11 +136,132 @@ namespace CtrEditor.ObjetosSim
|
|||
get => _visualRepresentation;
|
||||
set => _visualRepresentation = value;
|
||||
}
|
||||
[JsonIgnore]
|
||||
public SimulationManagerFP simulationManager;
|
||||
|
||||
public void SalvarDatosNoSerializables()
|
||||
{
|
||||
DataSave = new DataSaveToSerialize(_mainViewModel,_visualRepresentation,simulationManager);
|
||||
_mainViewModel = null;
|
||||
_visualRepresentation = null;
|
||||
simulationManager = null;
|
||||
}
|
||||
public void RestaurarDatosNoSerializables()
|
||||
{
|
||||
if (DataSave == null) return;
|
||||
DataSave.DataRestoreAfterSerialize(out _mainViewModel,out _visualRepresentation,out simulationManager);
|
||||
}
|
||||
|
||||
public void SetPLC(PLCModel plc)
|
||||
{
|
||||
_plc = plc;
|
||||
}
|
||||
|
||||
protected osBase ObtenerLink(string NameLink, Type tipoOsBase)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(NameLink) && _mainViewModel != null)
|
||||
{
|
||||
foreach (var objetoSimulable in _mainViewModel.ObjetosSimulables)
|
||||
{
|
||||
if (tipoOsBase.IsInstanceOfType(objetoSimulable) && objetoSimulable.Nombre == NameLink)
|
||||
{
|
||||
return objetoSimulable;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void CrearAnimacionStoryBoardTrasnporte(System.Windows.Shapes.Rectangle transporte)
|
||||
{
|
||||
if (_visualRepresentation == null) return;
|
||||
if (transporte == null) return;
|
||||
|
||||
_storyboard = new Storyboard();
|
||||
var animation = new DoubleAnimation
|
||||
{
|
||||
From = 0,
|
||||
To = 20, // Total Pixels Brush
|
||||
Duration = TimeSpan.FromSeconds(PixelToMeter.Instance.calc.PixelsToMeters(20) * 60),
|
||||
RepeatBehavior = RepeatBehavior.Forever
|
||||
};
|
||||
Storyboard.SetTarget(animation, transporte);
|
||||
Storyboard.SetTargetProperty(animation, new PropertyPath("(Rectangle.Fill).(VisualBrush.Transform).(TransformGroup.Children)[0].(TranslateTransform.X)"));
|
||||
_storyboard.Children.Add(animation);
|
||||
_storyboard.Begin();
|
||||
_storyboard.SetSpeedRatio(0);
|
||||
}
|
||||
|
||||
protected void ActualizarAnimacionStoryBoardTransporte(float velocidadActual)
|
||||
{
|
||||
if (_visualRepresentation == null) return;
|
||||
if (_storyboard == null) return;
|
||||
|
||||
if (!_mainViewModel.IsSimulationRunning)
|
||||
_storyboard.SetSpeedRatio(0);
|
||||
else
|
||||
_storyboard.SetSpeedRatio(velocidadActual);
|
||||
}
|
||||
|
||||
public void ActualizarLeftTop()
|
||||
{
|
||||
CanvasSetLeftinMeter(Left);
|
||||
CanvasSetTopinMeter(Top);
|
||||
}
|
||||
|
||||
public bool LeerBitTag(string Tag)
|
||||
{
|
||||
if (this._plc == null) return false;
|
||||
if (!string.IsNullOrEmpty(Tag))
|
||||
{
|
||||
if (Tag == "1") return true;
|
||||
else if (Tag == "0") return false;
|
||||
if (_plc != null)
|
||||
return _plc.LeerTagBool(Tag);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void EscribirBitTag(string Tag, bool Value)
|
||||
{
|
||||
if (_plc == null) return;
|
||||
if (!string.IsNullOrEmpty(Tag))
|
||||
if (_plc != null)
|
||||
_plc.EscribirTagBool(Tag, Value);
|
||||
}
|
||||
|
||||
public void EscribirWordTagScaled(string Tag, float Value, float IN_scale_Min, float IN_scale_Max, float OUT_scale_Min, float OUT_scale_Max)
|
||||
{
|
||||
if (_plc == null) return;
|
||||
if (!string.IsNullOrEmpty(Tag))
|
||||
{
|
||||
SDataValue plcData = new SDataValue();
|
||||
plcData.UInt16 = (ushort)((Value - IN_scale_Min) / (IN_scale_Max - IN_scale_Min) * (OUT_scale_Max - OUT_scale_Min) + OUT_scale_Min);
|
||||
_plc.EscribirTag(Tag, plcData);
|
||||
}
|
||||
}
|
||||
|
||||
public float LeerWordTagScaled(PLCModel _plc, string Tag, float IN_scale_Min, float IN_scale_Max, float OUT_scale_Min, float OUT_scale_Max)
|
||||
{
|
||||
if (_plc == null) return 0;
|
||||
if (!string.IsNullOrEmpty(Tag))
|
||||
{
|
||||
if (float.TryParse(Tag, out float v))
|
||||
return v;
|
||||
if (_plc != null)
|
||||
{
|
||||
SDataValue plcData = _plc.LeerTag(Tag);
|
||||
float Value = plcData.UInt16; // WORD
|
||||
return (Value - OUT_scale_Min) / (OUT_scale_Max - OUT_scale_Min) * (IN_scale_Max - IN_scale_Min) + IN_scale_Min;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void CanvasSetLeftinMeter(float left)
|
||||
{
|
||||
if (_visualRepresentation != null)
|
||||
Canvas.SetLeft(_visualRepresentation, PixelToMeter.Instance.calc.MetersToPixels(left));
|
||||
Canvas.SetLeft(_visualRepresentation, PixelToMeter.Instance.calc.MetersToPixels(left));
|
||||
}
|
||||
public float CanvasGetLeftinMeter()
|
||||
{
|
||||
|
@ -82,16 +282,151 @@ namespace CtrEditor.ObjetosSim
|
|||
else return 0f;
|
||||
}
|
||||
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
protected virtual void OnPropertyChanged(string propertyName)
|
||||
public (Vector2 TopLeft, Vector2 BottomRight) GetRectangleCoordinatesInMeter(System.Windows.Shapes.Rectangle rect)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
if (rect != null)
|
||||
{
|
||||
var _canvasLeft = CanvasGetLeftinMeter();
|
||||
var _canvasTop = CanvasGetTopinMeter();
|
||||
|
||||
// Obtiene la transformada del objeto visual
|
||||
GeneralTransform transform = rect.TransformToAncestor(_visualRepresentation);
|
||||
|
||||
// Obtiene la posición absoluta
|
||||
Point topLeft = transform.Transform(new Point(0, 0));
|
||||
Point bottomRight = transform.Transform(new Point(rect.ActualWidth, rect.ActualHeight));
|
||||
|
||||
return (new Vector2(PixelToMeter.Instance.calc.PixelsToMeters((float)topLeft.X) + _canvasLeft, PixelToMeter.Instance.calc.PixelsToMeters((float)topLeft.Y) + _canvasTop),
|
||||
new Vector2(PixelToMeter.Instance.calc.PixelsToMeters((float)bottomRight.X) + _canvasLeft, PixelToMeter.Instance.calc.PixelsToMeters((float)bottomRight.Y) + _canvasTop));
|
||||
}
|
||||
else return (new Vector2(0, 0), new Vector2(0, 0));
|
||||
}
|
||||
|
||||
public (Vector2 Start, Vector2 End) GetCenterLineVectors(System.Windows.Shapes.Rectangle rect)
|
||||
{
|
||||
if (rect == null)
|
||||
return (new Vector2(0, 0), new Vector2(0, 0));
|
||||
|
||||
var _canvasLeft = CanvasGetLeftinMeter();
|
||||
var _canvasTop = CanvasGetTopinMeter();
|
||||
|
||||
var transform = rect.TransformToAncestor(_visualRepresentation);
|
||||
|
||||
// Puntos en coordenadas locales del rectángulo no rotado
|
||||
Point startLocal = new Point(0, rect.ActualHeight / 2);
|
||||
Point endLocal = new Point(rect.ActualWidth, rect.ActualHeight / 2);
|
||||
|
||||
// Transformar estos puntos al sistema de coordenadas del ancestro
|
||||
Point transformedStart = transform.Transform(startLocal);
|
||||
Point transformedEnd = transform.Transform(endLocal);
|
||||
|
||||
// Convierte a unidades de Farseer (metros en este caso)
|
||||
Vector2 start = new Vector2(PixelToMeter.Instance.calc.PixelsToMeters((float)transformedStart.X) + _canvasLeft, PixelToMeter.Instance.calc.PixelsToMeters((float)transformedStart.Y) + _canvasTop);
|
||||
Vector2 end = new Vector2(PixelToMeter.Instance.calc.PixelsToMeters((float)transformedEnd.X) + _canvasLeft, PixelToMeter.Instance.calc.PixelsToMeters((float)transformedEnd.Y) + _canvasTop);
|
||||
|
||||
return (start, end);
|
||||
}
|
||||
|
||||
public Vector2 GetCurveCenterInMeter(float RadioExterno)
|
||||
{
|
||||
var _canvasLeft = CanvasGetLeftinMeter();
|
||||
var _canvasTop = CanvasGetTopinMeter();
|
||||
|
||||
// El centro del Canvas
|
||||
double centerX = RadioExterno + _canvasLeft;
|
||||
double centerY = RadioExterno + _canvasTop;
|
||||
|
||||
// Convertir a Vector2
|
||||
return new Vector2((float)centerX, (float)centerY);
|
||||
}
|
||||
|
||||
public Vector2 GetRectangleCenter(System.Windows.Shapes.Rectangle wpfRect)
|
||||
{
|
||||
var coords = GetRectangleCoordinatesInMeter(wpfRect);
|
||||
|
||||
Vector2 topLeft = coords.TopLeft;
|
||||
Vector2 bottomRight = coords.BottomRight;
|
||||
|
||||
// Calcular el centro, ancho y alto en metros
|
||||
return new Vector2((topLeft.X + bottomRight.X) / 2, (topLeft.Y + bottomRight.Y) / 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void UpdateRectangle(simTransporte simRect, System.Windows.Shapes.Rectangle wpfRect, float Alto, float Ancho, float Angulo)
|
||||
{
|
||||
if (simRect != null)
|
||||
simRect.Create(Ancho, Alto, GetRectangleCenter(wpfRect), Angulo);
|
||||
}
|
||||
|
||||
public void UpdateRectangle(simBarrera simRect, System.Windows.Shapes.Rectangle wpfRect, float Alto, float Ancho, float Angulo)
|
||||
{
|
||||
if (simRect != null)
|
||||
simRect.Create(Ancho, Alto, GetRectangleCenter(wpfRect), Angulo);
|
||||
}
|
||||
|
||||
public void UpdateCurve(simCurve curva,float RadioInterno, float RadioExterno, float startAngle, float endAngle)
|
||||
{
|
||||
curva.Create(RadioInterno, RadioExterno, startAngle, endAngle, GetCurveCenterInMeter(RadioExterno));
|
||||
}
|
||||
|
||||
public simCurve AddCurve(float RadioInterno, float RadioExterno, float startAngle, float endAngle)
|
||||
{
|
||||
return simulationManager.AddCurve(RadioInterno, RadioExterno, startAngle, endAngle, GetCurveCenterInMeter(RadioExterno));
|
||||
}
|
||||
|
||||
public simTransporte AddRectangle(SimulationManagerFP simulationManager, System.Windows.Shapes.Rectangle wpfRect, float Alto, float Ancho, float Angulo)
|
||||
{
|
||||
return simulationManager.AddRectangle(Ancho, Alto, GetRectangleCenter(wpfRect), Angulo);
|
||||
}
|
||||
|
||||
public simBarrera AddBarrera(SimulationManagerFP simulationManager, System.Windows.Shapes.Rectangle wpfRect, float Alto, float Ancho, float Angulo)
|
||||
{
|
||||
return simulationManager.AddBarrera(Ancho, Alto, GetRectangleCenter(wpfRect), Angulo);
|
||||
}
|
||||
|
||||
public void UpdateOrCreateLine(simGuia simGuia, System.Windows.Shapes.Rectangle wpfRect)
|
||||
{
|
||||
if (simGuia != null)
|
||||
{
|
||||
var coords = GetCenterLineVectors(wpfRect);
|
||||
|
||||
// Crear o actualizar simRectangle
|
||||
simGuia.Create(coords.Start, coords.End); // asumiendo que el ángulo inicial es 0
|
||||
}
|
||||
}
|
||||
|
||||
public simGuia AddLine(SimulationManagerFP simulationManager, System.Windows.Shapes.Rectangle wpfRect)
|
||||
{
|
||||
var coords = GetCenterLineVectors(wpfRect);
|
||||
return simulationManager.AddLine(coords.Start, coords.End);
|
||||
}
|
||||
|
||||
public ImageSource ImageFromPath(string value)
|
||||
{
|
||||
if (value is string stringValue)
|
||||
{
|
||||
return new BitmapImage(new Uri(stringValue, UriKind.RelativeOrAbsolute));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static protected T GetLastElement<T>(List<T> list) where T : class
|
||||
{
|
||||
if (list.Count > 0)
|
||||
{
|
||||
return list[list.Count - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class HiddenAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucBasicExample"
|
||||
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.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>
|
||||
|
||||
<UserControl.DataContext>
|
||||
<vm:osBasicExample />
|
||||
</UserControl.DataContext>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Content="{Binding Nombre}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Background="Transparent"
|
||||
Foreground="Black"/>
|
||||
|
||||
<Image Grid.Row="1" Source="{Binding ImageSource_oculta}"
|
||||
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Stretch="Uniform"/>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
|
@ -0,0 +1,137 @@
|
|||
using CtrEditor.Convertidores;
|
||||
using CtrEditor.Siemens;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using Newtonsoft.Json;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucBasicExample.xaml
|
||||
/// </summary>
|
||||
///
|
||||
|
||||
public partial class osBasicExample : osBase, IosBase
|
||||
{
|
||||
|
||||
// Otros datos y métodos relevantes para la simulación
|
||||
|
||||
public static string NombreClase()
|
||||
{
|
||||
return "Ejemplo";
|
||||
}
|
||||
private string nombre = NombreClase();
|
||||
public override string Nombre
|
||||
{
|
||||
get => nombre;
|
||||
set => SetProperty(ref nombre, value);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
[ObservableProperty]
|
||||
public ImageSource imageSource_oculta;
|
||||
|
||||
[ObservableProperty]
|
||||
public float tamano;
|
||||
[ObservableProperty]
|
||||
public float maxRatedHz;
|
||||
|
||||
[ObservableProperty]
|
||||
public float tiempoRampa;
|
||||
|
||||
partial void OnTiempoRampaChanged(float value)
|
||||
{
|
||||
if (value < 0.1f)
|
||||
value = 0.1f;
|
||||
tiempoRampa = value;
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
public bool encendido;
|
||||
[ObservableProperty]
|
||||
public int pLC_NumeroMotor;
|
||||
[ObservableProperty]
|
||||
public float ratio;
|
||||
|
||||
[ObservableProperty]
|
||||
public float velocidad;
|
||||
|
||||
partial void OnVelocidadChanged(float value)
|
||||
{
|
||||
if (value > 0)
|
||||
ImageSource_oculta = ImageFromPath("/imagenes/motorVerde.png");
|
||||
else
|
||||
ImageSource_oculta = ImageFromPath("/imagenes/motorNegro.png");
|
||||
}
|
||||
|
||||
public osBasicExample()
|
||||
{
|
||||
Tamano = 0.30f;
|
||||
PLC_NumeroMotor = 31;
|
||||
MaxRatedHz = 100;
|
||||
TiempoRampa = 3;
|
||||
ImageSource_oculta = ImageFromPath("/imagenes/motor2.png");
|
||||
}
|
||||
|
||||
public override void UpdateGeometryStart()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
|
||||
}
|
||||
public override void UpdatePLC(PLCModel plc, int elapsedMilliseconds)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
ActualizarLeftTop();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ucBasicExample : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucBasicExample()
|
||||
{
|
||||
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) { }
|
||||
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()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using System.Numerics;
|
||||
using CtrEditor.Convertidores;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucBotella.xaml
|
||||
/// </summary>
|
||||
///
|
||||
|
||||
public class osBotella : osBase
|
||||
{
|
||||
private Circle Geometria = new Circle();
|
||||
|
||||
// Otros datos y métodos relevantes para la simulación
|
||||
|
||||
private string _nombre = "Botella";
|
||||
|
||||
public float Diametro {
|
||||
get => Geometria.Diameter;
|
||||
set
|
||||
{
|
||||
Geometria.Diameter = value;
|
||||
OnPropertyChanged(nameof(Diametro));
|
||||
}
|
||||
}
|
||||
|
||||
public float Mass {
|
||||
get => Geometria.Mass;
|
||||
set
|
||||
{
|
||||
Geometria.Mass = value;
|
||||
OnPropertyChanged(nameof(Mass));
|
||||
}
|
||||
}
|
||||
|
||||
public float Overlap
|
||||
{
|
||||
get => Geometria.Overlap;
|
||||
set
|
||||
{
|
||||
Geometria.Overlap = value;
|
||||
OnPropertyChanged(nameof(Overlap));
|
||||
}
|
||||
}
|
||||
|
||||
public override float Left
|
||||
{
|
||||
get => Geometria.Left;
|
||||
set
|
||||
{
|
||||
Geometria.Left = value;
|
||||
CanvasSetLeftinMeter(value);
|
||||
OnPropertyChanged(nameof(Left));
|
||||
}
|
||||
}
|
||||
public override float Top
|
||||
{
|
||||
get => Geometria.Top;
|
||||
set
|
||||
{
|
||||
Geometria.Top = value;
|
||||
CanvasSetTopinMeter(value);
|
||||
OnPropertyChanged(nameof(Top));
|
||||
}
|
||||
}
|
||||
|
||||
public override string Nombre
|
||||
{
|
||||
get => _nombre;
|
||||
set
|
||||
{
|
||||
if (_nombre != value)
|
||||
{
|
||||
_nombre = value;
|
||||
OnPropertyChanged(nameof(Nombre));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public osBotella()
|
||||
{
|
||||
Diametro = 0.10f;
|
||||
}
|
||||
|
||||
public override void ConnectSimManager(SimulationManager simulationManager)
|
||||
{
|
||||
simulationManager.circles.Add(Geometria);
|
||||
}
|
||||
public override void UpdateGeometry()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
|
||||
}
|
||||
|
||||
public override void UpdateControl()
|
||||
{
|
||||
Top = Geometria.Top;
|
||||
Left = Geometria.Left;
|
||||
Overlap = Geometria.Overlap;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ucBotella : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucBotella()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
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()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using CtrEditor.Convertidores;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucGuia.xaml
|
||||
/// </summary>
|
||||
public class osGuia : osBase
|
||||
{
|
||||
private string _nombre = "Guia";
|
||||
|
||||
private Line Geometria = new Line();
|
||||
|
||||
public override float Left
|
||||
{
|
||||
get => Geometria.Left;
|
||||
set
|
||||
{
|
||||
Geometria.Left = value;
|
||||
CanvasSetLeftinMeter(value);
|
||||
OnPropertyChanged(nameof(Left));
|
||||
}
|
||||
}
|
||||
public override float Top
|
||||
{
|
||||
get => Geometria.Top;
|
||||
set
|
||||
{
|
||||
Geometria.Top = value;
|
||||
CanvasSetTopinMeter(value);
|
||||
OnPropertyChanged(nameof(Top));
|
||||
}
|
||||
}
|
||||
|
||||
public float Ancho
|
||||
{
|
||||
get => Geometria.Length;
|
||||
set
|
||||
{
|
||||
Geometria.Length = value;
|
||||
OnPropertyChanged(nameof(Ancho));
|
||||
}
|
||||
}
|
||||
public float AltoGuia
|
||||
{
|
||||
get => Geometria.Width;
|
||||
set
|
||||
{
|
||||
Geometria.Width = value;
|
||||
OnPropertyChanged(nameof(AltoGuia));
|
||||
}
|
||||
}
|
||||
|
||||
public float Angulo
|
||||
{
|
||||
get => Geometria.Angle;
|
||||
set
|
||||
{
|
||||
Geometria.Angle = value;
|
||||
OnPropertyChanged(nameof(Angulo));
|
||||
}
|
||||
}
|
||||
|
||||
public override string Nombre
|
||||
{
|
||||
get => _nombre;
|
||||
set
|
||||
{
|
||||
if (_nombre != value)
|
||||
{
|
||||
_nombre = value;
|
||||
OnPropertyChanged(nameof(Nombre));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public osGuia()
|
||||
{
|
||||
Ancho = 1;
|
||||
AltoGuia = 0.03f;
|
||||
}
|
||||
|
||||
public override void ConnectSimManager(SimulationManager simulationManager)
|
||||
{
|
||||
simulationManager.lines.Add(Geometria);
|
||||
}
|
||||
public override void UpdateGeometry()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
}
|
||||
public override void UpdateControl()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public partial class ucGuia : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucGuia()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
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()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,168 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using CtrEditor.Convertidores;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucTransporteCurva.xaml
|
||||
/// </summary>
|
||||
public class osTransporteCurva : osBase
|
||||
{
|
||||
private string _nombre = "Transporte Curva";
|
||||
|
||||
private float frictionCoefficient;
|
||||
private float velMax50hz; // en metros por minuto
|
||||
private float tiempoRampa;
|
||||
private bool esMarcha;
|
||||
|
||||
private Rectangle Geometria = new Rectangle();
|
||||
|
||||
public override float Left
|
||||
{
|
||||
get => Geometria.Left;
|
||||
set
|
||||
{
|
||||
Geometria.Left = value;
|
||||
CanvasSetLeftinMeter(value);
|
||||
OnPropertyChanged(nameof(Left));
|
||||
}
|
||||
}
|
||||
public override float Top
|
||||
{
|
||||
get => Geometria.Top;
|
||||
set
|
||||
{
|
||||
Geometria.Top = value;
|
||||
CanvasSetTopinMeter(value);
|
||||
OnPropertyChanged(nameof(Top));
|
||||
}
|
||||
}
|
||||
|
||||
public float RadioExterno
|
||||
{
|
||||
get => Geometria.Length;
|
||||
set
|
||||
{
|
||||
Geometria.Length = value;
|
||||
OnPropertyChanged(nameof(RadioExterno));
|
||||
}
|
||||
}
|
||||
public float RadioInterno
|
||||
{
|
||||
get => Geometria.Width;
|
||||
set
|
||||
{
|
||||
Geometria.Width = value;
|
||||
OnPropertyChanged(nameof(RadioInterno));
|
||||
}
|
||||
}
|
||||
|
||||
public float Angulo
|
||||
{
|
||||
get => Geometria.Angle;
|
||||
set
|
||||
{
|
||||
Geometria.Angle = value;
|
||||
OnPropertyChanged(nameof(Angulo));
|
||||
}
|
||||
}
|
||||
public float VelocidadActual
|
||||
{
|
||||
get => Geometria.Speed;
|
||||
set
|
||||
{
|
||||
Geometria.Speed = value;
|
||||
OnPropertyChanged(nameof(VelocidadActual));
|
||||
}
|
||||
}
|
||||
|
||||
public override string Nombre
|
||||
{
|
||||
get => _nombre;
|
||||
set
|
||||
{
|
||||
if (_nombre != value)
|
||||
{
|
||||
_nombre = value;
|
||||
OnPropertyChanged(nameof(Nombre));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 osTransporteCurva()
|
||||
{
|
||||
RadioExterno = 2;
|
||||
RadioInterno = 1;
|
||||
}
|
||||
|
||||
public override void ConnectSimManager(SimulationManager simulationManager)
|
||||
{
|
||||
simulationManager.rectangles.Add(Geometria);
|
||||
}
|
||||
public override void UpdateGeometry()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
|
||||
}
|
||||
|
||||
public override void UpdateControl()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public partial class ucTransporteCurva : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucTransporteCurva()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
public void Resize(float width, float height)
|
||||
{
|
||||
if (Datos is osTransporteCurva datos)
|
||||
datos.RadioExterno = 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 osTransporteCurva datos)
|
||||
datos.Angulo = Angle;
|
||||
}
|
||||
public void Highlight(bool State) { }
|
||||
public int ZIndex()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,243 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using CtrEditor.Convertidores;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucTransporteGuias.xaml
|
||||
/// </summary>
|
||||
public class osTransporteGuias : osBase
|
||||
{
|
||||
private string _nombre = "Transporte Guias";
|
||||
|
||||
private float frictionCoefficient;
|
||||
private float velMax50hz; // en metros por minuto
|
||||
private float tiempoRampa;
|
||||
private bool esMarcha;
|
||||
private double _distance;
|
||||
private float altoGuia;
|
||||
|
||||
private float left;
|
||||
private float top;
|
||||
|
||||
private Rectangle TransporteCentral = new Rectangle();
|
||||
private Line Guia_Superior = new Line();
|
||||
private Line Guia_Inferior = new Line();
|
||||
|
||||
public override float Left
|
||||
{
|
||||
get => left;
|
||||
set
|
||||
{
|
||||
left = value;
|
||||
CanvasSetLeftinMeter(value);
|
||||
OnPropertyChanged(nameof(Left));
|
||||
}
|
||||
}
|
||||
public override float Top
|
||||
{
|
||||
get => top;
|
||||
set
|
||||
{
|
||||
top = value;
|
||||
CanvasSetTopinMeter(value);
|
||||
OnPropertyChanged(nameof(Top));
|
||||
}
|
||||
}
|
||||
|
||||
public float Ancho
|
||||
{
|
||||
get => TransporteCentral.Length;
|
||||
set
|
||||
{
|
||||
TransporteCentral.Length = value;
|
||||
OnPropertyChanged(nameof(Ancho));
|
||||
}
|
||||
}
|
||||
public float AltoGuia
|
||||
{
|
||||
get => altoGuia;
|
||||
set
|
||||
{
|
||||
altoGuia = value;
|
||||
OnPropertyChanged(nameof(AltoGuia));
|
||||
}
|
||||
}
|
||||
|
||||
public float Alto
|
||||
{
|
||||
get => TransporteCentral.Width;
|
||||
set
|
||||
{
|
||||
TransporteCentral.Width = value;
|
||||
OnPropertyChanged(nameof(Alto));
|
||||
}
|
||||
}
|
||||
|
||||
public float Angulo
|
||||
{
|
||||
get => TransporteCentral.Angle;
|
||||
set
|
||||
{
|
||||
TransporteCentral.Angle = value;
|
||||
OnPropertyChanged(nameof(Angulo));
|
||||
}
|
||||
}
|
||||
public float VelocidadActual
|
||||
{
|
||||
get => TransporteCentral.Speed;
|
||||
set
|
||||
{
|
||||
TransporteCentral.Speed = value;
|
||||
OnPropertyChanged(nameof(VelocidadActual));
|
||||
}
|
||||
}
|
||||
|
||||
public double Distance
|
||||
{
|
||||
get { return _distance; }
|
||||
set
|
||||
{
|
||||
if (_distance != value)
|
||||
{
|
||||
_distance = value;
|
||||
OnPropertyChanged("Distance");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string Nombre
|
||||
{
|
||||
get => _nombre;
|
||||
set
|
||||
{
|
||||
if (_nombre != value)
|
||||
{
|
||||
_nombre = value;
|
||||
OnPropertyChanged(nameof(Nombre));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ActualizarGeometrias()
|
||||
{
|
||||
ucTransporteGuias ucTG = (ucTransporteGuias)_visualRepresentation;
|
||||
if (ucTG != null)
|
||||
{
|
||||
var _canvasLeft = CanvasGetLeftinMeter();
|
||||
var _canvasTop = CanvasGetTopinMeter();
|
||||
|
||||
var coordenadas = GetRectangleCoordinatesInMeter(ucTG.Transporte, ucTG);
|
||||
TransporteCentral.Left = coordenadas.Left + _canvasLeft;
|
||||
TransporteCentral.Top = coordenadas.Top + _canvasTop;
|
||||
|
||||
coordenadas = GetRectangleCoordinatesInMeter(ucTG.GuiaSuperior, ucTG);
|
||||
Guia_Superior.Left = coordenadas.Left + _canvasLeft;
|
||||
Guia_Superior.Top = coordenadas.Top + _canvasTop; ;
|
||||
|
||||
coordenadas = GetRectangleCoordinatesInMeter(ucTG.GuiaInferior, ucTG);
|
||||
Guia_Inferior.Left = coordenadas.Left + _canvasLeft;
|
||||
Guia_Inferior.Top = coordenadas.Top + _canvasTop; ;
|
||||
|
||||
TransporteCentral.Angle = Guia_Superior.Angle = Guia_Inferior.Angle = Angulo;
|
||||
Guia_Superior.Length = Guia_Inferior.Length = Ancho;
|
||||
}
|
||||
}
|
||||
|
||||
private (float Left, float Top) GetRectangleCoordinatesInMeter(System.Windows.Shapes.Rectangle rect, ucTransporteGuias ucTG)
|
||||
{
|
||||
if (rect != null)
|
||||
{
|
||||
// Obtiene la transformada del objeto visual
|
||||
GeneralTransform transform = rect.TransformToAncestor(ucTG);
|
||||
|
||||
// Obtiene la posición absoluta
|
||||
Point topLeft = transform.Transform(new Point(0, 0));
|
||||
//Point bottomRight = transform.Transform(new Point(rect.ActualWidth, rect.ActualHeight));
|
||||
return (PixelToMeter.Instance.calc.PixelsToMeters((float)topLeft.X), PixelToMeter.Instance.calc.PixelsToMeters((float)topLeft.Y));
|
||||
}
|
||||
else return (0,0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 osTransporteGuias()
|
||||
{
|
||||
Ancho = 1;
|
||||
Alto = 0.10f;
|
||||
AltoGuia = 0.03f;
|
||||
Distance = 0.01f;
|
||||
}
|
||||
|
||||
public override void ConnectSimManager(SimulationManager simulationManager)
|
||||
{
|
||||
simulationManager.rectangles.Add(TransporteCentral);
|
||||
simulationManager.lines.Add(Guia_Superior);
|
||||
simulationManager.lines.Add(Guia_Inferior);
|
||||
}
|
||||
public override void UpdateGeometry()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
ActualizarGeometrias();
|
||||
}
|
||||
|
||||
public override void UpdateControl()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public partial class ucTransporteGuias : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucTransporteGuias()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
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()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucTransporteTTop"
|
||||
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:convert="clr-namespace:CtrEditor.Convertidores">
|
||||
|
||||
<UserControl.Resources>
|
||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Canvas>
|
||||
<Rectangle Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}" Fill="Gray">
|
||||
<Rectangle.RenderTransform>
|
||||
<RotateTransform Angle="{Binding Angulo}"/>
|
||||
</Rectangle.RenderTransform>
|
||||
</Rectangle>
|
||||
</Canvas>
|
||||
|
||||
</UserControl>
|
||||
|
|
@ -1,170 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
using System.Numerics;
|
||||
using System.Windows.Markup;
|
||||
using CtrEditor.Convertidores;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucTransporteTTop.xaml
|
||||
/// </summary>
|
||||
///
|
||||
|
||||
public class osTransporteTTop : osBase
|
||||
{
|
||||
private string _nombre = "Transporte TTOP";
|
||||
|
||||
private float frictionCoefficient;
|
||||
private float velMax50hz; // en metros por minuto
|
||||
private float tiempoRampa;
|
||||
private bool esMarcha;
|
||||
|
||||
private Rectangle Geometria = new Rectangle();
|
||||
|
||||
public override float Left
|
||||
{
|
||||
get => Geometria.Left;
|
||||
set
|
||||
{
|
||||
Geometria.Left = value;
|
||||
CanvasSetLeftinMeter(value);
|
||||
OnPropertyChanged(nameof(Left));
|
||||
}
|
||||
}
|
||||
public override float Top
|
||||
{
|
||||
get => Geometria.Top;
|
||||
set
|
||||
{
|
||||
Geometria.Top = value;
|
||||
CanvasSetTopinMeter(value);
|
||||
OnPropertyChanged(nameof(Top));
|
||||
}
|
||||
}
|
||||
|
||||
public float Ancho {
|
||||
get => Geometria.Length;
|
||||
set
|
||||
{
|
||||
Geometria.Length = value;
|
||||
OnPropertyChanged(nameof(Ancho));
|
||||
}
|
||||
}
|
||||
public float Alto {
|
||||
get => Geometria.Width;
|
||||
set
|
||||
{
|
||||
Geometria.Width = value;
|
||||
OnPropertyChanged(nameof(Alto));
|
||||
}
|
||||
}
|
||||
|
||||
public float Angulo
|
||||
{
|
||||
get => Geometria.Angle;
|
||||
set
|
||||
{
|
||||
Geometria.Angle = value;
|
||||
OnPropertyChanged(nameof(Angulo));
|
||||
}
|
||||
}
|
||||
public float VelocidadActual
|
||||
{
|
||||
get => Geometria.Speed;
|
||||
set {
|
||||
Geometria.Speed = value;
|
||||
OnPropertyChanged(nameof(VelocidadActual));
|
||||
}
|
||||
}
|
||||
|
||||
public override string Nombre
|
||||
{
|
||||
get => _nombre;
|
||||
set
|
||||
{
|
||||
if (_nombre != value)
|
||||
{
|
||||
_nombre = value;
|
||||
OnPropertyChanged(nameof(Nombre));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 osTransporteTTop()
|
||||
{
|
||||
Ancho = 1;
|
||||
Alto = 0.10f;
|
||||
}
|
||||
|
||||
public override void ConnectSimManager(SimulationManager simulationManager)
|
||||
{
|
||||
simulationManager.rectangles.Add(Geometria);
|
||||
}
|
||||
public override void UpdateGeometry()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
|
||||
}
|
||||
|
||||
public override void UpdateControl()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public partial class ucTransporteTTop : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucTransporteTTop()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
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()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
<UserControl x:Class="CtrEditor.ObjetosSim.ucVMmotorSim"
|
||||
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.ObjetosSim"
|
||||
mc:Ignorable="d"
|
||||
xmlns:convert="clr-namespace:CtrEditor.Convertidores">
|
||||
|
||||
<UserControl.Resources>
|
||||
<convert:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Image Source="/motor2.png"
|
||||
Width="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Height="{Binding Tamano, Converter={StaticResource MeterToPixelConverter}}"
|
||||
Stretch="Uniform"/>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
|
@ -1,132 +0,0 @@
|
|||
using CtrEditor.Convertidores;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace CtrEditor.ObjetosSim
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ucVMmotorSim.xaml
|
||||
/// </summary>
|
||||
public class osVMmotorSim : osBase
|
||||
{
|
||||
|
||||
|
||||
// Otros datos y métodos relevantes para la simulación
|
||||
|
||||
private string _nombre = "VetroMeccanica Motor";
|
||||
private float _tamano;
|
||||
private float _left;
|
||||
private float _top;
|
||||
private float _numeroMotor;
|
||||
|
||||
public float Tamano
|
||||
{
|
||||
get => _tamano;
|
||||
set
|
||||
{
|
||||
_tamano = value;
|
||||
OnPropertyChanged(nameof(Tamano));
|
||||
}
|
||||
}
|
||||
|
||||
public float PLC_NumeroMotor
|
||||
{
|
||||
get => _numeroMotor;
|
||||
set
|
||||
{
|
||||
_numeroMotor = value;
|
||||
OnPropertyChanged(nameof(PLC_NumeroMotor));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override float Left
|
||||
{
|
||||
get => _left;
|
||||
set
|
||||
{
|
||||
_left = value;
|
||||
CanvasSetLeftinMeter(value);
|
||||
OnPropertyChanged(nameof(Left));
|
||||
}
|
||||
}
|
||||
public override float Top
|
||||
{
|
||||
get => _top;
|
||||
set
|
||||
{
|
||||
_top = value;
|
||||
CanvasSetTopinMeter(value);
|
||||
OnPropertyChanged(nameof(Top));
|
||||
}
|
||||
}
|
||||
|
||||
public override string Nombre
|
||||
{
|
||||
get => _nombre;
|
||||
set
|
||||
{
|
||||
if (_nombre != value)
|
||||
{
|
||||
_nombre = value;
|
||||
OnPropertyChanged(nameof(Nombre));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public osVMmotorSim()
|
||||
{
|
||||
Tamano = 0.30f;
|
||||
}
|
||||
|
||||
public override void ConnectSimManager(SimulationManager simulationManager)
|
||||
{
|
||||
}
|
||||
public override void UpdateGeometry()
|
||||
{
|
||||
// Se llama antes de la simulacion
|
||||
|
||||
}
|
||||
|
||||
public override void UpdateControl()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ucVMmotorSim : UserControl, IDataContainer
|
||||
{
|
||||
public osBase? Datos { get; set; }
|
||||
|
||||
public ucVMmotorSim()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
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()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,20 +25,24 @@ namespace CtrEditor.Siemens
|
|||
/// </summary>
|
||||
public class PLCViewModel : INotifyPropertyChanged
|
||||
{
|
||||
private readonly PLCModel _plcModel;
|
||||
public readonly PLCModel PLCInterface;
|
||||
private readonly DispatcherTimer _timer;
|
||||
private string _cpuTime;
|
||||
private string _connectionStatus = "offline";
|
||||
private string _ip = "10.1.30.11";
|
||||
private string _name = "PLC";
|
||||
private string lastError;
|
||||
public bool IsConnected { get; private set; }
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public event EventHandler RefreshEvent;
|
||||
|
||||
public PLCViewModel()
|
||||
{
|
||||
_plcModel = new PLCModel();
|
||||
_timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(1000) };
|
||||
IsConnected = false;
|
||||
PLCInterface = new PLCModel();
|
||||
_timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(30) };
|
||||
_timer.Tick += (s, e) => Refresh();
|
||||
|
||||
ConnectCommand = new RelayCommand(Connect, () => true);
|
||||
|
@ -98,41 +102,51 @@ namespace CtrEditor.Siemens
|
|||
}
|
||||
}
|
||||
|
||||
private void Connect()
|
||||
public void Connect()
|
||||
{
|
||||
// Implementa la conexión utilizando PLCModel
|
||||
_plcModel.Instance = SimulationRuntimeManager.CreateInterface(Name);
|
||||
_plcModel.Instance.OnSoftwareConfigurationChanged += Instance_OnSoftwareConfigurationChanged;
|
||||
//_plcModel.Instance.CommunicationInterface = ECommunicationInterface.Softbus;
|
||||
|
||||
if (_plcModel.Instance != null)
|
||||
try
|
||||
{
|
||||
_plcModel.UpdateTagList();
|
||||
_timer.Start();
|
||||
ConnectionStatus = "connected";
|
||||
// Implementa la conexión utilizando PLCModel
|
||||
PLCInterface.Instance = SimulationRuntimeManager.CreateInterface(Name);
|
||||
PLCInterface.Instance.OnSoftwareConfigurationChanged += Instance_OnSoftwareConfigurationChanged;
|
||||
//_plcModel.Instance.CommunicationInterface = ECommunicationInterface.Softbus;
|
||||
|
||||
if (PLCInterface.Instance != null)
|
||||
{
|
||||
PLCInterface.UpdateTagList();
|
||||
_timer.Start();
|
||||
ConnectionStatus = "connected";
|
||||
IsConnected = true;
|
||||
}
|
||||
} catch (Exception ex)
|
||||
{
|
||||
LastError = ex.Message;
|
||||
ConnectionStatus = "offline";
|
||||
}
|
||||
}
|
||||
|
||||
private void Instance_OnSoftwareConfigurationChanged(IInstance instance, SOnSoftwareConfigChangedParameter event_param)
|
||||
{
|
||||
_plcModel.UpdateTagList();
|
||||
|
||||
PLCInterface.UpdateTagList();
|
||||
}
|
||||
|
||||
private void Disconnect()
|
||||
public void Disconnect()
|
||||
{
|
||||
IsConnected = false;
|
||||
_timer.Stop();
|
||||
ConnectionStatus = "offline";
|
||||
_plcModel.Instance = null;
|
||||
PLCInterface.Instance = null;
|
||||
}
|
||||
|
||||
private void Refresh()
|
||||
{
|
||||
if (_plcModel.Instance != null)
|
||||
if (PLCInterface.Instance != null)
|
||||
{
|
||||
|
||||
CpuTime = _plcModel.LeerInt16("\"DB HMI\".CPU_Scan_Time")?.ToString() ?? "N/A";
|
||||
LastError = _plcModel.LastError;
|
||||
CpuTime = PLCInterface.LeerTagInt16("\"DB HMI\".CPU_Scan_Time")?.ToString() ?? "N/A";
|
||||
LastError = PLCInterface.LastError;
|
||||
|
||||
// Disparar el evento RefreshEvent
|
||||
RefreshEvent?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,7 +167,7 @@ namespace CtrEditor.Siemens
|
|||
IsConfigured = false;
|
||||
try
|
||||
{
|
||||
Instance?.UpdateTagList( ETagListDetails.IO | ETagListDetails.DB);
|
||||
Instance?.UpdateTagList(ETagListDetails.IO | ETagListDetails.DB, true); // ETagListDetails.IO | ETagListDetails.DB
|
||||
IsConfigured = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -186,7 +200,29 @@ namespace CtrEditor.Siemens
|
|||
LastError = ex.Message;
|
||||
}
|
||||
}
|
||||
|
||||
public void EscribirTag(string pTag, SDataValue Value)
|
||||
{
|
||||
try
|
||||
{
|
||||
Instance?.Write(pTag, Value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LastError = pTag + ":" + ex.Message;
|
||||
}
|
||||
}
|
||||
public SDataValue LeerTag(string pTag)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Instance.Read(pTag);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LastError = pTag + ":" + ex.Message;
|
||||
return new SDataValue();
|
||||
}
|
||||
}
|
||||
public void EscribirTagBool(string pTag, bool pValue)
|
||||
{
|
||||
try
|
||||
|
@ -198,6 +234,18 @@ namespace CtrEditor.Siemens
|
|||
LastError = pTag + ":" + ex.Message;
|
||||
}
|
||||
}
|
||||
public void EscribirTagInt16(string pTag, int pValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
Instance?.WriteInt16(pTag,(short) pValue);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LastError = pTag + ":" + ex.Message;
|
||||
}
|
||||
}
|
||||
|
||||
public bool LeerTagBool(string pTag)
|
||||
{
|
||||
try
|
||||
|
@ -211,7 +259,7 @@ namespace CtrEditor.Siemens
|
|||
}
|
||||
}
|
||||
|
||||
public int? LeerInt16(string pTag)
|
||||
public int? LeerTagInt16(string pTag)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -0,0 +1,641 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using CtrEditor.Convertidores;
|
||||
using System.Windows;
|
||||
using System.Diagnostics;
|
||||
using CtrEditor.ObjetosSim;
|
||||
using System.Windows.Documents;
|
||||
using nkast.Aether.Physics2D;
|
||||
using nkast.Aether.Physics2D.Dynamics;
|
||||
using nkast.Aether.Physics2D.Common;
|
||||
using nkast.Aether.Physics2D.Collision.Shapes;
|
||||
|
||||
namespace CtrEditor.Simulacion
|
||||
{
|
||||
public class simBase
|
||||
{
|
||||
public Body Body { get; protected set; }
|
||||
public World _world;
|
||||
|
||||
public void RemoverBody()
|
||||
{
|
||||
if (Body != null)
|
||||
{
|
||||
_world.Remove(Body);
|
||||
}
|
||||
}
|
||||
public void SetPosition(float x, float y)
|
||||
{
|
||||
Body.SetTransform(new Vector2(x, y), Body.Rotation);
|
||||
}
|
||||
public void SetPosition(Vector2 centro)
|
||||
{
|
||||
Body.SetTransform(centro, Body.Rotation);
|
||||
}
|
||||
}
|
||||
|
||||
public class simCurve : simBase
|
||||
{
|
||||
private float _innerRadius;
|
||||
private float _outerRadius;
|
||||
private float _startAngle;
|
||||
private float _endAngle;
|
||||
public float Speed { get; set; } // Velocidad para efectos de cinta transportadora
|
||||
|
||||
public simCurve(World world, float innerRadius, float outerRadius, float startAngle, float endAngle, Vector2 position)
|
||||
{
|
||||
_world = world;
|
||||
_innerRadius = innerRadius;
|
||||
_outerRadius = outerRadius;
|
||||
_startAngle = Microsoft.Xna.Framework.MathHelper.ToRadians(startAngle);
|
||||
_endAngle = Microsoft.Xna.Framework.MathHelper.ToRadians(endAngle);
|
||||
Create(position);
|
||||
}
|
||||
|
||||
public void Create(float innerRadius, float outerRadius, float startAngle, float endAngle, Vector2 position)
|
||||
{
|
||||
if (_world == null) return;
|
||||
_innerRadius = innerRadius;
|
||||
_outerRadius = outerRadius;
|
||||
_startAngle = Microsoft.Xna.Framework.MathHelper.ToRadians(startAngle);
|
||||
_endAngle = Microsoft.Xna.Framework.MathHelper.ToRadians(endAngle);
|
||||
Create(position);
|
||||
}
|
||||
|
||||
public void Create(Vector2 position)
|
||||
{
|
||||
RemoverBody();
|
||||
|
||||
// Crear la geometría del sensor de curva
|
||||
List<Vertices> segments = CreateCurveVertices(_innerRadius, _outerRadius, _startAngle, _endAngle);
|
||||
Body = new Body();
|
||||
foreach (var segment in segments)
|
||||
{
|
||||
var shape = new PolygonShape(segment, 1f);
|
||||
var fixture = Body.CreateFixture(shape);
|
||||
fixture.IsSensor = true;
|
||||
}
|
||||
Body.Position = position;
|
||||
Body.BodyType = BodyType.Static;
|
||||
Body.Tag = this;
|
||||
}
|
||||
|
||||
public void SetSpeed(float speed)
|
||||
{
|
||||
Speed = speed;
|
||||
}
|
||||
|
||||
private List<Vertices> CreateCurveVertices(float innerRadius, float outerRadius, float startAngle, float endAngle)
|
||||
{
|
||||
List<Vertices> verticesList = new List<Vertices>();
|
||||
int segments = 32;
|
||||
float angleStep = (endAngle - startAngle) / segments;
|
||||
|
||||
Vertices innerVertices = new Vertices();
|
||||
Vertices outerVertices = new Vertices();
|
||||
|
||||
for (int i = 0; i <= segments; i++)
|
||||
{
|
||||
float angle = startAngle + i * angleStep;
|
||||
innerVertices.Add(new Vector2(innerRadius * (float)Math.Cos(angle), innerRadius * (float)Math.Sin(angle)));
|
||||
outerVertices.Add(new Vector2(outerRadius * (float)Math.Cos(angle), outerRadius * (float)Math.Sin(angle)));
|
||||
}
|
||||
|
||||
outerVertices.Reverse();
|
||||
innerVertices.AddRange(outerVertices);
|
||||
verticesList.Add(innerVertices);
|
||||
|
||||
return verticesList;
|
||||
}
|
||||
|
||||
public void ApplyCurveEffect(Fixture bottle)
|
||||
{
|
||||
Vector2 centerToBottle = bottle.Body.Position - Body.Position;
|
||||
float distanceToCenter = centerToBottle.Length();
|
||||
|
||||
if (distanceToCenter >= _innerRadius && distanceToCenter <= _outerRadius)
|
||||
{
|
||||
// Calcular la velocidad tangencial
|
||||
float speedMetersPerSecond = Speed / 60.0f;
|
||||
float angularVelocity = speedMetersPerSecond / distanceToCenter;
|
||||
|
||||
// Vector tangente (perpendicular al radio)
|
||||
Vector2 tangent = new Vector2(-centerToBottle.Y, centerToBottle.X);
|
||||
tangent.Normalize();
|
||||
|
||||
// Velocidad deseada
|
||||
Vector2 desiredVelocity = tangent * angularVelocity * distanceToCenter;
|
||||
bottle.Body.LinearVelocity = desiredVelocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class simDescarte : simBase
|
||||
{
|
||||
private float _radius;
|
||||
|
||||
public simDescarte(World world, float diameter, Vector2 position)
|
||||
{
|
||||
_world = world;
|
||||
_radius = diameter / 2;
|
||||
Create(position);
|
||||
}
|
||||
|
||||
public void SetDiameter(float diameter)
|
||||
{
|
||||
_radius = diameter / 2;
|
||||
Create(Body.Position); // Recrear el círculo con el nuevo tamaño
|
||||
}
|
||||
|
||||
public void Create(Vector2 position)
|
||||
{
|
||||
RemoverBody();
|
||||
Body = _world.CreateCircle(_radius, 1f, position);
|
||||
|
||||
Body.FixtureList[0].IsSensor = true;
|
||||
Body.BodyType = BodyType.Static;
|
||||
Body.Tag = this; // Importante para la identificación durante la colisión
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class simTransporte : simBase
|
||||
{
|
||||
public float Speed { get; set; } // Velocidad para efectos de cinta transportadora
|
||||
public float DistanceGuide2Guide { get; set; }
|
||||
public bool TransportWithGuides = false;
|
||||
|
||||
public simTransporte(World world, float width, float height, Vector2 position, float angle = 0)
|
||||
{
|
||||
_world = world;
|
||||
Create(width, height, position, angle);
|
||||
}
|
||||
|
||||
public float Angle
|
||||
{
|
||||
get { return Microsoft.Xna.Framework.MathHelper.ToDegrees(Body.Rotation); }
|
||||
set { Body.Rotation = Microsoft.Xna.Framework.MathHelper.ToRadians(value); }
|
||||
}
|
||||
|
||||
public new void SetPosition(float x, float y)
|
||||
{
|
||||
Body.Position = new Vector2(x, y);
|
||||
}
|
||||
|
||||
public void SetSpeed(float speed)
|
||||
{
|
||||
Speed = speed;
|
||||
}
|
||||
|
||||
public void SetDimensions(float width, float height)
|
||||
{
|
||||
Body.Remove(Body.FixtureList[0]);
|
||||
|
||||
var newShape = new PolygonShape(PolygonTools.CreateRectangle(width / 2, height / 2), 1f);
|
||||
Body.CreateFixture(newShape);
|
||||
}
|
||||
public void Create(float width, float height, Vector2 position, float angle = 0)
|
||||
{
|
||||
RemoverBody();
|
||||
Body = _world.CreateRectangle( width, height, 1f, position);
|
||||
Body.FixtureList[0].IsSensor = true;
|
||||
Body.BodyType = BodyType.Static;
|
||||
Body.Rotation = Microsoft.Xna.Framework.MathHelper.ToRadians(angle);
|
||||
Body.Tag = this; // Importante para la identificación durante la colisión
|
||||
}
|
||||
}
|
||||
|
||||
public class simBarrera : simBase
|
||||
{
|
||||
public bool LuzCortada = false;
|
||||
|
||||
public simBarrera(World world, float width, float height, Vector2 position, float angle = 0)
|
||||
{
|
||||
_world = world;
|
||||
Create(width, height, position, angle);
|
||||
}
|
||||
|
||||
public float Angle
|
||||
{
|
||||
get { return Microsoft.Xna.Framework.MathHelper.ToDegrees(Body.Rotation); }
|
||||
set { Body.Rotation = Microsoft.Xna.Framework.MathHelper.ToRadians(value); }
|
||||
}
|
||||
|
||||
public new void SetPosition(float x, float y)
|
||||
{
|
||||
Body.Position = new Vector2(x, y);
|
||||
}
|
||||
|
||||
public void SetDimensions(float width, float height)
|
||||
{
|
||||
Body.Remove(Body.FixtureList[0]);
|
||||
|
||||
var newShape = new PolygonShape(PolygonTools.CreateRectangle(width / 2, height / 2), 1f);
|
||||
Body.CreateFixture(newShape);
|
||||
}
|
||||
|
||||
public void Create(float width, float height, Vector2 position, float angle = 0)
|
||||
{
|
||||
RemoverBody();
|
||||
Body = _world.CreateRectangle( width, height, 1f, position);
|
||||
Body.FixtureList[0].IsSensor = true;
|
||||
Body.BodyType = BodyType.Static;
|
||||
Body.Rotation = Microsoft.Xna.Framework.MathHelper.ToRadians(angle);
|
||||
Body.Tag = this; // Importante para la identificación durante la colisión
|
||||
LuzCortada = false;
|
||||
}
|
||||
}
|
||||
|
||||
public class simGuia : simBase
|
||||
{
|
||||
public simGuia(World world, Vector2 start, Vector2 end)
|
||||
{
|
||||
_world = world;
|
||||
Create(start, end);
|
||||
}
|
||||
|
||||
public void Create(Vector2 start, Vector2 end)
|
||||
{
|
||||
RemoverBody();
|
||||
Body = _world.CreateEdge( start, end);
|
||||
Body.BodyType = BodyType.Static;
|
||||
Body.Tag = this; // Importante para la identificación durante la colisión
|
||||
}
|
||||
|
||||
public void UpdateVertices(Vector2 newStart, Vector2 newEnd)
|
||||
{
|
||||
Create(newStart, newEnd); // Recrear la línea con nuevos vértices
|
||||
}
|
||||
}
|
||||
|
||||
public class simBotella : simBase
|
||||
{
|
||||
private float _radius;
|
||||
private float _mass;
|
||||
public bool Descartar = false;
|
||||
|
||||
public simBotella(World world, float diameter, Vector2 position, float mass)
|
||||
{
|
||||
_world = world;
|
||||
_radius = diameter / 2;
|
||||
_mass = mass;
|
||||
Create(position);
|
||||
}
|
||||
|
||||
public float CenterX
|
||||
{
|
||||
get { return Body.Position.X; }
|
||||
set { }
|
||||
}
|
||||
|
||||
public float CenterY
|
||||
{
|
||||
get { return Body.Position.Y; }
|
||||
set { }
|
||||
}
|
||||
|
||||
public Vector2 Center
|
||||
{
|
||||
get { return Body.Position; }
|
||||
}
|
||||
|
||||
public float Mass
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_mass <= 0)
|
||||
_mass = 1;
|
||||
return _mass;
|
||||
}
|
||||
set { _mass = value; }
|
||||
}
|
||||
|
||||
private void Create(Vector2 position)
|
||||
{
|
||||
RemoverBody();
|
||||
Body = _world.CreateCircle( _radius, 0.2f, position);
|
||||
Body.BodyType = BodyType.Dynamic;
|
||||
|
||||
// Restablecer manejador de eventos de colisión
|
||||
Body.OnCollision += HandleCollision;
|
||||
//Body.OnSeparation += HandleOnSeparation;
|
||||
|
||||
Body.Tag = this; // Importante para la identificación durante la colisión
|
||||
|
||||
// Configurar la fricción
|
||||
Body.SetFriction(0.3f);
|
||||
|
||||
// Configurar amortiguamiento
|
||||
Body.LinearDamping = 0.4f; // Ajustar para controlar la reducción de la velocidad lineal
|
||||
Body.AngularDamping = 0.4f; // Ajustar para controlar la reducción de la velocidad angular
|
||||
Body.SetRestitution(0.2f); // Baja restitución para menos rebote
|
||||
|
||||
Body.IsBullet = true;
|
||||
}
|
||||
|
||||
public void SetDiameter(float diameter)
|
||||
{
|
||||
_radius = diameter / 2;
|
||||
Create(Body.Position); // Recrear el círculo con el nuevo tamaño
|
||||
}
|
||||
|
||||
public void SetMass(float mass)
|
||||
{
|
||||
Mass = mass;
|
||||
}
|
||||
|
||||
private bool HandleCollision(Fixture fixtureA, Fixture fixtureB, nkast.Aether.Physics2D.Dynamics.Contacts.Contact contact)
|
||||
{
|
||||
if (fixtureB.Body.Tag is simBarrera Sensor)
|
||||
{
|
||||
Sensor.LuzCortada = true;
|
||||
return true;
|
||||
}
|
||||
else if (fixtureB.Body.Tag is simCurve curve)
|
||||
{
|
||||
curve.ApplyCurveEffect(fixtureA);
|
||||
return true; // No aplicar respuestas físicas
|
||||
}
|
||||
else if (fixtureB.Body.Tag is simDescarte)
|
||||
{
|
||||
Descartar = true;
|
||||
return true;
|
||||
}
|
||||
else if (fixtureB.Body.Tag is simTransporte)
|
||||
{
|
||||
simTransporte conveyor = fixtureB.Body.Tag as simTransporte;
|
||||
|
||||
if (conveyor.Speed != 0)
|
||||
{
|
||||
|
||||
CircleShape circleShape = fixtureA.Shape as CircleShape;
|
||||
PolygonShape polygonShape = fixtureB.Shape as PolygonShape;
|
||||
|
||||
// Obtener centro y radio del círculo
|
||||
Vector2 centroCirculo = fixtureA.Body.Position;
|
||||
float radio = circleShape.Radius;
|
||||
|
||||
// Obtener los vértices del polígono (rectángulo)
|
||||
Vector2[] vertices = new Vector2[polygonShape.Vertices.Count];
|
||||
float cos = (float)Math.Cos(fixtureB.Body.Rotation);
|
||||
float sin = (float)Math.Sin(fixtureB.Body.Rotation);
|
||||
|
||||
for (int i = 0; i < polygonShape.Vertices.Count; i++)
|
||||
{
|
||||
Vector2 vertex = polygonShape.Vertices[i];
|
||||
float rotatedX = vertex.X * cos - vertex.Y * sin + fixtureB.Body.Position.X;
|
||||
float rotatedY = vertex.X * sin + vertex.Y * cos + fixtureB.Body.Position.Y;
|
||||
vertices[i] = new Vector2(rotatedX, rotatedY);
|
||||
}
|
||||
|
||||
// Calcular el porcentaje de la superficie compartida
|
||||
float porcentajeCompartido = InterseccionCirculoRectanguloAether.CalcularSuperficieCompartida(vertices, centroCirculo, radio);
|
||||
|
||||
// Aplicar el efecto del transportador usando el porcentaje calculado
|
||||
//if (conveyor.TransportWithGuides)
|
||||
// if (conveyor.DistanceGuide2Guide <= radio * 2)
|
||||
// CenterFixtureOnConveyor(fixtureA, conveyor);
|
||||
ApplyConveyorEffect(conveyor, fixtureA, porcentajeCompartido);
|
||||
|
||||
}
|
||||
return true; // No aplicar respuestas físicas
|
||||
}
|
||||
return true; // No aplicar respuestas físicas
|
||||
}
|
||||
|
||||
private void ApplyConveyorEffect(simTransporte conveyor, Fixture circleFixture, float porcentajeCompartido)
|
||||
{
|
||||
float speedMetersPerSecond = conveyor.Speed / 60.0f;
|
||||
Vector2 desiredVelocity = new Vector2((float)Math.Cos(conveyor.Body.Rotation), (float)Math.Sin(conveyor.Body.Rotation)) * speedMetersPerSecond;
|
||||
circleFixture.Body.LinearVelocity += desiredVelocity * porcentajeCompartido;
|
||||
}
|
||||
|
||||
private void CenterFixtureOnConveyor(Fixture fixtureA, simTransporte conveyor)
|
||||
{
|
||||
// Obtener el centro del conveyor
|
||||
Vector2 conveyorCenter = conveyor.Body.Position;
|
||||
|
||||
// Calcular el vector de la línea horizontal centrada de conveyor
|
||||
float halfDistance = conveyor.DistanceGuide2Guide / 2;
|
||||
float cos = (float)Math.Cos(conveyor.Body.Rotation);
|
||||
float sin = (float)Math.Sin(conveyor.Body.Rotation);
|
||||
|
||||
Vector2 offset = new Vector2(halfDistance * cos, halfDistance * sin);
|
||||
|
||||
// Línea horizontal centrada de conveyor en el espacio del mundo
|
||||
Vector2 lineStart = conveyorCenter - offset;
|
||||
Vector2 lineEnd = conveyorCenter + offset;
|
||||
|
||||
// Proyectar el centro de fixtureA sobre la línea horizontal
|
||||
Vector2 fixtureCenter = fixtureA.Body.Position;
|
||||
Vector2 closestPoint = ProjectPointOntoLine(fixtureCenter, lineStart, lineEnd);
|
||||
|
||||
// Mover fixtureA al punto más cercano en la línea horizontal
|
||||
fixtureA.Body.Position = closestPoint;
|
||||
}
|
||||
|
||||
private Vector2 ProjectPointOntoLine(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
|
||||
{
|
||||
Vector2 lineDirection = lineEnd - lineStart;
|
||||
lineDirection.Normalize();
|
||||
|
||||
Vector2 pointToLineStart = point - lineStart;
|
||||
Vector2.Dot(ref pointToLineStart,ref lineDirection, out float projectionLength);
|
||||
|
||||
return lineStart + projectionLength * lineDirection;
|
||||
}
|
||||
}
|
||||
|
||||
public class SimulationManagerFP
|
||||
{
|
||||
private World world;
|
||||
private Canvas simulationCanvas;
|
||||
public List<simBase> Cuerpos;
|
||||
|
||||
private Stopwatch stopwatch;
|
||||
private double stopwatch_last;
|
||||
|
||||
public Canvas DebugCanvas { get => simulationCanvas; set => simulationCanvas = value; }
|
||||
|
||||
public SimulationManagerFP()
|
||||
{
|
||||
world = new World(new Vector2(0, 0)); // Vector2.Zero
|
||||
Cuerpos = new List<simBase>();
|
||||
stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
if (world.BodyList.Count > 0)
|
||||
world.Clear();
|
||||
if (Cuerpos.Count > 0)
|
||||
Cuerpos.Clear();
|
||||
}
|
||||
|
||||
public void Step()
|
||||
{
|
||||
// Detener el cronómetro y obtener el tiempo transcurrido en milisegundos
|
||||
float elapsedMilliseconds = (float)(stopwatch.Elapsed.TotalMilliseconds - stopwatch_last);
|
||||
stopwatch_last = stopwatch.Elapsed.TotalMilliseconds;
|
||||
|
||||
// Pasar el tiempo transcurrido al método Step
|
||||
world.Step(elapsedMilliseconds / 1000.0f);
|
||||
}
|
||||
|
||||
public void Remove(simBase Objeto)
|
||||
{
|
||||
if (Objeto != null)
|
||||
{
|
||||
Objeto.RemoverBody();
|
||||
Cuerpos.Remove(Objeto);
|
||||
}
|
||||
}
|
||||
|
||||
public simCurve AddCurve(float innerRadius, float outerRadius, float startAngle, float endAngle, Vector2 position)
|
||||
{
|
||||
simCurve curva = new simCurve(world, innerRadius, outerRadius, startAngle, endAngle, position);
|
||||
Cuerpos.Add(curva);
|
||||
return curva;
|
||||
}
|
||||
|
||||
public simBotella AddCircle(float diameter, Vector2 position, float mass)
|
||||
{
|
||||
simBotella circle = new simBotella(world, diameter, position, mass);
|
||||
Cuerpos.Add(circle);
|
||||
return circle;
|
||||
}
|
||||
|
||||
public simTransporte AddRectangle(float width, float height, Vector2 position, float angle)
|
||||
{
|
||||
simTransporte rectangle = new simTransporte(world, width, height, position, angle);
|
||||
Cuerpos.Add(rectangle);
|
||||
return rectangle;
|
||||
}
|
||||
|
||||
public simBarrera AddBarrera(float width, float height, Vector2 position, float angle)
|
||||
{
|
||||
simBarrera rectangle = new simBarrera(world, width, height, position, angle);
|
||||
Cuerpos.Add(rectangle);
|
||||
return rectangle;
|
||||
}
|
||||
|
||||
public simGuia AddLine(Vector2 start, Vector2 end)
|
||||
{
|
||||
simGuia line = new simGuia(world, start, end);
|
||||
Cuerpos.Add(line);
|
||||
return line;
|
||||
}
|
||||
|
||||
public simDescarte AddDescarte(float diameter, Vector2 position)
|
||||
{
|
||||
simDescarte descarte = new simDescarte(world, diameter, position);
|
||||
Cuerpos.Add(descarte);
|
||||
return descarte;
|
||||
}
|
||||
|
||||
public void Debug_DrawInitialBodies()
|
||||
{
|
||||
Debug_ClearSimulationShapes();
|
||||
world.Step(0.01f); // Para actualizar la BodyList
|
||||
foreach (Body body in world.BodyList)
|
||||
{
|
||||
foreach (Fixture fixture in body.FixtureList)
|
||||
{
|
||||
DrawShape(fixture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Debug_ClearSimulationShapes()
|
||||
{
|
||||
var simulationShapes = simulationCanvas.Children.OfType<System.Windows.Shapes.Shape>().Where(s => s.Tag as string == "Simulation").ToList();
|
||||
foreach (var shape in simulationShapes)
|
||||
{
|
||||
simulationCanvas.Children.Remove(shape);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawShape(Fixture fixture)
|
||||
{
|
||||
System.Windows.Shapes.Shape shape;
|
||||
switch (fixture.Shape.ShapeType)
|
||||
{
|
||||
case ShapeType.Circle:
|
||||
shape = DrawCircle(fixture);
|
||||
break;
|
||||
case ShapeType.Polygon:
|
||||
shape = DrawPolygon(fixture);
|
||||
break;
|
||||
case ShapeType.Edge:
|
||||
shape = DrawEdge(fixture);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
shape.Tag = "Simulation"; // Marcar para simulación
|
||||
Canvas.SetZIndex(shape, 20);
|
||||
simulationCanvas.Children.Add(shape);
|
||||
}
|
||||
|
||||
private float p(float x)
|
||||
{
|
||||
float c = PixelToMeter.Instance.calc.MetersToPixels(x);
|
||||
return c;
|
||||
}
|
||||
|
||||
private System.Windows.Shapes.Shape DrawEdge(Fixture fixture)
|
||||
{
|
||||
EdgeShape edge = fixture.Shape as EdgeShape;
|
||||
Line line = new Line
|
||||
{
|
||||
X1 = p(edge.Vertex1.X + fixture.Body.Position.X), // Aplicar escala y posición
|
||||
Y1 = p(edge.Vertex1.Y + fixture.Body.Position.Y),
|
||||
X2 = p(edge.Vertex2.X + fixture.Body.Position.X),
|
||||
Y2 = p(edge.Vertex2.Y + fixture.Body.Position.Y),
|
||||
Stroke = Brushes.Black,
|
||||
StrokeThickness = 2
|
||||
};
|
||||
return line;
|
||||
}
|
||||
|
||||
private System.Windows.Shapes.Shape DrawCircle(Fixture fixture)
|
||||
{
|
||||
CircleShape circle = fixture.Shape as CircleShape;
|
||||
Ellipse ellipse = new Ellipse
|
||||
{
|
||||
Width = p(circle.Radius * 2), // Escalado para visualización
|
||||
Height = p(circle.Radius * 2), // Escalado para visualización
|
||||
Stroke = Brushes.Black,
|
||||
StrokeThickness = 2
|
||||
};
|
||||
Canvas.SetLeft(ellipse, p(fixture.Body.Position.X - circle.Radius));
|
||||
Canvas.SetTop(ellipse, p(fixture.Body.Position.Y - circle.Radius));
|
||||
return ellipse;
|
||||
}
|
||||
|
||||
private System.Windows.Shapes.Shape DrawPolygon(Fixture fixture)
|
||||
{
|
||||
Polygon polygon = new Polygon { Stroke = Brushes.Black, StrokeThickness = 2 };
|
||||
PolygonShape polyShape = fixture.Shape as PolygonShape;
|
||||
|
||||
float cos = (float)Math.Cos(fixture.Body.Rotation);
|
||||
float sin = (float)Math.Sin(fixture.Body.Rotation);
|
||||
|
||||
foreach (Vector2 vertex in polyShape.Vertices)
|
||||
{
|
||||
float rotatedX = vertex.X * cos - vertex.Y * sin + fixture.Body.Position.X;
|
||||
float rotatedY = vertex.X * sin + vertex.Y * cos + fixture.Body.Position.Y;
|
||||
|
||||
polygon.Points.Add(new Point(p(rotatedX), p(rotatedY)));
|
||||
}
|
||||
|
||||
return polygon;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,641 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Factories;
|
||||
using FarseerPhysics.Collision.Shapes;
|
||||
using nkast.Aether.Physics2D.Common;
|
||||
using CtrEditor.Convertidores;
|
||||
using FarseerPhysics.Common;
|
||||
using System.Windows;
|
||||
using System.Diagnostics;
|
||||
|
||||
using FarseerPhysics.Dynamics.Joints;
|
||||
using CtrEditor.ObjetosSim;
|
||||
using System.Windows.Documents;
|
||||
|
||||
namespace CtrEditor.Simulacion
|
||||
{
|
||||
public class simBase
|
||||
{
|
||||
public Body Body { get; protected set; }
|
||||
public World _world;
|
||||
|
||||
public void RemoverBody()
|
||||
{
|
||||
if (Body != null)
|
||||
{
|
||||
_world.RemoveBody(Body);
|
||||
}
|
||||
}
|
||||
public void SetPosition(float x, float y)
|
||||
{
|
||||
Body.SetTransform(new Vector2(x, y), Body.Rotation);
|
||||
}
|
||||
public void SetPosition(Vector2 centro)
|
||||
{
|
||||
Body.SetTransform(centro, Body.Rotation);
|
||||
}
|
||||
}
|
||||
|
||||
public class simCurve : simBase
|
||||
{
|
||||
private float _innerRadius;
|
||||
private float _outerRadius;
|
||||
private float _startAngle;
|
||||
private float _endAngle;
|
||||
public float Speed { get; set; } // Velocidad para efectos de cinta transportadora
|
||||
|
||||
public simCurve(World world, float innerRadius, float outerRadius, float startAngle, float endAngle, Vector2 position)
|
||||
{
|
||||
_world = world;
|
||||
_innerRadius = innerRadius;
|
||||
_outerRadius = outerRadius;
|
||||
_startAngle = MathHelper.ToRadians(startAngle);
|
||||
_endAngle = MathHelper.ToRadians(endAngle);
|
||||
Create(position);
|
||||
}
|
||||
|
||||
public void Create(float innerRadius, float outerRadius, float startAngle, float endAngle, Vector2 position)
|
||||
{
|
||||
if (_world == null) return;
|
||||
_innerRadius = innerRadius;
|
||||
_outerRadius = outerRadius;
|
||||
_startAngle = MathHelper.ToRadians(startAngle);
|
||||
_endAngle = MathHelper.ToRadians(endAngle);
|
||||
Create(position);
|
||||
}
|
||||
|
||||
public void Create(Vector2 position)
|
||||
{
|
||||
RemoverBody();
|
||||
|
||||
// Crear la geometría del sensor de curva
|
||||
List<Vertices> segments = CreateCurveVertices(_innerRadius, _outerRadius, _startAngle, _endAngle);
|
||||
Body = new Body(_world);
|
||||
foreach (var segment in segments)
|
||||
{
|
||||
var shape = new PolygonShape(segment, 1f);
|
||||
var fixture = Body.CreateFixture(shape);
|
||||
fixture.IsSensor = true;
|
||||
}
|
||||
Body.Position = position;
|
||||
Body.BodyType = BodyType.Static;
|
||||
Body.UserData = this;
|
||||
}
|
||||
|
||||
public void SetSpeed(float speed)
|
||||
{
|
||||
Speed = speed;
|
||||
}
|
||||
|
||||
private List<Vertices> CreateCurveVertices(float innerRadius, float outerRadius, float startAngle, float endAngle)
|
||||
{
|
||||
List<Vertices> verticesList = new List<Vertices>();
|
||||
int segments = 32;
|
||||
float angleStep = (endAngle - startAngle) / segments;
|
||||
|
||||
Vertices innerVertices = new Vertices();
|
||||
Vertices outerVertices = new Vertices();
|
||||
|
||||
for (int i = 0; i <= segments; i++)
|
||||
{
|
||||
float angle = startAngle + i * angleStep;
|
||||
innerVertices.Add(new Vector2(innerRadius * (float)Math.Cos(angle), innerRadius * (float)Math.Sin(angle)));
|
||||
outerVertices.Add(new Vector2(outerRadius * (float)Math.Cos(angle), outerRadius * (float)Math.Sin(angle)));
|
||||
}
|
||||
|
||||
outerVertices.Reverse();
|
||||
innerVertices.AddRange(outerVertices);
|
||||
verticesList.Add(innerVertices);
|
||||
|
||||
return verticesList;
|
||||
}
|
||||
|
||||
public void ApplyCurveEffect(Fixture bottle)
|
||||
{
|
||||
Vector2 centerToBottle = bottle.Body.Position - Body.Position;
|
||||
float distanceToCenter = centerToBottle.Length();
|
||||
|
||||
if (distanceToCenter >= _innerRadius && distanceToCenter <= _outerRadius)
|
||||
{
|
||||
// Calcular la velocidad tangencial
|
||||
float speedMetersPerSecond = Speed / 60.0f;
|
||||
float angularVelocity = speedMetersPerSecond / distanceToCenter;
|
||||
|
||||
// Vector tangente (perpendicular al radio)
|
||||
Vector2 tangent = new Vector2(-centerToBottle.Y, centerToBottle.X);
|
||||
tangent.Normalize();
|
||||
|
||||
// Velocidad deseada
|
||||
Vector2 desiredVelocity = tangent * angularVelocity * distanceToCenter;
|
||||
bottle.Body.LinearVelocity = desiredVelocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class simDescarte : simBase
|
||||
{
|
||||
private float _radius;
|
||||
|
||||
public simDescarte(World world, float diameter, Vector2 position)
|
||||
{
|
||||
_world = world;
|
||||
_radius = diameter / 2;
|
||||
Create(position);
|
||||
}
|
||||
|
||||
public void SetDiameter(float diameter)
|
||||
{
|
||||
_radius = diameter / 2;
|
||||
Create(Body.Position); // Recrear el círculo con el nuevo tamaño
|
||||
}
|
||||
|
||||
public void Create(Vector2 position)
|
||||
{
|
||||
RemoverBody();
|
||||
Body = BodyFactory.CreateCircle(_world, _radius, 1f, position);
|
||||
|
||||
Body.FixtureList[0].IsSensor = true;
|
||||
Body.BodyType = BodyType.Static;
|
||||
Body.UserData = this; // Importante para la identificación durante la colisión
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class simTransporte : simBase
|
||||
{
|
||||
public float Speed { get; set; } // Velocidad para efectos de cinta transportadora
|
||||
public float DistanceGuide2Guide { get; set; }
|
||||
public bool TransportWithGuides = false;
|
||||
|
||||
public simTransporte(World world, float width, float height, Vector2 position, float angle = 0)
|
||||
{
|
||||
_world = world;
|
||||
Create(width, height, position, angle);
|
||||
}
|
||||
|
||||
public float Angle
|
||||
{
|
||||
get { return MathHelper.ToDegrees(Body.Rotation); }
|
||||
set { Body.Rotation = MathHelper.ToRadians(value); }
|
||||
}
|
||||
|
||||
public new void SetPosition(float x, float y)
|
||||
{
|
||||
Body.Position = new Vector2(x, y);
|
||||
}
|
||||
|
||||
public void SetSpeed(float speed)
|
||||
{
|
||||
Speed = speed;
|
||||
}
|
||||
|
||||
public void SetDimensions(float width, float height)
|
||||
{
|
||||
Body.DestroyFixture(Body.FixtureList[0]);
|
||||
|
||||
var newShape = new PolygonShape(PolygonTools.CreateRectangle(width / 2, height / 2), 1f);
|
||||
Body.CreateFixture(newShape);
|
||||
}
|
||||
public void Create(float width, float height, Vector2 position, float angle = 0)
|
||||
{
|
||||
RemoverBody();
|
||||
Body = BodyFactory.CreateRectangle(_world, width, height, 1f, position);
|
||||
Body.FixtureList[0].IsSensor = true;
|
||||
Body.BodyType = BodyType.Static;
|
||||
Body.Rotation = MathHelper.ToRadians(angle);
|
||||
Body.UserData = this; // Importante para la identificación durante la colisión
|
||||
}
|
||||
}
|
||||
|
||||
public class simBarrera : simBase
|
||||
{
|
||||
public bool LuzCortada = false;
|
||||
|
||||
public simBarrera(World world, float width, float height, Vector2 position, float angle = 0)
|
||||
{
|
||||
_world = world;
|
||||
Create(width, height, position, angle);
|
||||
}
|
||||
|
||||
public float Angle
|
||||
{
|
||||
get { return MathHelper.ToDegrees(Body.Rotation); }
|
||||
set { Body.Rotation = MathHelper.ToRadians(value); }
|
||||
}
|
||||
|
||||
public new void SetPosition(float x, float y)
|
||||
{
|
||||
Body.Position = new Vector2(x, y);
|
||||
}
|
||||
|
||||
public void SetDimensions(float width, float height)
|
||||
{
|
||||
Body.DestroyFixture(Body.FixtureList[0]);
|
||||
|
||||
var newShape = new PolygonShape(PolygonTools.CreateRectangle(width / 2, height / 2), 1f);
|
||||
Body.CreateFixture(newShape);
|
||||
}
|
||||
|
||||
public void Create(float width, float height, Vector2 position, float angle = 0)
|
||||
{
|
||||
RemoverBody();
|
||||
Body = BodyFactory.CreateRectangle(_world, width, height, 1f, position);
|
||||
Body.FixtureList[0].IsSensor = true;
|
||||
Body.BodyType = BodyType.Static;
|
||||
Body.Rotation = MathHelper.ToRadians(angle);
|
||||
Body.UserData = this; // Importante para la identificación durante la colisión
|
||||
LuzCortada = false;
|
||||
}
|
||||
}
|
||||
|
||||
public class simGuia : simBase
|
||||
{
|
||||
public simGuia(World world, Vector2 start, Vector2 end)
|
||||
{
|
||||
_world = world;
|
||||
Create(start, end);
|
||||
}
|
||||
|
||||
public void Create(Vector2 start, Vector2 end)
|
||||
{
|
||||
RemoverBody();
|
||||
Body = BodyFactory.CreateEdge(_world, start, end);
|
||||
Body.BodyType = BodyType.Static;
|
||||
Body.UserData = this; // Importante para la identificación durante la colisión
|
||||
}
|
||||
|
||||
public void UpdateVertices(Vector2 newStart, Vector2 newEnd)
|
||||
{
|
||||
Create(newStart, newEnd); // Recrear la línea con nuevos vértices
|
||||
}
|
||||
}
|
||||
|
||||
public class simBotella : simBase
|
||||
{
|
||||
private float _radius;
|
||||
private float _mass;
|
||||
public bool Descartar = false;
|
||||
|
||||
public simBotella(World world, float diameter, Vector2 position, float mass)
|
||||
{
|
||||
_world = world;
|
||||
_radius = diameter / 2;
|
||||
_mass = mass;
|
||||
Create(position);
|
||||
}
|
||||
|
||||
public float CenterX
|
||||
{
|
||||
get { return Body.Position.X; }
|
||||
set { }
|
||||
}
|
||||
|
||||
public float CenterY
|
||||
{
|
||||
get { return Body.Position.Y; }
|
||||
set { }
|
||||
}
|
||||
|
||||
public Vector2 Center
|
||||
{
|
||||
get { return Body.Position; }
|
||||
}
|
||||
|
||||
public float Mass
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_mass <= 0)
|
||||
_mass = 1;
|
||||
return _mass;
|
||||
}
|
||||
set { _mass = value; }
|
||||
}
|
||||
|
||||
private void Create(Vector2 position)
|
||||
{
|
||||
RemoverBody();
|
||||
Body = BodyFactory.CreateCircle(_world, _radius, 0.2f, position);
|
||||
Body.BodyType = BodyType.Dynamic;
|
||||
|
||||
// Restablecer manejador de eventos de colisión
|
||||
Body.OnCollision += HandleCollision;
|
||||
//Body.OnSeparation += HandleOnSeparation;
|
||||
|
||||
Body.UserData = this; // Importante para la identificación durante la colisión
|
||||
|
||||
// Configurar la fricción
|
||||
Body.Friction = 0.3f; // Ajustar según sea necesario para tu simulación
|
||||
|
||||
// Configurar amortiguamiento
|
||||
Body.LinearDamping = 0.4f; // Ajustar para controlar la reducción de la velocidad lineal
|
||||
Body.AngularDamping = 0.4f; // Ajustar para controlar la reducción de la velocidad angular
|
||||
Body.Restitution = 0.2f; // Baja restitución para menos rebote
|
||||
// Body.IsBullet = true;
|
||||
}
|
||||
|
||||
public void SetDiameter(float diameter)
|
||||
{
|
||||
_radius = diameter / 2;
|
||||
Create(Body.Position); // Recrear el círculo con el nuevo tamaño
|
||||
}
|
||||
|
||||
public void SetMass(float mass)
|
||||
{
|
||||
Mass = mass;
|
||||
}
|
||||
|
||||
private bool HandleCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
|
||||
{
|
||||
if (fixtureB.Body.UserData is simBarrera Sensor)
|
||||
{
|
||||
Sensor.LuzCortada = true;
|
||||
return true;
|
||||
}
|
||||
else if (fixtureB.Body.UserData is simCurve curve)
|
||||
{
|
||||
curve.ApplyCurveEffect(fixtureA);
|
||||
return true; // No aplicar respuestas físicas
|
||||
}
|
||||
else if (fixtureB.Body.UserData is simDescarte)
|
||||
{
|
||||
Descartar = true;
|
||||
return true;
|
||||
} else if (fixtureB.Body.UserData is simTransporte)
|
||||
{
|
||||
simTransporte conveyor = fixtureB.Body.UserData as simTransporte;
|
||||
|
||||
if ( conveyor.Speed != 0 ) {
|
||||
|
||||
CircleShape circleShape = fixtureA.Shape as CircleShape;
|
||||
PolygonShape polygonShape = fixtureB.Shape as PolygonShape;
|
||||
|
||||
// Obtener centro y radio del círculo
|
||||
Vector2 centroCirculo = fixtureA.Body.Position;
|
||||
float radio = circleShape.Radius;
|
||||
|
||||
// Obtener los vértices del polígono (rectángulo)
|
||||
Vector2[] vertices = new Vector2[polygonShape.Vertices.Count];
|
||||
float cos = (float)Math.Cos(fixtureB.Body.Rotation);
|
||||
float sin = (float)Math.Sin(fixtureB.Body.Rotation);
|
||||
|
||||
for (int i = 0; i < polygonShape.Vertices.Count; i++)
|
||||
{
|
||||
Vector2 vertex = polygonShape.Vertices[i];
|
||||
float rotatedX = vertex.X * cos - vertex.Y * sin + fixtureB.Body.Position.X;
|
||||
float rotatedY = vertex.X * sin + vertex.Y * cos + fixtureB.Body.Position.Y;
|
||||
vertices[i] = new Vector2(rotatedX, rotatedY);
|
||||
}
|
||||
|
||||
// Calcular el porcentaje de la superficie compartida
|
||||
float porcentajeCompartido = InterseccionCirculoRectangulo.CalcularSuperficieCompartida(vertices, centroCirculo, radio);
|
||||
|
||||
// Aplicar el efecto del transportador usando el porcentaje calculado
|
||||
if (conveyor.TransportWithGuides)
|
||||
if (conveyor.DistanceGuide2Guide <= radio * 2)
|
||||
CenterFixtureOnConveyor(fixtureA, conveyor);
|
||||
ApplyConveyorEffect(conveyor, fixtureA, porcentajeCompartido);
|
||||
|
||||
}
|
||||
return true; // No aplicar respuestas físicas
|
||||
}
|
||||
return true; // No aplicar respuestas físicas
|
||||
}
|
||||
|
||||
private void ApplyConveyorEffect(simTransporte conveyor, Fixture circleFixture, float porcentajeCompartido)
|
||||
{
|
||||
float speedMetersPerSecond = conveyor.Speed / 60.0f;
|
||||
Vector2 desiredVelocity = new Vector2((float)Math.Cos(conveyor.Body.Rotation), (float)Math.Sin(conveyor.Body.Rotation)) * speedMetersPerSecond;
|
||||
circleFixture.Body.LinearVelocity += desiredVelocity * porcentajeCompartido;
|
||||
}
|
||||
|
||||
private void CenterFixtureOnConveyor(Fixture fixtureA, simTransporte conveyor)
|
||||
{
|
||||
// Obtener el centro del conveyor
|
||||
Vector2 conveyorCenter = conveyor.Body.Position;
|
||||
|
||||
// Calcular el vector de la línea horizontal centrada de conveyor
|
||||
float halfDistance = conveyor.DistanceGuide2Guide / 2;
|
||||
float cos = (float)Math.Cos(conveyor.Body.Rotation);
|
||||
float sin = (float)Math.Sin(conveyor.Body.Rotation);
|
||||
|
||||
Vector2 offset = new Vector2(halfDistance * cos, halfDistance * sin);
|
||||
|
||||
// Línea horizontal centrada de conveyor en el espacio del mundo
|
||||
Vector2 lineStart = conveyorCenter - offset;
|
||||
Vector2 lineEnd = conveyorCenter + offset;
|
||||
|
||||
// Proyectar el centro de fixtureA sobre la línea horizontal
|
||||
Vector2 fixtureCenter = fixtureA.Body.Position;
|
||||
Vector2 closestPoint = ProjectPointOntoLine(fixtureCenter, lineStart, lineEnd);
|
||||
|
||||
// Mover fixtureA al punto más cercano en la línea horizontal
|
||||
fixtureA.Body.Position = closestPoint;
|
||||
}
|
||||
|
||||
private Vector2 ProjectPointOntoLine(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
|
||||
{
|
||||
Vector2 lineDirection = lineEnd - lineStart;
|
||||
lineDirection.Normalize();
|
||||
|
||||
Vector2 pointToLineStart = point - lineStart;
|
||||
float projectionLength = Vector2.Dot(pointToLineStart, lineDirection);
|
||||
|
||||
return lineStart + projectionLength * lineDirection;
|
||||
}
|
||||
}
|
||||
|
||||
public class SimulationManagerFP
|
||||
{
|
||||
private World world;
|
||||
private Canvas simulationCanvas;
|
||||
public List<simBase> Cuerpos;
|
||||
|
||||
private Stopwatch stopwatch;
|
||||
private double stopwatch_last;
|
||||
|
||||
public Canvas DebugCanvas { get => simulationCanvas; set => simulationCanvas = value; }
|
||||
|
||||
public SimulationManagerFP()
|
||||
{
|
||||
world = new World(new Vector2(0, 0)); // Vector2.Zero
|
||||
Cuerpos = new List<simBase>();
|
||||
stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
if (world.BodyList.Count > 0)
|
||||
world.Clear();
|
||||
if (Cuerpos.Count > 0)
|
||||
Cuerpos.Clear();
|
||||
}
|
||||
|
||||
public void Step()
|
||||
{
|
||||
// Detener el cronómetro y obtener el tiempo transcurrido en milisegundos
|
||||
float elapsedMilliseconds = (float) (stopwatch.Elapsed.TotalMilliseconds - stopwatch_last);
|
||||
stopwatch_last = stopwatch.Elapsed.TotalMilliseconds;
|
||||
|
||||
// Pasar el tiempo transcurrido al método Step
|
||||
world.Step(elapsedMilliseconds / 1000.0f);
|
||||
}
|
||||
|
||||
public void Remove(simBase Objeto)
|
||||
{
|
||||
if (Objeto != null)
|
||||
{
|
||||
Objeto.RemoverBody();
|
||||
Cuerpos.Remove(Objeto);
|
||||
}
|
||||
}
|
||||
|
||||
public simCurve AddCurve(float innerRadius, float outerRadius, float startAngle, float endAngle, Vector2 position)
|
||||
{
|
||||
simCurve curva = new simCurve( world, innerRadius, outerRadius, startAngle, endAngle, position);
|
||||
Cuerpos.Add(curva);
|
||||
return curva;
|
||||
}
|
||||
|
||||
public simBotella AddCircle(float diameter, Vector2 position, float mass)
|
||||
{
|
||||
simBotella circle = new simBotella(world, diameter, position, mass);
|
||||
Cuerpos.Add(circle);
|
||||
return circle;
|
||||
}
|
||||
|
||||
public simTransporte AddRectangle(float width, float height, Vector2 position, float angle)
|
||||
{
|
||||
simTransporte rectangle = new simTransporte(world, width, height, position, angle);
|
||||
Cuerpos.Add(rectangle);
|
||||
return rectangle;
|
||||
}
|
||||
|
||||
public simBarrera AddBarrera(float width, float height, Vector2 position, float angle)
|
||||
{
|
||||
simBarrera rectangle = new simBarrera(world, width, height, position, angle);
|
||||
Cuerpos.Add(rectangle);
|
||||
return rectangle;
|
||||
}
|
||||
|
||||
public simGuia AddLine(Vector2 start, Vector2 end)
|
||||
{
|
||||
simGuia line = new simGuia(world, start, end);
|
||||
Cuerpos.Add(line);
|
||||
return line;
|
||||
}
|
||||
|
||||
public simDescarte AddDescarte(float diameter, Vector2 position)
|
||||
{
|
||||
simDescarte descarte = new simDescarte(world, diameter, position);
|
||||
Cuerpos.Add(descarte);
|
||||
return descarte;
|
||||
}
|
||||
|
||||
public void Debug_DrawInitialBodies()
|
||||
{
|
||||
Debug_ClearSimulationShapes();
|
||||
world.Step(0.01f); // Para actualizar la BodyList
|
||||
foreach (Body body in world.BodyList)
|
||||
{
|
||||
foreach (Fixture fixture in body.FixtureList)
|
||||
{
|
||||
DrawShape(fixture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Debug_ClearSimulationShapes()
|
||||
{
|
||||
var simulationShapes = simulationCanvas.Children.OfType<System.Windows.Shapes.Shape>().Where(s => s.Tag as string == "Simulation").ToList();
|
||||
foreach (var shape in simulationShapes)
|
||||
{
|
||||
simulationCanvas.Children.Remove(shape);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawShape(Fixture fixture)
|
||||
{
|
||||
System.Windows.Shapes.Shape shape;
|
||||
switch (fixture.ShapeType)
|
||||
{
|
||||
case ShapeType.Circle:
|
||||
shape = DrawCircle(fixture);
|
||||
break;
|
||||
case ShapeType.Polygon:
|
||||
shape = DrawPolygon(fixture);
|
||||
break;
|
||||
case ShapeType.Edge:
|
||||
shape = DrawEdge(fixture);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
shape.Tag = "Simulation"; // Marcar para simulación
|
||||
Canvas.SetZIndex(shape, 20);
|
||||
simulationCanvas.Children.Add(shape);
|
||||
}
|
||||
|
||||
private float p(float x)
|
||||
{
|
||||
float c = PixelToMeter.Instance.calc.MetersToPixels(x);
|
||||
return c;
|
||||
}
|
||||
|
||||
private System.Windows.Shapes.Shape DrawEdge(Fixture fixture)
|
||||
{
|
||||
EdgeShape edge = fixture.Shape as EdgeShape;
|
||||
Line line = new Line
|
||||
{
|
||||
X1 = p(edge.Vertex1.X + fixture.Body.Position.X), // Aplicar escala y posición
|
||||
Y1 = p(edge.Vertex1.Y + fixture.Body.Position.Y),
|
||||
X2 = p(edge.Vertex2.X + fixture.Body.Position.X),
|
||||
Y2 = p(edge.Vertex2.Y + fixture.Body.Position.Y),
|
||||
Stroke = Brushes.Black,
|
||||
StrokeThickness = 2
|
||||
};
|
||||
return line;
|
||||
}
|
||||
|
||||
private System.Windows.Shapes.Shape DrawCircle(Fixture fixture)
|
||||
{
|
||||
CircleShape circle = fixture.Shape as CircleShape;
|
||||
Ellipse ellipse = new Ellipse
|
||||
{
|
||||
Width = p(circle.Radius * 2), // Escalado para visualización
|
||||
Height = p(circle.Radius * 2), // Escalado para visualización
|
||||
Stroke = Brushes.Black,
|
||||
StrokeThickness = 2
|
||||
};
|
||||
Canvas.SetLeft(ellipse, p(fixture.Body.Position.X - circle.Radius));
|
||||
Canvas.SetTop(ellipse, p(fixture.Body.Position.Y - circle.Radius));
|
||||
return ellipse;
|
||||
}
|
||||
|
||||
private System.Windows.Shapes.Shape DrawPolygon(Fixture fixture)
|
||||
{
|
||||
Polygon polygon = new Polygon { Stroke = Brushes.Black, StrokeThickness = 2 };
|
||||
PolygonShape polyShape = fixture.Shape as PolygonShape;
|
||||
|
||||
float cos = (float)Math.Cos(fixture.Body.Rotation);
|
||||
float sin = (float)Math.Sin(fixture.Body.Rotation);
|
||||
|
||||
foreach (Vector2 vertex in polyShape.Vertices)
|
||||
{
|
||||
float rotatedX = vertex.X * cos - vertex.Y * sin + fixture.Body.Position.X;
|
||||
float rotatedY = vertex.X * sin + vertex.Y * cos + fixture.Body.Position.Y;
|
||||
|
||||
polygon.Points.Add(new Point(p(rotatedX), p(rotatedY)));
|
||||
}
|
||||
|
||||
return polygon;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FarseerPhysics.Collision;
|
||||
using Microsoft.VisualBasic.Devices;
|
||||
using nkast.Aether.Physics2D.Common;
|
||||
|
||||
namespace CtrEditor.Simulacion
|
||||
{
|
||||
internal class InterseccionCirculoRectangulo
|
||||
{
|
||||
// Definición de la función CalcularSuperficieCompartida
|
||||
public static float CalcularSuperficieCompartida(Vector2[] vertices, Vector2 center, float r)
|
||||
{
|
||||
float totalCircleArea = (float)Math.PI * r * r;
|
||||
|
||||
// Distancia a líneas ajustado
|
||||
float[] distances = new float[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
distances[i] = DistanceFromLine(center, vertices[i], vertices[(i + 1) % 4]);
|
||||
}
|
||||
|
||||
float minDistance = float.MaxValue;
|
||||
foreach (var dist in distances)
|
||||
{
|
||||
if (Math.Abs(dist) < Math.Abs(minDistance))
|
||||
minDistance = dist;
|
||||
}
|
||||
float d = Math.Abs(minDistance);
|
||||
|
||||
float sharedArea = 0;
|
||||
if (Array.TrueForAll(distances, dist => Math.Abs(dist) > r))
|
||||
{
|
||||
sharedArea = totalCircleArea;
|
||||
}
|
||||
else if (d < r)
|
||||
{
|
||||
float cosTheta = Math.Min(1, d / r);
|
||||
float sinTheta = (float)Math.Sqrt(Math.Max(0, r * r - d * d));
|
||||
if (minDistance < 0) // El centro está dentro del rectángulo
|
||||
{
|
||||
float areaOutside = r * r * (float)Math.Acos(cosTheta) - d * sinTheta;
|
||||
sharedArea = totalCircleArea - areaOutside;
|
||||
}
|
||||
else // El centro está fuera del rectángulo
|
||||
{
|
||||
sharedArea = r * r * (float)Math.Acos(cosTheta) - d * sinTheta;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sharedArea = 0;
|
||||
}
|
||||
|
||||
return sharedArea / totalCircleArea;
|
||||
}
|
||||
|
||||
public static float DistanceFromLine(Vector2 point, Vector2 start, Vector2 end)
|
||||
{
|
||||
float A = end.Y - start.Y;
|
||||
float B = start.X - end.X;
|
||||
float C = end.X * start.Y - start.X * end.Y;
|
||||
float distance = (A * point.X + B * point.Y + C) / (float)Math.Sqrt(A * A + B * B);
|
||||
return distance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class InterseccionCirculoRectanguloAether
|
||||
{
|
||||
// Definición de la función CalcularSuperficieCompartida
|
||||
public static float CalcularSuperficieCompartida(nkast.Aether.Physics2D.Common.Vector2[] vertices, nkast.Aether.Physics2D.Common.Vector2 center, float r)
|
||||
{
|
||||
float totalCircleArea = (float)Math.PI * r * r;
|
||||
|
||||
// Distancia a líneas ajustado
|
||||
float[] distances = new float[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
distances[i] = DistanceFromLine(center, vertices[i], vertices[(i + 1) % 4]);
|
||||
}
|
||||
|
||||
float minDistance = float.MaxValue;
|
||||
foreach (var dist in distances)
|
||||
{
|
||||
if (Math.Abs(dist) < Math.Abs(minDistance))
|
||||
minDistance = dist;
|
||||
}
|
||||
float d = Math.Abs(minDistance);
|
||||
|
||||
float sharedArea = 0;
|
||||
if (Array.TrueForAll(distances, dist => Math.Abs(dist) > r))
|
||||
{
|
||||
sharedArea = totalCircleArea;
|
||||
}
|
||||
else if (d < r)
|
||||
{
|
||||
float cosTheta = Math.Min(1, d / r);
|
||||
float sinTheta = (float)Math.Sqrt(Math.Max(0, r * r - d * d));
|
||||
if (minDistance < 0) // El centro está dentro del rectángulo
|
||||
{
|
||||
float areaOutside = r * r * (float)Math.Acos(cosTheta) - d * sinTheta;
|
||||
sharedArea = totalCircleArea - areaOutside;
|
||||
}
|
||||
else // El centro está fuera del rectángulo
|
||||
{
|
||||
sharedArea = r * r * (float)Math.Acos(cosTheta) - d * sinTheta;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sharedArea = 0;
|
||||
}
|
||||
|
||||
return sharedArea / totalCircleArea;
|
||||
}
|
||||
|
||||
public static float DistanceFromLine(nkast.Aether.Physics2D.Common.Vector2 point, nkast.Aether.Physics2D.Common.Vector2 start, nkast.Aether.Physics2D.Common.Vector2 end)
|
||||
{
|
||||
float A = end.Y - start.Y;
|
||||
float B = start.X - end.X;
|
||||
float C = end.X * start.Y - start.X * end.Y;
|
||||
float distance = (A * point.X + B * point.Y + C) / (float)Math.Sqrt(A * A + B * B);
|
||||
return distance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 2.5 KiB |