Коротко. Про афинные преобразования. Только код
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.
- Умножение матриц некоммутативно:
- , но
Комментариев нет:
Отправить комментарий