mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-06-03 05:58:14 +02:00
fpvectorial: Many improvements to the layer system, svg reading of colors and of paths
git-svn-id: trunk@39672 -
This commit is contained in:
parent
5b91afa3ef
commit
6c7d1e61e7
@ -1922,7 +1922,7 @@ begin
|
||||
|
||||
{ if Length(AStr) <= 1 then Exit;
|
||||
|
||||
Result := StrToFloat(Copy(AStr, 2, Length(AStr) - 1));}
|
||||
Result := StrToFloat(Copy(AStr, 2, Length(AStr) - 1), FPointSeparator);}
|
||||
end;
|
||||
|
||||
function TvDXFVectorialReader.ConvertDXFStringToUTF8(AStr: string): string;
|
||||
|
@ -530,6 +530,8 @@ type
|
||||
function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
|
||||
end;
|
||||
|
||||
{ TvEntityWithSubEntities }
|
||||
|
||||
TvEntityWithSubEntities = class(TvEntity)
|
||||
private
|
||||
FCurIndex: Integer;
|
||||
@ -544,8 +546,8 @@ type
|
||||
function GetNextEntity: TvEntity;
|
||||
procedure AddEntity(AEntity: TvEntity);
|
||||
procedure Clear; override;
|
||||
//
|
||||
// Never add a Render() procedure to TvBlock, because blocks are invisible!
|
||||
procedure Render(ADest: TFPCustomCanvas; ADestX: Integer = 0;
|
||||
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0); override;
|
||||
end;
|
||||
|
||||
{@@
|
||||
@ -556,6 +558,9 @@ type
|
||||
{ TvBlock }
|
||||
|
||||
TvBlock = class(TvEntityWithSubEntities)
|
||||
public
|
||||
procedure Render(ADest: TFPCustomCanvas; ADestX: Integer = 0;
|
||||
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0); override;
|
||||
end;
|
||||
|
||||
{@@
|
||||
@ -581,8 +586,6 @@ type
|
||||
|
||||
TvLayer = class(TvEntityWithSubEntities)
|
||||
public
|
||||
procedure Render(ADest: TFPCustomCanvas; ADestX: Integer = 0;
|
||||
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0); override;
|
||||
end;
|
||||
|
||||
{ TvVectorialDocument }
|
||||
@ -676,6 +679,7 @@ type
|
||||
procedure AddLineToPath(AX, AY: Double; AColor: TFPColor); overload;
|
||||
procedure AddLineToPath(AX, AY, AZ: Double); overload;
|
||||
procedure GetCurrentPathPenPos(var AX, AY: Double);
|
||||
procedure GetTmpPathStartPos(var AX, AY: Double);
|
||||
procedure AddBezierToPath(AX1, AY1, AX2, AY2, AX3, AY3: Double); overload;
|
||||
procedure AddBezierToPath(AX1, AY1, AZ1, AX2, AY2, AZ2, AX3, AY3, AZ3: Double); overload;
|
||||
procedure SetBrushColor(AColor: TFPColor);
|
||||
@ -694,7 +698,9 @@ type
|
||||
function AddBlock(AName: string; AX, AY, AZ: Double): TvBlock;
|
||||
function AddInsert(AX, AY, AZ: Double; ABlock: TvBlock): TvInsert;
|
||||
// Layers
|
||||
function AddLayer(AName: string): TvLayer;
|
||||
function AddLayerAndSetAsCurrent(AName: string): TvLayer;
|
||||
procedure ClearLayerSelection();
|
||||
// Dimensions
|
||||
function AddAlignedDimension(BaseLeft, BaseRight, DimLeft, DimRight: T3DPoint; AOnlyCreate: Boolean = False): TvAlignedDimension;
|
||||
function AddRadialDimension(AIsDiameter: Boolean; ACenter, ADimLeft, ADimRight: T3DPoint; AOnlyCreate: Boolean = False): TvRadialDimension;
|
||||
@ -2619,6 +2625,27 @@ begin
|
||||
FElements.Clear;
|
||||
end;
|
||||
|
||||
procedure TvEntityWithSubEntities.Render(ADest: TFPCustomCanvas;
|
||||
ADestX: Integer; ADestY: Integer; AMulX: Double; AMulY: Double);
|
||||
var
|
||||
lEntity: TvEntity;
|
||||
begin
|
||||
inherited Render(ADest, ADestX, ADestY, AMulX, AMulY);
|
||||
lEntity := GetFirstEntity();
|
||||
while lEntity <> nil do
|
||||
begin
|
||||
{$IFDEF FPVECTORIAL_DEBUG_BLOCKS}
|
||||
//WriteLn(Format('[TvInsert.Render] Name=%s Block=%s Entity=%s EntityXY=%f | %f BlockXY=%f | %f InsertXY=%f | %f',
|
||||
// [Name, Block.Name, lEntity.ClassName, lEntity.X, lEntity.Y, Block.X, Block.Y, X, Y]));
|
||||
{$ENDIF}
|
||||
|
||||
// Render
|
||||
lEntity.Render(ADest, ADestX, ADestY, AMulX, AMuly);
|
||||
|
||||
lEntity := GetNextEntity();
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TvInsert }
|
||||
|
||||
procedure TvInsert.Render(ADest: TFPCustomCanvas; ADestX: Integer;
|
||||
@ -2647,27 +2674,12 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TvLayer }
|
||||
{ TvBlock }
|
||||
|
||||
procedure TvLayer.Render(ADest: TFPCustomCanvas; ADestX: Integer;
|
||||
procedure TvBlock.Render(ADest: TFPCustomCanvas; ADestX: Integer;
|
||||
ADestY: Integer; AMulX: Double; AMulY: Double);
|
||||
var
|
||||
lEntity: TvEntity;
|
||||
begin
|
||||
inherited Render(ADest, ADestX, ADestY, AMulX, AMulY);
|
||||
lEntity := GetFirstEntity();
|
||||
while lEntity <> nil do
|
||||
begin
|
||||
{$IFDEF FPVECTORIAL_DEBUG_BLOCKS}
|
||||
//WriteLn(Format('[TvInsert.Render] Name=%s Block=%s Entity=%s EntityXY=%f | %f BlockXY=%f | %f InsertXY=%f | %f',
|
||||
// [Name, Block.Name, lEntity.ClassName, lEntity.X, lEntity.Y, Block.X, Block.Y, X, Y]));
|
||||
{$ENDIF}
|
||||
|
||||
// Render
|
||||
lEntity.Render(ADest, ADestX, ADestY, AMulX, AMuly);
|
||||
|
||||
lEntity := GetNextEntity();
|
||||
end;
|
||||
// TvBlock.Render must be empty! Because blocks are invisible by themselves
|
||||
end;
|
||||
|
||||
{ TvVectorialPage }
|
||||
@ -2796,6 +2808,7 @@ begin
|
||||
FEntities.ForEachCall(CallbackDeleteEntity, nil);
|
||||
FEntities.Clear();
|
||||
ClearTmpPath();
|
||||
ClearLayerSelection();
|
||||
end;
|
||||
|
||||
{@@
|
||||
@ -2828,8 +2841,17 @@ end;
|
||||
}
|
||||
function TvVectorialPage.AddEntity(AEntity: TvEntity): Integer;
|
||||
begin
|
||||
Result := FEntities.Count;
|
||||
FEntities.Add(Pointer(AEntity));
|
||||
if FCurrentLayer = nil then
|
||||
begin
|
||||
Result := FEntities.Count;
|
||||
FEntities.Add(Pointer(AEntity));
|
||||
end
|
||||
// If a layer is selected as current, add elements to it instead
|
||||
else
|
||||
begin
|
||||
Result := FCurrentLayer.GetSubpartCount();
|
||||
FCurrentLayer.AddEntity(AEntity);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TvVectorialPage.AddPathCopyMem(APath: TPath; AOnlyCreate: Boolean = False): TPath;
|
||||
@ -2944,6 +2966,18 @@ begin
|
||||
AY := T2DSegment(FTmpPath.PointsEnd).Y;
|
||||
end;
|
||||
|
||||
procedure TvVectorialPage.GetTmpPathStartPos(var AX, AY: Double);
|
||||
begin
|
||||
AX := 0;
|
||||
AY := 0;
|
||||
if (FTmpPath = nil) or (FTmpPath.GetSubpartCount() <= 0) or (FTmpPath.Points = nil) then Exit;
|
||||
if FTmpPath.Points is T2DSegment then
|
||||
begin
|
||||
AX := T2DSegment(FTmpPath.Points).X;
|
||||
AY := T2DSegment(FTmpPath.Points).Y;
|
||||
end;
|
||||
end;
|
||||
|
||||
{@@
|
||||
Adds a bezier element to the path. It starts where the previous element ended
|
||||
and it goes throw the control points [AX1, AY1] and [AX2, AY2] and ends
|
||||
@ -3125,9 +3159,21 @@ begin
|
||||
Result := lInsert;
|
||||
end;
|
||||
|
||||
function TvVectorialPage.AddLayer(AName: string): TvLayer;
|
||||
begin
|
||||
Result := TvLayer.Create;
|
||||
AddEntity(Result);
|
||||
end;
|
||||
|
||||
function TvVectorialPage.AddLayerAndSetAsCurrent(AName: string): TvLayer;
|
||||
begin
|
||||
Result := nil;//TvLayer.Create;
|
||||
Result := AddLayer(AName);
|
||||
FCurrentLayer := Result;
|
||||
end;
|
||||
|
||||
procedure TvVectorialPage.ClearLayerSelection;
|
||||
begin
|
||||
FCurrentLayer := nil;
|
||||
end;
|
||||
|
||||
|
||||
|
@ -18,7 +18,19 @@ uses
|
||||
fpvectorial, fpvutils;
|
||||
|
||||
type
|
||||
TSVGTokenType = (sttMoveTo, sttLineTo, sttBezierTo, sttFloatValue);
|
||||
TSVGTokenType = (
|
||||
// moves
|
||||
sttMoveTo, sttRelativeMoveTo,
|
||||
// Close Path
|
||||
sttClosePath,
|
||||
// lines
|
||||
sttLineTo, sttRelativeLineTo,
|
||||
// cubic beziers
|
||||
sttBezierTo, sttRelativeBezierTo,
|
||||
// quadratic beziers
|
||||
sttQuadraticBezierTo, sttRelativeQuadraticBezierTo,
|
||||
// numbers
|
||||
sttFloatValue);
|
||||
|
||||
TSVGToken = class
|
||||
TokenType: TSVGTokenType;
|
||||
@ -116,12 +128,24 @@ var
|
||||
begin
|
||||
lToken := TSVGToken.Create;
|
||||
|
||||
lStr := LowerCase(AStr);
|
||||
lStr := Trim(AStr);
|
||||
if lStr = '' then Exit;
|
||||
|
||||
if lStr[1] = 'm' then lToken.TokenType := sttMoveTo
|
||||
else if lStr[1] = 'l' then lToken.TokenType := sttLineTo
|
||||
else if lStr[1] = 'c' then lToken.TokenType := sttBezierTo
|
||||
// Moves
|
||||
if lStr[1] = 'M' then lToken.TokenType := sttMoveTo
|
||||
else if lStr[1] = 'm' then lToken.TokenType := sttRelativeMoveTo
|
||||
// Close Path
|
||||
else if lStr[1] = 'Z' then lToken.TokenType := sttClosePath
|
||||
else if lStr[1] = 'z' then lToken.TokenType := sttClosePath
|
||||
// Lines
|
||||
else if lStr[1] = 'L' then lToken.TokenType := sttLineTo
|
||||
else if lStr[1] = 'l' then lToken.TokenType := sttRelativeLineTo
|
||||
// cubic Bézier curve commands
|
||||
else if lStr[1] = 'C' then lToken.TokenType := sttBezierTo
|
||||
else if lStr[1] = 'c' then lToken.TokenType := sttRelativeBezierTo
|
||||
// quadratic beziers
|
||||
else if lStr[1] = 'Q' then lToken.TokenType := sttQuadraticBezierTo
|
||||
else if lStr[1] = 'q' then lToken.TokenType := sttRelativeQuadraticBezierTo
|
||||
else
|
||||
begin
|
||||
lToken.TokenType := sttFloatValue;
|
||||
@ -148,7 +172,7 @@ var
|
||||
i: Integer;
|
||||
lTmpStr: string = '';
|
||||
lState: Integer;
|
||||
lCurChar: Char;
|
||||
lFirstTmpStrChar, lCurChar: Char;
|
||||
begin
|
||||
lState := 0;
|
||||
|
||||
@ -171,7 +195,22 @@ begin
|
||||
lTmpStr := '';
|
||||
end
|
||||
else
|
||||
begin
|
||||
// Check for a break, from letter to number
|
||||
if (Length(lTmpStr) >= 1) then
|
||||
begin
|
||||
lFirstTmpStrChar := lTmpStr[1];
|
||||
if ((lFirstTmpStrChar in ['a'..'z', 'A'..'Z']) and not (lCurChar in ['a'..'z', 'A'..'Z'])) or
|
||||
(not (lFirstTmpStrChar in ['a'..'z', 'A'..'Z']) and (lCurChar in ['a'..'z', 'A'..'Z'])) then
|
||||
begin
|
||||
AddToken(lTmpStr);
|
||||
lTmpStr := '';
|
||||
Continue;
|
||||
end;
|
||||
end;
|
||||
|
||||
lTmpStr := lTmpStr + lCurChar;
|
||||
end;
|
||||
|
||||
Inc(i);
|
||||
end;
|
||||
@ -182,6 +221,9 @@ begin
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
// If there is a token still to be added, add it now
|
||||
if (lState = 0) and (lTmpStr <> '') then AddToken(lTmpStr);
|
||||
end;
|
||||
|
||||
{ Example of a supported SVG image:
|
||||
@ -256,15 +298,16 @@ begin
|
||||
if (Length(lValue) > 1) and (lValue[1] = '#') then
|
||||
begin
|
||||
lStr := Copy(lValue, 2, 2);
|
||||
Result.Red := StrToInt('$'+lStr);
|
||||
Result.Red := StrToInt('$'+lStr)*$101;
|
||||
lStr := Copy(lValue, 4, 2);
|
||||
Result.Blue := StrToInt('$'+lStr);
|
||||
Result.Green := StrToInt('$'+lStr)*$101;
|
||||
lStr := Copy(lValue, 6, 2);
|
||||
Result.Green := StrToInt('$'+lStr);
|
||||
Result.Blue := StrToInt('$'+lStr)*$101;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// Support for named colors
|
||||
// List here: http://www.december.com/html/spec/colorsvghex.html
|
||||
case lValue of
|
||||
'black': Result := colBlack;
|
||||
'navy': Result.Blue := $8080;
|
||||
@ -336,13 +379,55 @@ begin
|
||||
Result.Green := $8B8B;
|
||||
Result.Blue := $5757;
|
||||
end;
|
||||
'darkslategray', 'darkslategrey':
|
||||
begin
|
||||
Result.Red := $2F2F;
|
||||
Result.Green := $4F4F;
|
||||
Result.Blue := $4F4F;
|
||||
end;
|
||||
'limegreen':
|
||||
begin
|
||||
Result.Red := $3232;
|
||||
Result.Green := $CDCD;
|
||||
Result.Blue := $3232;
|
||||
end;
|
||||
'mediumseagreen':
|
||||
begin
|
||||
Result.Red := $3C3C;
|
||||
Result.Green := $CBCB;
|
||||
Result.Blue := $7171;
|
||||
end;
|
||||
'turquoise':
|
||||
begin
|
||||
Result.Red := $4040;
|
||||
Result.Green := $E0E0;
|
||||
Result.Blue := $D0D0;
|
||||
end;
|
||||
'royalblue':
|
||||
begin
|
||||
Result.Red := $4141;
|
||||
Result.Green := $6969;
|
||||
Result.Blue := $E1E1;
|
||||
end;
|
||||
'steelblue':
|
||||
begin
|
||||
Result.Red := $4646;
|
||||
Result.Green := $8282;
|
||||
Result.Blue := $B4B4;
|
||||
end;
|
||||
'darkslateblue':
|
||||
begin
|
||||
Result.Red := $4848;
|
||||
Result.Green := $3D3D;
|
||||
Result.Blue := $8B8B;
|
||||
end;
|
||||
'mediumturquoise':
|
||||
begin
|
||||
Result.Red := $4848;
|
||||
Result.Green := $D1D1;
|
||||
Result.Blue := $CCCC;
|
||||
end;
|
||||
{
|
||||
darkslategray #2F4F4F
|
||||
darkslategrey #2F4F4F limegreen #32CD32
|
||||
mediumseagreen #3CB371
|
||||
turquoise #40E0D0 royalblue #4169E1
|
||||
steelblue #4682B4
|
||||
darkslateblue #483D8B mediumturquoise #48D1CC
|
||||
indigo #4B0082
|
||||
darkolivegreen #556B2F cadetblue #5F9EA0
|
||||
cornflowerblue #6495ED
|
||||
@ -365,10 +450,31 @@ chartreuse #7FFF00
|
||||
'purple': Result := colPurple;
|
||||
'olive': Result := colOlive;
|
||||
'gray', 'grey': Result := colGray;
|
||||
'skyblue':
|
||||
begin
|
||||
Result.Red := $8787;
|
||||
Result.Green := $CECE;
|
||||
Result.Blue := $EBEB;
|
||||
end;
|
||||
'lightskyblue':
|
||||
begin
|
||||
Result.Red := $8787;
|
||||
Result.Green := $CECE;
|
||||
Result.Blue := $FAFA;
|
||||
end;
|
||||
'blueviolet':
|
||||
begin
|
||||
Result.Red := $8A8A;
|
||||
Result.Green := $2B2B;
|
||||
Result.Blue := $E2E2;
|
||||
end;
|
||||
'darkred': Result.Red := $8B8B;
|
||||
'darkmagenta':
|
||||
begin
|
||||
Result.Red := $8B8B;
|
||||
Result.Blue := $8B8B;
|
||||
end;
|
||||
{
|
||||
skyblue #87CEEB lightskyblue #87CEFA
|
||||
blueviolet #8A2BE2
|
||||
darkred #8B0000 darkmagenta #8B008B
|
||||
saddlebrown #8B4513
|
||||
darkseagreen #8FBC8F lightgreen #90EE90
|
||||
mediumpurple #9370DB
|
||||
@ -384,8 +490,15 @@ lightsteelblue #B0C4DE
|
||||
darkgoldenrod #B8860B
|
||||
mediumorchid #BA55D3 rosybrown #BC8F8F
|
||||
darkkhaki #BDB76B
|
||||
silver(16) #C0C0C0 mediumvioletred #C71585
|
||||
indianred #CD5C5C
|
||||
}
|
||||
'silver': Result := colSilver;
|
||||
'mediumvioletred':
|
||||
begin
|
||||
Result.Red := $C7C7;
|
||||
Result.Green := $1515;
|
||||
Result.Blue := $8585;
|
||||
end;
|
||||
{indianred #CD5C5C
|
||||
peru #CD853F chocolate #D2691E
|
||||
tan #D2B48C
|
||||
lightgray #D3D3D3 lightgrey #D3D3D3
|
||||
@ -396,11 +509,56 @@ palevioletred #DB7093
|
||||
plum #DDA0DD
|
||||
burlywood #DEB887 lightcyan #E0FFFF
|
||||
lavender #E6E6FA
|
||||
darksalmon #E9967A violet #EE82EE
|
||||
palegoldenrod #EEE8AA
|
||||
lightcoral #F08080 khaki #F0E68C
|
||||
aliceblue #F0F8FF
|
||||
honeydew #F0FFF0 azure #F0FFFF
|
||||
}
|
||||
'darksalmon':
|
||||
begin
|
||||
Result.Red := $E9E9;
|
||||
Result.Green := $9696;
|
||||
Result.Blue := $7A7A;
|
||||
end;
|
||||
'violet':
|
||||
begin
|
||||
Result.Red := $EEEE;
|
||||
Result.Green := $8282;
|
||||
Result.Blue := $EEEE;
|
||||
end;
|
||||
'palegoldenrod':
|
||||
begin
|
||||
Result.Red := $EEEE;
|
||||
Result.Green := $E8E8;
|
||||
Result.Blue := $AAAA;
|
||||
end;
|
||||
'lightcoral':
|
||||
begin
|
||||
Result.Red := $F0F0;
|
||||
Result.Green := $8080;
|
||||
Result.Blue := $8080;
|
||||
end;
|
||||
'khaki':
|
||||
begin
|
||||
Result.Red := $F0F0;
|
||||
Result.Green := $E6E6;
|
||||
Result.Blue := $8C8C;
|
||||
end;
|
||||
'aliceblue':
|
||||
begin
|
||||
Result.Red := $F0F0;
|
||||
Result.Green := $F8F8;
|
||||
Result.Blue := $FFFF;
|
||||
end;
|
||||
'honeydew':
|
||||
begin
|
||||
Result.Red := $F0F0;
|
||||
Result.Green := $FFFF;
|
||||
Result.Blue := $F0F0;
|
||||
end;
|
||||
'azure':
|
||||
begin
|
||||
Result.Red := $F0F0;
|
||||
Result.Green := $FFFF;
|
||||
Result.Blue := $FFFF;
|
||||
end;
|
||||
{
|
||||
sandybrown #F4A460
|
||||
wheat #F5DEB3 beige #F5F5DC
|
||||
whitesmoke #F5F5F5
|
||||
@ -710,16 +868,22 @@ begin
|
||||
AData.StartPath();
|
||||
ReadPathFromString(UTF8Encode(lDStr), AData, ADoc);
|
||||
lPath := AData.EndPath();
|
||||
// Add the pen
|
||||
// Add default SVG pen/brush
|
||||
lPath.Pen.Style := psClear;
|
||||
lPath.Brush.Color := colBlack;
|
||||
lPath.Brush.Style := bsSolid;
|
||||
// Add the pen/brush
|
||||
ReadSVGStyle(lStyleStr, lPath);
|
||||
end;
|
||||
|
||||
// Documentation: http://www.w3.org/TR/SVG/paths.html
|
||||
procedure TvSVGVectorialReader.ReadPathFromString(AStr: string;
|
||||
AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
||||
var
|
||||
i: Integer;
|
||||
X, Y, X2, Y2, X3, Y3: Double;
|
||||
CurX, CurY: Double;
|
||||
lCurTokenType: TSVGTokenType;
|
||||
begin
|
||||
FSVGPathTokenizer.Tokens.Clear;
|
||||
FSVGPathTokenizer.TokenizePathString(AStr);
|
||||
@ -729,31 +893,74 @@ begin
|
||||
i := 0;
|
||||
while i < FSVGPathTokenizer.Tokens.Count do
|
||||
begin
|
||||
if FSVGPathTokenizer.Tokens.Items[i].TokenType = sttMoveTo then
|
||||
lCurTokenType := FSVGPathTokenizer.Tokens.Items[i].TokenType;
|
||||
// --------------
|
||||
// Moves
|
||||
// --------------
|
||||
if lCurTokenType in [sttMoveTo, sttRelativeMoveTo] then
|
||||
begin
|
||||
CurX := FSVGPathTokenizer.Tokens.Items[i+1].Value;
|
||||
CurY := FSVGPathTokenizer.Tokens.Items[i+2].Value;
|
||||
ConvertSVGCoordinatesToFPVCoordinates(AData, CurX, CurY, CurX, CurY);
|
||||
X := FSVGPathTokenizer.Tokens.Items[i+1].Value;
|
||||
Y := FSVGPathTokenizer.Tokens.Items[i+2].Value;
|
||||
ConvertSVGCoordinatesToFPVCoordinates(AData, X, Y, X, Y);
|
||||
|
||||
// take care of relative or absolute
|
||||
if lCurTokenType = sttRelativeMoveTo then
|
||||
begin
|
||||
CurX := CurX + X;
|
||||
CurY := CurY + Y;
|
||||
end
|
||||
else
|
||||
begin
|
||||
CurX := X;
|
||||
CurY := Y;
|
||||
end;
|
||||
AData.AddMoveToPath(CurX, CurY);
|
||||
|
||||
Inc(i, 3);
|
||||
end
|
||||
else if FSVGPathTokenizer.Tokens.Items[i].TokenType = sttLineTo then
|
||||
// --------------
|
||||
// Close Path
|
||||
// --------------
|
||||
else if lCurTokenType = sttClosePath then
|
||||
begin
|
||||
// Get the first point
|
||||
AData.GetTmpPathStartPos(X, Y);
|
||||
|
||||
// And repeat it
|
||||
CurX := X;
|
||||
CurY := Y;
|
||||
AData.AddLineToPath(CurX, CurY);
|
||||
|
||||
Inc(i, 3);
|
||||
end
|
||||
// --------------
|
||||
// Lines
|
||||
// --------------
|
||||
else if lCurTokenType in [sttLineTo, sttRelativeLineTo] then
|
||||
begin
|
||||
X := FSVGPathTokenizer.Tokens.Items[i+1].Value;
|
||||
Y := FSVGPathTokenizer.Tokens.Items[i+2].Value;
|
||||
ConvertSVGDeltaToFPVDelta(AData, X, Y, X, Y);
|
||||
|
||||
// LineTo uses relative coordenates in SVG
|
||||
CurX := CurX + X;
|
||||
CurY := CurY + Y;
|
||||
|
||||
// "l" LineTo uses relative coordenates in SVG
|
||||
if lCurTokenType = sttRelativeLineTo then
|
||||
begin
|
||||
CurX := CurX + X;
|
||||
CurY := CurY + Y;
|
||||
end
|
||||
else
|
||||
begin
|
||||
CurX := X;
|
||||
CurY := Y;
|
||||
end;
|
||||
AData.AddLineToPath(CurX, CurY);
|
||||
|
||||
Inc(i, 3);
|
||||
end
|
||||
else if FSVGPathTokenizer.Tokens.Items[i].TokenType = sttBezierTo then
|
||||
// --------------
|
||||
// Cubic Bezier
|
||||
// --------------
|
||||
else if lCurTokenType in [sttBezierTo, sttRelativeBezierTo] then
|
||||
begin
|
||||
X2 := FSVGPathTokenizer.Tokens.Items[i+1].Value;
|
||||
Y2 := FSVGPathTokenizer.Tokens.Items[i+2].Value;
|
||||
@ -766,14 +973,49 @@ begin
|
||||
ConvertSVGDeltaToFPVDelta(AData, X3, Y3, X3, Y3);
|
||||
ConvertSVGDeltaToFPVDelta(AData, X, Y, X, Y);
|
||||
|
||||
AData.AddBezierToPath(X2 + CurX, Y2 + CurY, X3 + CurX, Y3 + CurY, X + CurX, Y + CurY);
|
||||
|
||||
// BezierTo uses relative coordenates in SVG
|
||||
CurX := CurX + X;
|
||||
CurY := CurY + Y;
|
||||
if lCurTokenType = sttRelativeBezierTo then
|
||||
begin
|
||||
AData.AddBezierToPath(X2 + CurX, Y2 + CurY, X3 + CurX, Y3 + CurY, X + CurX, Y + CurY);
|
||||
CurX := CurX + X;
|
||||
CurY := CurY + Y;
|
||||
end
|
||||
else
|
||||
begin
|
||||
AData.AddBezierToPath(X2, Y2, X3, Y3, X, Y);
|
||||
CurX := X;
|
||||
CurY := Y;
|
||||
end;
|
||||
|
||||
Inc(i, 7);
|
||||
end
|
||||
// --------------
|
||||
// Quadratic Bezier
|
||||
// --------------
|
||||
else if lCurTokenType in [sttQuadraticBezierTo, sttRelativeQuadraticBezierTo] then
|
||||
begin
|
||||
X2 := FSVGPathTokenizer.Tokens.Items[i+1].Value;
|
||||
Y2 := FSVGPathTokenizer.Tokens.Items[i+2].Value;
|
||||
X := FSVGPathTokenizer.Tokens.Items[i+3].Value;
|
||||
Y := FSVGPathTokenizer.Tokens.Items[i+4].Value;
|
||||
|
||||
ConvertSVGDeltaToFPVDelta(AData, X2, Y2, X2, Y2);
|
||||
ConvertSVGDeltaToFPVDelta(AData, X, Y, X, Y);
|
||||
|
||||
if lCurTokenType = sttRelativeQuadraticBezierTo then
|
||||
begin
|
||||
AData.AddBezierToPath(X2 + CurX, Y2 + CurY, X2 + CurX, Y2 + CurY, X + CurX, Y + CurY);
|
||||
CurX := CurX + X;
|
||||
CurY := CurY + Y;
|
||||
end
|
||||
else
|
||||
begin
|
||||
AData.AddBezierToPath(X2, Y2, X2, Y2, X, Y);
|
||||
CurX := X;
|
||||
CurY := Y;
|
||||
end;
|
||||
|
||||
Inc(i, 5);
|
||||
end
|
||||
else
|
||||
begin
|
||||
Inc(i);
|
||||
@ -998,7 +1240,7 @@ begin
|
||||
end
|
||||
else // If there is no unit, just use StrToFloat
|
||||
begin
|
||||
Result := StrToFloat(AStr);
|
||||
Result := StrToFloat(AStr, FPointSeparator);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user