使用矩阵放大固定点 [英] Zoom in on a fixed point using matrices

查看:106
本文介绍了使用矩阵放大固定点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用单个全局矩阵实现围绕固定点的缩放.运行时,如果单击了控件,则控件会缩放,但是每次单击时,测试矩形将进一步向下和向右移动. 据我所知,每个变换(到原点,比例尺和回到原始位置)都可以单独很好地工作,但是当我将所有三个变换结合在一起时,我并没有得到正确的行为.

I'm trying to implement scaling about a fixed point using a single global matrix. When run when, if the control is clicked it scaled but the test rectangles move further down and to right with each click. As far as I can tell each transformation (to the origin, scale, and back to the original location) is working fine individually but when I combine all 3 together I don't get the correct behavior.

缩放代码

单击控件时(应)将代码转换为原点,按比例放大,然后转换回原始位置.

When the control is clicked the code (should) translate to the origin, scale up by a factor, then translate back to the original position.

protected override void OnMouseDown(MouseEventArgs e)
      {
         base.OnMouseDown(e);
         if (e.Button == System.Windows.Forms.MouseButtons.Left)
         {
            float xPos = e.Location.X - viewMatrix.OffsetX;
            float yPos = e.Location.Y - viewMatrix.OffsetY;

            Matrix translateOrigin = new Matrix(1, 0, 0, 1, -xPos, -yPos);
            Matrix translateBack = new Matrix(1, 0, 0, 1, xPos, yPos);
            Matrix scaleMatrix = new Matrix(1.5f, 0, 0, 1.5f, 0, 0);

            viewMatrix.Multiply(translateOrigin);
            viewMatrix.Multiply(scaleMatrix);
            viewMatrix.Multiply(translateBack);
         }
         else
         {
            viewMatrix = new Matrix();
         }
         Refresh();
      }

绘图代码

这是我用来绘制的代码.这两个矩形仅供参考,new Pen(2)上的第二个值是确保我的线保持1像素宽.

This is the code that I'm using to draw. The two rectangles are just for reference and the second value on the new Pen(2) is to make sure my lines stay 1 pixel wide.

protected override void OnPaint(PaintEventArgs e)
      {
         base.OnPaint(e);

         GraphicsState gState = e.Graphics.Save();

         e.Graphics.MultiplyTransform(viewMatrix);
         e.Graphics.DrawRectangle(new Pen(Color.Pink, 1.0f / viewMatrix.Elements[3]), -5, -5, 10, 10);
         e.Graphics.DrawRectangle(new Pen(Color.Pink, 1.0f / viewMatrix.Elements[3]), 20, 20, 10, 10);

         e.Graphics.Restore(gState);
      }

修改

休息一整天(或2天)后,再次查看代码,我意识到自己脑子里有一个错误的想法(这是我在一天结束时试图弄清楚这一点的结果).我正在寻找的行为是视图将随着单击的点保持在同一位置而缩放.例如,如果我单击其中一个矩形的右下角,则视图将缩放该视图,并将其保持在鼠标的右下角.

Looking at the code again after a good day (or 2) of rest I realized I had the wrong idea stuck in my head (this is what I get for trying to figure this out at the end of the day). The behavior that I'm looking for is that the view will scale with the clicked point staying in the same spot. Example if I clicked the lower right hand corner of one of the rectangles the view would zoom it keeping the lower right under the mouse.

编辑2

在@TaW的大量帮助下,我得出了以下代码,这些代码将缩放并保持鼠标下的点固定.

After a lot of help from @TaW I came out with the following code that will zoom and keep the point under the mouse fixed.

protected override void OnMouseDown(MouseEventArgs e)
{
 base.OnMouseDown(e);

 if (e.Button == System.Windows.Forms.MouseButtons.Left)
 {

    //Get the inverse of the view matrix so that we can transform the mouse point into the view
    Matrix viewMatrixRev = viewMatrix.Clone();
    viewMatrixRev.Invert();

    //Translate the mouse point
    PointF mousePoint = e.Location;
    viewMatrixRev.TransformPoints(new PointF[] { mousePoint });

    //Transform the view
    viewMatrix.Translate(-mousePoint.X, -mousePoint.Y, MatrixOrder.Append);
    viewMatrix.Scale(zoom, zoom, MatrixOrder.Append);
    viewMatrix.Translate(mousePoint.X, mousePoint.Y, MatrixOrder.Append);
 }
 else
 {
    viewMatrix = new Matrix();
 }
 Refresh();
}

推荐答案

Matrix.Multiply 带有一个参数

Matrix.Multiply with one argument

通过前面添加指定的矩阵,将此矩阵与在矩阵参数中指定的矩阵相乘.

Multiplies this Matrix by the matrix specified in the matrix parameter, by prepending the specified Matrix.

因此,您的矩阵序列以相反的顺序应用.

So, your matrix sequence is being applied in reverse order.

尝试以下方法:

viewMatrix.Multiply(translateOrigin, MatrixOrder.Append);
viewMatrix.Multiply(scaleMatrix, MatrixOrder.Append);
viewMatrix.Multiply(translateBack, MatrixOrder.Append);


这个想法很简单.


The idea is simple.

所有您需要做的就是按照正确的顺序平移到原点,缩放并平移回枢轴(鼠标点). 您的viewMatrix保留先前的结果,因此应在之后应用新的转换矩阵,这将由MatrixOrder.Append完成.

All you need to do is to translate to the origin, scale, and translate back to the pivot (mouse point) in proper order. Your viewMatrix keeps the previous result, so the new transformation matrix should be applied after it, and that would be done by MatrixOrder.Append.

现在的解决方案是:

float xPos = e.Location.X;
float yPos = e.Location.Y;

Matrix translateOrigin = new Matrix(1, 0, 0, 1, -xPos, -yPos);
Matrix translateBack = new Matrix(1, 0, 0, 1, xPos, yPos);
Matrix scaleMatrix = new Matrix(1.5f, 0, 0, 1.5f, 0, 0);

viewMatrix.Multiply(translateOrigin, MatrixOrder.Append);
viewMatrix.Multiply(scaleMatrix, MatrixOrder.Append);
viewMatrix.Multiply(translateBack, MatrixOrder.Append);

此外,这可以更简单地完成.

In addition, this can be done more simply.

float xPos = e.Location.X;
float yPos = e.Location.Y;

viewMatrix.Translate(-xPos, -yPos, MatrixOrder.Append);
viewMatrix.Scale(1.5f, 1.5f, MatrixOrder.Append);
viewMatrix.Translate(xPos, yPos, MatrixOrder.Append);

这篇关于使用矩阵放大固定点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