Zoom to a point on the screen

BlitzMax Forums/BlitzMax Beginners Area/Zoom to a point on the screen

EOF(Posted 2010) [#1]
I thought this would be straight forward but I cannot figure it out!

What I want to do is zoom into a particular area of the whole display
(I have a scaling routine in place which takes care of everything so that's not a problem)


Some example params:
physical view area = 512,384
zoom=2.0             ' any value here but min=1.0
xpos=MouseX()
ypos=MouseY()


As per above, I would like to zoom into the graphics wherever the mouse pointer is using a factor of 2.0 *
It sounds simple but I cannot seem to get the offsets correct (via SetOrigin)

From the example parameters the zoomed graphics would be twice as big as the 'physical' display area
If say, the mouse is at 20,50 how do I calculate the offsets to shift the graphics?

Bearing in mind the zoom could be anything from 1.0 onwards *


Czar Flavius(Posted 2010) [#2]
I agree this is difficult and it took me many hours to figure this out. Here is some code I produced in case it is of any use to you. TVec2 just has fields x and y, and a few methods such as scal which means multiply, Sub(tract) and Add. _view is the top left corner of the current viewing window. Click to cell takes the current mouse pointer position on the screen and converts it to the coordinate it is over on the map. When drawing you also have to pass along the current zoom/scale to everything so they are drawn at the correct size. I wish I could better explain the code but I barely understand it myself, as I wrote it through trial and error.

	'scroll along the map by the distance delta
	Method scroll(delta:TVec2)
		_view.Add(delta.Scal(1.0/_zoom_scale), _view)
		If _view.x < 0 Then _view.x = 0
		If _view.x > _size.x - TSettings.resolution_x*(1.0/_zoom_scale) Then _view.x = (_size.x - TSettings.resolution_x*(1.0/_zoom_scale))
		If _view.y < 0 Then _view.y = 0
		If _view.y > _size.y - TSettings.resolution_y*(1.0/_zoom_scale) Then _view.y = (_size.y - TSettings.resolution_y*(1.0/_zoom_scale))
	End Method
	
	'go immediately to this position of the map
	Method set_view(pos:TVec2)
		Global tempvec:TVec2 = New TVec2
		_view = pos.Sub((tempvec.Set(TSettings.resolution_x/2, TSettings.resolution_y/2).Scal(1.0/_zoom_scale)))
	End Method
	
	Method zoom_in()	
		Global vec:TVec2 = New TVec2
		vec = (click_to_cell(New TVec2.Set( TSettings.resolution_x/2, TSettings.resolution_y/2)))
		_zoom_scale :+ 0.02
		If _zoom_scale > 1.0 Then _zoom_scale = 1.0
		set_view(vec)
	End Method
	
	Method zoom_out()
		Global vec:TVec2 = New TVec2
		vec = (click_to_cell(New TVec2.Set( TSettings.resolution_x/2, TSettings.resolution_y/2)))
		_zoom_scale :- 0.02
		If _zoom_scale < 0.2 Then _zoom_scale = 0.2
		set_view(vec)
	End Method

	Method click_to_cell:TVec2(click:TVec2)
		Return get_view_area().Add(click.Scal(1.0/_zoom_scale))
	End Method

	Method get_view_area:TVec2()
		Return _view.Copy()
	End Method



Oddball(Posted 2010) [#3]
My Odd2D driver can do this for you. In fact that is precisely why I started the project, well that and full screen rotation. You set the point you want to zoom in on using SetScreenFocus, and then zoom in/out with SetZoom. Simples.

Odd2D discussion thread
Odd2D direct download


EOF(Posted 2010) [#4]
Thanks both

David,
It sounds like we are both aiming at the same thing
My lightweight OpenGL code also allows rotation, zoom, and origin offsetting

EDIT: Solved!

' transform the display (zoom into point at mouse position)
Local mxoffs#=Float(MouseX())*zoom-Float(MouseX())
Local myoffs#=Float(MouseY())*zoom-Float(MouseY())
SetScale zoom,zoom
SetOrigin -mxoffs , -myoffs