skip to Main Content

I’ve been doing a project in Visual Studio 2022 in C# using WPF, based on the Cobbs method to measure the degree of scoliosis.

Basically for you to understand how I have taken that method to code what I did was that when drawing two lines in real time where they cut they form an angle and that angle is the Cobbs angle which is the one that tells you the degree of scoliosis.

I have been trying to figure out how to paint a second red dot on the WPF canvas to finish drawing a first line because the first and second dots determine where the line starts and ends. The problem is that when I do the second click anywhere on the canvas but with the cursor not moving it does not draw the second red dot, it only draws the second red dot if I click with the cursor moving, which is very uncomfortable for a doctor using this program, and the same thing happens to me with the second line.

However when I make the first click in any part of the canvas without moving the cursor in the case of the first red point where the line begins if it draws it, and repeats the same process with the second line. And the rest if it works perfectly, I just needed to know if there was someone who knew about this if you could comment something you know or any experience. Thanks for watching guys.

I have tried everything, modifying the code, but I don’t know why I feel that it is a tiny error, but I can’t find it.

Here is the code of MainWindow.xaml.cs:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace CobbAngleMeasurement 
{
    public partial class MainWindow : Window
    {
        private Point? startPoint = null;
        private Point? endPoint = null;
        private Point? secondStartPoint = null;
        private Point? secondEndPoint = null;
        private Point? currentPoint = null;
        private bool drawingFirstLine = true;
        private int lineCount = 0;

        public MainWindow() 
        {
            InitializeComponent();
        }

        private void Canvas_MouseDown(object sender, MouseButtonEventArgs e) 
        {
            if (lineCount >= 2) 
            {
                startPoint = null;
                endPoint = null;
                secondStartPoint = null;
                secondEndPoint = null;
                lineCount = 0;
                canvas.Children.Clear();
            }

            if (drawingFirstLine)
            {
                if (!startPoint.HasValue)
                {
                    startPoint = e.GetPosition(canvas);
                    DrawPoint(startPoint.Value);
                }
                else
                {
                    endPoint = e.GetPosition(canvas);
                    drawingFirstLine = false;
                    lineCount++;
                    DrawPoint(endPoint.Value);
                    DrawLine(startPoint.Value, endPoint.Value);
                }
            }
            else
            {
                if (!secondStartPoint.HasValue)
                {
                    secondStartPoint = e.GetPosition(canvas);
                    DrawPoint(secondStartPoint.Value);
                }
                else
                {
                    secondEndPoint = e.GetPosition(canvas);
                    drawingFirstLine = true;
                    lineCount++;
                    DrawPoint(secondEndPoint.Value);
                    DrawLine(secondStartPoint.Value, secondEndPoint.Value);
                }
            }
            currentPoint = null;
            e.Handled = true;

 // Asegúrate de que el evento se maneje correctamente
        }

        private void Canvas_MouseMove(object sender, MouseEventArgs e)
        {
            if (startPoint.HasValue && !endPoint.HasValue)
            {
                currentPoint = e.GetPosition(canvas);
                canvas.Children.Clear();
                DrawAllElements();
                DrawLine(startPoint.Value, currentPoint.Value);
            }
            else if (secondStartPoint.HasValue && !secondEndPoint.HasValue)
            {
                currentPoint = e.GetPosition(canvas);
                canvas.Children.Clear();
                DrawAllElements();
                DrawLine(secondStartPoint.Value, currentPoint.Value);

                if (startPoint.HasValue && endPoint.HasValue)
                {
                    float intersectionAngle = CalculateIntersectionAngle(startPoint.Value, endPoint.Value, secondStartPoint.Value, currentPoint.Value);
                    DrawAngle(intersectionAngle, secondStartPoint.Value);
                }
}e.Handled = true;

                // Asegúrate de que el evento se maneje correctamente
        }

        private void Canvas_MouseEnter(object sender, MouseEventArgs e)
        {
            this.Cursor = Cursors.Cross;
        }

        private void Canvas_MouseLeave(object sender, MouseEventArgs e)
        {
            this.Cursor = Cursors.Arrow;
        }

        private void btnCalculateAngle_Click(object sender, RoutedEventArgs e)
        {
            if (startPoint.HasValue && endPoint.HasValue && secondStartPoint.HasValue && secondEndPoint.HasValue)
            {
                float intersectionAngle = CalculateIntersectionAngle(startPoint.Value, endPoint.Value, secondStartPoint.Value, secondEndPoint.Value);
                MessageBox.Show($"El ángulo de intersección es: { intersectionAngle:F2} grados", "Ángulo Calculado", MessageBoxButton.OK, MessageBoxImage.Information);
            }
            else
            {
                MessageBox.Show("Por favor, dibuje ambas líneas antes de calcular el ángulo.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        private void DrawLine(Point p1, Point p2)
        {
            Line line = new Line { X1 = p1.X,Y1 = p1.Y,X2 = p2.X,Y2 = p2.Y,Stroke = Brushes.Red,StrokeThickness = 2} ;
            canvas.Children.Add(line);
        }

        private void DrawPoint(Point p)
        {
            Ellipse ellipse = new Ellipse { Fill = Brushes.Red,Width = 6,Height = 6} ;
            Canvas.SetLeft(ellipse, p.X - 3);
            Canvas.SetTop(ellipse, p.Y - 3);
            canvas.Children.Add(ellipse);
        }

        private void DrawAllElements()
        {
            if (startPoint.HasValue)
            {
                DrawPoint(startPoint.Value);
            }

            if (endPoint.HasValue)
            {
                DrawPoint(endPoint.Value);
                DrawLine(startPoint.Value, endPoint.Value);
            }

            if (secondStartPoint.HasValue)
            {
                DrawPoint(secondStartPoint.Value);
            }

            if (secondEndPoint.HasValue)
            {
                DrawPoint(secondEndPoint.Value);
                DrawLine(secondStartPoint.Value, secondEndPoint.Value);
            }
        }

        private void btnClear_Click(object sender, RoutedEventArgs e)
        {
            startPoint = null;
            endPoint = null;
            secondStartPoint = null;
            secondEndPoint = null;
            lineCount = 0;
            canvas.Children.Clear();
        }

        private void DrawAngle(float angle, Point position)
        {
            TextBlock angleText = new TextBlock
            {
                Text = $" { angle:F2} °",Foreground = Brushes.Red,FontWeight = FontWeights.Bold};
                Canvas.SetLeft(angleText, position.X + 10);
                Canvas.SetTop(angleText, position.Y - 20);
                canvas.Children.Add(angleText);

                if (angleTextBlock != null)
                {
                    angleTextBlock.Text = $" { angle:F2} °";
                }
            } 
        }

        private float CalculateAngle(Point p1, Point p2)
        {
            double deltaY = p2.Y - p1.Y;
            double deltaX = p2.X - p1.X;
            return (float)(Math.Atan2(deltaY, deltaX) * (180.0 / Math.PI));
        }

        private float CalculateIntersectionAngle(Point p1, Point p2, Point p3, Point p4)
        {
            float angle1 = CalculateAngle(p1, p2);
            float angle2 = CalculateAngle(p3, p4);
            float intersectionAngle = Math.Abs(angle1 - angle2);

            if (intersectionAngle >= 90)
            {
                intersectionAngle = 180 - intersectionAngle;
            }

            if (intersectionAngle < 0)
            {
                intersectionAngle = -intersectionAngle;
            }

            if (intersectionAngle == 90)
            {
                return 90;
            }

            if (intersectionAngle > 90)
            {
                intersectionAngle = 180 - intersectionAngle;
            }

            return intersectionAngle;
        }
    }
}

MainWindow.xaml markup:

<Window x:Class="CobbAngleMeasurement.MainWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         Title="Medición del Ángulo de Cobb" Height="900" Width="1024"
         >
     <Grid>
         <Canvas
              Name="canvas" Width="800" Height="800"
                 MouseDown="Canvas_MouseDown"
                 MouseMove="Canvas_MouseMove"
                 MouseEnter="Canvas_MouseEnter"
                 MouseLeave="Canvas_MouseLeave" Margin="0,0,94,77"
                 >
                              <Canvas.Background>
                 <ImageBrush ImageSource="/Cobbs_angulo.jpg"  Stretch="None"/>
             </Canvas.Background>
             <!-- Aquí se dibujarán las líneas y puntos -->
         </Canvas>
         <TextBlock Name="angleTextBlock" Foreground="Red" FontWeight="Bold" FontSize="16"
                     Margin="10,10,0,0" HorizontalAlignment="Left" VerticalAlignment="Top"/>
         <Button Name="btnCalculateAngle" Content="Calcular Ángulo" Width="120" Height="40"
                 HorizontalAlignment="Right" VerticalAlignment="Bottom"
                 Margin="0,0,20,20" Click="btnCalculateAngle_Click"/>
         <Button Content="Limpiar" Click="btnClear_Click" Width="120" Height="40"
 HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,20,70"/>
     </Grid>
</Window>

2

Answers


  1. It is a bit unclear how exactly your line creation and drawing is supposed to work.

    You may perhaps want to start drawing a line on mouse down and end drawing it on mouse up. A first mouse down/move/up sequence would draw the first line and a second such sequence would draw the second line. A third mouse down would clear the drawing.

    The drawing code could be much simplified by using a single Path element as a child element the Canvas:

    <Canvas
        MouseLeftButtonDown="Canvas_MouseLeftButtonDown"
        MouseLeftButtonUp="Canvas_MouseLeftButtonUp"
        MouseMove="Canvas_MouseMove">
    
        <Canvas.Background>
            <ImageBrush ImageSource="/Cobbs_angulo.jpg"  Stretch="None"/>
        </Canvas.Background>
    
        <Path x:Name="path" Fill="Red" Stroke="Red" StrokeThickness="2"/>
    
        <TextBlock x:Name="angleTextBlock"/>
    </Canvas>
    

    The code behind would look like shown below.

    It updates the Data property of the Path with a GeometryGroup containing the lines and points. Note that the mouse should be captured and that the IsCaptured state of the mouse is used to determine whether a line is currently drawn or not.

    The UpdateDrawing method would also update the existing TextBlock named angleText.

    public partial class MainWindow : Window
    {
        private Point? p1;
        private Point? p2;
        private Point? p3;
        private Point? p4;
    
        public MainWindow()
        {
            InitializeComponent();
        }
    
        private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var canvas = (UIElement)sender;
    
            if (canvas.CaptureMouse())
            {
                if (!p1.HasValue)
                {
                    p1 = p2 = e.GetPosition(canvas);
                }
                else if (!p3.HasValue)
                {
                    p3 = p4 = e.GetPosition(canvas);
                }
                else
                {
                    p1 = p2 = p3 = p4 = null;
                }
    
                UpdateDrawing();
            }
        }
    
        private void Canvas_MouseMove(object sender, MouseEventArgs e)
        {
            var canvas = (UIElement)sender;
    
            if (canvas.IsMouseCaptured)
            {
                if (p4.HasValue)
                {
                    p4 = e.GetPosition(canvas);
                }
                else if (p2.HasValue)
                {
                    p2 = e.GetPosition(canvas);
                }
    
                UpdateDrawing();
            }
        }
    
        private void Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            var canvas = (UIElement)sender;
    
            canvas.ReleaseMouseCapture();
        }
    
        private void UpdateDrawing()
        {
            var geometry = new GeometryGroup();
    
            if (p1.HasValue && p2.HasValue)
            {
                geometry.Children.Add(new LineGeometry(p1.Value, p2.Value));
                geometry.Children.Add(new EllipseGeometry(p1.Value, 3, 3));
                geometry.Children.Add(new EllipseGeometry(p2.Value, 3, 3));
            }
    
            if (p3.HasValue && p4.HasValue)
            {
                geometry.Children.Add(new LineGeometry(p3.Value, p4.Value));
                geometry.Children.Add(new EllipseGeometry(p3.Value, 3, 3));
                geometry.Children.Add(new EllipseGeometry(p4.Value, 3, 3));
            }
    
            path.Data = geometry;
    
            if (p1.HasValue && p2.HasValue && p3.HasValue && p4.HasValue)
            {
                // calculate angle and TextBlock position
                ...
                Canvas.SetLeft(angleTextBlock, anglePosition.X);
                Canvas.SetTop(angleTextBlock, anglePosition.Y);
                angleTextBlock.Text = $" {angle:F2} °";
                angleTextBlock.Visibility = Visibility.Visible;
            }
            else
            {
                angleTextBlock.Visibility = Visibility.Collapsed;
            }
        }
    }
    
    Login or Signup to reply.
  2. The "2 clicks" is a problem; try capturing the points on "down and up" instead:

    1. Handle "PointerPressed" / Mouse down event; capture first point
    2. Handle PointerMoved / MouseMoved event, if necessary
    3. Handle "PointerReleased" / Mouse up event; capture 2nd point; draw line.

    (Tap line to delete?)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search