mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-09-12 22:19:09 +02:00
fpvectorial: Preparation for curved text support
git-svn-id: trunk@48989 -
This commit is contained in:
parent
2eb361b9f3
commit
2186008a0c
@ -281,6 +281,9 @@ type
|
||||
// Fields for linking the list
|
||||
Previous: TPathSegment;
|
||||
Next: TPathSegment;
|
||||
// mathematical methods
|
||||
function GetLength(): Double; virtual;
|
||||
// edition methods
|
||||
procedure Move(ADeltaX, ADeltaY: Double); virtual;
|
||||
procedure Rotate(AAngle: Double; ABase: T3DPoint); virtual; // Angle in radians
|
||||
procedure CalculateBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double); virtual;
|
||||
@ -300,6 +303,9 @@ type
|
||||
T2DSegment = class(TPathSegment)
|
||||
public
|
||||
X, Y: Double;
|
||||
// mathematical methods
|
||||
function GetLength(): Double; override;
|
||||
// edition methods
|
||||
procedure Move(ADeltaX, ADeltaY: Double); override;
|
||||
procedure Rotate(AAngle: Double; ABase: T3DPoint); override;
|
||||
function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
|
||||
@ -314,6 +320,12 @@ type
|
||||
In Bezier segments, we remain using the X and Y coordinates for the ending point.
|
||||
The starting point is where the previous segment ended, so that the intermediary
|
||||
bezier control points are [X2, Y2] and [X3, Y3].
|
||||
|
||||
Equations:
|
||||
|
||||
B(t) = (1-t)³ [Prev.X, Prev.Y] + 3 (1-t)² t [X2, Y2] + 3 (1-t) t² [X3, Y3] + t³ [X,Y], 0<=t<=1
|
||||
|
||||
B'(t) = 3 (1-t)² [X2-Prev.X, Y2-Prev.Y] + 6 (1-t) t [X3-X2, Y3-Y2] + 3 t² [X-X3,Y-Y3]
|
||||
}
|
||||
|
||||
{ T2DBezierSegment }
|
||||
@ -515,6 +527,7 @@ type
|
||||
Points: TPathSegment; // Beginning of the double-linked list
|
||||
PointsEnd: TPathSegment;// End of the double-linked list
|
||||
CurPoint: TPathSegment; // Used in PrepareForSequentialReading and Next
|
||||
CurWalkDistanceInCurSegment: Double;// Used in PrepareForWalking and NextWalk
|
||||
ClipPath: TPath;
|
||||
ClipMode: TvClipMode;
|
||||
constructor Create(APage: TvPage); override;
|
||||
@ -522,7 +535,9 @@ type
|
||||
procedure Clear; override;
|
||||
procedure Assign(ASource: TPath);
|
||||
procedure PrepareForSequentialReading;
|
||||
procedure PrepareForWalking;
|
||||
function Next(): TPathSegment;
|
||||
procedure NextWalk(ADistance: Double; out AX, AY, ATangentAngle: Double);
|
||||
procedure CalculateBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double); override;
|
||||
procedure AppendSegment(ASegment: TPathSegment);
|
||||
procedure AppendMoveToSegment(AX, AY: Double);
|
||||
@ -567,6 +582,22 @@ type
|
||||
function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
|
||||
end;
|
||||
|
||||
{ TvCurvedText }
|
||||
|
||||
// TvCurvedText supports only one line
|
||||
TvCurvedText = class(TvText)
|
||||
public
|
||||
Path: TPath;
|
||||
//constructor Create(APage: TvPage); override;
|
||||
//destructor Destroy; override;
|
||||
//function TryToSelect(APos: TPoint; var ASubpart: Cardinal): TvFindEntityResult; override;
|
||||
//procedure CalculateBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double); override;
|
||||
procedure Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo; ADestX: Integer = 0;
|
||||
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0; ADoDraw: Boolean = True); override;
|
||||
//function GetEntityFeatures: TvEntityFeatures; override;
|
||||
//function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
|
||||
end;
|
||||
|
||||
TvFieldKind = (vfkNumPages, vfkPage, vfkAuthor, vfkDateCreated, vfkDate);
|
||||
|
||||
{ TvField }
|
||||
@ -1649,14 +1680,201 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TvField }
|
||||
{ TvStyle }
|
||||
|
||||
constructor TvField.Create(APage: TvPage);
|
||||
constructor TvStyle.Create;
|
||||
begin
|
||||
inherited Create(APage);
|
||||
// Defaults
|
||||
SuppressSpacingBetweenSameParagraphs:=False;
|
||||
end;
|
||||
|
||||
DateFormat := 'dd/MM/yyyy hh:mm:ss';
|
||||
NumberFormat := vnfDecimal;
|
||||
function TvStyle.GetKind: TvStyleKind;
|
||||
begin
|
||||
if Parent = nil then Result := Kind
|
||||
else Result := Parent.GetKind();
|
||||
end;
|
||||
|
||||
procedure TvStyle.Clear;
|
||||
begin
|
||||
Name := '';
|
||||
Parent := nil;
|
||||
Kind := vskTextBody;
|
||||
Alignment := vsaLeft;
|
||||
|
||||
//
|
||||
{Pen.Color := col;
|
||||
Brush := nil;
|
||||
Font := nil;}
|
||||
SetElements := [];
|
||||
//
|
||||
MarginTop := 0;
|
||||
MarginBottom := 0;
|
||||
MarginLeft := 0;
|
||||
MarginRight := 0;
|
||||
//
|
||||
end;
|
||||
|
||||
procedure TvStyle.CopyFrom(AFrom: TvStyle);
|
||||
begin
|
||||
Clear();
|
||||
ApplyOver(AFrom);
|
||||
end;
|
||||
|
||||
procedure TvStyle.ApplyOver(AFrom: TvStyle);
|
||||
begin
|
||||
if AFrom = nil then Exit;
|
||||
|
||||
// Pen
|
||||
|
||||
if spbfPenColor in AFrom.SetElements then
|
||||
Pen.Color := AFrom.Pen.Color;
|
||||
if spbfPenStyle in AFrom.SetElements then
|
||||
Pen.Style := AFrom.Pen.Style;
|
||||
if spbfPenWidth in AFrom.SetElements then
|
||||
Pen.Width := AFrom.Pen.Width;
|
||||
|
||||
// Brush
|
||||
|
||||
if spbfBrushColor in AFrom.SetElements then
|
||||
Brush.Color := AFrom.Brush.Color;
|
||||
if spbfBrushStyle in AFrom.SetElements then
|
||||
Brush.Style := AFrom.Brush.Style;
|
||||
{if spbfBrushGradient in AFrom.SetElements then
|
||||
Brush.Gra := AFrom.Brush.Style;}
|
||||
if spbfBrushKind in AFrom.SetElements then
|
||||
Brush.Kind := AFrom.Brush.Kind;
|
||||
|
||||
// Font
|
||||
|
||||
if spbfFontColor in AFrom.SetElements then
|
||||
Font.Color := AFrom.Font.Color;
|
||||
if spbfFontSize in AFrom.SetElements then
|
||||
Font.Size := AFrom.Font.Size;
|
||||
if spbfFontName in AFrom.SetElements then
|
||||
Font.Name := AFrom.Font.Name;
|
||||
if spbfFontBold in AFrom.SetElements then
|
||||
Font.Bold := AFrom.Font.Bold;
|
||||
if spbfFontItalic in AFrom.SetElements then
|
||||
Font.Italic := AFrom.Font.Italic;
|
||||
If spbfFontUnderline in AFrom.SetElements then
|
||||
Font.Underline := AFrom.Font.Underline;
|
||||
If spbfFontStrikeThrough in AFrom.SetElements then
|
||||
Font.StrikeThrough := AFrom.Font.StrikeThrough;
|
||||
If spbfAlignment in AFrom.SetElements then
|
||||
Alignment := AFrom.Alignment;
|
||||
|
||||
// TextAnchor
|
||||
if spbfTextAnchor in AFrom.SetElements then
|
||||
TextAnchor := AFrom.TextAnchor;
|
||||
|
||||
// Style
|
||||
|
||||
if sseMarginTop in AFrom.SetElements then
|
||||
MarginTop := AFrom.MarginTop;
|
||||
If sseMarginBottom in AFrom.SetElements then
|
||||
MarginBottom := AFrom.MarginBottom;
|
||||
If sseMarginLeft in AFrom.SetElements then
|
||||
MarginLeft := AFrom.MarginLeft;
|
||||
If sseMarginRight in AFrom.SetElements then
|
||||
MarginRight := AFrom.MarginRight;
|
||||
|
||||
// Other
|
||||
SuppressSpacingBetweenSameParagraphs:=AFrom.SuppressSpacingBetweenSameParagraphs;
|
||||
|
||||
SetElements := AFrom.SetElements + SetElements;
|
||||
end;
|
||||
|
||||
procedure TvStyle.ApplyIntoEntity(ADest: TvEntityWithPenBrushAndFont);
|
||||
begin
|
||||
if ADest = nil then Exit;
|
||||
|
||||
// Pen
|
||||
|
||||
if spbfPenColor in SetElements then
|
||||
ADest.Pen.Color := Pen.Color;
|
||||
if spbfPenStyle in SetElements then
|
||||
ADest.Pen.Style := Pen.Style;
|
||||
if spbfPenWidth in SetElements then
|
||||
ADest.Pen.Width := Pen.Width;
|
||||
|
||||
// Brush
|
||||
|
||||
if spbfBrushColor in SetElements then
|
||||
ADest.Brush.Color := Brush.Color;
|
||||
if spbfBrushStyle in SetElements then
|
||||
ADest.Brush.Style := Brush.Style;
|
||||
{if spbfBrushGradient in SetElements then
|
||||
Brush.Gra := AFrom.Brush.Style;}
|
||||
if spbfBrushKind in SetElements then
|
||||
ADest.Brush.Kind := Brush.Kind;
|
||||
|
||||
// Font
|
||||
|
||||
if spbfFontColor in SetElements then
|
||||
ADest.Font.Color := Font.Color;
|
||||
if spbfFontSize in SetElements then
|
||||
ADest.Font.Size := Font.Size;
|
||||
if spbfFontName in SetElements then
|
||||
ADest.Font.Name := Font.Name;
|
||||
if spbfFontBold in SetElements then
|
||||
ADest.Font.Bold := Font.Bold;
|
||||
if spbfFontItalic in SetElements then
|
||||
ADest.Font.Italic := Font.Italic;
|
||||
If spbfFontUnderline in SetElements then
|
||||
ADest.Font.Underline := Font.Underline;
|
||||
If spbfFontStrikeThrough in SetElements then
|
||||
ADest.Font.StrikeThrough := Font.StrikeThrough;
|
||||
{If spbfAlignment in SetElements then
|
||||
ADest.Alignment := Alignment; }
|
||||
|
||||
// TextAnchor
|
||||
if spbfTextAnchor in SetElements then
|
||||
ADest.TextAnchor := TextAnchor;
|
||||
end;
|
||||
|
||||
function TvStyle.CreateStyleCombinedWithParent: TvStyle;
|
||||
begin
|
||||
Result := TvStyle.Create;
|
||||
Result.CopyFrom(Self);
|
||||
if Parent <> nil then Result.ApplyOver(Parent);
|
||||
end;
|
||||
|
||||
function TvStyle.GenerateDebugTree(ADestRoutine: TvDebugAddItemProc;
|
||||
APageItem: Pointer): Pointer;
|
||||
var
|
||||
lStr, lParentName: string;
|
||||
begin
|
||||
if Parent <> nil then lParentName := Parent.Name
|
||||
else lParentName := '<No Parent>';
|
||||
|
||||
lStr := Format('[%s] Name=%s Parent=%s',
|
||||
[Self.ClassName, Name, lParentName]);
|
||||
|
||||
if spbfPenColor in SetElements then
|
||||
lStr := lStr + Format(' Pen.Color=%s', [TvEntity.GenerateDebugStrForFPColor(Pen.Color)]);
|
||||
{ spbfPenStyle, spbfPenWidth,
|
||||
spbfBrushColor, spbfBrushStyle, spbfBrushGradient,}
|
||||
if spbfFontColor in SetElements then
|
||||
lStr := lStr + Format(' Font.Color=%s', [TvEntity.GenerateDebugStrForFPColor(Pen.Color)]);
|
||||
if spbfFontSize in SetElements then
|
||||
lStr := lStr + Format(' Font.Size=%d', [Font.Size]);
|
||||
if spbfFontName in SetElements then
|
||||
lStr := lStr + ' Font.Name=' + Font.Name;
|
||||
if spbfFontBold in SetElements then
|
||||
if Font.Bold then lStr := lStr + Format(' Font.Bold=%s', [BoolToStr(Font.Bold)]);
|
||||
if spbfFontItalic in SetElements then
|
||||
if Font.Italic then lStr := lStr + Format(' Font.Bold=%s', [BoolToStr(Font.Italic)]);
|
||||
{
|
||||
spbfFontUnderline, spbfFontStrikeThrough, spbfAlignment,
|
||||
// Page style
|
||||
sseMarginTop, sseMarginBottom, sseMarginLeft, sseMarginRight
|
||||
);
|
||||
Font.Size, Font.Name, Font.Orientation,
|
||||
BoolToStr(Font.Underline),
|
||||
BoolToStr(Font.StrikeThrough),
|
||||
GetEnumName(TypeInfo(TvTextAnchor), integer(TextAnchor))}
|
||||
lStr := lStr + FExtraDebugStr;
|
||||
Result := ADestRoutine(lStr, APageItem);
|
||||
end;
|
||||
|
||||
{ TvListLevelStyle }
|
||||
@ -2200,203 +2418,6 @@ begin
|
||||
Result:=inherited GenerateDebugTree(ADestRoutine, APageItem);
|
||||
end;
|
||||
|
||||
{ TvStyle }
|
||||
|
||||
constructor TvStyle.Create;
|
||||
begin
|
||||
// Defaults
|
||||
SuppressSpacingBetweenSameParagraphs:=False;
|
||||
end;
|
||||
|
||||
function TvStyle.GetKind: TvStyleKind;
|
||||
begin
|
||||
if Parent = nil then Result := Kind
|
||||
else Result := Parent.GetKind();
|
||||
end;
|
||||
|
||||
procedure TvStyle.Clear;
|
||||
begin
|
||||
Name := '';
|
||||
Parent := nil;
|
||||
Kind := vskTextBody;
|
||||
Alignment := vsaLeft;
|
||||
|
||||
//
|
||||
{Pen.Color := col;
|
||||
Brush := nil;
|
||||
Font := nil;}
|
||||
SetElements := [];
|
||||
//
|
||||
MarginTop := 0;
|
||||
MarginBottom := 0;
|
||||
MarginLeft := 0;
|
||||
MarginRight := 0;
|
||||
//
|
||||
end;
|
||||
|
||||
procedure TvStyle.CopyFrom(AFrom: TvStyle);
|
||||
begin
|
||||
Clear();
|
||||
ApplyOver(AFrom);
|
||||
end;
|
||||
|
||||
procedure TvStyle.ApplyOver(AFrom: TvStyle);
|
||||
begin
|
||||
if AFrom = nil then Exit;
|
||||
|
||||
// Pen
|
||||
|
||||
if spbfPenColor in AFrom.SetElements then
|
||||
Pen.Color := AFrom.Pen.Color;
|
||||
if spbfPenStyle in AFrom.SetElements then
|
||||
Pen.Style := AFrom.Pen.Style;
|
||||
if spbfPenWidth in AFrom.SetElements then
|
||||
Pen.Width := AFrom.Pen.Width;
|
||||
|
||||
// Brush
|
||||
|
||||
if spbfBrushColor in AFrom.SetElements then
|
||||
Brush.Color := AFrom.Brush.Color;
|
||||
if spbfBrushStyle in AFrom.SetElements then
|
||||
Brush.Style := AFrom.Brush.Style;
|
||||
{if spbfBrushGradient in AFrom.SetElements then
|
||||
Brush.Gra := AFrom.Brush.Style;}
|
||||
if spbfBrushKind in AFrom.SetElements then
|
||||
Brush.Kind := AFrom.Brush.Kind;
|
||||
|
||||
// Font
|
||||
|
||||
if spbfFontColor in AFrom.SetElements then
|
||||
Font.Color := AFrom.Font.Color;
|
||||
if spbfFontSize in AFrom.SetElements then
|
||||
Font.Size := AFrom.Font.Size;
|
||||
if spbfFontName in AFrom.SetElements then
|
||||
Font.Name := AFrom.Font.Name;
|
||||
if spbfFontBold in AFrom.SetElements then
|
||||
Font.Bold := AFrom.Font.Bold;
|
||||
if spbfFontItalic in AFrom.SetElements then
|
||||
Font.Italic := AFrom.Font.Italic;
|
||||
If spbfFontUnderline in AFrom.SetElements then
|
||||
Font.Underline := AFrom.Font.Underline;
|
||||
If spbfFontStrikeThrough in AFrom.SetElements then
|
||||
Font.StrikeThrough := AFrom.Font.StrikeThrough;
|
||||
If spbfAlignment in AFrom.SetElements then
|
||||
Alignment := AFrom.Alignment;
|
||||
|
||||
// TextAnchor
|
||||
if spbfTextAnchor in AFrom.SetElements then
|
||||
TextAnchor := AFrom.TextAnchor;
|
||||
|
||||
// Style
|
||||
|
||||
if sseMarginTop in AFrom.SetElements then
|
||||
MarginTop := AFrom.MarginTop;
|
||||
If sseMarginBottom in AFrom.SetElements then
|
||||
MarginBottom := AFrom.MarginBottom;
|
||||
If sseMarginLeft in AFrom.SetElements then
|
||||
MarginLeft := AFrom.MarginLeft;
|
||||
If sseMarginRight in AFrom.SetElements then
|
||||
MarginRight := AFrom.MarginRight;
|
||||
|
||||
// Other
|
||||
SuppressSpacingBetweenSameParagraphs:=AFrom.SuppressSpacingBetweenSameParagraphs;
|
||||
|
||||
SetElements := AFrom.SetElements + SetElements;
|
||||
end;
|
||||
|
||||
procedure TvStyle.ApplyIntoEntity(ADest: TvEntityWithPenBrushAndFont);
|
||||
begin
|
||||
if ADest = nil then Exit;
|
||||
|
||||
// Pen
|
||||
|
||||
if spbfPenColor in SetElements then
|
||||
ADest.Pen.Color := Pen.Color;
|
||||
if spbfPenStyle in SetElements then
|
||||
ADest.Pen.Style := Pen.Style;
|
||||
if spbfPenWidth in SetElements then
|
||||
ADest.Pen.Width := Pen.Width;
|
||||
|
||||
// Brush
|
||||
|
||||
if spbfBrushColor in SetElements then
|
||||
ADest.Brush.Color := Brush.Color;
|
||||
if spbfBrushStyle in SetElements then
|
||||
ADest.Brush.Style := Brush.Style;
|
||||
{if spbfBrushGradient in SetElements then
|
||||
Brush.Gra := AFrom.Brush.Style;}
|
||||
if spbfBrushKind in SetElements then
|
||||
ADest.Brush.Kind := Brush.Kind;
|
||||
|
||||
// Font
|
||||
|
||||
if spbfFontColor in SetElements then
|
||||
ADest.Font.Color := Font.Color;
|
||||
if spbfFontSize in SetElements then
|
||||
ADest.Font.Size := Font.Size;
|
||||
if spbfFontName in SetElements then
|
||||
ADest.Font.Name := Font.Name;
|
||||
if spbfFontBold in SetElements then
|
||||
ADest.Font.Bold := Font.Bold;
|
||||
if spbfFontItalic in SetElements then
|
||||
ADest.Font.Italic := Font.Italic;
|
||||
If spbfFontUnderline in SetElements then
|
||||
ADest.Font.Underline := Font.Underline;
|
||||
If spbfFontStrikeThrough in SetElements then
|
||||
ADest.Font.StrikeThrough := Font.StrikeThrough;
|
||||
{If spbfAlignment in SetElements then
|
||||
ADest.Alignment := Alignment; }
|
||||
|
||||
// TextAnchor
|
||||
if spbfTextAnchor in SetElements then
|
||||
ADest.TextAnchor := TextAnchor;
|
||||
end;
|
||||
|
||||
function TvStyle.CreateStyleCombinedWithParent: TvStyle;
|
||||
begin
|
||||
Result := TvStyle.Create;
|
||||
Result.CopyFrom(Self);
|
||||
if Parent <> nil then Result.ApplyOver(Parent);
|
||||
end;
|
||||
|
||||
function TvStyle.GenerateDebugTree(ADestRoutine: TvDebugAddItemProc;
|
||||
APageItem: Pointer): Pointer;
|
||||
var
|
||||
lStr, lParentName: string;
|
||||
begin
|
||||
if Parent <> nil then lParentName := Parent.Name
|
||||
else lParentName := '<No Parent>';
|
||||
|
||||
lStr := Format('[%s] Name=%s Parent=%s',
|
||||
[Self.ClassName, Name, lParentName]);
|
||||
|
||||
if spbfPenColor in SetElements then
|
||||
lStr := lStr + Format(' Pen.Color=%s', [TvEntity.GenerateDebugStrForFPColor(Pen.Color)]);
|
||||
{ spbfPenStyle, spbfPenWidth,
|
||||
spbfBrushColor, spbfBrushStyle, spbfBrushGradient,}
|
||||
if spbfFontColor in SetElements then
|
||||
lStr := lStr + Format(' Font.Color=%s', [TvEntity.GenerateDebugStrForFPColor(Pen.Color)]);
|
||||
if spbfFontSize in SetElements then
|
||||
lStr := lStr + Format(' Font.Size=%d', [Font.Size]);
|
||||
if spbfFontName in SetElements then
|
||||
lStr := lStr + ' Font.Name=' + Font.Name;
|
||||
if spbfFontBold in SetElements then
|
||||
if Font.Bold then lStr := lStr + Format(' Font.Bold=%s', [BoolToStr(Font.Bold)]);
|
||||
if spbfFontItalic in SetElements then
|
||||
if Font.Italic then lStr := lStr + Format(' Font.Bold=%s', [BoolToStr(Font.Italic)]);
|
||||
{
|
||||
spbfFontUnderline, spbfFontStrikeThrough, spbfAlignment,
|
||||
// Page style
|
||||
sseMarginTop, sseMarginBottom, sseMarginLeft, sseMarginRight
|
||||
);
|
||||
Font.Size, Font.Name, Font.Orientation,
|
||||
BoolToStr(Font.Underline),
|
||||
BoolToStr(Font.StrikeThrough),
|
||||
GetEnumName(TypeInfo(TvTextAnchor), integer(TextAnchor))}
|
||||
lStr := lStr + FExtraDebugStr;
|
||||
Result := ADestRoutine(lStr, APageItem);
|
||||
end;
|
||||
|
||||
{ TvTableRow }
|
||||
|
||||
constructor TvTableRow.create(APage: TvPage);
|
||||
@ -2808,6 +2829,11 @@ end;
|
||||
|
||||
{ TPathSegment }
|
||||
|
||||
function TPathSegment.GetLength: Double;
|
||||
begin
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
procedure TPathSegment.Move(ADeltaX, ADeltaY: Double);
|
||||
begin
|
||||
|
||||
@ -2839,6 +2865,14 @@ end;
|
||||
|
||||
{ T2DSegment }
|
||||
|
||||
function T2DSegment.GetLength: Double;
|
||||
begin
|
||||
Result := 0;
|
||||
if Previous = nil then Exit;
|
||||
if not (Previous is T2DSegment) then Exit;
|
||||
Result := sqrt(sqr(X - T2DSegment(Previous).X) + sqr(Y + T2DSegment(Previous).Y));
|
||||
end;
|
||||
|
||||
procedure T2DSegment.Move(ADeltaX, ADeltaY: Double);
|
||||
begin
|
||||
X := X + ADeltaX;
|
||||
@ -3392,6 +3426,13 @@ begin
|
||||
CurPoint := nil;
|
||||
end;
|
||||
|
||||
procedure TPath.PrepareForWalking;
|
||||
begin
|
||||
PrepareForSequentialReading();
|
||||
CurWalkDistanceInCurSegment := 0;
|
||||
Next();
|
||||
end;
|
||||
|
||||
function TPath.Next(): TPathSegment;
|
||||
begin
|
||||
if CurPoint = nil then Result := Points
|
||||
@ -3400,6 +3441,22 @@ begin
|
||||
CurPoint := Result;
|
||||
end;
|
||||
|
||||
// Walk is walking a distance in the path and obtaining the point where we land and the current tangent
|
||||
procedure TPath.NextWalk(ADistance: Double; out AX, AY, ATangentAngle: Double);
|
||||
var
|
||||
lCurPoint: TPathSegment;
|
||||
lDistanceRemaining: Double;
|
||||
begin
|
||||
lCurPoint := CurPoint;
|
||||
lDistanceRemaining := ADistance;
|
||||
|
||||
// get the current segment
|
||||
while lDistanceRemaining > lCurPoint.GetLength() do
|
||||
begin
|
||||
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TPath.CalculateBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double);
|
||||
var
|
||||
lSegment: TPathSegment;
|
||||
@ -4132,6 +4189,57 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TvCurvedText }
|
||||
|
||||
procedure TvCurvedText.Render(ADest: TFPCustomCanvas;
|
||||
var ARenderInfo: TvRenderInfo; ADestX: Integer; ADestY: Integer;
|
||||
AMulX: Double; AMulY: Double; ADoDraw: Boolean);
|
||||
|
||||
function CoordToCanvasX(ACoord: Double): Integer;
|
||||
begin
|
||||
Result := Round(ADestX + AmulX * ACoord);
|
||||
end;
|
||||
|
||||
function CoordToCanvasY(ACoord: Double): Integer;
|
||||
begin
|
||||
Result := Round(ADestY + AmulY * ACoord);
|
||||
end;
|
||||
|
||||
var
|
||||
i: Integer;
|
||||
lText, lUTF8Char: string;
|
||||
lX, lY: integer;
|
||||
begin
|
||||
inherited Render(ADest, ARenderInfo, ADestX, ADestY, AMulX, AMulY, ADoDraw);
|
||||
|
||||
InitializeRenderInfo(ARenderInfo);
|
||||
|
||||
// Don't draw anything if we have alpha=zero
|
||||
if Font.Color.Alpha = 0 then Exit;
|
||||
|
||||
ADest.Font.FPColor := AdjustColorToBackground(Font.Color, ARenderInfo);
|
||||
lText := Value.Strings[0];
|
||||
Render_NextText_X := CoordToCanvasX(X);
|
||||
|
||||
// render each character separately
|
||||
for i := 0 to UTF8Length(lText)-1 do
|
||||
begin
|
||||
lUTF8Char := UTF8Copy(lText, i+1, 1);
|
||||
|
||||
ADest.TextOut(lX, lY, lUTF8Char);
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TvField }
|
||||
|
||||
constructor TvField.Create(APage: TvPage);
|
||||
begin
|
||||
inherited Create(APage);
|
||||
|
||||
DateFormat := 'dd/MM/yyyy hh:mm:ss';
|
||||
NumberFormat := vnfDecimal;
|
||||
end;
|
||||
|
||||
{ TvCircle }
|
||||
|
||||
procedure TvCircle.Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo; ADestX: Integer;
|
||||
|
@ -53,6 +53,9 @@ function Make3DPoint(AX, AY, AZ: Double): T3DPoint;
|
||||
procedure EllipticalArcToBezier(Xc, Yc, Rx, Ry, startAngle, endAngle: Double; var P1, P2, P3, P4: T3DPoint);
|
||||
procedure CircularArcToBezier(Xc, Yc, R, startAngle, endAngle: Double; var P1, P2, P3, P4: T3DPoint);
|
||||
procedure AddBezierToPoints(P1, P2, P3, P4: T3DPoint; var Points: TPointsArray);
|
||||
function BezierEquation_GetPoint(t: Double; P1, P2, P3, P4: T3DPoint): T3DPoint;
|
||||
function BezierEquation_GetLength(P1, P2, P3, P4: T3DPoint; AMaxT: Double = 1; ASteps: Integer = 30): Double;
|
||||
function BezierEquation_GetT_ForLength(P1, P2, P3, P4: T3DPoint; ALength: Double; ASteps: Integer = 30): Double;
|
||||
procedure ConvertPathToPoints(APath: TPath; ADestX, ADestY: Integer; AMulX, AMulY: Double; var Points: TPointsArray);
|
||||
function Rotate2DPoint(P, RotCenter: TPoint; alpha:double): TPoint;
|
||||
function Rotate3DPointInXY(P, RotCenter: T3DPoint; alpha:double): T3DPoint;
|
||||
@ -234,6 +237,7 @@ end;
|
||||
procedure AddBezierToPoints(P1, P2, P3, P4: T3DPoint; var Points: TPointsArray);
|
||||
var
|
||||
CurveLength, k, CurX, CurY, LastPoint: Integer;
|
||||
CurPoint: T3DPoint;
|
||||
t: Double;
|
||||
begin
|
||||
{$ifdef FPVECTORIAL_BEZIERTOPOINTS_DEBUG}
|
||||
@ -250,8 +254,7 @@ begin
|
||||
for k := 1 to CurveLength do
|
||||
begin
|
||||
t := k / CurveLength;
|
||||
CurX := Round(sqr(1 - t) * (1 - t) * P1.X + 3 * t * sqr(1 - t) * P2.X + 3 * t * t * (1 - t) * P3.X + t * t * t * P4.X);
|
||||
CurY := Round(sqr(1 - t) * (1 - t) * P1.Y + 3 * t * sqr(1 - t) * P2.Y + 3 * t * t * (1 - t) * P3.Y + t * t * t * P4.Y);
|
||||
CurPoint := BezierEquation_GetPoint(t, P1, P2, P3, P4);
|
||||
Points[LastPoint+k].X := CurX;
|
||||
Points[LastPoint+k].Y := CurY;
|
||||
{$ifdef FPVECTORIAL_BEZIERTOPOINTS_DEBUG}
|
||||
@ -263,6 +266,67 @@ begin
|
||||
{$endif}
|
||||
end;
|
||||
|
||||
function BezierEquation_GetPoint(t: Double; P1, P2, P3, P4: T3DPoint): T3DPoint;
|
||||
begin
|
||||
Result.X := Round(sqr(1 - t) * (1 - t) * P1.X + 3 * t * sqr(1 - t) * P2.X + 3 * t * t * (1 - t) * P3.X + t * t * t * P4.X);
|
||||
Result.Y := Round(sqr(1 - t) * (1 - t) * P1.Y + 3 * t * sqr(1 - t) * P2.Y + 3 * t * t * (1 - t) * P3.Y + t * t * t * P4.Y);
|
||||
end;
|
||||
|
||||
// See http://www.lemoda.net/maths/bezier-length/index.html
|
||||
// See http://steve.hollasch.net/cgindex/curves/cbezarclen.html for a more complex method
|
||||
function BezierEquation_GetLength(P1, P2, P3, P4: T3DPoint; AMaxT: Double; ASteps: Integer): Double;
|
||||
var
|
||||
lCurT, x_diff, y_diff: Double;
|
||||
i, lCurStep: Integer;
|
||||
lCurPoint, lPrevPoint: T3DPoint;
|
||||
begin
|
||||
Result := 0.0;
|
||||
|
||||
for i := 0 to ASteps do
|
||||
begin
|
||||
lCurT := i / ASteps;
|
||||
if lCurT > AMaxT then Exit;
|
||||
lCurPoint := BezierEquation_GetPoint(lCurT, P1, P2, P3, P4);
|
||||
if i = 0 then
|
||||
begin
|
||||
lPrevPoint := lCurPoint;
|
||||
Continue;
|
||||
end;
|
||||
|
||||
x_diff := lCurPoint.x - lPrevPoint.x;
|
||||
y_diff := lCurPoint.y - lPrevPoint.y;
|
||||
Result := Result + sqrt(sqr(x_diff) + sqr(y_diff));
|
||||
lPrevPoint := lCurPoint;
|
||||
end;
|
||||
end;
|
||||
|
||||
function BezierEquation_GetT_ForLength(P1, P2, P3, P4: T3DPoint; ALength: Double; ASteps: Integer): Double;
|
||||
var
|
||||
i: Integer;
|
||||
LeftT, RightT: Double;
|
||||
|
||||
function IsLeftBetter(): Boolean;
|
||||
var
|
||||
lLeftLen, lRightLen: Double;
|
||||
begin
|
||||
lLeftLen := BezierEquation_GetLength(P1, P2, P3, P4, LeftT, ASteps);
|
||||
lRightLen := BezierEquation_GetLength(P1, P2, P3, P4, RightT, ASteps);
|
||||
Result := Abs(lLeftLen - ALength) < Abs(lRightLen - ALength);
|
||||
end;
|
||||
|
||||
begin
|
||||
LeftT := 0;
|
||||
RightT := 1;
|
||||
|
||||
for i := 0 to ASteps do
|
||||
begin
|
||||
if IsLeftBetter() then
|
||||
RightT := (RightT + LeftT) / 2
|
||||
else
|
||||
LeftT := (RightT + LeftT) / 2;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure ConvertPathToPoints(APath: TPath; ADestX, ADestY: Integer; AMulX, AMulY: Double; var Points: TPointsArray);
|
||||
var
|
||||
i, LastPoint: Integer;
|
||||
|
@ -2628,6 +2628,20 @@ var
|
||||
lCurObject := lTextSpanStack.Pop();
|
||||
if lCurObject <> nil then lCurObject.Free;
|
||||
end
|
||||
else if lNodeName = 'textPath' then
|
||||
begin
|
||||
lText := lParagraph.AddText(lNodeValue);
|
||||
|
||||
lText.Font.Size := 10;
|
||||
lText.Name := lName;
|
||||
// Apply the layer style
|
||||
ApplyLayerStyles(lText);
|
||||
|
||||
// Apply the layer style
|
||||
ApplyStackStylesToText(lText);
|
||||
|
||||
// Add the curvature
|
||||
end
|
||||
else
|
||||
begin
|
||||
lText := lParagraph.AddText(lNodeValue);
|
||||
|
Loading…
Reference in New Issue
Block a user