Только код.
По мотивам - MindStream. Как мы пишем ПО под FireMonkey. Часть 2
Репозитарий - https://bitbucket.org/ingword/mindstream/src/285eaac25daa915044ebda73d2313a6b5843f577/ConcreteShapes/msLineWithArrow.pas?at=Developing
Что тут написано?
Что такое "единичная окружность"?
Что такое "проекция отрезка на оси"?
Что такое "граничные условия"?
Можно ли сделать проще?
По мотивам - MindStream. Как мы пишем ПО под FireMonkey. Часть 2
Репозитарий - https://bitbucket.org/ingword/mindstream/src/285eaac25daa915044ebda73d2313a6b5843f577/ConcreteShapes/msLineWithArrow.pas?at=Developing
unit msLineWithArrow;
interface
uses
msShape,
msLine,
FMX.Graphics,
System.Types,
msInterfaces,
System.Math.Vectors
;
type
TmsLineWithArrow = class(TmsLine)
protected
function GetFinishPointForDraw: TPointF; override;
procedure DoDrawTo(const aCtx: TmsDrawContext); override;
function GetArrowAngleRotation : Single;
function GetDrawBounds: TRectF; override;
end;//TmsLineWithArrow
implementation
uses
msSmallTriangle,
SysUtils,
System.Math,
System.UITypes,
FMX.Types
;
procedure TmsLineWithArrow.DoDrawTo(const aCtx: TmsDrawContext);
var
l_Proxy : ImsShape;
l_OriginalMatrix: TMatrix;
l_Matrix: TMatrix;
l_Angle : Single;
l_CenterPoint,
l_LineFinishPoint : TPointF;
begin
inherited;
if (StartPoint <> FinishPoint) then
begin
l_OriginalMatrix := aCtx.rCanvas.Matrix;
try
l_LineFinishPoint := TPointF.Create(FinishPoint.X - TmsSmallTriangle.InitialHeight / 2,
FinishPoint.Y);
l_Proxy := TmsSmallTriangle.Create(l_LineFinishPoint);
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
l_Proxy := nil;
end;//try..finally
finally
aCtx.rCanvas.SetMatrix(l_OriginalMatrix);
// - восстанавливаем ОРИГИНАЛЬНУЮ матрицу
end;//try..finally
end;//(StartPoint <> FinishPoint)
end;
function TmsLineWithArrow.GetArrowAngleRotation: single;
var
l_ALength, l_CLength,
l_AlphaAngle,
l_X, l_Y, l_RotationAngle : Single;
l_PointC : TPointF;
l_Invert : SmallInt;
begin
// Формула расчета растояний между двумя точками
l_X := (FinishPoint.X - StartPoint.X) * (FinishPoint.X - StartPoint.X);
l_Y := (FinishPoint.Y - StartPoint.Y) * (FinishPoint.Y - StartPoint.Y);
l_CLength := sqrt( l_X + l_Y);
l_PointC := TPointF.Create(FinishPoint.X, StartPoint.Y);
// Формула расчета растояний между двумя точками
l_X := (l_PointC.X - StartPoint.X) * (l_PointC.X - StartPoint.X);
l_Y := (l_PointC.Y - StartPoint.Y) * (l_PointC.Y - StartPoint.Y);
l_ALength := sqrt( l_X + l_Y);
// In Radian
l_AlphaAngle := ArcSin(l_ALength / l_CLength);
l_Invert := 1;
if (FinishPoint.X > StartPoint.X) then
begin
l_RotationAngle := Pi / 2 * 3;
if FinishPoint.Y > StartPoint.Y then
l_Invert := -1;
end//FinishPoint.X > StartPoint.X
else
begin
l_RotationAngle := Pi / 2;
if FinishPoint.Y < StartPoint.Y then
l_Invert := -1;
end;//FinishPoint.X > StartPoint.X
Result := l_Invert * (l_AlphaAngle + l_RotationAngle);
end;
function TmsLineWithArrow.GetDrawBounds: TRectF;
begin
Result := inherited GetDrawBounds;
if SameValue(Result.Left, Result.Right) then
begin
Result.Right := Result.Left + TmsSmallTriangle.InitialHeight;
Result.Left := Result.Left - TmsSmallTriangle.InitialHeight;
end;//SameValue(Result.Left, Result.Right)
if SameValue(Result.Top, Result.Bottom) then
begin
Result.Bottom := Result.Top + TmsSmallTriangle.InitialHeight;
Result.Top := Result.Top - TmsSmallTriangle.InitialHeight;
end;//SameValue(Result.Top, Result.Bottom)
end;
function TmsLineWithArrow.GetFinishPointForDraw: TPointF;
var
l_Angle : Single;
begin
l_Angle := GetArrowAngleRotation;
Result := TPointF.Create(FinishPoint.X - TmsSmallTriangle.InitialHeight * Cos(l_Angle),
FinishPoint.Y - TmsSmallTriangle.InitialHeight * Sin(l_Angle));
end;
end.
Что тут написано?
function TmsLineWithArrow.GetFinishPointForDraw: TPointF;
var
l_Angle : Single;
begin
l_Angle := GetArrowAngleRotation;
Result := TPointF.Create(FinishPoint.X - TmsSmallTriangle.InitialHeight * Cos(l_Angle),
FinishPoint.Y - TmsSmallTriangle.InitialHeight * Sin(l_Angle));
end;
Что такое "единичная окружность"?
Что такое "проекция отрезка на оси"?
Что такое "граничные условия"?
Можно ли сделать проще?
Комментариев нет:
Отправить комментарий