Коротко. Про афинные преобразования. Только код
https://bitbucket.org/ingword/mindstream/src/e0239b6d47ed4a74d4095731b3180e576ad5f5fa/ConcreteShapes/msLineWithArrow.pas?at=MS-7_Lulin_Upgrade
Было:
А правильно так:
Что изменилось?
Обратная матрица.
"Квадратная матрица обратима тогда и только тогда, когда она невырожденная, то есть её определитель не равен нулю. Для неквадратных матриц и вырожденных матриц обратных матриц не существует. Однако возможно обобщить это понятие и ввести псевдообратные матрицы, похожие на обратные по многим свойствам."
Иначе например ОРИГИНАЛЬНЫЙ параллельный перенос - не будет работать.
Делайте выводы.
P.S. l_OriginalMatrix * l_OriginalMatrix.Inverse == TMatrix.Identity ;-)
Единичная матрица.
P.S.S. Итоговый код:
Из этого делаем простой вывод.
Что перемножение матриц - НЕ коммутативно.
Что и "логично" - A * B != B * A.
https://bitbucket.org/ingword/mindstream/src/e0239b6d47ed4a74d4095731b3180e576ad5f5fa/ConcreteShapes/msLineWithArrow.pas?at=MS-7_Lulin_Upgrade
Было:
procedure TmsLineWithArrow.DoDrawTo(const aCtx: TmsDrawContext);
var
l_Proxy : TmsShape;
l_OriginalMatrix: TMatrix;
l_Matrix: TMatrix;
l_Angle : Single;
l_CenterPoint : TPointF;
l_TextRect : TRectF;
begin
inherited;
if (StartPoint <> FinishPoint) then
begin
l_OriginalMatrix := aCtx.rCanvas.Matrix;
try
l_Proxy := TmsSmallTriangle.CreateInner(FinishPoint);
try
// in Radian
l_Angle := GetArrowAngleRotation;
// create a point around which will rotate
l_CenterPoint := TPointF.Create(FinishPoint.X, FinishPoint.Y);
l_Matrix := l_OriginalMatrix;
l_Matrix := l_Matrix * TMatrix.CreateTranslation(-l_CenterPoint.X,-l_CenterPoint.Y);
l_Matrix := l_Matrix * TMatrix.CreateRotation(l_Angle);
l_Matrix := l_Matrix * TMatrix.CreateTranslation(l_CenterPoint.X,l_CenterPoint.Y);
aCtx.rCanvas.SetMatrix(l_Matrix);
l_Proxy.DrawTo(aCtx);
finally
FreeAndNil(l_Proxy);
end;//try..finally
finally
aCtx.rCanvas.SetMatrix(l_OriginalMatrix);
end;
end;//(StartPoint <> FinishPoint)
end;
А правильно так:
procedure TmsLineWithArrow.DoDrawTo(const aCtx: TmsDrawContext);
var
l_Proxy : TmsShape;
l_OriginalMatrix: TMatrix;
l_Matrix: TMatrix;
l_Angle : Single;
l_CenterPoint : TPointF;
l_TextRect : TRectF;
begin
inherited;
if (StartPoint <> FinishPoint) then
begin
l_OriginalMatrix := aCtx.rCanvas.Matrix;
try
l_Proxy := TmsSmallTriangle.CreateInner(FinishPoint);
try
// in Radian
l_Angle := GetArrowAngleRotation;
// create a point around which will rotate
l_CenterPoint := TPointF.Create(FinishPoint.X, FinishPoint.Y);
l_Matrix := l_OriginalMatrix * l_OriginalMatrix.Inverse;
l_Matrix := l_Matrix * TMatrix.CreateTranslation(-l_CenterPoint.X,-l_CenterPoint.Y);
l_Matrix := l_Matrix * TMatrix.CreateRotation(l_Angle);
l_Matrix := l_Matrix * TMatrix.CreateTranslation(l_CenterPoint.X,l_CenterPoint.Y);
l_Matrix := l_Matrix * l_OriginalMatrix;
aCtx.rCanvas.SetMatrix(l_Matrix);
l_Proxy.DrawTo(aCtx);
finally
FreeAndNil(l_Proxy);
end;//try..finally
finally
aCtx.rCanvas.SetMatrix(l_OriginalMatrix);
end;
end;//(StartPoint <> FinishPoint)
end;
Что изменилось?
l_Matrix := l_OriginalMatrix * l_OriginalMatrix.Inverse; // - СНИМАЕМ оригинальную матрицу
Обратная матрица.
"Квадратная матрица обратима тогда и только тогда, когда она невырожденная, то есть её определитель не равен нулю. Для неквадратных матриц и вырожденных матриц обратных матриц не существует. Однако возможно обобщить это понятие и ввести псевдообратные матрицы, похожие на обратные по многим свойствам."
l_Matrix := l_Matrix * l_OriginalMatrix; // - ПРИМЕНЯЕМ оригинальную матрицу
Иначе например ОРИГИНАЛЬНЫЙ параллельный перенос - не будет работать.
Делайте выводы.
P.S. l_OriginalMatrix * l_OriginalMatrix.Inverse == TMatrix.Identity ;-)
Единичная матрица.
P.S.S. Итоговый код:
procedure TmsLineWithArrow.DoDrawTo(const aCtx: TmsDrawContext);
var
l_Proxy : TmsShape;
l_OriginalMatrix: TMatrix;
l_Matrix: TMatrix;
l_Angle : Single;
l_CenterPoint : TPointF;
l_TextRect : TRectF;
begin
inherited;
if (StartPoint <> FinishPoint) then
begin
l_OriginalMatrix := aCtx.rCanvas.Matrix;
try
l_Proxy := TmsSmallTriangle.CreateInner(FinishPoint);
try
// in Radian
l_Angle := GetArrowAngleRotation;
l_CenterPoint := FinishPoint;
l_Matrix := TMatrix.Identity;
// - СНИМАЕМ оригинальную матрицу, точнее берём ЕДИНИЧНУЮ матрицу
// https://ru.wikipedia.org/wiki/%D0%95%D0%B4%D0%B8%D0%BD%D0%B8%D1%87%D0%BD%D0%B0%D1%8F_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86%D0%B0
l_Matrix := l_Matrix * TMatrix.CreateTranslation(-l_CenterPoint.X,-l_CenterPoint.Y);
// - задаём точку, вокруг которой вертим
l_Matrix := l_Matrix * TMatrix.CreateRotation(l_Angle);
// - задаём угол поворота
l_Matrix := l_Matrix * TMatrix.CreateTranslation(l_CenterPoint.X,l_CenterPoint.Y);
// - задаём начало координат
l_Matrix := l_Matrix * l_OriginalMatrix;
// - ПРИМЕНЯЕМ оригинальную матрицу
// Иначе например ОРИГИНАЛЬНЫЙ параллельный перенос - не будет работать.
// https://ru.wikipedia.org/wiki/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%BF%D0%B5%D1%80%D0%B5%D0%BD%D0%BE%D1%81
aCtx.rCanvas.SetMatrix(l_Matrix);
// - применяем нашу "комплексную" матрицу
l_Proxy.DrawTo(aCtx);
// - отрисовываем примитив с учётом матрицы преобразований
finally
FreeAndNil(l_Proxy);
end;//try..finally
finally
aCtx.rCanvas.SetMatrix(l_OriginalMatrix);
// - восстанавливаем ОРИГИНАЛЬНУЮ матрицу
end;//try..finally
end;//(StartPoint <> FinishPoint)
end;
Из этого делаем простой вывод.
Что перемножение матриц - НЕ коммутативно.
Что и "логично" - A * B != B * A.
- Умножение матриц некоммутативно:
, но 
Комментариев нет:
Отправить комментарий