mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-11-22 13:49:29 +01:00
fpvectorial: Many fixes in ODG handling, specially of custom-shape, frame and coordenates, but not yet working properly for the test file
git-svn-id: trunk@44118 -
This commit is contained in:
parent
b699d68760
commit
16b4faacff
@ -344,12 +344,13 @@ type
|
|||||||
public
|
public
|
||||||
RX, RY, XRotation: Double; // RX and RY are the X and Y half axis sizes
|
RX, RY, XRotation: Double; // RX and RY are the X and Y half axis sizes
|
||||||
LeftmostEllipse, ClockwiseArcFlag: Boolean;
|
LeftmostEllipse, ClockwiseArcFlag: Boolean;
|
||||||
CX, CY: Double;
|
CX, CY: Double; // Ellipse center
|
||||||
|
CenterSetByUser: Boolean; // defines if we should use LeftmostEllipse to calculate the center, or if CX, CY is set directly
|
||||||
procedure CalculateCenter;
|
procedure CalculateCenter;
|
||||||
procedure CalculateEllipseBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double);
|
procedure CalculateEllipseBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double);
|
||||||
|
function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
TvFindEntityResult = (vfrNotFound, vfrFound, vfrSubpartFound);
|
TvFindEntityResult = (vfrNotFound, vfrFound, vfrSubpartFound);
|
||||||
|
|
||||||
TvRenderInfo = record
|
TvRenderInfo = record
|
||||||
@ -490,6 +491,7 @@ type
|
|||||||
procedure AppendMoveToSegment(AX, AY: Double);
|
procedure AppendMoveToSegment(AX, AY: Double);
|
||||||
procedure AppendLineToSegment(AX, AY: Double);
|
procedure AppendLineToSegment(AX, AY: Double);
|
||||||
procedure AppendEllipticalArc(ARadX, ARadY, AXAxisRotation, ADestX, ADestY: Double; ALeftmostEllipse, AClockwiseArcFlag: Boolean); // See http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
|
procedure AppendEllipticalArc(ARadX, ARadY, AXAxisRotation, ADestX, ADestY: Double; ALeftmostEllipse, AClockwiseArcFlag: Boolean); // See http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
|
||||||
|
procedure AppendEllipticalArcWithCenter(ARadX, ARadY, AXAxisRotation, ADestX, ADestY, ACenterX, ACenterY: Double; AClockwiseArcFlag: Boolean); // See http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
|
||||||
procedure Move(ADeltaX, ADeltaY: Double); override;
|
procedure Move(ADeltaX, ADeltaY: Double); override;
|
||||||
procedure MoveSubpart(ADeltaX, ADeltaY: Double; ASubpart: Cardinal); override;
|
procedure MoveSubpart(ADeltaX, ADeltaY: Double; ASubpart: Cardinal); override;
|
||||||
function MoveToSubpart(ASubpart: Cardinal): TPathSegment;
|
function MoveToSubpart(ASubpart: Cardinal): TPathSegment;
|
||||||
@ -1791,6 +1793,8 @@ var
|
|||||||
CX1, CY1, CX2, CY2, LeftMostX, LeftMostY, RightMostX, RightMostY: Double;
|
CX1, CY1, CX2, CY2, LeftMostX, LeftMostY, RightMostX, RightMostY: Double;
|
||||||
RotatedCenter: T3DPoint;
|
RotatedCenter: T3DPoint;
|
||||||
begin
|
begin
|
||||||
|
if CenterSetByUser then Exit;
|
||||||
|
|
||||||
// Rotated Ellipse equation:
|
// Rotated Ellipse equation:
|
||||||
// (xcosθ+ysinθ)^2 / RX^2 + (ycosθ−xsinθ)^2 / RY^2 = 1
|
// (xcosθ+ysinθ)^2 / RX^2 + (ycosθ−xsinθ)^2 / RY^2 = 1
|
||||||
//
|
//
|
||||||
@ -1960,6 +1964,21 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function T2DEllipticalArcSegment.GenerateDebugTree(
|
||||||
|
ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer;
|
||||||
|
var
|
||||||
|
lStr: string;
|
||||||
|
lStrLeftmostEllipse, lStrClockwiseArcFlag: string;
|
||||||
|
begin
|
||||||
|
if LeftmostEllipse then lStrLeftmostEllipse := 'true'
|
||||||
|
else lStrLeftmostEllipse := 'false';
|
||||||
|
if ClockwiseArcFlag then lStrClockwiseArcFlag := 'true'
|
||||||
|
else lStrClockwiseArcFlag := 'false';
|
||||||
|
lStr := Format('[%s] X=%f Y=%f RX=%f RY=%f LeftmostEllipse=%s ClockwiseArcFlag=%s CX=%f CY=%f',
|
||||||
|
[Self.ClassName, X, Y, RX, RY, lStrLeftmostEllipse, lStrClockwiseArcFlag, CX, CY]);
|
||||||
|
Result := ADestRoutine(lStr, APageItem);
|
||||||
|
end;
|
||||||
|
|
||||||
{ TvVerticalFormulaStack }
|
{ TvVerticalFormulaStack }
|
||||||
|
|
||||||
function TvVerticalFormulaStack.CalculateHeight(ADest: TFPCustomCanvas): Double;
|
function TvVerticalFormulaStack.CalculateHeight(ADest: TFPCustomCanvas): Double;
|
||||||
@ -2611,6 +2630,27 @@ begin
|
|||||||
AppendSegment(segment);
|
AppendSegment(segment);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TPath.AppendEllipticalArcWithCenter(ARadX, ARadY, AXAxisRotation,
|
||||||
|
ADestX, ADestY, ACenterX, ACenterY: Double; AClockwiseArcFlag: Boolean);
|
||||||
|
var
|
||||||
|
segment: T2DEllipticalArcSegment;
|
||||||
|
begin
|
||||||
|
segment := T2DEllipticalArcSegment.Create;
|
||||||
|
segment.SegmentType := st2DEllipticalArc;
|
||||||
|
segment.X := ADestX;
|
||||||
|
segment.Y := ADestY;
|
||||||
|
segment.RX := ARadX;
|
||||||
|
segment.RY := ARadY;
|
||||||
|
segment.CX := ACenterX;
|
||||||
|
segment.CY := ACenterY;
|
||||||
|
segment.XRotation := AXAxisRotation;
|
||||||
|
segment.LeftmostEllipse := False; // which value would it have?
|
||||||
|
segment.ClockwiseArcFlag := AClockwiseArcFlag;
|
||||||
|
segment.CenterSetByUser := True;
|
||||||
|
|
||||||
|
AppendSegment(segment);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TPath.Move(ADeltaX, ADeltaY: Double);
|
procedure TPath.Move(ADeltaX, ADeltaY: Double);
|
||||||
var
|
var
|
||||||
i: Integer;
|
i: Integer;
|
||||||
|
|||||||
@ -55,6 +55,8 @@ uses
|
|||||||
fpvectorial, fpvutils, lazutf8;
|
fpvectorial, fpvutils, lazutf8;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
TDoubleArray = array of Double;
|
||||||
|
|
||||||
TSVGTokenType = (
|
TSVGTokenType = (
|
||||||
// moves
|
// moves
|
||||||
sttMoveTo, sttRelativeMoveTo,
|
sttMoveTo, sttRelativeMoveTo,
|
||||||
@ -95,6 +97,7 @@ type
|
|||||||
Destructor Destroy; override;
|
Destructor Destroy; override;
|
||||||
procedure AddToken(AStr: string);
|
procedure AddToken(AStr: string);
|
||||||
procedure TokenizePathString(AStr: string);
|
procedure TokenizePathString(AStr: string);
|
||||||
|
procedure TokenizeFunctions(AStr: string);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TODGStyle = class(TvStyle)
|
TODGStyle = class(TvStyle)
|
||||||
@ -116,7 +119,7 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
TCustomShapeInfo = packed record
|
TCustomShapeInfo = packed record
|
||||||
Width, Height: Double; // in milimiters
|
Left, Top, Width, Height: Double; // in milimiters
|
||||||
ViewBox_Left, ViewBox_Top, ViewBox_Width, ViewBox_Height: Double; // unitless
|
ViewBox_Left, ViewBox_Top, ViewBox_Width, ViewBox_Height: Double; // unitless
|
||||||
VariableNames: array of string;
|
VariableNames: array of string;
|
||||||
VariableValues: array of Double;
|
VariableValues: array of Double;
|
||||||
@ -133,6 +136,9 @@ type
|
|||||||
FMasterPages: TFPList; // of TODGMasterPage;
|
FMasterPages: TFPList; // of TODGMasterPage;
|
||||||
//FSVGPathTokenizer: TSVGPathTokenizer;
|
//FSVGPathTokenizer: TSVGPathTokenizer;
|
||||||
//
|
//
|
||||||
|
function ReadSpaceSeparatedFloats(AInput: string; AOtherSeparators: string): TDoubleArray;
|
||||||
|
function ReadSpaceSeparatedStrings(AInput: string; AOtherSeparators: string): TStringList;
|
||||||
|
//
|
||||||
procedure DeleteStyle(data,arg:pointer);
|
procedure DeleteStyle(data,arg:pointer);
|
||||||
procedure ApplyGraphicAttributeToPenAndBrush(ANodeName, ANodeValue: string; var APen: TvPen; var ABrush: TvBrush);
|
procedure ApplyGraphicAttributeToPenAndBrush(ANodeName, ANodeValue: string; var APen: TvPen; var ABrush: TvBrush);
|
||||||
procedure ApplyGraphicAttributeToEntity(ANodeName, ANodeValue: string; ADest: TvEntityWithPen);
|
procedure ApplyGraphicAttributeToEntity(ANodeName, ANodeValue: string; ADest: TvEntityWithPen);
|
||||||
@ -166,11 +172,14 @@ type
|
|||||||
procedure ConvertODGDeltaToFPVDelta(
|
procedure ConvertODGDeltaToFPVDelta(
|
||||||
const AData: TvVectorialPage;
|
const AData: TvVectorialPage;
|
||||||
const ASrcX, ASrcY: Double; var ADestX, ADestY: Double);
|
const ASrcX, ASrcY: Double; var ADestX, ADestY: Double);
|
||||||
procedure ConvertViewBoxCoordinatesToODGCoordinates(
|
procedure ConvertViewBoxCoordinatesToFPVCoordinates(
|
||||||
|
const AData: TvVectorialPage; const AInfo: TCustomShapeInfo;
|
||||||
|
const ASrcX, ASrcY: Double; var ADestX, ADestY: Double);
|
||||||
|
procedure ConvertViewBoxDeltaToFPVDelta(
|
||||||
const AInfo: TCustomShapeInfo;
|
const AInfo: TCustomShapeInfo;
|
||||||
const ASrcX, ASrcY: Double; var ADestX, ADestY: Double);
|
const ASrcX, ASrcY: Double; var ADestX, ADestY: Double);
|
||||||
procedure ConvertViewBoxDeltaToODGDelta(
|
procedure ConvertMilimiterCoordinatesToFPVCoordinates(
|
||||||
const AInfo: TCustomShapeInfo;
|
const AData: TvVectorialPage;
|
||||||
const ASrcX, ASrcY: Double; var ADestX, ADestY: Double);
|
const ASrcX, ASrcY: Double; var ADestX, ADestY: Double);
|
||||||
public
|
public
|
||||||
{ General reading methods }
|
{ General reading methods }
|
||||||
@ -434,6 +443,106 @@ begin
|
|||||||
if (lState = 0) and (lTmpStr <> '') then AddToken(lTmpStr);
|
if (lState = 0) and (lTmpStr <> '') then AddToken(lTmpStr);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TSVGPathTokenizer.TokenizeFunctions(AStr: string);
|
||||||
|
const
|
||||||
|
Str_Space: Char = ' ';
|
||||||
|
Str_Start_Params: Char = '(';
|
||||||
|
Str_End_Params: Char = ')';
|
||||||
|
ListOfCommandLetters: set of Char = ['a'..'d', 'f'..'z', 'A'..'D', 'F'..'Z'];
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
lTmpStr: string = '';
|
||||||
|
lState: Integer;
|
||||||
|
lFirstTmpStrChar, lCurChar: Char;
|
||||||
|
lToken: TSVGToken;
|
||||||
|
begin
|
||||||
|
lState := 0;
|
||||||
|
|
||||||
|
i := 1;
|
||||||
|
while i <= Length(AStr) do
|
||||||
|
begin
|
||||||
|
case lState of
|
||||||
|
0: // Adding to the tmp string
|
||||||
|
begin
|
||||||
|
lCurChar := AStr[i];
|
||||||
|
if lCurChar in [Str_Start_Params, Str_End_Params] then
|
||||||
|
begin
|
||||||
|
lState := 1;
|
||||||
|
// Add the token
|
||||||
|
lToken := TSVGToken.Create;
|
||||||
|
lToken.StrValue := lTmpStr;
|
||||||
|
Tokens.Add(lToken);
|
||||||
|
//
|
||||||
|
lTmpStr := '';
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
lTmpStr := lTmpStr + lCurChar;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Inc(i);
|
||||||
|
end;
|
||||||
|
1: // Removing spaces
|
||||||
|
begin
|
||||||
|
if AStr[i] <> Str_Space then lState := 0
|
||||||
|
else Inc(i);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// If there is a token still to be added, add it now
|
||||||
|
if (lState = 0) and (lTmpStr <> '') then AddToken(lTmpStr);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TvODGVectorialReader.ReadSpaceSeparatedFloats(AInput: string;
|
||||||
|
AOtherSeparators: string): TDoubleArray;
|
||||||
|
var
|
||||||
|
lStrings: TStringList;
|
||||||
|
lInputStr: string;
|
||||||
|
lMatrixElements: array of Double;
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
lStrings := TStringList.Create;
|
||||||
|
try
|
||||||
|
lStrings.Delimiter := ' ';
|
||||||
|
// now other separator too
|
||||||
|
lInputStr := AInput;
|
||||||
|
for i := 1 to Length(AOtherSeparators) do
|
||||||
|
begin
|
||||||
|
lInputStr := StringReplace(lInputStr, AOtherSeparators[i], ' ', [rfReplaceAll]);
|
||||||
|
end;
|
||||||
|
//
|
||||||
|
lStrings.DelimitedText := lInputStr;
|
||||||
|
SetLength(lMatrixElements, lStrings.Count);
|
||||||
|
for i := 0 to lStrings.Count-1 do
|
||||||
|
begin
|
||||||
|
lMatrixElements[i] := StringWithUnitToFloat(lStrings.Strings[i]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result := lMatrixElements;
|
||||||
|
finally
|
||||||
|
lStrings.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TvODGVectorialReader.ReadSpaceSeparatedStrings(AInput: string;
|
||||||
|
AOtherSeparators: string): TStringList;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
lInputStr: String;
|
||||||
|
begin
|
||||||
|
Result := TStringList.Create;
|
||||||
|
Result.Delimiter := ' ';
|
||||||
|
// now other separator too
|
||||||
|
lInputStr := AInput;
|
||||||
|
for i := 1 to Length(AOtherSeparators) do
|
||||||
|
begin
|
||||||
|
lInputStr := StringReplace(lInputStr, AOtherSeparators[i], ' ', [rfReplaceAll]);
|
||||||
|
end;
|
||||||
|
//
|
||||||
|
Result.DelimitedText := lInputStr;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TvODGVectorialReader.DeleteStyle(data, arg: pointer);
|
procedure TvODGVectorialReader.DeleteStyle(data, arg: pointer);
|
||||||
begin
|
begin
|
||||||
TObject(data).Free;
|
TObject(data).Free;
|
||||||
@ -869,25 +978,23 @@ begin
|
|||||||
sttEllipticArcTo, sttRelativeEllipticArcTo, sttEllipticArcToWithAngle:
|
sttEllipticArcTo, sttRelativeEllipticArcTo, sttEllipticArcToWithAngle:
|
||||||
begin
|
begin
|
||||||
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+1]);
|
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+1]);
|
||||||
x1 := CurToken.Value;// + ADeltaX;
|
x1 := CurToken.Value;
|
||||||
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+2]);
|
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+2]);
|
||||||
y1 := CurToken.Value;// + ADeltaY;
|
y1 := CurToken.Value;
|
||||||
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+3]);
|
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+3]);
|
||||||
x2 := ResolveEnhancedGeometryFormula(CurToken, AInfo) / 2;
|
x2 := ResolveEnhancedGeometryFormula(CurToken, AInfo) / 2;
|
||||||
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+4]);
|
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+4]);
|
||||||
y2 := ResolveEnhancedGeometryFormula(CurToken, AInfo) / 2;
|
y2 := ResolveEnhancedGeometryFormula(CurToken, AInfo) / 2;
|
||||||
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+5]);
|
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+5]);
|
||||||
t1 := CurToken.Value;
|
t1 := CurToken.Value;
|
||||||
t1 := t1 / Pi;
|
t1 := DegToRad(t1);
|
||||||
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+6]);
|
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+6]);
|
||||||
t2 := CurToken.Value;
|
t2 := CurToken.Value;
|
||||||
t2 := t2 / Pi;
|
t2 := DegToRad(t2);
|
||||||
|
|
||||||
ConvertViewBoxCoordinatesToODGCoordinates(AInfo, x1, y1, x1, y1);
|
ConvertViewBoxCoordinatesToFPVCoordinates(AData, AInfo, x1, y1, x1, y1);
|
||||||
ConvertODGCoordinatesToFPVCoordinates(AData, x1, y1, x1, y1);
|
|
||||||
|
|
||||||
ConvertViewBoxDeltaToODGDelta(AInfo, x2, y2, x2, y2);
|
ConvertViewBoxDeltaToFPVDelta(AInfo, x2, y2, x2, y2);
|
||||||
ConvertODGDeltaToFPVDelta(AData, x2, y2, x2, y2);
|
|
||||||
|
|
||||||
// Parametrized Ellipse equation
|
// Parametrized Ellipse equation
|
||||||
lSrcX := x2 * Cos(t1) + x1;
|
lSrcX := x2 * Cos(t1) + x1;
|
||||||
@ -897,7 +1004,7 @@ begin
|
|||||||
|
|
||||||
// See http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
|
// See http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
|
||||||
ADest.AppendMoveToSegment(lSrcX, lSrcY);
|
ADest.AppendMoveToSegment(lSrcX, lSrcY);
|
||||||
ADest.AppendEllipticalArc(x2, y2, 0, lDestX, lDestY, False, False);
|
ADest.AppendEllipticalArcWithCenter(x2, y2, 0, lDestX, lDestY, x1, y1, t2 > t1);
|
||||||
|
|
||||||
Inc(j, 7);
|
Inc(j, 7);
|
||||||
end;
|
end;
|
||||||
@ -979,6 +1086,12 @@ begin
|
|||||||
lWidth := 0.0;
|
lWidth := 0.0;
|
||||||
lHeight := 0.0;
|
lHeight := 0.0;
|
||||||
|
|
||||||
|
lSkewX := 0.0;
|
||||||
|
lSkewY := 0.0;
|
||||||
|
lRotate := 0.0;
|
||||||
|
lTranslateX := 0.0;
|
||||||
|
lTranslateY := 0.0;
|
||||||
|
|
||||||
lGroup := TvEntityWithSubEntities.Create(AData);
|
lGroup := TvEntityWithSubEntities.Create(AData);
|
||||||
lPath := TPath.Create(Adata);
|
lPath := TPath.Create(Adata);
|
||||||
lGroup.AddEntity(lPath);
|
lGroup.AddEntity(lPath);
|
||||||
@ -1006,10 +1119,7 @@ begin
|
|||||||
// lEllipse.Name := UTF16ToUTF8(ANode.Attributes.Item[i].NodeValue)
|
// lEllipse.Name := UTF16ToUTF8(ANode.Attributes.Item[i].NodeValue)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
ConvertODGCoordinatesToFPVCoordinates(
|
ConvertMilimiterCoordinatesToFPVCoordinates(AData, x1, y1, x2, y2);
|
||||||
AData, x1, y1, x2, y2);
|
|
||||||
ConvertODGDeltaToFPVDelta(
|
|
||||||
AData, lWidth, lHeight, lWidth, lHeight);
|
|
||||||
|
|
||||||
// Go through sub-nodes
|
// Go through sub-nodes
|
||||||
lCurNode := ANode.FirstChild;
|
lCurNode := ANode.FirstChild;
|
||||||
@ -1030,6 +1140,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
'draw:enhanced-geometry':
|
'draw:enhanced-geometry':
|
||||||
begin
|
begin
|
||||||
|
lInfo.Left := x1 + lTranslateX;
|
||||||
|
lInfo.Top := y1 + lTranslateY;
|
||||||
lInfo.Width := lWidth;
|
lInfo.Width := lWidth;
|
||||||
lInfo.Height := lHeight;
|
lInfo.Height := lHeight;
|
||||||
ReadEnhancedGeometryNodeToTPath(lCurNode, AData, lPath, x1, y1, lInfo);
|
ReadEnhancedGeometryNodeToTPath(lCurNode, AData, lPath, x1, y1, lInfo);
|
||||||
@ -1312,6 +1424,15 @@ end;
|
|||||||
|
|
||||||
procedure TvODGVectorialReader.GetDrawTransforms(AInputStr: string; out ASkewX,
|
procedure TvODGVectorialReader.GetDrawTransforms(AInputStr: string; out ASkewX,
|
||||||
ASkewY, ARotate, ATranslateX, ATranslateY: Double);
|
ASkewY, ARotate, ATranslateX, ATranslateY: Double);
|
||||||
|
var
|
||||||
|
// transform
|
||||||
|
MA, MB, MC, MD, ME, MF: Double;
|
||||||
|
lMTranslateX, lMTranslateY, lMScaleX, lMScaleY, lMSkewX, lMSkewY, lMRotate: Double;
|
||||||
|
lTokenizer: TSVGPathTokenizer;
|
||||||
|
i: Integer;
|
||||||
|
lFunctionName, lParamStr: string;
|
||||||
|
lMatrixElements: array of Double;
|
||||||
|
lMatrixStrElements: TStringList;
|
||||||
begin
|
begin
|
||||||
ASkewX := 0.0;
|
ASkewX := 0.0;
|
||||||
ASkewY := 0.0;
|
ASkewY := 0.0;
|
||||||
@ -1319,7 +1440,60 @@ begin
|
|||||||
ATranslateX := 0.0;
|
ATranslateX := 0.0;
|
||||||
ATranslateY := 0.0;
|
ATranslateY := 0.0;
|
||||||
|
|
||||||
|
// Examples:
|
||||||
|
// transform="matrix(0.860815 0 -0 1.07602 339.302 489.171)"
|
||||||
|
// transform="scale(0.24) translate(0, 35)"
|
||||||
|
// transform="rotate(90)"
|
||||||
|
lTokenizer := TSVGPathTokenizer.Create;
|
||||||
|
try
|
||||||
|
lTokenizer.TokenizeFunctions(AInputStr);
|
||||||
|
|
||||||
|
i := 0;
|
||||||
|
while i < lTokenizer.Tokens.Count-1 do
|
||||||
|
begin
|
||||||
|
lFunctionName := Trim(lTokenizer.Tokens.Items[i].StrValue);
|
||||||
|
lParamStr := lTokenizer.Tokens.Items[i+1].StrValue;
|
||||||
|
//lMatrixElements := ReadSpaceSeparatedFloats(lParamStr, ',');
|
||||||
|
|
||||||
|
if lFunctionName = 'matrix' then
|
||||||
|
begin
|
||||||
|
{ReadSVGTransformationMatrix(lParamStr, MA, MB, MC, MD, ME, MF);
|
||||||
|
|
||||||
|
ConvertTransformationMatrixToOperations(MA, MB, MC, MD, ME, MF,
|
||||||
|
lMTranslateX, lMTranslateY, lMScaleX, lMScaleY, lMSkewX, lMSkewY, lMRotate);
|
||||||
|
|
||||||
|
ConvertSVGDeltaToFPVDelta(nil,
|
||||||
|
lMTranslateX, lMTranslateY,
|
||||||
|
lMTranslateX, lMTranslateY);
|
||||||
|
|
||||||
|
ADestEntity.Move(lMTranslateX, lMTranslateY);
|
||||||
|
ADestEntity.Scale(lMScaleX, lMScaleY); }
|
||||||
|
end
|
||||||
|
else if lFunctionName = 'scale' then
|
||||||
|
begin
|
||||||
|
;
|
||||||
|
end
|
||||||
|
else if lFunctionName = 'translate' then
|
||||||
|
begin
|
||||||
|
lMatrixStrElements := ReadSpaceSeparatedStrings(lParamStr, ',');
|
||||||
|
try
|
||||||
|
ATranslateX := StringWithUnitToFloat(lMatrixStrElements.Strings[0]);
|
||||||
|
ATranslateY := StringWithUnitToFloat(lMatrixStrElements.Strings[1]);
|
||||||
|
finally
|
||||||
|
lMatrixStrElements.Free;
|
||||||
|
end;
|
||||||
|
//ADestEntity.Move(lMatrixElements[0], lMatrixElements[1]);
|
||||||
|
end
|
||||||
|
else if lFunctionName = 'rotate' then
|
||||||
|
begin
|
||||||
|
//ADestEntity.Rotate(lMatrixElements[0], Make3DPoint(0, 0, 0));
|
||||||
|
end;
|
||||||
|
|
||||||
|
Inc(i, 2);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
lTokenizer.Free;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TvODGVectorialReader.ReadSVGColor(AValue: string): TFPColor;
|
function TvODGVectorialReader.ReadSVGColor(AValue: string): TFPColor;
|
||||||
@ -1764,25 +1938,44 @@ end;
|
|||||||
|
|
||||||
We should use these formulas to obtain the X, Y position from something in the drawing:
|
We should use these formulas to obtain the X, Y position from something in the drawing:
|
||||||
|
|
||||||
Xreal = Xenhanced-path * (draw:custom-shape_svg:width / svg:viewBox_Width) + svg:viewBox_Xo;
|
Xreal = (Xenhanced-path - ViewBox_X0) * (draw:custom-shape_svg:width / svg:viewBox_Width) + svg:viewBox_Xo;
|
||||||
And the same for Y
|
And the same for Y
|
||||||
|
|
||||||
For sizes just use without Xo
|
For sizes just use without Xo
|
||||||
|
|
||||||
|
<draw:custom-shape draw:style-name="gr6" draw:text-style-name="P1" draw:layer="layout" svg:width="3.783cm" svg:height="3.602cm" draw:transform="skewX (-0.000872664625997166) rotate (-1.62385433605552) translate (19.087cm 20.266cm)">
|
||||||
|
<text:p />
|
||||||
|
<draw:enhanced-geometry svg:viewBox="0 0 21600 21600" draw:glue-points="10800 0 3163 3163 0 10800 3163 18437 10800 21600 18437 18437 21600 10800 18437 3163" draw:text-areas="3163 3163 18437 18437" draw:type="ring" draw:modifiers="647.870425914817"
|
||||||
|
draw:enhanced-path="U 10800 10800 10800 10800 0 360 Z U 10800 10800 ?f1 ?f1 0 360 N">
|
||||||
|
<draw:equation draw:name="f0" draw:formula="$0 " />
|
||||||
|
<draw:equation draw:name="f1" draw:formula="10800-$0 " />
|
||||||
|
<draw:handle draw:handle-position="$0 10800" draw:handle-range-x-minimum="0" draw:handle-range-x-maximum="10800" />
|
||||||
|
</draw:enhanced-geometry>
|
||||||
|
</draw:custom-shape>
|
||||||
}
|
}
|
||||||
procedure TvODGVectorialReader.ConvertViewBoxCoordinatesToODGCoordinates(
|
procedure TvODGVectorialReader.ConvertViewBoxCoordinatesToFPVCoordinates(
|
||||||
const AInfo: TCustomShapeInfo; const ASrcX, ASrcY: Double; var ADestX,
|
const AData: TvVectorialPage; const AInfo: TCustomShapeInfo;
|
||||||
ADestY: Double);
|
const ASrcX, ASrcY: Double; var ADestX, ADestY: Double);
|
||||||
begin
|
begin
|
||||||
ADestX := ASrcX * (AInfo.Width / AInfo.ViewBox_Width) + AInfo.ViewBox_Left;
|
ADestX := (ASrcX - AInfo.ViewBox_Left) * (AInfo.Width / AInfo.ViewBox_Width) + AInfo.Left;
|
||||||
ADestY := ASrcY * (AInfo.Height / AInfo.ViewBox_Height) + AInfo.ViewBox_Top;
|
ADestY := (ASrcY - AInfo.ViewBox_Top) * (AInfo.Height / AInfo.ViewBox_Height) + AInfo.Top;
|
||||||
|
ADestY := AData.Height - ADestY;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TvODGVectorialReader.ConvertViewBoxDeltaToODGDelta(
|
procedure TvODGVectorialReader.ConvertViewBoxDeltaToFPVDelta(
|
||||||
const AInfo: TCustomShapeInfo; const ASrcX, ASrcY: Double; var ADestX,
|
const AInfo: TCustomShapeInfo; const ASrcX, ASrcY: Double; var ADestX,
|
||||||
ADestY: Double);
|
ADestY: Double);
|
||||||
begin
|
begin
|
||||||
ADestX := ASrcX * (AInfo.Width / AInfo.ViewBox_Width);
|
ADestX := (ASrcX - AInfo.ViewBox_Left) * (AInfo.Width / AInfo.ViewBox_Width);
|
||||||
ADestY := ASrcY * (AInfo.Height / AInfo.ViewBox_Height);
|
ADestY := (ASrcY - AInfo.ViewBox_Top) * (AInfo.Height / AInfo.ViewBox_Height);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TvODGVectorialReader.ConvertMilimiterCoordinatesToFPVCoordinates(
|
||||||
|
const AData: TvVectorialPage; const ASrcX, ASrcY: Double; var ADestX,
|
||||||
|
ADestY: Double);
|
||||||
|
begin
|
||||||
|
ADestX := ASrcX;
|
||||||
|
ADestY := AData.Height - ASrcY;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
constructor TvODGVectorialReader.Create;
|
constructor TvODGVectorialReader.Create;
|
||||||
|
|||||||
@ -92,6 +92,8 @@ type
|
|||||||
function ReadEntityFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument): TvEntity;
|
function ReadEntityFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument): TvEntity;
|
||||||
function ReadCircleFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument): TvEntity;
|
function ReadCircleFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument): TvEntity;
|
||||||
function ReadEllipseFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument): TvEntity;
|
function ReadEllipseFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument): TvEntity;
|
||||||
|
function ReadFrameFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument): TvEntity;
|
||||||
|
function ReadFrameTextFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument): TvEntity;
|
||||||
function ReadImageFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument): TvEntity;
|
function ReadImageFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument): TvEntity;
|
||||||
procedure ReadLayerFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
procedure ReadLayerFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
||||||
function ReadLineFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument): TvEntity;
|
function ReadLineFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument): TvEntity;
|
||||||
@ -957,7 +959,7 @@ begin
|
|||||||
i := 0;
|
i := 0;
|
||||||
while i < lTokenizer.Tokens.Count-1 do
|
while i < lTokenizer.Tokens.Count-1 do
|
||||||
begin
|
begin
|
||||||
lFunctionName := lTokenizer.Tokens.Items[i].StrValue;
|
lFunctionName := Trim(lTokenizer.Tokens.Items[i].StrValue);
|
||||||
lParamStr := lTokenizer.Tokens.Items[i+1].StrValue;
|
lParamStr := lTokenizer.Tokens.Items[i+1].StrValue;
|
||||||
lMatrixElements := ReadSpaceSeparatedFloats(lParamStr, ',');
|
lMatrixElements := ReadSpaceSeparatedFloats(lParamStr, ',');
|
||||||
|
|
||||||
@ -1226,6 +1228,7 @@ begin
|
|||||||
case lEntityName of
|
case lEntityName of
|
||||||
'circle': Result := ReadCircleFromNode(ANode, AData, ADoc);
|
'circle': Result := ReadCircleFromNode(ANode, AData, ADoc);
|
||||||
'ellipse': Result := ReadEllipseFromNode(ANode, AData, ADoc);
|
'ellipse': Result := ReadEllipseFromNode(ANode, AData, ADoc);
|
||||||
|
'frame': Result := ReadFrameFromNode(ANode, AData, ADoc);
|
||||||
'g': ReadLayerFromNode(ANode, AData, ADoc);
|
'g': ReadLayerFromNode(ANode, AData, ADoc);
|
||||||
'image': Result := ReadImageFromNode(ANode, AData, ADoc);
|
'image': Result := ReadImageFromNode(ANode, AData, ADoc);
|
||||||
'line': Result := ReadLineFromNode(ANode, AData, ADoc);
|
'line': Result := ReadLineFromNode(ANode, AData, ADoc);
|
||||||
@ -1342,6 +1345,173 @@ begin
|
|||||||
Result := lEllipse;
|
Result := lEllipse;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{
|
||||||
|
<draw:frame draw:style-name="gr5" draw:layer="layout" svg:width="9.024cm" svg:height="0.963cm"
|
||||||
|
draw:transform="rotate (-1.58737695468884) translate (2.3cm 1.197cm)">
|
||||||
|
<draw:text-box>
|
||||||
|
<text:p>Jump opposite arm and leg up</text:p>
|
||||||
|
</draw:text-box>
|
||||||
|
</draw:frame>
|
||||||
|
|
||||||
|
<draw:frame draw:style-name="gr5" draw:layer="layout" svg:width="15.07cm" svg:height="1.115cm" svg:x="2.6cm" svg:y="26.9cm">
|
||||||
|
<draw:text-box>
|
||||||
|
<text:p>
|
||||||
|
<text:span text:style-name="T1">Back muscle movement</text:span>
|
||||||
|
<text:span text:style-name="T2">opposite</text:span>
|
||||||
|
<text:span text:style-name="T3">arm</text:span>
|
||||||
|
and
|
||||||
|
<text:span text:style-name="T3">leg</text:span>
|
||||||
|
up
|
||||||
|
</text:p>
|
||||||
|
</draw:text-box>
|
||||||
|
</draw:frame>
|
||||||
|
}
|
||||||
|
function TvSVGVectorialReader.ReadFrameFromNode(ANode: TDOMNode;
|
||||||
|
AData: TvVectorialPage; ADoc: TvVectorialDocument): TvEntity;
|
||||||
|
var
|
||||||
|
lTextStr: string = '';
|
||||||
|
lx, ly: double;
|
||||||
|
lText: TvText;
|
||||||
|
i: Integer;
|
||||||
|
lNodeName, lNodeValue, lSubNodeName, lSubNodeValue: DOMString;
|
||||||
|
lCurNode, lCurSubNode: TDOMNode;
|
||||||
|
begin
|
||||||
|
lx := 0.0;
|
||||||
|
ly := 0.0;
|
||||||
|
Result := nil;
|
||||||
|
|
||||||
|
lText := nil;//TvText.Create(nil);
|
||||||
|
|
||||||
|
// Apply the layer style
|
||||||
|
ApplyLayerStyles(lText);
|
||||||
|
|
||||||
|
// read the attributes
|
||||||
|
for i := 0 to ANode.Attributes.Length - 1 do
|
||||||
|
begin
|
||||||
|
lNodeName := ANode.Attributes.Item[i].NodeName;
|
||||||
|
lNodeValue := ANode.Attributes.Item[i].NodeValue;
|
||||||
|
if lNodeName = 'svg:x' then
|
||||||
|
lx := lx + StringWithUnitToFloat(lNodeValue)
|
||||||
|
else if lNodeName = 'svg:y' then
|
||||||
|
ly := ly + StringWithUnitToFloat(lNodeValue)
|
||||||
|
else if lNodeName = 'draw:style-name' then
|
||||||
|
ReadSVGStyle(lNodeValue, lText);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Get the text contents
|
||||||
|
lCurNode := Anode.FirstChild;
|
||||||
|
while lCurNode <> nil do
|
||||||
|
begin
|
||||||
|
lNodeName := LowerCase(lCurNode.NodeName);
|
||||||
|
if lNodeName <> 'draw:text-box' then Continue;
|
||||||
|
|
||||||
|
lCurSubNode := lCurNode.FirstChild;
|
||||||
|
while lCurSubNode <> nil do
|
||||||
|
begin
|
||||||
|
lSubNodeName := LowerCase(lCurSubNode.NodeName);
|
||||||
|
if lSubNodeName <> 'draw:text-box' then Continue;
|
||||||
|
|
||||||
|
lText := ReadFrameTextFromNode(lCurNode, AData, ADoc) as TvText;
|
||||||
|
Break;
|
||||||
|
|
||||||
|
lCurSubNode := lCurSubNode.NextSibling;
|
||||||
|
end;
|
||||||
|
if lText <> nil then Break;
|
||||||
|
|
||||||
|
lCurNode := lCurNode.NextSibling;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if lText = nil then Exit;
|
||||||
|
|
||||||
|
// Set the coordinates
|
||||||
|
ConvertSVGCoordinatesToFPVCoordinates(
|
||||||
|
AData, lx, ly, lText.X, lText.Y);
|
||||||
|
|
||||||
|
// Finalization
|
||||||
|
Result := lText;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{
|
||||||
|
<text:p>Jump opposite arm and leg up</text:p>
|
||||||
|
|
||||||
|
<text:p>
|
||||||
|
<text:span text:style-name="T1">Back muscle movement</text:span>
|
||||||
|
<text:span text:style-name="T2">opposite</text:span>
|
||||||
|
<text:span text:style-name="T3">arm</text:span>
|
||||||
|
and
|
||||||
|
<text:span text:style-name="T3">leg</text:span>
|
||||||
|
up
|
||||||
|
</text:p>
|
||||||
|
}
|
||||||
|
function TvSVGVectorialReader.ReadFrameTextFromNode(ANode: TDOMNode;
|
||||||
|
AData: TvVectorialPage; ADoc: TvVectorialDocument): TvEntity;
|
||||||
|
var
|
||||||
|
lTextStr: string = '';
|
||||||
|
lx, ly: double;
|
||||||
|
lText: TvText;
|
||||||
|
i: Integer;
|
||||||
|
lNodeName, lNodeValue: DOMString;
|
||||||
|
lCurNode: TDOMNode;
|
||||||
|
begin
|
||||||
|
lx := 0.0;
|
||||||
|
ly := 0.0;
|
||||||
|
|
||||||
|
lText := TvText.Create(nil);
|
||||||
|
|
||||||
|
// Apply the layer style
|
||||||
|
{ApplyLayerStyles(lText);
|
||||||
|
|
||||||
|
// read the attributes
|
||||||
|
for i := 0 to ANode.Attributes.Length - 1 do
|
||||||
|
begin
|
||||||
|
lNodeName := ANode.Attributes.Item[i].NodeName;
|
||||||
|
lNodeValue := ANode.Attributes.Item[i].NodeValue;
|
||||||
|
if lNodeName = 'x' then
|
||||||
|
lx := lx + StringWithUnitToFloat(lNodeValue)
|
||||||
|
else if lNodeName = 'y' then
|
||||||
|
ly := ly + StringWithUnitToFloat(lNodeValue)
|
||||||
|
else if lNodeName = 'id' then
|
||||||
|
lText.Name := lNodeValue
|
||||||
|
else if lNodeName = 'style' then
|
||||||
|
ReadSVGStyle(lNodeValue, lText);
|
||||||
|
end;}
|
||||||
|
|
||||||
|
// The text contents are inside as a child text, not as a attribute
|
||||||
|
// ex: <text x="0" y="15" fill="red" transform="rotate(30 20,40)">I love SVG</text>
|
||||||
|
if Anode.FirstChild <> nil then
|
||||||
|
lTextStr := Anode.FirstChild.NodeValue;
|
||||||
|
// Add the first line
|
||||||
|
lText.Value.Add(lTextStr);
|
||||||
|
|
||||||
|
// Recover the position if there was a transformation matrix
|
||||||
|
//lx := lx + lText.X;
|
||||||
|
//ly := ly + lText.Y;
|
||||||
|
|
||||||
|
// Set the coordinates
|
||||||
|
ConvertSVGCoordinatesToFPVCoordinates(
|
||||||
|
AData, lx, ly, lText.X, lText.Y);
|
||||||
|
|
||||||
|
// Now add other lines, which appear as <tspan ...>another line</tspan>
|
||||||
|
// Example:
|
||||||
|
// <text x="10" y="20" style="fill:red;">Several lines:
|
||||||
|
// <tspan x="10" y="45">First line</tspan>
|
||||||
|
// <tspan x="10" y="70">Second line</tspan>
|
||||||
|
// </text>
|
||||||
|
// These other lines can be positioned, so they need to appear as independent TvText elements
|
||||||
|
{ lCurNode := Anode.FirstChild;
|
||||||
|
while lCurNode <> nil do
|
||||||
|
begin
|
||||||
|
lNodeName := LowerCase(lCurNode.NodeName);
|
||||||
|
if lNodeName <> 'tspan' then Continue;
|
||||||
|
ReadTextFromNode(lCurNode, AData, ADoc);
|
||||||
|
|
||||||
|
lCurNode := lCurNode.NextSibling;
|
||||||
|
end;}
|
||||||
|
|
||||||
|
// Finalization
|
||||||
|
Result := lText;
|
||||||
|
end;
|
||||||
|
|
||||||
// <image width="92.5" x="0" y="0" height="76.0429"
|
// <image width="92.5" x="0" y="0" height="76.0429"
|
||||||
// xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKMAAACGCAYAA
|
// xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKMAAACGCAYAA
|
||||||
// ACxDToF......" clip-path="url(#Clip0)" transform="matrix(1 0 0 1 0 0)"/>
|
// ACxDToF......" clip-path="url(#Clip0)" transform="matrix(1 0 0 1 0 0)"/>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user