I want to do something like ZoomTool in the portable application Global Mapper. You know when the user left-clicks on the image the application would zoom to the user's location of click and if right-clicks the application would zoom out of the user's location of click. So I took the COpenGLControl class and did some customizations on it, to make it suitable for 2D image rendering. here's the full customized class but if you're not interested, there's no need to download it. I will explain the important parts.

the code used to simulate something like ZoomTool in Global mapper portable application if the user places the mouse on the window and then left-clicks, will zoom in to the location of click

void COpenGLControl::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_fPosX = (float)point.x;
m_fPosY = (float)point.y;
if (nFlags & MK_LBUTTON)
    m_fZoom = 1.1*m_fZoom;
OnDraw(NULL);
CWnd::OnLButtonDown(nFlags, point);
}  

the code used to simulate something like ZoomTool in Global mapper portable application if the user places the mouse on the window and then right-clicks, will zoom out of the location of click

void COpenGLControl::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_fPosX = (float)point.x;
m_fPosY = (float)point.y;
if (nFlags & MK_RBUTTON)
    m_fZoom = 0.9*m_fZoom;
OnDraw(NULL);
CWnd::OnRButtonDown(nFlags, point);
}  

the code used to apply transformations on the coordinate-system

void COpenGLControl::OnDraw(CDC *pDC)
{
wglMakeCurrent(hdc,hrc);
// If the current view is perspective...
glLoadIdentity();
glScalef(m_fZoom,m_fZoom,1.0);
glTranslatef(m_fPosX, m_fPosY, 0.0f);
wglMakeCurrent(NULL, NULL);
}  

I don't have trouble with zooming parts, just having trouble with functions OnLButtonDown and OnRButtonDown on the translate part. the program does not zoom in or out the user's click location.
I mean that I expect the function this behavior:

For example when I click the location (350,460), this point should go to center of window just as in ZoomToFullExtent function when I set m_fPosX and m_fPosY equal to zero the point (0,0) goes to the center of window
In fact up to know I thought glTranslatef(m_fPosX,m_fPosY,0) translates the point (m_fPosX,m_fPosY) to the center of window but seems that it's not true
Can you help me solve the problem and translate the point of click to the center of window after zooming in?

see what I want to simulate in picture:

this is global mapper program and I want to zoom to the region specified by red circle: enter image description here So I click the zoomtool at top and left-click on that area in the picture. You see the area goes to the center of the window
enter image description here
but in the code that I have provided using glTranslatef , the location of click does not go to the center of window. What is the appropriate code to go to the center when zooming to a specific point?


ALMOST THE FINAL ANSWER

taking the idea from @Andon M.Coleman I finally wrote the code this form:

void COpenGLControl::OnSize(UINT nType, int cx, int cy)
{
wglMakeCurrent(hdc, hrc);
CWnd::OnSize(nType, cx, cy);

if (0 >= cx || 0 >= cy || nType == SIZE_MINIMIZED) return;
oglWindowWidth = cx;
oglWindowHeight = cy;
// Map the OpenGL coordinates.
glViewport(0, 0, oglWindowWidth, oglWindowHeight);

// Projection view
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set our current view perspective
glOrtho(-oglWindowWidth/2, oglWindowWidth/2, -oglWindowHeight/2,oglWindowHeight/2, 1, -1);
// Model view
glMatrixMode(GL_MODELVIEW);
wglMakeCurrent(NULL, NULL);
}  

void COpenGLControl::OnDraw(CDC *pDC)
{
// TODO: Camera controls
wglMakeCurrent(hdc,hrc);
glLoadIdentity();
gluLookAt(0,0,1,0,0,0,0,1,0);
glTranslatef(m_fPosX, m_fPosY, 0.0f);
glScalef(m_fZoom,m_fZoom,1.0);
wglMakeCurrent(NULL, NULL);
}  

void COpenGLControl::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if (WantToUseZoomTool)
{
    if (nFlags & MK_LBUTTON)
    {
        m_fZoom = 1.1f*m_fZoom;
        m_fZoomInverse = 1/m_fZoom;
        int diffX = (int)(point.x - oglWindowWidth/2);
        int diffY = (int)(point.y - oglWindowHeight/2);
        m_fPosX -= (float)diffX;
        m_fPosY += (float)diffY;
    }
    OnDraw(NULL);
}
CWnd::OnLButtonDown(nFlags, point);
}  

void COpenGLControl::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if (WantToUseZoomTool)
{
    if (nFlags & MK_RBUTTON)
    {
        m_fZoom = 0.9f*m_fZoom;
        m_fZoomInverse = 1/m_fZoom;
        int diffX = (int)(point.x - oglWindowWidth/2);
        int diffY = (int)(point.y - oglWindowHeight/2);
        m_fPosX -= (float)diffX;
        m_fPosY += (float)diffY;
    }
    OnDraw(NULL);
}
CWnd::OnRButtonDown(nFlags, point);
}  

it seems that there's no need to divide diffX and diffY by the scale factor if I do so the image will be disappeared from the scene completely. the code almost perfectly does well except that slightly gets far of the window's center that I think it is because zooming right after translation since that when I deleted the lines:

        m_fZoom = 1.1f*m_fZoom;
        m_fZoomInverse = 1/m_fZoom;  
        m_fZoom = 0.9f*m_fZoom;
        m_fZoomInverse = 1/m_fZoom;  

I saw that every point that I click goes exactly to the center. Any help to enhance the code in order to eliminate those slight displacements?

有帮助吗?

解决方案

You should have enough information to solve this already, you have your origin (m_fPosX,m_fPosY) and a scale factor (m_fZoom). When it comes time to zoom into the image focused around the cursor's position, you calculate the distance the cursor is from the center of the screen (e.g. CursorPos - WindowDimensions / 2) divide this by your scale factor and add it to your origin.

Initially your scale factor would be 1.0, but when you zoom in/out it will obviously grow. As long as you translate before scaling this should work.

其他提示

 m_fZoom = 1.1f*m_fZoom;
    m_fZoomInverse = 1/m_fZoom;  
    m_fZoom = 0.9f*m_fZoom;
    m_fZoomInverse = 1/m_fZoom;

Due note that when zooming in and zooming back out again multiplying by 0.9 after 1.1 does not set you back at the original size. ie 0.9 * 1.1 = 0.99 != 1 (this of course gets worse the longer you continue...).

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top