Mike O
Mike O

Reputation: 149

Zoom in and out and keep current pixel at mouse coordinates

So... I have this code I wrote to that draws a quad in ortho mode in Opengl. I know where its located and its size. Sometimes square.. some times its rectangular. What I'm attempting to do is zoom in and out and stay over the same location on the quad. I thought it would work but It's not. Knowing the distance from the mouse location to the corner, offset.x and the difference equaling rect_size.x- old_size_w the basic math would me this: (offset.x/rect_size.x) * difference. That should give me the scale of how much the location needs to move based on where the mouse is sitting. I hope someone can sort this out.. Thank you!....

Some numbers...

     location = 100,100
     old_size_w = 1024
     rect_size.x = 1088 (new size old_ * 1.0625)
     mouse_delta.x = 425
     offset = 100 - 425 (-325)
     difference = 1088-1024 (64)
     delta_x = 325/1088 (.2987132....)
     x_offset = Cint(delta_x * difference) (19) (19.11764...)

SO.... we are only moving by 19 pixels.. If we do the math from the other direction.. the 2 must = the difference from the old zoom and the new zoom

    delta_x = (1088-325) /1088 (.701286...)
    x_offset2 = Cint(delta_x * difference) (45) (44.88235...)
    19 + 45 = 64   <--- this proves out the math

Yet... I am getting a nasty shift that gets worse the closer to the right of the image I move. Maybe someone can find the problem.. r_x is remaining X in the code below and is for proving the math.

  Public Sub img_scale_up()
    If Not ready_to_render Then Return
    If Zoom_Factor >= 4.0 Then
        Zoom_Factor = 4.0
        Return 'to big and the t_bmp creation will hammer memory.
    End If
    Dim amt As Single = 0.0625
    Zoom_Factor += amt


    Dim offset As New Point
    'old_w and old_h are the orginal size of the image.

    Dim old_size_w, old_size_h As Double
    old_size_w = (old_w * (Zoom_Factor - amt))
    old_size_h = (old_h * (Zoom_Factor - amt))
    offset = rect_location - (mouse_delta)
    rect_size.X = Zoom_Factor * old_w
    rect_size.Y = Zoom_Factor * old_h
    Dim r_x As Double = ((rect_size.X - -offset.X) / rect_size.X) * (rect_size.X - old_size_w)
    Dim delta_x As Double = CSng(offset.X / rect_size.X)
    Dim delta_y As Double = CSng(offset.Y / rect_size.Y)
    Dim x_offset = delta_x * (rect_size.X - old_size_w)
    Dim y_offset = delta_y * (rect_size.Y - old_size_h)

    rect_location.X += CInt(x_offset)
    rect_location.Y += CInt(y_offset)

    draw_(current_image)

Upvotes: 0

Views: 1552

Answers (3)

Mike O
Mike O

Reputation: 149

Ok.. I sorted this out.. I used the a couple of the wrong values for both zooming in and out. This is the entire code for zooming around the mouse center and maintaining the center of the mouse. Anyone trying to figure this out.. well here's the code that works perfectly :)

Public Sub img_scale_up()
    If Not ready_to_render Then Return
    If Zoom_Factor >= 4.0 Then
        Zoom_Factor = 4.0
        Return 'to big and the t_bmp creation will hammer memory.
    End If
    Dim amt As Single = 0.0625
    Zoom_Factor += amt

    'this bit of math zooms the texture around the mouses center during the resize.
    'old_w and old_h is the original size of the image in width and height
    'mouse_pos is current mouse position in the window.

    Dim offset As New Point
    Dim old_size_w, old_size_h As Double
    old_size_w = (old_w * (Zoom_Factor - amt))
    old_size_h = (old_h * (Zoom_Factor - amt))

    offset = rect_location - (mouse_pos)

    rect_size.X = Zoom_Factor * old_w
    rect_size.Y = Zoom_Factor * old_h

    Dim delta_x As Double = CDbl(offset.X / old_size_w)
    Dim delta_y As Double = CDbl(offset.Y / old_size_h)

    Dim x_offset = delta_x * (rect_size.X - old_size_w)
    Dim y_offset = delta_y * (rect_size.Y - old_size_h)

    rect_location.X += CInt(x_offset)
    rect_location.Y += CInt(y_offset)

    draw_(current_image)
End Sub

Public Sub img_scale_down()
    If Not ready_to_render Then Return
    If Zoom_Factor <= 0.25 Then
        Zoom_Factor = 0.25
        Return
    End If
    Dim amt As Single = 0.0625
    Zoom_Factor -= amt

    'this bit of math zooms the texture around the mouses center during the resize.
    'old_w and old_h is the original size of the image in width and height
    'mouse_pos is current mouse position in the window.

    Dim offset As New Point
    Dim old_size_w, old_size_h As Double

    old_size_w = (old_w * (Zoom_Factor - amt))
    old_size_h = (old_h * (Zoom_Factor - amt))

    offset = rect_location - (mouse_pos)

    rect_size.X = Zoom_Factor * old_w
    rect_size.Y = Zoom_Factor * old_h

    Dim delta_x As Double = CDbl(offset.X / (rect_size.X + (rect_size.X - old_size_w)))
    Dim delta_y As Double = CDbl(offset.Y / (rect_size.Y + (rect_size.Y - old_size_h)))

    Dim x_offset = delta_x * (rect_size.X - old_size_w)
    Dim y_offset = delta_y * (rect_size.Y - old_size_h)

    rect_location.X += -CInt(x_offset)
    rect_location.Y += -CInt(y_offset)

    draw_(current_image)
End Sub

Upvotes: 1

Spektre
Spektre

Reputation: 51923

I usually get lost (doing silly mistakes) in deriving the right equations (as I use many view transform formulas not just one) and mostly I am to lazy to derive so I do it like this instead:

  1. convert mouse position to coordinate system where offset is not scaled

    if it is screen or world coordinate system depends on your transformation order. Store the result as mx0,my0

  2. apply zoom change

  3. convert mouse position to coordinate system where offset is not scaled

    it is the same as #1 but with updated zoom. Store the result as mx1,my1

  4. update offset

    simply add:

    offset_x += mx0-mx1;
    offset_y += my0-my1;
    

    Where offset_x,offset_y holds your view offset (position).

Also see Zooming graphics based on current mouse position

Upvotes: 1

Malcolm McLean
Malcolm McLean

Reputation: 6404

Store mouse position as u, v where u and v are on 0.0 - 1.0. Translate your image so that mouse it as 0, 0. Manipulate, in this case by scaling. Then translate back so that 0, 0, goes to u. v.

Upvotes: 1

Related Questions