Answered draw rectangle at x degrees angle WPF

  • Monday, May 28, 2012 4:30 PM
     
     

    anyone please help me with this newbie WPF drawing problem - i've spend hours googleing at drawing rectangle in wpf but nothing i saw was helpful. so hoping to get a quick easy to understand tutorial / answer here without scarifying much more of my times.

    all i want is to be able to draw a rectangle by given two points.

    p1(x,y) and p2(x,y)

    maybe with the setting width and thickness of the rectangle, too.

    now, those p1 and p2 give me a Cartesian angle, and, i want to draw the rectangle at that angle.

    an illustrated example is in the pic below.

    thanks for any help


    • Edited by pokerMaster Monday, May 28, 2012 4:30 PM
    •  

All Replies

  • Monday, May 28, 2012 4:52 PM
     
     Answered Has Code

    Hi,

    if you use a Canvas and the Shapes-Rectangle you could do something like:

            Point p1 = new Point(100, 200);
            Point p2 = new Point(400, 20);
    
            private void button1_Click(object sender, RoutedEventArgs e)
            {
                Vector v = p2 - p1;
                double width = Math.Sqrt(v.X * v.X + v.Y * v.Y);
                double cos_w = v.X / width;
                double w_rad = Math.Acos(cos_w);
                double w = w_rad * 180.0 / Math.PI;
    
                Rectangle r = new Rectangle();
                r.Width = width;
    
                //this is set by "hand"; I dont know which value you want to have here
                r.Height = 50;
                r.SetValue(Canvas.LeftProperty, p1.X);
                r.SetValue(Canvas.TopProperty, p1.Y - r.Height / 2.0);
    
                r.Stroke = new SolidColorBrush(Colors.Red);
                r.StrokeThickness = 2;
                r.RenderTransform = new RotateTransform(-w, 0, r.Height / 2.0);
     
                canvas1.Children.Add(r);
    
                //draw the two points:
                Ellipse e1 = new Ellipse();
                e1.Width = 4;
                e1.Height = 4;
                e1.SetValue(Canvas.LeftProperty, p1.X - 2.0);
                e1.SetValue(Canvas.TopProperty, p1.Y - 2.0);
    
                Ellipse e2 = new Ellipse();
                e2.Width = 4;
                e2.Height = 4;
                e2.SetValue(Canvas.LeftProperty, p2.X - 2.0);
                e2.SetValue(Canvas.TopProperty, p2.Y - 2.0);
    
                e1.Stroke = e2.Stroke = new SolidColorBrush(Colors.Blue);
                e1.StrokeThickness = e2.StrokeThickness = 2;
                canvas1.Children.Add(e1);
                canvas1.Children.Add(e2);
            }

    The Xaml (without the Window-Tag):

        <Canvas Name="canvas1">
            <Button Canvas.Left="384" Canvas.Top="245" Content="Button" Height="23" Name="button1" Width="75" Click="button1_Click" />
        </Canvas>

    Regards,

      Thorsten

    • Marked As Answer by pokerMaster Tuesday, May 29, 2012 6:08 PM
    •  
  • Monday, May 28, 2012 5:00 PM
     
     

    Hi Thorsten,

    I see the code you give works in buttonClick event. can this be done in a non-event way?

    I mean, I just want a DrawRecFunction();

  • Monday, May 28, 2012 5:36 PM
     
     Answered Has Code

    Hi,

        public partial class MainWindow : Window
        {
            Point p1 = new Point(100, 200);
            Point p2 = new Point(400, 20);
            Rectangle r = new Rectangle();
            Ellipse e1 = new Ellipse();
            Ellipse e2 = new Ellipse();
    
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                p1 = e.GetPosition(canvas1);
                DrawRect();
            }
    
            private void Canvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
            {
                p2 = e.GetPosition(canvas1);
                DrawRect();
            }
    
            private void DrawRect()
            {
                Vector v = p2 - p1;
                double width = Math.Sqrt(v.X * v.X + v.Y * v.Y);
                double cos_w = v.X / width;
                double w_rad = Math.Acos(cos_w);
                double w = w_rad * 180.0 / Math.PI;
    
                if (p2.Y < p1.Y)
                    w = -w;
    
                r.Width = width;
    
                //this is set by "hand"; I dont know which value you want to have here
                r.Height = 50;
                r.SetValue(Canvas.LeftProperty, p1.X);
                r.SetValue(Canvas.TopProperty, p1.Y - r.Height / 2.0);
    
                r.Stroke = new SolidColorBrush(Colors.Red);
                r.StrokeThickness = 2;
                r.RenderTransform = new RotateTransform(w, 0, r.Height / 2.0);
    
                //draw the two points:
                e1.Width = 4;
                e1.Height = 4;
                e1.SetValue(Canvas.LeftProperty, p1.X - 2.0);
                e1.SetValue(Canvas.TopProperty, p1.Y - 2.0);
    
                e2.Width = 4;
                e2.Height = 4;
                e2.SetValue(Canvas.LeftProperty, p2.X - 2.0);
                e2.SetValue(Canvas.TopProperty, p2.Y - 2.0);
    
                e1.Stroke = e2.Stroke = new SolidColorBrush(Colors.Blue);
                e1.StrokeThickness = e2.StrokeThickness = 2;
    
                if (canvas1.Children.Contains(r) == false)
                {
                    canvas1.Children.Add(r);
                    canvas1.Children.Add(e1);
                    canvas1.Children.Add(e2);
                }
            }
        }

    and the Xaml:

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Canvas MouseLeftButtonDown="Canvas_MouseLeftButtonDown" MouseRightButtonDown="Canvas_MouseRightButtonDown" Name="canvas1"
                HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Aqua">
            
        </Canvas>
    </Window>

    This will add a rectangle (if it doesnt exist as canvas child) and the two points when clicking. So you can call the method to adjust the rectangle whenever needed...

    A different way was to create your own drawing surface (maybe derviving from canvas) and add/remove visual childs to that.

    Regards,

      Thorsten



  • Monday, May 28, 2012 5:53 PM
     
     

    Hi Thorsten,

    Thank you for your effort trying helping me here.

    but, that is not what i really want to have for my project; though, i am sure someone else would find the code helpful to them.

    what I need is to be able to draw a rectangle from the p1 and p2. also, i am going to draw a lot of rectangles on my Canvas. So, that was what i meant in my previous comment. What I need is a generic function that does the drawing rectangle by having me giving the p1 and p2. and, once I hit the run button in VS, I want to see the rectangle display there, with no mouse click.

    I might be a heck here, but don't get me wrong. I am very appreciate your help.

  • Monday, May 28, 2012 6:07 PM
     
     Answered Has Code

    ... so maybe make a method aout of the code like:

            //the height is used as in your picture, so, that the points are
            //in the middle of the short sides...
            private void DrawRect(Canvas c, Rectangle r, Point p1, Point p2, double height)
            {
                Vector v = p2 - p1;
                double width = Math.Sqrt(v.X * v.X + v.Y * v.Y);
                double cos_w = v.X / width;
                double w_rad = Math.Acos(cos_w);
                double w = w_rad * 180.0 / Math.PI;
    
                if (p2.Y < p1.Y)
                    w = -w;
    
                r.Width = width;
    
                //this is set by "hand"; I dont know which value you want to have here
                r.Height = height;
                r.SetValue(Canvas.LeftProperty, p1.X);
                r.SetValue(Canvas.TopProperty, p1.Y - r.Height / 2.0);
    
                r.Stroke = new SolidColorBrush(Colors.Red);
                r.StrokeThickness = 2;
                r.RenderTransform = new RotateTransform(w, 0, r.Height / 2.0);
    
                //maybe remove this
                if (c.Children.Contains(r) == false)
                {
                    c.Children.Add(r);
                }
            }

    and call it whenever needed...

    DrawRect(canvas1, new Rectangle(), p1, p2, 50);

    But think of making your own design-surface here (as I mentioned above). If you really will have a lot (thousands of) rectangles, the way using drawingVisuals instead of Shape-Controls will be more performant. And you can handle all visuals in one class, so the code will stay somewhat more tidy.

    Regards,

      Thorsten

  • Monday, May 28, 2012 6:31 PM
     
     

    Thank you Thorsten, that is exactly what I was looking for!!

    Though, if you can help me understanding your code would be helpful to me, and to other. can you comment the lines in your code?

  • Monday, May 28, 2012 6:43 PM
     
     Answered Has Code

    Hi,

            //the height is used as in your picture, so, that the points are
            //in the middle of the short sides...
            private void DrawRect(Canvas c, Rectangle r, Point p1, Point p2, double height)
            {
                //get distances
                Vector v = p2 - p1;
                double width = Math.Sqrt(v.X * v.X + v.Y * v.Y);
    
                //get the angle (relation of triangle sides will give the cosine in radians)
                double cos_w = v.X / width;
                double w_rad = Math.Acos(cos_w);
                double w = w_rad * 180.0 / Math.PI;
    
                // clockwisw / non clockwise
                if (p2.Y < p1.Y)
                    w = -w;
    
                //set the width
                r.Width = width;
    
                //the height
                //this is set by "hand"; I dont know which value you want to have here
                r.Height = height;
    
                //set the Location of the Rectangle relative to the containing Canvas
                r.SetValue(Canvas.LeftProperty, p1.X);
                r.SetValue(Canvas.TopProperty, p1.Y - r.Height / 2.0);
    
                //Stroke-Color and Thickness
                r.Stroke = new SolidColorBrush(Colors.Red);
                r.StrokeThickness = 2;
    
                //now do the rotation with a RenderTransform (pass the angle and the location of the point p1
                //as parameters, angle is straightforward, the location is the point at which the rotation will have its origin,
                //so the rectangle will be rotated around that point)
                r.RenderTransform = new RotateTransform(w, 0, r.Height / 2.0);
    
                //maybe remove this
                if (c.Children.Contains(r) == false)
                {
                    c.Children.Add(r);
                }
            }

    Regards,

      Thorsten

    • Proposed As Answer by LeeCampbell Tuesday, May 29, 2012 4:32 PM
    • Marked As Answer by pokerMaster Tuesday, May 29, 2012 6:07 PM
    •  
  • Monday, May 28, 2012 6:58 PM
     
     

    Thanks, your comments helps me understand a lot.

    also, when the rectangle got render into the main display, it is pretty tiny, is there a way i can set it so that it can "fit to screen" or to 25% of screen at bottom half, ..etc?

    this is my XAML...

    <Window x:Class="wpf.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Border>
                <Canvas HorizontalAlignment="Center" VerticalAlignment="Center" Name="myCanvas"
              Width="0" Height="0"
              RenderTransform="1 0 0 -1 0 0">
                </Canvas>
            </Border>
        </Grid>
    </Window>


    • Edited by pokerMaster Monday, May 28, 2012 6:59 PM
    •  
  • Tuesday, May 29, 2012 12:50 AM
     
     

    the width is set by the distance of the points x-distance, the height of the rectangle passed as parameter... so to make it smaller or bigger, change these values.

    Btw: This is a rather unusual way to construct a rectangle, I just followed your picture in your first post. Usually to create a rectangle from two points, one point specifies the upper-left-corner and the other the lower-right one (so both width and height could be computed from the relation of the two points).

    Regards,

      Thorsten

  • Tuesday, May 29, 2012 2:43 PM
     
     

    Hi Thorsten,

    I am also very interested in know how to draw a rectangle with "one point specifies the upper-left-corner and the other the lower-right one (so both width and height could be computed from the relation of the two points)."

    Can you give an example?

  • Tuesday, May 29, 2012 4:47 PM
     
     Answered Has Code

    Hi,

            //p1 is the topLeft corner of the rectangle, p2 the bottomright corner - so a unrotated rectangle is constructed from the points
            private void DrawRect(Canvas c, Rectangle r, Point p1, Point p2, Brush stroke, double strokeThickness, double angle)
            {
                //get distances
                Vector v = p2 - p1;
    
                r.Width = v.X;
                r.Height = v.Y;
    
                //set the Location of the Rectangle relative to the containing Canvas
                r.SetValue(Canvas.LeftProperty, p1.X);
                r.SetValue(Canvas.TopProperty, p1.Y);
    
                //Stroke-Color and Thickness
                r.Stroke = stroke;
                r.StrokeThickness = strokeThickness;
    
                //now do the rotation with a RenderTransform (pass the angle and the location of the point p1
                //as parameters, angle is straightforward, the location is the point at which the rotation will have its origin,
                //so the rectangle will be rotated around that point)
                RotateTransform rot = r.RenderTransform as RotateTransform;
    
                if (rot != null)
                    rot.Angle = angle;
                else
                    r.RenderTransform = new RotateTransform(angle, 0, 0);
    
                //maybe remove this
                if (c.Children.Contains(r) == false)
                {
                    c.Children.Add(r);
                }
            }

    call it like:

    DrawRect(canvas1, new Rectangle(), new Point(50, 50), new Point(300, 200), new SolidColorBrush(Colors.Red), 2, 0);

    Regards,

      Thorsten