locked
Resizing a rotated rectangle RRS feed

  • Question

  • HI,

    I have a problem with resizing the rectangle when rotating a rectangle at an angle.

    I am drawing a rectangle on a windows form.

    When rectangle at zero degrees i am able to move, resize the rectangle, when rotated at an angle using matrix class, i am not able to resize the edges of the rectangle.

    The problem i am facing is when rotated at an angle, the resizing is not happening, but at zero degrees angle i am to resize.

    Please give solution to my problem.


    RotateControl(float ChangedValue,Graphics graphics) 
    {
       float newAngleValue = ChangedValue;
    
                Pen myPen = new Pen(Color.Blue, 1);
                Matrix matrix = new Matrix();
    
                float rectWidth = _rectangle.Width / 2;
                float rectHeight = _rectangle.Height / 2;
    
                float centerX = _rectangle.Left + rectWidth;
                float centerY = _rectangle.Top + rectHeight;
    
                PointF points = new PointF(centerX, centerY);
                matrix.RotateAt(ChangedValue, points, MatrixOrder.Append);
    
                graphics.Transform = matrix;
    }
     void control_MouseDown(object sender, MouseEventArgs e)
    {
    _rectangle= new Rectangle(ptStart.X, ptStart.Y, 0, 0);
    }
    void control_MouseMove(object sender, MouseEventArgs e)
    {
    
    _rectangle = new Rectangle(point,size);
    //Here i am drawing the rectangle in the mousmove event.
    switch(resizeFlag)
    {
    //Resize Logic
    }
    }
    
    
    
    
    
    
    
    
    
    
    
    Give me a solution to the problem(Resizing problem when rotated a rectangle at an angle).






    Friday, February 5, 2010 12:54 PM

