mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-11-20 04:39:28 +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
|
||||
RX, RY, XRotation: Double; // RX and RY are the X and Y half axis sizes
|
||||
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 CalculateEllipseBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double);
|
||||
function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
|
||||
end;
|
||||
|
||||
|
||||
TvFindEntityResult = (vfrNotFound, vfrFound, vfrSubpartFound);
|
||||
|
||||
TvRenderInfo = record
|
||||
@ -490,6 +491,7 @@ type
|
||||
procedure AppendMoveToSegment(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 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 MoveSubpart(ADeltaX, ADeltaY: Double; ASubpart: Cardinal); override;
|
||||
function MoveToSubpart(ASubpart: Cardinal): TPathSegment;
|
||||
@ -1791,6 +1793,8 @@ var
|
||||
CX1, CY1, CX2, CY2, LeftMostX, LeftMostY, RightMostX, RightMostY: Double;
|
||||
RotatedCenter: T3DPoint;
|
||||
begin
|
||||
if CenterSetByUser then Exit;
|
||||
|
||||
// Rotated Ellipse equation:
|
||||
// (xcosθ+ysinθ)^2 / RX^2 + (ycosθ−xsinθ)^2 / RY^2 = 1
|
||||
//
|
||||
@ -1960,6 +1964,21 @@ begin
|
||||
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 }
|
||||
|
||||
function TvVerticalFormulaStack.CalculateHeight(ADest: TFPCustomCanvas): Double;
|
||||
@ -2611,6 +2630,27 @@ begin
|
||||
AppendSegment(segment);
|
||||
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);
|
||||
var
|
||||
i: Integer;
|
||||
|
||||
@ -55,6 +55,8 @@ uses
|
||||
fpvectorial, fpvutils, lazutf8;
|
||||
|
||||
type
|
||||
TDoubleArray = array of Double;
|
||||
|
||||
TSVGTokenType = (
|
||||
// moves
|
||||
sttMoveTo, sttRelativeMoveTo,
|
||||
@ -95,6 +97,7 @@ type
|
||||
Destructor Destroy; override;
|
||||
procedure AddToken(AStr: string);
|
||||
procedure TokenizePathString(AStr: string);
|
||||
procedure TokenizeFunctions(AStr: string);
|
||||
end;
|
||||
|
||||
TODGStyle = class(TvStyle)
|
||||
@ -116,7 +119,7 @@ type
|
||||
end;
|
||||
|
||||
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
|
||||
VariableNames: array of string;
|
||||
VariableValues: array of Double;
|
||||
@ -133,6 +136,9 @@ type
|
||||
FMasterPages: TFPList; // of TODGMasterPage;
|
||||
//FSVGPathTokenizer: TSVGPathTokenizer;
|
||||
//
|
||||
function ReadSpaceSeparatedFloats(AInput: string; AOtherSeparators: string): TDoubleArray;
|
||||
function ReadSpaceSeparatedStrings(AInput: string; AOtherSeparators: string): TStringList;
|
||||
//
|
||||
procedure DeleteStyle(data,arg:pointer);
|
||||
procedure ApplyGraphicAttributeToPenAndBrush(ANodeName, ANodeValue: string; var APen: TvPen; var ABrush: TvBrush);
|
||||
procedure ApplyGraphicAttributeToEntity(ANodeName, ANodeValue: string; ADest: TvEntityWithPen);
|
||||
@ -166,11 +172,14 @@ type
|
||||
procedure ConvertODGDeltaToFPVDelta(
|
||||
const AData: TvVectorialPage;
|
||||
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 ASrcX, ASrcY: Double; var ADestX, ADestY: Double);
|
||||
procedure ConvertViewBoxDeltaToODGDelta(
|
||||
const AInfo: TCustomShapeInfo;
|
||||
procedure ConvertMilimiterCoordinatesToFPVCoordinates(
|
||||
const AData: TvVectorialPage;
|
||||
const ASrcX, ASrcY: Double; var ADestX, ADestY: Double);
|
||||
public
|
||||
{ General reading methods }
|
||||
@ -434,6 +443,106 @@ begin
|
||||
if (lState = 0) and (lTmpStr <> '') then AddToken(lTmpStr);
|
||||
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);
|
||||
begin
|
||||
TObject(data).Free;
|
||||
@ -869,25 +978,23 @@ begin
|
||||
sttEllipticArcTo, sttRelativeEllipticArcTo, sttEllipticArcToWithAngle:
|
||||
begin
|
||||
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+1]);
|
||||
x1 := CurToken.Value;// + ADeltaX;
|
||||
x1 := CurToken.Value;
|
||||
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+2]);
|
||||
y1 := CurToken.Value;// + ADeltaY;
|
||||
y1 := CurToken.Value;
|
||||
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+3]);
|
||||
x2 := ResolveEnhancedGeometryFormula(CurToken, AInfo) / 2;
|
||||
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+4]);
|
||||
y2 := ResolveEnhancedGeometryFormula(CurToken, AInfo) / 2;
|
||||
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+5]);
|
||||
t1 := CurToken.Value;
|
||||
t1 := t1 / Pi;
|
||||
t1 := DegToRad(t1);
|
||||
CurToken := TSVGToken(lTokenizer.Tokens.Items[j+6]);
|
||||
t2 := CurToken.Value;
|
||||
t2 := t2 / Pi;
|
||||
t2 := DegToRad(t2);
|
||||
|
||||
ConvertViewBoxCoordinatesToODGCoordinates(AInfo, x1, y1, x1, y1);
|
||||
ConvertODGCoordinatesToFPVCoordinates(AData, x1, y1, x1, y1);
|
||||
ConvertViewBoxCoordinatesToFPVCoordinates(AData, AInfo, x1, y1, x1, y1);
|
||||
|
||||
ConvertViewBoxDeltaToODGDelta(AInfo, x2, y2, x2, y2);
|
||||
ConvertODGDeltaToFPVDelta(AData, x2, y2, x2, y2);
|
||||
ConvertViewBoxDeltaToFPVDelta(AInfo, x2, y2, x2, y2);
|
||||
|
||||
// Parametrized Ellipse equation
|
||||
lSrcX := x2 * Cos(t1) + x1;
|
||||
@ -897,7 +1004,7 @@ begin
|
||||
|
||||
// See http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
|
||||
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);
|
||||
end;
|
||||
@ -979,6 +1086,12 @@ begin
|
||||
lWidth := 0.0;
|
||||
lHeight := 0.0;
|
||||
|
||||
lSkewX := 0.0;
|
||||
lSkewY := 0.0;
|
||||
lRotate := 0.0;
|
||||
lTranslateX := 0.0;
|
||||
lTranslateY := 0.0;
|
||||
|
||||
lGroup := TvEntityWithSubEntities.Create(AData);
|
||||
lPath := TPath.Create(Adata);
|
||||
lGroup.AddEntity(lPath);
|
||||
@ -1006,10 +1119,7 @@ begin
|
||||
// lEllipse.Name := UTF16ToUTF8(ANode.Attributes.Item[i].NodeValue)
|
||||
end;
|
||||
|
||||
ConvertODGCoordinatesToFPVCoordinates(
|
||||
AData, x1, y1, x2, y2);
|
||||
ConvertODGDeltaToFPVDelta(
|
||||
AData, lWidth, lHeight, lWidth, lHeight);
|
||||
ConvertMilimiterCoordinatesToFPVCoordinates(AData, x1, y1, x2, y2);
|
||||
|
||||
// Go through sub-nodes
|
||||
lCurNode := ANode.FirstChild;
|
||||
@ -1030,6 +1140,8 @@ begin
|
||||
end;
|
||||
'draw:enhanced-geometry':
|
||||
begin
|
||||
lInfo.Left := x1 + lTranslateX;
|
||||
lInfo.Top := y1 + lTranslateY;
|
||||
lInfo.Width := lWidth;
|
||||
lInfo.Height := lHeight;
|
||||
ReadEnhancedGeometryNodeToTPath(lCurNode, AData, lPath, x1, y1, lInfo);
|
||||
@ -1312,6 +1424,15 @@ end;
|
||||
|
||||
procedure TvODGVectorialReader.GetDrawTransforms(AInputStr: string; out ASkewX,
|
||||
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
|
||||
ASkewX := 0.0;
|
||||
ASkewY := 0.0;
|
||||
@ -1319,7 +1440,60 @@ begin
|
||||
ATranslateX := 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;
|
||||
|
||||
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:
|
||||
|
||||
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
|
||||
|
||||
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(
|
||||
const AInfo: TCustomShapeInfo; const ASrcX, ASrcY: Double; var ADestX,
|
||||
ADestY: Double);
|
||||
procedure TvODGVectorialReader.ConvertViewBoxCoordinatesToFPVCoordinates(
|
||||
const AData: TvVectorialPage; const AInfo: TCustomShapeInfo;
|
||||
const ASrcX, ASrcY: Double; var ADestX, ADestY: Double);
|
||||
begin
|
||||
ADestX := ASrcX * (AInfo.Width / AInfo.ViewBox_Width) + AInfo.ViewBox_Left;
|
||||
ADestY := ASrcY * (AInfo.Height / AInfo.ViewBox_Height) + AInfo.ViewBox_Top;
|
||||
ADestX := (ASrcX - AInfo.ViewBox_Left) * (AInfo.Width / AInfo.ViewBox_Width) + AInfo.Left;
|
||||
ADestY := (ASrcY - AInfo.ViewBox_Top) * (AInfo.Height / AInfo.ViewBox_Height) + AInfo.Top;
|
||||
ADestY := AData.Height - ADestY;
|
||||
end;
|
||||
|
||||
procedure TvODGVectorialReader.ConvertViewBoxDeltaToODGDelta(
|
||||
procedure TvODGVectorialReader.ConvertViewBoxDeltaToFPVDelta(
|
||||
const AInfo: TCustomShapeInfo; const ASrcX, ASrcY: Double; var ADestX,
|
||||
ADestY: Double);
|
||||
begin
|
||||
ADestX := ASrcX * (AInfo.Width / AInfo.ViewBox_Width);
|
||||
ADestY := ASrcY * (AInfo.Height / AInfo.ViewBox_Height);
|
||||
ADestX := (ASrcX - AInfo.ViewBox_Left) * (AInfo.Width / AInfo.ViewBox_Width);
|
||||
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;
|
||||
|
||||
constructor TvODGVectorialReader.Create;
|
||||
|
||||
@ -92,6 +92,8 @@ type
|
||||
function ReadEntityFromNode(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 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;
|
||||
procedure ReadLayerFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument);
|
||||
function ReadLineFromNode(ANode: TDOMNode; AData: TvVectorialPage; ADoc: TvVectorialDocument): TvEntity;
|
||||
@ -957,7 +959,7 @@ begin
|
||||
i := 0;
|
||||
while i < lTokenizer.Tokens.Count-1 do
|
||||
begin
|
||||
lFunctionName := lTokenizer.Tokens.Items[i].StrValue;
|
||||
lFunctionName := Trim(lTokenizer.Tokens.Items[i].StrValue);
|
||||
lParamStr := lTokenizer.Tokens.Items[i+1].StrValue;
|
||||
lMatrixElements := ReadSpaceSeparatedFloats(lParamStr, ',');
|
||||
|
||||
@ -1226,6 +1228,7 @@ begin
|
||||
case lEntityName of
|
||||
'circle': Result := ReadCircleFromNode(ANode, AData, ADoc);
|
||||
'ellipse': Result := ReadEllipseFromNode(ANode, AData, ADoc);
|
||||
'frame': Result := ReadFrameFromNode(ANode, AData, ADoc);
|
||||
'g': ReadLayerFromNode(ANode, AData, ADoc);
|
||||
'image': Result := ReadImageFromNode(ANode, AData, ADoc);
|
||||
'line': Result := ReadLineFromNode(ANode, AData, ADoc);
|
||||
@ -1342,6 +1345,173 @@ begin
|
||||
Result := lEllipse;
|
||||
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"
|
||||
// xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKMAAACGCAYAA
|
||||
// ACxDToF......" clip-path="url(#Clip0)" transform="matrix(1 0 0 1 0 0)"/>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user