Corner of rotated box

Just starting out? Need help? Post your questions and find answers here.
wombats
Enthusiast
Enthusiast
Posts: 663
Joined: Thu Dec 29, 2011 5:03 pm

Corner of rotated box

Post by wombats »

Hi,

I'm working towards implementing resizing shapes in my project, but I am unsure how to determine where the corners of the box are when its rotated. For example, when the box is rotated to 40 degrees, what was the bottom-right corner is now at the bottom. Is there a formula or something I can use to determine where the corners are?

Code: Select all

EnableExplicit

Structure Box
  x.i : y.i
  w.i : h.i
  angle.i
EndStructure

Global handleSize = 6

Global *b.Box = AllocateStructure(Box)
With *b
  \x = 270 : \y = 178
  \w = 100 : \h = 125
  \angle = 0
EndWith

Procedure DrawCanvas()
  Protected txt$
  txt$ = ~"Left/right to rotate\n\n0 to reset\n\nEscape to end\n\n\nAngle: " + Str(*b\angle) + Chr(176)
  If StartVectorDrawing(CanvasVectorOutput(0))
    VectorSourceColor(RGBA(0, 0, 0, 255))
    FillVectorOutput()
    VectorSourceColor(RGBA(255, 255, 255, 255))
    MovePathCursor(20, 20)
    DrawVectorParagraph(txt$, 200, 200)
    RotateCoordinates(*b\x + *b\w / 2, *b\y + *b\h / 2, *b\angle)
    AddPathBox(*b\x, *b\y, *b\w, *b\h)  
    VectorSourceColor(RGBA(0, 0, 255, 255))
    StrokePath(1)
    StopVectorDrawing()
  EndIf
EndProcedure

