Zoom an vector drawn image

Just starting out? Need help? Post your questions and find answers here.
Amundo
Enthusiast
Enthusiast
Posts: 200
Joined: Thu Feb 16, 2006 1:41 am
Location: New Zealand

Re: Zoom an vector drawn image

Post by Amundo »

Nice examples, guys.

Does anyone have an example that zooms AND rotates AND moves along the X/Y axis?
Win10, PB6.x, okayish CPU, onboard video card, fuzzy monitor (or is that my eyesight?)
"When the facts change, I change my mind" - John Maynard Keynes
Little John
Addict
Addict
Posts: 4777
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Zoom an vector drawn image

Post by Little John »

Amundo wrote:Does anyone have an example that zooms AND rotates AND moves along the X/Y axis?
Here you go! :-)

Besides rotating and moving, zooming now can also be done with the keyboard.

Code: Select all

; LJ 2017-04-04, <http://www.purebasic.fr/english/viewtopic.php?p=505458#p505458>
; successfully tested with PB 5.60 (x64) on Windows 10

CompilerIf #PB_Compiler_Version < 550
   MessageRequester("Error", "PureBasic version 5.50 or newer required because the new bounding box functions are used.")

CompilerElse
   EnableExplicit

   Structure PointD
      x.d
      y.d
   EndStructure

   Structure Polygon
      Array p.PointD(0)
      center.PointD
      color.i
      width.i
   EndStructure

   ;-----------------------------------------------------------------------

   Macro Rect2Polar_D (_x_, _y_)
      ; -- convert rectangular coordinates to polar coordinates
      ; in : _x_, _y_: rectangular coordinates
      ; out: corresponding distance

      Sqr((_x_)*(_x_) + (_y_)*(_y_))
   EndMacro

   Macro Rect2Polar_A (_x_, _y_)
      ; -- convert rectangular coordinates to polar coordinates
      ; in : _x_, _y_: rectangular coordinates
      ; out: corresponding angle, expressed in rad;
      ;      ]-Pi; +Pi]

      ATan2(_x_, _y_)
   EndMacro

   ;-----------------------------------------------------------------------

   Macro Polar2Rect_X (_distance_, _angle_)
      ; -- convert polar coordinates to rectangular coordinates
      ; in : _distance_: must be >= 0
      ;      _angle_   : expressed in rad
      ; out: corresponding x coordinate

      ((_distance_) * Cos(_angle_))
   EndMacro

   Macro Polar2Rect_Y (_distance_, _angle_)
      ; -- convert polar coordinates to rectangular coordinates
      ; in : _distance_: must be >= 0
      ;      _angle_   : expressed in rad
      ; out: corresponding y coordinate

      ((_distance_) * Sin(_angle_))
   EndMacro

   ;-----------------------------------------------------------------------

   Procedure DrawObject (canvas.i, *obj.Polygon)
      Protected.i i, last = ArraySize(*obj\p())

      If StartVectorDrawing(CanvasVectorOutput(canvas))
         ; clear canvas
         VectorSourceColor(RGBA(255, 255, 255, 255))
         FillVectorOutput()

         ; draw object and get the center of its bounding box
         With *obj
            MovePathCursor(\p(0)\x, \p(0)\y)
            For i = 1 To last
               AddPathLine(\p(i)\x, \p(i)\y)
            Next
            ClosePath()

            \center\x = PathBoundsX() + PathBoundsWidth()/2.0
            \center\y = PathBoundsY() + PathBoundsHeight()/2.0

            VectorSourceColor(\color)
            StrokePath(\width)
         EndWith

         StopVectorDrawing()
      EndIf
   EndProcedure


   Procedure ZoomObject (canvas.i, *obj.Polygon, factor.d)
      Protected.i i, last = ArraySize(*obj\p())

      With *obj
         For i = 0 To last
            \p(i)\x + factor * (\p(i)\x - \center\x)
            \p(i)\y + factor * (\p(i)\y - \center\y)
         Next
      EndWith

      DrawObject(canvas, *obj)
   EndProcedure


   Procedure RotateObject (canvas.i, *obj.Polygon, rotation.d)
      Protected.i i, last = ArraySize(*obj\p())
      Protected.d distance, angle
      
      rotation = Radian(rotation)
      With *obj
         For i = 0 To last
            distance = Rect2Polar_D(\p(i)\x - \center\x, \p(i)\y - \center\y)
            angle    = Rect2Polar_A(\p(i)\x - \center\x, \p(i)\y - \center\y)
            \p(i)\x = \center\x + Polar2Rect_X(distance, angle + rotation)
            \p(i)\y = \center\y + Polar2Rect_Y(distance, angle + rotation)
         Next
      EndWith

      DrawObject(canvas, *obj)
   EndProcedure


   Procedure MoveObject_Horizontal (canvas.i, *obj.Polygon, dx.d)
      Protected.i i, last = ArraySize(*obj\p())

      With *obj
         For i = 0 To last
            \p(i)\x + dx
         Next
      EndWith

      DrawObject(canvas, *obj)
   EndProcedure


   Procedure MoveObject_Vertical (canvas.i, *obj.Polygon, dy.d)
      Protected.i i, last = ArraySize(*obj\p())

      With *obj
         For i = 0 To last
            \p(i)\y + dy
         Next
      EndWith

      DrawObject(canvas, *obj)
   EndProcedure

   ;-======================================================================

   ; Windows
   Enumeration
      #WinMain
   EndEnumeration

   ; Gadgets
   Enumeration
      #Canvas
   EndEnumeration

   Define obj.Polygon, dw.i, event.i


   ;-- Create a window with a canvas gadget
   If OpenWindow(#WinMain, 0, 0, 400, 400, "Canvas demo", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) = 0
      MessageRequester("Fatal error", "Couldn't open main window.")
      End
   EndIf

   CanvasGadget(#Canvas, 0, 0, 400, 400, #PB_Canvas_Keyboard)
   SetActiveGadget(#Canvas)    ; set the keyboard focus on the canvas gadget

   ;-- Define a polygon
   With obj
      Dim \p(4)
      \p(0)\x = 100.0 : \p(0)\y = 250.0
      \p(1)\x = 250.0 : \p(1)\y = 250.0
      \p(2)\x = 250.0 : \p(2)\y = 170.0
      \p(3)\x = 175.0 : \p(3)\y = 140.0
      \p(4)\x = 100.0 : \p(4)\y = 170.0
      \color = RGBA(255, 0, 0, 255)
      \width = 2
   EndWith

   ;-- Show the polygon
   DrawObject(#Canvas, @obj)


   ;-- Process events
   Repeat
      event = WaitWindowEvent()

      If event = #PB_Event_Gadget
         Select EventGadget()
            Case #Canvas
               Select EventType()
                  Case #PB_EventType_MouseWheel
                     ;-- Zoom
                     dw = GetGadgetAttribute(#Canvas, #PB_Canvas_WheelDelta)
                     ZoomObject(#Canvas, @obj, 0.1*dw)

                  Case #PB_EventType_KeyDown
                     Select GetGadgetAttribute(#Canvas, #PB_Canvas_Key)
                           ;-- Zoom
                        Case #PB_Shortcut_Add
                           ZoomObject(#Canvas, @obj,  0.1)
                        Case #PB_Shortcut_Subtract
                           ZoomObject(#Canvas, @obj, -0.1)

                           ;-- Rotate (angle expressed in degrees)
                        Case #PB_Shortcut_PageDown
                           RotateObject(#Canvas, @obj,  6.0)
                        Case #PB_Shortcut_PageUp
                           RotateObject(#Canvas, @obj, -6.0)

                           ;-- Move
                        Case #PB_Shortcut_Right
                           MoveObject_Horizontal(#Canvas, @obj,  3)
                        Case #PB_Shortcut_Left
                           MoveObject_Horizontal(#Canvas, @obj, -3)
                        Case #PB_Shortcut_Down
                           MoveObject_Vertical(#Canvas, @obj,  3)
                        Case #PB_Shortcut_Up
                           MoveObject_Vertical(#Canvas, @obj, -3)
                     EndSelect
               EndSelect
         EndSelect
      EndIf
   Until event = #PB_Event_CloseWindow
CompilerEndIf
Last edited by Little John on Tue Apr 04, 2017 3:05 pm, edited 1 time in total.
Little John
Addict
Addict
Posts: 4777
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Zoom an vector drawn image

Post by Little John »

Here is another version, using the built-in vector commands TranslateCoordinates() and RotateCoordinates() for moving and rotating, respectively. For zooming, I didn't manage to use ScaleCoordinates() properly, since I want to use the center of the object as anchor point, not the upper left corner.
Now it doesn't make much sense anymore to write some parts of the code as separate procedures. However, I didn't change that, so that it's easier to compare this code with the previous one.

Code: Select all

; LJ 2017-04-04, <http://www.purebasic.fr/english/viewtopic.php?p=505463#p505463>
; successfully tested with PB 5.60 (x64) on Windows 10

CompilerIf #PB_Compiler_Version < 550
   MessageRequester("Error", "PureBasic version 5.50 or newer required because the new bounding box functions are used.")

CompilerElse
   EnableExplicit

   Structure PointD
      x.d
      y.d
   EndStructure

   Structure Polygon
      Array p.PointD(0)
      center.PointD
      color.i
      width.i
      angle.d
      offset.PointD
   EndStructure

   
   Procedure DrawObject (canvas.i, *obj.Polygon)
      Protected.i i, last = ArraySize(*obj\p())

      If StartVectorDrawing(CanvasVectorOutput(canvas))
         ; clear canvas
         VectorSourceColor(RGBA(255, 255, 255, 255))
         FillVectorOutput()
         
         ; draw object and get the center of its bounding box
         With *obj
            TranslateCoordinates(\offset\x, \offset\y)
            RotateCoordinates(\center\x, \center\y, \angle)
            
            MovePathCursor(\p(0)\x, \p(0)\y)
            For i = 1 To last
               AddPathLine(\p(i)\x, \p(i)\y)
            Next
            ClosePath()

            \center\x = PathBoundsX() + PathBoundsWidth()/2.0
            \center\y = PathBoundsY() + PathBoundsHeight()/2.0
            
            VectorSourceColor(\color)
            StrokePath(\width)
         EndWith

         StopVectorDrawing()
      EndIf
   EndProcedure


   Procedure ZoomObject (canvas.i, *obj.Polygon, factor.d)
      Protected.i i, last = ArraySize(*obj\p())

      With *obj
         For i = 0 To last
            \p(i)\x + factor * (\p(i)\x - \center\x)
            \p(i)\y + factor * (\p(i)\y - \center\y)
         Next
      EndWith

      DrawObject(canvas, *obj)
   EndProcedure


   Procedure RotateObject (canvas.i, *obj.Polygon, rotation.d)
      *obj\angle + rotation
      DrawObject(canvas, *obj)
   EndProcedure


   Procedure MoveObject_Horizontal (canvas.i, *obj.Polygon, dx.d)
      *obj\offset\x + dx
      DrawObject(canvas, *obj)
   EndProcedure


   Procedure MoveObject_Vertical (canvas.i, *obj.Polygon, dy.d)
      *obj\offset\y + dy
      DrawObject(canvas, *obj)
   EndProcedure

   ;-======================================================================

   ; Windows
   Enumeration
      #WinMain
   EndEnumeration

   ; Gadgets
   Enumeration
      #Canvas
   EndEnumeration

   Define obj.Polygon, dw.i, event.i


   ;-- Create a window with a canvas gadget
   If OpenWindow(#WinMain, 0, 0, 400, 400, "Canvas demo", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) = 0
      MessageRequester("Fatal error", "Couldn't open main window.")
      End
   EndIf

   CanvasGadget(#Canvas, 0, 0, 400, 400, #PB_Canvas_Keyboard)
   SetActiveGadget(#Canvas)    ; set the keyboard focus on the canvas gadget

   ;-- Define a polygon
   With obj
      Dim \p(4)
      \p(0)\x = 100.0 : \p(0)\y = 250.0
      \p(1)\x = 250.0 : \p(1)\y = 250.0
      \p(2)\x = 250.0 : \p(2)\y = 170.0
      \p(3)\x = 175.0 : \p(3)\y = 140.0
      \p(4)\x = 100.0 : \p(4)\y = 170.0
      \color = RGBA(255, 0, 0, 255)
      \width = 2
      \angle = 0.0
      \offset\x = 0.0
      \offset\y = 0.0
   EndWith

   ;-- Show the polygon
   DrawObject(#Canvas, @obj)


   ;-- Process events
   Repeat
      event = WaitWindowEvent()

      If event = #PB_Event_Gadget
         Select EventGadget()
            Case #Canvas
               Select EventType()
                  Case #PB_EventType_MouseWheel
                     ;-- Zoom
                     dw = GetGadgetAttribute(#Canvas, #PB_Canvas_WheelDelta)
                     ZoomObject(#Canvas, @obj, 0.1*dw)

                  Case #PB_EventType_KeyDown
                     Select GetGadgetAttribute(#Canvas, #PB_Canvas_Key)
                           ;-- Zoom
                        Case #PB_Shortcut_Add
                           ZoomObject(#Canvas, @obj,  0.1)
                        Case #PB_Shortcut_Subtract
                           ZoomObject(#Canvas, @obj, -0.1)
                           
                           ;-- Rotate (angle expressed in degrees)
                        Case #PB_Shortcut_PageDown
                           RotateObject(#Canvas, @obj,  6.0)
                        Case #PB_Shortcut_PageUp
                           RotateObject(#Canvas, @obj, -6.0)

                           ;-- Move
                        Case #PB_Shortcut_Right
                           MoveObject_Horizontal(#Canvas, @obj,  3)
                        Case #PB_Shortcut_Left
                           MoveObject_Horizontal(#Canvas, @obj, -3)
                        Case #PB_Shortcut_Down
                           MoveObject_Vertical(#Canvas, @obj,  3)
                        Case #PB_Shortcut_Up
                           MoveObject_Vertical(#Canvas, @obj, -3)
                     EndSelect
               EndSelect
         EndSelect
      EndIf
   Until event = #PB_Event_CloseWindow
CompilerEndIf
Last edited by Little John on Tue Apr 04, 2017 3:07 pm, edited 1 time in total.
User avatar
skywalk
Addict
Addict
Posts: 4211
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Zoom an vector drawn image

Post by skywalk »

Thanks for the comparison code Little John. 8)
Small problem. Rotating the object completely does not arrive at its original angle? Small skew.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Little John
Addict
Addict
Posts: 4777
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Zoom an vector drawn image

Post by Little John »

Hello skywalk, many thanks for your bug report.
Obviously, choosing 0.1 radians (about 5.73 degrees) as step for rotating wasn't a good idea. :D :oops:
In both codes above, I've changed that now to 6.0 degrees, which should work fine (at least in theory).
Thanks again!
User avatar
skywalk
Addict
Addict
Posts: 4211
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Zoom an vector drawn image

Post by skywalk »

Ah, makes sense now. I was thinking degrees(°).
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Amundo
Enthusiast
Enthusiast
Posts: 200
Joined: Thu Feb 16, 2006 1:41 am
Location: New Zealand

Re: Zoom an vector drawn image

Post by Amundo »

LittleJohn, I can't thank you enough, I will use your code to move horizontally/vertically, which was the last piece I needed.

(I think I have the code to translate the coordinates necessary, but would have had to translate it for this situation).

Thanks a million for all your help!

Edit: Actually, I've completely lost the plot!! The only thing I need to fix is the zoom!
Win10, PB6.x, okayish CPU, onboard video card, fuzzy monitor (or is that my eyesight?)
"When the facts change, I change my mind" - John Maynard Keynes
Post Reply