Как реализовать масштабирование относительно произвольной точки? Реализую специализированный 2D-редактор в .NET. Хочу реализовать масштабирование относительно курсора. В GDI+ у класса Graphics есть замечательное свойство Transform, которое позволяет с помощью аппарата аффинных преобразований в матричной форме реализовать то, что мне нужно. Во всех книжках пишут, что для масштабирования относительно произвольной точки необходимо:выполнить преобразование смещения так, чтобы точка относительно которой масштабируем сместилась в начало координатвыполнить непосредственно масштабирование относительно начала координатвыполнить преобразование смещение так, чтобы начало координат сместилось в исходную точку. То есть в рамках моего приложения достаточно правильным образом менять матрицу Transform при вращении колесика мыши. Делаю так:public class DrawingAreaControl : UserControl { public DrawingAreaControl() { DoubleBuffered = true; transform = new Matrix(); } public Matrix transform { get; set; }
protected override void OnPaint(PaintEventArgs e) { e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; e.Graphics.Transform = transform; base.OnPaint(e); } const float SCALE_MUL = 1.05f; protected override void OnMouseWheel(MouseEventArgs e) { base.OnMouseWheel(e); transform.Multiply(new Matrix(1, 0, 0, 1, e.Location.X, e.Location.Y)); transform.Multiply(e.Delta > 0 ? new Matrix(SCALE_MUL, 0, 0, SCALE_MUL, 0, 0) : new Matrix(1 / SCALE_MUL, 0, 0, 1 / SCALE_MUL, 0, 0)); transform.Multiply(new Matrix(1, 0, 0, 1, -e.Location.X, -e.Location.Y)); Invalidate(); } } но это не работает так как надо. После нескольких масштабирований, рисунок под мышкой начинает убегать и уже нет нужного масштабирования относительно курсора. По любому это из-за неправильного расчета преобразований в начало координат и обратно. Как вычислить их, чтобы работало правильно?
Проблема заключается в том, что вы неправильно компенсируете смещение при выполнении преобразований относительно курсора. Вместо этого, вам нужно сначала выполнить преобразование относительно курсора, а затем отменить это преобразование для коррекции расположения курсора на холсте.
Таким образом, вы сначала выполняете преобразование относительно курсора, затем масштабирование и, наконец, отменяете преобразование относительно курсора. Это должно исправить проблему с уходом изображения от курсора при масштабировании.
Проблема заключается в том, что вы неправильно компенсируете смещение при выполнении преобразований относительно курсора. Вместо этого, вам нужно сначала выполнить преобразование относительно курсора, а затем отменить это преобразование для коррекции расположения курсора на холсте.
Приведу пример ваших методов с исправлениями:
protected override void OnMouseWheel(MouseEventArgs e){
base.OnMouseWheel(e);
Matrix translationMatrix = new Matrix();
translationMatrix.Translate(e.Location.X, e.Location.Y);
Matrix scaleMatrix = new Matrix();
scaleMatrix.Scale(e.Delta > 0 ? SCALE_MUL : 1 / SCALE_MUL, e.Delta > 0 ? SCALE_MUL : 1 / SCALE_MUL);
Matrix revertTranslationMatrix = new Matrix();
revertTranslationMatrix.Translate(-e.Location.X, -e.Location.Y);
Matrix tempMatrix = new Matrix();
tempMatrix.Multiply(revertTranslationMatrix);
tempMatrix.Multiply(scaleMatrix);
tempMatrix.Multiply(translationMatrix);
transform.Multiply(tempMatrix);
Invalidate();
}
Таким образом, вы сначала выполняете преобразование относительно курсора, затем масштабирование и, наконец, отменяете преобразование относительно курсора. Это должно исправить проблему с уходом изображения от курсора при масштабировании.