Procedure OnCanvasEvents()
  Select EventType()
    Case #PB_EventType_KeyDown
      Select GetGadgetAttribute(0, #PB_Canvas_Key)
        Case #PB_Shortcut_Left
          *b\angle - 3
          If *b\angle < 0
            *b\angle = 359
          EndIf
          If *b\angle > 359
            *b\angle = 0
          EndIf
        Case #PB_Shortcut_Right
          *b\angle + 3
          If *b\angle < 0
            *b\angle = 359
          EndIf
          If *b\angle > 359
            *b\angle = 0
          EndIf
        Case #PB_Shortcut_0 : *b\angle = 0
        Case #PB_Shortcut_Escape : End
      EndSelect
      DrawCanvas()
  EndSelect
EndProcedure

If OpenWindow(0, 0, 0, 640, 480, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  CanvasGadget(0, 0, 0, 640, 480, #PB_Canvas_Keyboard)
  BindGadgetEvent(0, @OnCanvasEvents(), #PB_All)
  DrawCanvas()
  SetActiveGadget(0)
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: Corner of rotated box

Post by Mijikai »

U can just calculate the new positions.

This code for example rotates one point around another point (anchor):

Code: Select all

Structure VECTOR_STRUCT
  x.f
  y.f
EndStructure

Procedure.i RotateAnchoredPoint(*Anchor.VECTOR_STRUCT,*Point.VECTOR_STRUCT,Angle.f,*Out.VECTOR_STRUCT)
  Protected angle_sin.f
  Protected angle_cos.f
  Protected pos_x.f
  Protected pos_y.f
  angle_sin = Sin(angle)
  angle_cos = Cos(angle)
  pos_x = *Point\x - *Anchor\x
  pos_y = *Point\y - *Anchor\y
  *Out\x = (angle_cos * pos_x) - (angle_sin * pos_y) + *Anchor\x
  *Out\y = (angle_sin * pos_x) + (angle_cos * pos_y) + *Anchor\y
  ProcedureReturn #Null
EndProcedure
If you have a box just do this for all corner points (the anchor point would be the box center).
wombats
Enthusiast
Enthusiast
Posts: 663
Joined: Thu Dec 29, 2011 5:03 pm

Re: Corner of rotated box

Post by wombats »

Hi,

Thanks for your reply and code.

How would I know which corner does what - for example, if I want to change the mouse corner to #PB_Cursor_LeftUpRightDown when the mouse is over it?
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: Corner of rotated box

Post by Mijikai »

Im not sure if i understand you correctly - do you want to check if the mouse is inside the rectangle or just know where the corners are?

If u want to always know where which corner is u can either store the angle or mark at least two (diagonal) corner points.
Im not sure how to detect if a point is in a rotated rectangle i would need to look it up.
wombats
Enthusiast
Enthusiast
Posts: 663
Joined: Thu Dec 29, 2011 5:03 pm

Re: Corner of rotated box

Post by wombats »

Sorry for not being clearer.

With the first box, the black mark is at the top-right and I would change the cursor to #PB_Cursor_LeftDownRightUp. In the second, because the box has been rotated, it's at the bottom, so the cursor would need to be #PB_Cursor_UpDown.

Image
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: Corner of rotated box

Post by Mijikai »

So you need to do both and see which corner is the closest in order to set the correct mouse cursor.
#NULL
Addict
Addict
Posts: 1440
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Corner of rotated box

Post by #NULL »

You need to know your center of rotation. If you rotate your box around the center of the box, you would get the distance from that center to the unrotated corner. Then you can rotate that vector by the same amount by which you rotate the box, then add the center position again to the rotated vector and you have your new corner position.

For rotated box collision you can check this out:
Rotated Box Collision Detection 2d/3d

Similar to what I wrote above, for collision detection you can also get the distance from your center of rotation to the mouse position, then unrotate (reverse rotate) that relative mouse position vector by the amount of your box rotation, and then do a normal box collision check (point in rectangle, without rotation).

I hope that helps :)
wombats
Enthusiast
Enthusiast
Posts: 663
Joined: Thu Dec 29, 2011 5:03 pm

Re: Corner of rotated box

Post by wombats »

Thanks for your replies. What I am struggling to understand how to do is identify what a resize handle should be based on the rotation of the box. At 0º, the handle for changing the height is going to be at the bottom, whereas at 45º, it's shifted up and to the left.

If I reverse the rotation of the handle, that gives me its position at 0º, but that doesn't help me figure out what that handle should actually be. The position of the handle should always be on the outside of the box, but when the angle exceeds 90º, it starts to move inside the box.

The handle is correctly identified at 0º and 180º, but at any other angle, it would take on a different function. I am struggling to figure out how to identify what that function should be based on the rotation.

Code: Select all

EnableExplicit

Structure PointF
  x.f
  y.f
EndStructure

Procedure.i RotateAnchoredPoint(*Anchor.PointF,*Point.PointF,Angle.f,*Out.PointF)
  Protected angle_sin.f
  Protected angle_cos.f
  Protected pos_x.f
  Protected pos_y.f
  angle_sin = Sin(Radian(angle))
  angle_cos = Cos(Radian(angle))
  pos_x = *Point\x - *Anchor\x
  pos_y = *Point\y - *Anchor\y
  *Out\x = (angle_cos * pos_x) - (angle_sin * pos_y) + *Anchor\x
  *Out\y = (angle_sin * pos_x) + (angle_cos * pos_y) + *Anchor\y
  ProcedureReturn #Null
EndProcedure

Structure Box
  x.i : y.i
  w.i : h.i
  angle.f
  handle.PointF
  rotatedHandle.PointF
EndStructure

Global handleSize = 6

Global *b.Box = AllocateStructure(Box)
With *b
  \x = 270 : \y = 178
  \w = 100 : \h = 125
  \angle = 0
  \handle\x = \x + \w
  \handle\y = \y + (\h / 2) 
EndWith

Procedure DrawCanvas()
  Protected txt$
  txt$ = ~"Left/right to rotate\n\n0 to reset\n\nEscape to end\n\n\nAngle: " + Str(*b\angle) + Chr(176)
  If StartVectorDrawing(CanvasVectorOutput(0))
    VectorSourceColor(RGBA(0, 0, 0, 255))
    FillVectorOutput()
    VectorSourceColor(RGBA(255, 255, 255, 255))
    MovePathCursor(20, 20)
    DrawVectorParagraph(txt$, 200, 200)
    RotateCoordinates(*b\x + *b\w / 2, *b\y + *b\h / 2, *b\angle)
    AddPathBox(*b\x, *b\y, *b\w, *b\h)  
    VectorSourceColor(RGBA(0, 0, 255, 255))
    StrokePath(1)
    StopVectorDrawing()
    If StartDrawing(CanvasOutput(0))
      Define center.PointF, rotated.PointF
      center\x = *b\x + *b\w / 2
      center\y = *b\y + *b\h / 2
      RotateAnchoredPoint(@center, @*b\handle, *b\angle, @*b\rotatedHandle)
      Box(*b\rotatedHandle\x, *b\rotatedHandle\y, 5, 5, RGB(255, 255, 0))
      StopDrawing()
    EndIf
  EndIf
EndProcedure

Procedure OnCanvasEvents()
  Select EventType()
    Case #PB_EventType_MouseMove
      Define mx, my
      mx = GetGadgetAttribute(0, #PB_Canvas_MouseX)
      my = GetGadgetAttribute(0, #PB_Canvas_MouseY)
      If mx => *b\rotatedHandle\x And mx < *b\rotatedHandle\x + 5 And my => *b\rotatedHandle\y And my < *b\rotatedHandle\y + 5
        SetGadgetAttribute(0, #PB_Canvas_Cursor, #PB_Cursor_LeftRight)
      Else
        SetGadgetAttribute(0, #PB_Canvas_Cursor, #PB_Cursor_Default)
      EndIf
    Case #PB_EventType_KeyDown
      Select GetGadgetAttribute(0, #PB_Canvas_Key)
        Case #PB_Shortcut_Left
          *b\angle - 3
          If *b\angle < 0
            *b\angle = 359
          EndIf
          If *b\angle > 359
            *b\angle = 0
          EndIf
        Case #PB_Shortcut_Right
          *b\angle + 3
          If *b\angle < 0
            *b\angle = 359
          EndIf
          If *b\angle > 359
            *b\angle = 0
          EndIf
        Case #PB_Shortcut_0 : *b\angle = 0
        Case #PB_Shortcut_Escape : End
      EndSelect
      DrawCanvas()
  EndSelect
EndProcedure

If OpenWindow(0, 0, 0, 640, 480, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  CanvasGadget(0, 0, 0, 640, 480, #PB_Canvas_Keyboard)
  BindGadgetEvent(0, @OnCanvasEvents(), #PB_All)
  DrawCanvas()
  SetActiveGadget(0)
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: Corner of rotated box

Post by Mijikai »

Use the angle to decide what cursor is drawn:

Code: Select all

Case #PB_EventType_MouseMove
      Define mx, my
      mx = GetGadgetAttribute(0, #PB_Canvas_MouseX)
      my = GetGadgetAttribute(0, #PB_Canvas_MouseY)
      If mx => *b\rotatedHandle\x And mx < *b\rotatedHandle\x + 5 And my => *b\rotatedHandle\y And my < *b\rotatedHandle\y + 5
        If *b\angle < 45 Or *b\angle > 315;example only covers 0° +- 90° & LeftRight + UpDown
          SetGadgetAttribute(0, #PB_Canvas_Cursor, #PB_Cursor_LeftRight)
        Else
          If (*b\angle > 45 And *b\angle < 90) Or (*b\angle < 315 And *b\angle > 270)
            SetGadgetAttribute(0, #PB_Canvas_Cursor, #PB_Cursor_UpDown)
          Else
            SetGadgetAttribute(0, #PB_Canvas_Cursor, #PB_Cursor_Default)
          EndIf
        EndIf
;...
Post Reply