using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Shapes; namespace CtrEditor.ObjetosSim.UserControls { /// /// Interaction logic for CircularSegment.xaml /// public partial class CircularSegment : UserControl { public double Angle { get { return (double)GetValue(AngleProperty); } set { SetValue(AngleProperty, value); } } public static readonly DependencyProperty AngleProperty = DependencyProperty.Register("Angle", typeof(double), typeof(CircularSegment), new PropertyMetadata(0.0)); public double OuterRadius { get { return (double)GetValue(OuterRadiusProperty); } set { SetValue(OuterRadiusProperty, value); } } public static readonly DependencyProperty OuterRadiusProperty = DependencyProperty.Register("OuterRadius", typeof(double), typeof(CircularSegment), new PropertyMetadata(100.0, OnPropertyChanged)); public double InnerRadius { get { return (double)GetValue(InnerRadiusProperty); } set { SetValue(InnerRadiusProperty, value); } } public static readonly DependencyProperty InnerRadiusProperty = DependencyProperty.Register("InnerRadius", typeof(double), typeof(CircularSegment), new PropertyMetadata(80.0, OnPropertyChanged)); public double StartAngle { get { return (double)GetValue(StartAngleProperty); } set { SetValue(StartAngleProperty, value); } } public static readonly DependencyProperty StartAngleProperty = DependencyProperty.Register("StartAngle", typeof(double), typeof(CircularSegment), new PropertyMetadata(0.0, OnPropertyChanged)); public double EndAngle { get { return (double)GetValue(EndAngleProperty); } set { SetValue(EndAngleProperty, value); } } public static readonly DependencyProperty EndAngleProperty = DependencyProperty.Register("EndAngle", typeof(double), typeof(CircularSegment), new PropertyMetadata(90.0, OnPropertyChanged)); // Nuevas propiedades para las guías public bool ShowGuides { get { return (bool)GetValue(ShowGuidesProperty); } set { SetValue(ShowGuidesProperty, value); } } public static readonly DependencyProperty ShowGuidesProperty = DependencyProperty.Register("ShowGuides", typeof(bool), typeof(CircularSegment), new PropertyMetadata(false, OnPropertyChanged)); public double GuideDistance { get { return (double)GetValue(GuideDistanceProperty); } set { SetValue(GuideDistanceProperty, value); } } public static readonly DependencyProperty GuideDistanceProperty = DependencyProperty.Register("GuideDistance", typeof(double), typeof(CircularSegment), new PropertyMetadata(5.0, OnPropertyChanged)); public double GuideThickness { get { return (double)GetValue(GuideThicknessProperty); } set { SetValue(GuideThicknessProperty, value); } } public static readonly DependencyProperty GuideThicknessProperty = DependencyProperty.Register("GuideThickness", typeof(double), typeof(CircularSegment), new PropertyMetadata(2.0, OnPropertyChanged)); public static readonly DependencyProperty GuideStrokeProperty = DependencyProperty.Register("GuideStroke", typeof(Brush), typeof(CircularSegment), new PropertyMetadata(new SolidColorBrush(Colors.DarkBlue), OnGuidePropertyChanged)); public Brush GuideStroke { get { return (Brush)GetValue(GuideStrokeProperty); } set { SetValue(GuideStrokeProperty, value); } } public CircularSegment() { InitializeComponent(); this.Loaded += CircularSegment_Loaded; } private void CircularSegment_Loaded(object sender, RoutedEventArgs e) { System.Diagnostics.Debug.WriteLine("CircularSegment_Loaded called"); DrawSegment(); } // Propiedad pública para acceder al Path desde código externo public System.Windows.Shapes.Path TransportePath => path; private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as CircularSegment)?.DrawSegment(); } private static void OnGuidePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as CircularSegment)?.DrawSegment(); } private void DrawSegment() { System.Diagnostics.Debug.WriteLine($"DrawSegment called - ShowGuides: {ShowGuides}"); if (OuterRadius <= 0 || InnerRadius <= 0 || StartAngle == EndAngle) return; // Limpiar canvas existente - mantener solo el path principal for (int i = mainCanvas.Children.Count - 1; i >= 0; i--) { if (mainCanvas.Children[i] != path) { mainCanvas.Children.RemoveAt(i); } } DrawMainSegment(); if (ShowGuides) { System.Diagnostics.Debug.WriteLine("About to call DrawGuides()"); DrawGuides(); } } private void DrawMainSegment() { PathGeometry geometry = new PathGeometry(); PathFigure figure = new PathFigure(); // Calcula el centro del Canvas (suponemos que el Canvas es lo suficientemente grande) Point center = new Point(OuterRadius, OuterRadius); // Calcular los puntos de inicio y fin del arco externo Point startPoint = new Point(center.X + Math.Cos(StartAngle * Math.PI / 180) * OuterRadius, center.Y + Math.Sin(StartAngle * Math.PI / 180) * OuterRadius); Point endPoint = new Point(center.X + Math.Cos(EndAngle * Math.PI / 180) * OuterRadius, center.Y + Math.Sin(EndAngle * Math.PI / 180) * OuterRadius); // Crear arco externo bool largeArc = Math.Abs(EndAngle - StartAngle) > 180.0; figure.StartPoint = startPoint; figure.Segments.Add(new ArcSegment(endPoint, new Size(OuterRadius, OuterRadius), 0, largeArc, SweepDirection.Clockwise, true)); // Crear línea hacia el arco interno figure.Segments.Add(new LineSegment(new Point(center.X + Math.Cos(EndAngle * Math.PI / 180) * InnerRadius, center.Y + Math.Sin(EndAngle * Math.PI / 180) * InnerRadius), true)); // Crear arco interno startPoint = new Point(center.X + Math.Cos(StartAngle * Math.PI / 180) * InnerRadius, center.Y + Math.Sin(StartAngle * Math.PI / 180) * InnerRadius); figure.Segments.Add(new ArcSegment(startPoint, new Size(InnerRadius, InnerRadius), 0, largeArc, SweepDirection.Counterclockwise, true)); // Cerrar la figura figure.IsClosed = true; geometry.Figures.Add(figure); path.Data = geometry; } private void DrawGuides() { Point center = new Point(OuterRadius, OuterRadius); // Calcular radios de las guías double outerGuideRadius = OuterRadius + GuideDistance; double innerGuideRadius = InnerRadius - GuideDistance; System.Diagnostics.Debug.WriteLine($"DrawGuides - Creating guides with radii: Outer={outerGuideRadius}, Inner={innerGuideRadius}"); // Asegurar que el radio interior no sea negativo if (innerGuideRadius < 1.0) innerGuideRadius = 1.0; // Crear guía exterior CreateGuideArc(center, outerGuideRadius, "OuterGuide"); // Crear guía interior solo si el radio es válido if (innerGuideRadius > 1.0) { CreateGuideArc(center, innerGuideRadius, "InnerGuide"); } } private void CreateGuideArc(Point center, double radius, string name) { var guidePath = new System.Windows.Shapes.Path { Name = name, Stroke = GuideStroke, StrokeThickness = GuideThickness, Fill = null }; // Crear geometría del arco double radiansStart = StartAngle * Math.PI / 180.0; double radiansEnd = EndAngle * Math.PI / 180.0; Point startPoint = new Point( center.X + radius * Math.Cos(radiansStart), center.Y + radius * Math.Sin(radiansStart) ); Point endPoint = new Point( center.X + radius * Math.Cos(radiansEnd), center.Y + radius * Math.Sin(radiansEnd) ); // Crear el arco usando ArcSegment var pathGeometry = new PathGeometry(); var pathFigure = new PathFigure { StartPoint = startPoint }; var arcSegment = new ArcSegment { Point = endPoint, Size = new Size(radius, radius), SweepDirection = SweepDirection.Clockwise, IsLargeArc = Math.Abs(EndAngle - StartAngle) > 180 }; pathFigure.Segments.Add(arcSegment); pathGeometry.Figures.Add(pathFigure); guidePath.Data = pathGeometry; System.Diagnostics.Debug.WriteLine($"Adding guide {name} to canvas"); mainCanvas.Children.Add(guidePath); } } }