All replies

  • NO body is there to reply my question?

    Hay please help me guys.
    • Proposed as answer by Aland Li Tuesday, February 9, 2010 6:54 AM
    • Unproposed as answer by Aland Li Tuesday, February 9, 2010 6:54 AM
    Tuesday, February 9, 2010 4:56 AM
  • Hi friends,

    I am facing a problem when trying to resize a rotated rectangle at an angle.
    At zero degrees, the resize i am able to do. But when rotated at an angle resize is not happening

    I am using Matrix class for rotating a rectangle.

    I tried with many different ways but i am not getting the resize rectangle when rotated at an angle.

    Please see my code:

     void control_MouseDown(object sender, MouseEventArgs e)
            {
                Cursor cursor = (sender as Control).Cursor;
                if (e.Button != MouseButtons.Left)
                {
                    return;
                }
                if (nodeSelected == GetNodeSelectable(e.Location))
                {
                    if (nodeSelected == PosSizableRect.None)
                    {
                        if (cursor == _parentCursor)
                        { 
                           _rectangle.Location = new Point(e.X, e.Y);
                        }
                    }
                }
                else
                {
                    nodeSelected = GetNodeSelectable(e.Location);
                }
                oldX = e.X;
                oldY = e.Y;
            }
    
            void control_MouseMove(object sender, MouseEventArgs e)
            {
                Cursor cursor = (sender as Control).Cursor;
                if (e.Button == MouseButtons.None || e.Button != MouseButtons.Left)
                {
                    Cursor cursors = ChangeCursor(sender as Control, e.Location);
                    return;
                }
                if (nodeSelected == GetNodeSelectable(e.Location))
                {
                    if (nodeSelected == PosSizableRect.None)
                    {
                        if (cursor == _parentCursor)
                        {
                            _rectangle.Size = new Size(e.X - _rectangle.X, e.Y - _rectangle.Y);
                        }
    
                        if (_rectangle.Contains(new Point(e.X, e.Y)))
                        {
                            _rectangle.X = _rectangle.X + e.X - oldX;
                            _rectangle.Y = _rectangle.Y + e.Y - oldY;
                        }
                    }
                }
                    else
                    {
                        PosSizableRect SelectNode = nodeSelected;
                        switch (SelectNode)
                        {
                            case PosSizableRect.LeftUp:
                                _rectangle.X += e.X - oldX;
                                _rectangle.Width -= e.X - oldX;
                                _rectangle.Y += e.Y - oldY;
                                _rectangle.Height -= e.Y - oldY;
                                break;
                            case PosSizableRect.LeftMiddle:
                                _rectangle.X += e.X - oldX;
                                _rectangle.Width -= e.X - oldX;
                                break;
                            case PosSizableRect.LeftBottom:
                                _rectangle.Width -= e.X - oldX;
                                _rectangle.X += e.X - oldX;
                                _rectangle.Height += e.Y - oldY;
                                break;
                            case PosSizableRect.BottomMiddle:
                                _rectangle.Height += e.Y - oldY;
                                break;
                            case PosSizableRect.RightUp:
                                _rectangle.Width += e.X - oldX;
                                _rectangle.Y += e.Y - oldY;
                                _rectangle.Height -= e.Y - oldY;
                                break;
                            case PosSizableRect.RightBottom:
                                _rectangle.Width += e.X - oldX;
                                _rectangle.Height += e.Y - oldY;
                                break;
                            case PosSizableRect.RightMiddle:
                                _rectangle.Width += e.X - oldX;
                                break;
                            case PosSizableRect.UpMiddle:
                                _rectangle.Y += e.Y - oldY;
                                _rectangle.Height -= e.Y - oldY;
                                break;
                            case PosSizableRect.None:
                                if (_rectangle.Contains(new Point(e.X, e.Y)))
                                {
                                    _rectangle.X = _rectangle.X + e.X - oldX;
                                    _rectangle.Y = _rectangle.Y + e.Y - oldY;
                                }
                                break;
                        }
                    }
    
                oldX = e.X;
                oldY = e.Y;
            
                (sender as Control).Invalidate();
            }
    
            void control_Paint(object sender, PaintEventArgs e)
            {
                if (_rectangle.Width == 0 && _rectangle.Height == 0)
                {
                    return;
                }
                try
                {
                    //Matrix transformMatrix = e.Graphics.Transform;
                    RotateControl(Angle, e.Graphics);
                    e.Graphics.DrawRectangle(new Pen(Color.Red),_rectangle);
                    foreach (PosSizableRect pos in Enum.GetValues(typeof(PosSizableRect)))
                    {
                        e.Graphics.DrawRectangle(new Pen(Color.Red), GetRect(pos));
                    }
                  (sender as Control).Invalidate();
                }
    
                catch (Exception exception)
                {
                    MessageBox.Show(exception.Message);
                }
            }
    
            private Cursor ChangeCursor(Control control, Point p)
            {
                Point newPoint = new Point(Convert.ToInt32(p.X + _xOffset), Convert.ToInt32(p.Y - _yOffset));
    
                Cursor cursor = GetCursor(GetNodeSelectable(newPoint));
                if (cursor == null)
                {
                    if (_rectangle.Contains(newPoint))
                    {
                        cursor = Cursors.SizeAll;
                    }
                    else
                    {
                        cursor = _parentCursor;
                    }
                }
               return control.Cursor = cursor;
            }
    
            private Cursor GetCursor(PosSizableRect p)
            {
                switch (p)
                {
                    //case PosSizableRect.LeftUp:
                    //    return Cursors.SizeNWSE;
    
                    //case PosSizableRect.LeftMiddle:
                    //    return Cursors.SizeWE;
    
                    //case PosSizableRect.LeftBottom:
                    //    return Cursors.SizeNESW;
    
                    //case PosSizableRect.BottomMiddle:
                    //    return Cursors.SizeNS;
    
                    //case PosSizableRect.RightUp:
                    //    return Cursors.SizeNESW;
    
                    //case PosSizableRect.RightBottom:
                    //    return Cursors.SizeNWSE;
    
                    case PosSizableRect.RightMiddle:
                        return Cursors.SizeWE;
    
                    //case PosSizableRect.UpMiddle:
                    //    return Cursors.SizeNS;
    
                    default:
                        return null;
                }
            }
    
            private PosSizableRect GetNodeSelectable(Point p)
            {
                Point newPoint = new Point(Convert.ToInt32(p.X + _xOffset), Convert.ToInt32(p.Y - _yOffset));
    
                foreach (PosSizableRect r in Enum.GetValues(typeof(PosSizableRect)))
                {
                    _smallRect = GetRect(r);
                    if (_smallRect.Contains(newPoint))
                    {
                        return r;
                    }
                }
                return PosSizableRect.None;
            }
    
            private Rectangle GetRect(PosSizableRect pos)
            {
                switch (pos)
                {
                    //case PosSizableRect.LeftUp:
                    //    return CreateRectSizableNode(_rectangle.X, _rectangle.Y);
    
                    //case PosSizableRect.LeftMiddle:
                    //    return CreateRectSizableNode(_rectangle.X, _rectangle.Y + _rectangle.Height / 2);
    
                    //case PosSizableRect.LeftBottom:
                    //    return CreateRectSizableNode(_rectangle.X, _rectangle.Y + _rectangle.Height);
    
                    //case PosSizableRect.BottomMiddle:
                    //    return CreateRectSizableNode(_rectangle.X + _rectangle.Width / 2, _rectangle.Y + _rectangle.Height);
    
                    //case PosSizableRect.RightUp:
                    //    return CreateRectSizableNode(_rectangle.X + _rectangle.Width, _rectangle.Y);
    
                    //case PosSizableRect.RightBottom:
                    //    return CreateRectSizableNode(_rectangle.X + _rectangle.Width, _rectangle.Y + _rectangle.Height);
    
                    case PosSizableRect.RightMiddle:
                        return CreateRectSizableNode(_rectangle.X + _rectangle.Width, _rectangle.Y + _rectangle.Height / 2);
    
                    //case PosSizableRect.UpMiddle:
                    //    return CreateRectSizableNode(_rectangle.X + _rectangle.Width / 2, _rectangle.Y);
                }
    
                return new Rectangle();
            }
                  
    
            private Rectangle CreateRectSizableNode(int x, int y)
            {
                return new Rectangle(x - sizeNodeRect / 2, y - sizeNodeRect / 2, sizeNodeRect, sizeNodeRect);
            }
    
            private void RotateControl(float ChangedValue,Graphics graphics)
            {
                Matrix matrix = new Matrix();
    
                float centerX = (_rectangle.Left) + (_rectangle.Width / 2);
                float centerY = (_rectangle.Top) + (_rectangle.Height / 2);
                
                PointF points = new PointF(centerX, centerY);
    
                matrix.RotateAt(ChangedValue, points, MatrixOrder.Append);
    
                _xOffset = matrix.OffsetX;
                _yOffset = matrix.OffsetY;
    
                graphics.Transform = matrix;
            }
    Please help me out to resolve the issue.

    -ShaneNarrifield
    • Merged by Aland Li Tuesday, February 16, 2010 7:39 AM Duplicated
    • Merged by Aland Li Tuesday, February 16, 2010 7:39 AM
    Tuesday, February 9, 2010 6:24 AM
  • Hi Shanenarri,

    Based on my understanding, you want the rectangle to rotate and resize based on its center. It is hard to implement this when we only set a transform matrix to the graphics. We need to create a GraphicsPath and add a position independent rectangle in it. Then we can apply the rotation and scaling on the GraphicsPath. When we finishes transforming the GraphicsPath, we need to apply some translating transformation on the Graphics to move the rectangle to its position.

    You can follow the code snippet below:
        Rectangle _rectangle = new Rectangle(100, 100, 100, 100);
        private PointF _scale = new PointF(1,1);
        private float _angle = 0.0f;
        private Point _translate = Point.Empty;
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
    
            float rectWidth = _rectangle.Width / 2;
            float rectHeight = _rectangle.Height / 2;
    
            float centerX = _rectangle.Left + rectWidth;
            float centerY = _rectangle.Top + rectHeight;
            
            //Rotate and scale the rectangle in its center.
            
            //The matrix below only manipulates the shape, which is independent on its location.
            Matrix grapthMatrix = new Matrix();
            grapthMatrix.Rotate(_angle);
            grapthMatrix.Scale(_scale.X,_scale.Y);
    
            GraphicsPath graph = new GraphicsPath();
            //Add the rectangle, its center is origin '0,0'
            graph.AddRectangle(new Rectangle(Point.Truncate(new PointF(-rectWidth,-rectHeight)),_rectangle.Size));
            graph.Transform(grapthMatrix);
            
            e.Graphics.ResetTransform();
            Matrix matrix = new Matrix();
    
            //Move the rectangle to its location
            matrix.Translate(centerX, centerY); 
            //Move it to the new place.
            matrix.Translate(_translate.X, _translate.Y);
    
            e.Graphics.Transform = matrix;
    
            e.Graphics.FillPath(Brushes.Yellow, graph);
        }


    Let me know if this does not help.
    Aland Li



    Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
    Tuesday, February 9, 2010 8:48 AM
  • HI,

    In the code snippet, i see

    matrix.Translate(_translate.X, _translate.Y);

    What are _translate.x, _translate.y mean?

    Also

    grapthMatrix.Scale(_scale.X,_scale.Y); is this line indicates the resize logic??? then what for _scale.x and _scale.y intended for?


    Tuesday, February 9, 2010 9:51 AM
  • Hi Shanenarri,

     _translate is a member to store the scaling factors. You can change it when you scale the rectangle.

    Regards,
    Aland Li
    Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
    Tuesday, February 9, 2010 10:09 AM
  • Hi,

    If u want i can post my whole project.
    I am not able to get the resize point when rotated at an angle.

    -ShaneNarrifield.

    Tuesday, February 9, 2010 11:53 AM
  • Hi Shanenarri,

    You can upload it to a web site, such as sky driver.

    Regards,
    Aland Li
    Please mark the replies as answers if they help and unmark if they don't. This can be beneficial to other community members reading the thread.
    Tuesday, February 9, 2010 12:01 PM
  • HI aland,

    Go through the following link for the project.

    http://cid-0e0fc9e50d0e627c.skydrive.live.com/self.aspx/.Public/RotateRectangle.cs.cs

    Help me in this regard(resizing problem when rotated a rectagle at an angle)

    Thanks,
    Shanenarrifield
    Wednesday, February 10, 2010 10:12 AM
  • I had a look at the code you posted on skydrive.

    I can suggest a way to detect the resize nodes, and the correct bounds of the rotated rectangle (for detecting and moving the entire rectangle).

    However, I can't come up with a way to correctly resize your rectangle once detected. Your rectangle is an 'integer' one (type is Rectangle). Are you able to change it to the float type (RectangleF)?

    The method relies on transforming the mouse co-ordinates to what they would be for an unrotated rectangle. This is because you store your rectangle in its unrotated form, then rotate it by applying a rotate transform to the Graphics object used for rendering.

    Add the following code ...

    private PointF getMidPoint()
    {
        float centerX = (_rectangle.Left) + (_rectangle.Width / 2);
        float centerY = (_rectangle.Top) + (_rectangle.Height / 2);
    
        return new PointF(centerX, centerY);
    }
    
    Point transformedPoint(PointF original, PointF origin)
    {
        PointF[] pts = new PointF[1];
    
        using (Matrix matrix = new Matrix())
        {
            matrix.RotateAt(-Angle, origin);
            pts[0] = original;
            matrix.TransformPoints(pts);
        }
    
        return new Point((int)pts[0].X, (int)pts[0].Y);
    }
    
    Point transformedPoint(PointF original)
    {
        return transformedPoint(original, getMidPoint());
    }
    

    Then modify your code at the following places:

    First, in your method which checks for a node: (GetNodeSelectable)
    Add the following line at the start of the method's code. This positions the test point at the location it would have, if the rectangle was unrotated. This works because the nodes you create have locations on the unrotated rectangle.

        // Transform the point.
        p = transformedPoint(p);

    Second, in your ChangeCursor method:

    Change the following line ...

        if (_rectangle.Contains(p))
    ... to:
        // Change to checking for the transformed point.
        if (_rectangle.Contains(transformedPoint(p)))

    Finally, in the mouse move handler:

    Change the following line,

    else if (_rectangle.Contains(new Point(e.X, e.Y)))
    to,
    else if (_rectangle.Contains(transformedPoint(e.Location)))
    • Edited by Chris50 Wednesday, February 10, 2010 7:40 PM Formatting
    Wednesday, February 10, 2010 7:19 PM
  • What about the small rectangles drawn on the base rectangle for resizing the edges.

    Do we really need to chanage the small rectangle points also when rotated at an angle?
    HOw to redraw rotated rectangle when transformationpoints are set?

    Thursday, February 11, 2010 5:18 AM
  • Hai Chris,

    Thanks for the help and now i am able to resize the rectangle according to the rotation made at an angle.

    Thanks once again.

    Can i know how to change the cursor according to the angle of rotation since i am using standard cursors from the Cursors class. Is there a way to rotate the cursors according to the angles made??
    Thursday, February 11, 2010 12:15 PM
  • As far as I know, cursors can't be rotated. I might be wrong, though.

    The only solution that I can think of is to add code that takes account of the rectangle's rotation angle to choose the 'closest' or 'best' cursor for that angle. I know of a few graphics programs that use this approach.

    So for example, if you normally have a 'North-South' cursor for the upper and lower rectangle line handles, then when your rectangle is rotated to 90 degrees (or near to 90 degrees), you could change the cursor for these to the 'East-West' one.

    Thursday, February 11, 2010 3:22 PM
  • Hi chrish,

    If you can see MSWord 2007 , we can draw different shapes say something like rectangle drawing.
    There, cursors are angled and updated according to the angle of rectangle rotation.

    Can you have a look at that rectangle. I am not really getting idea how the cursors are angled according to the rectangle rotation.

    Thanks,
    Shanenarrifield

    Thursday, February 11, 2010 5:15 PM
  • Hi chris,

    Thanks for all your inputs and suggestions.
    Upto now i am to able move,resize, rotate and resize rectangle(OCR Selection tool) after rotation i am able to perform resize operation but with cursor positions getting the problem.

    But, i am not really sure how to resize the the rectangle when it is resized in the reverse direction.
    Please have a look at my code.

    I have placed my project in the following link. Please have a look at it.
    http://cid-0e0fc9e50d0e627c.skydrive.live.com/browse.aspx/.Public

    I am facing lot of issues(reverse resizing,rotation resizing) with resizing when rotated please have a fix for my problem.

    -Shanenarrifield.
    Monday, February 15, 2010 10:15 AM
  • I'm struggling with the same problem in a current project. Could you please provide the sources again on your SkyDrive?

    Thank you!

    Thursday, August 2, 2012 9:00 AM