Browse Source

--- Merging r18218 into '.':
U packages/fpvectorial/src/fpvectorial.pas
--- Merging r18221 into '.':
G packages/fpvectorial/src/fpvectorial.pas
--- Merging r18240 into '.':
U packages/fpvectorial/examples/fpvwritetest.pas
--- Merging r18250 into '.':
G packages/fpvectorial/src/fpvectorial.pas
U packages/fpvectorial/src/epsvectorialreader.pas
--- Merging r18258 into '.':
U packages/fpvectorial/src/dxfvectorialreader.pas
G packages/fpvectorial/src/fpvectorial.pas
U packages/fpvectorial/src/fpvtocanvas.pas
--- Merging r18260 into '.':
U packages/fpvectorial/src/svgvectorialwriter.pas
G packages/fpvectorial/src/fpvectorial.pas
G packages/fpvectorial/src/fpvtocanvas.pas

# revisions: 18218,18221,18240,18250,18258,18260
------------------------------------------------------------------------
r18218 | sekelsenmat | 2011-08-16 13:07:19 +0200 (Tue, 16 Aug 2011) | 1 line
Changed paths:
M /trunk/packages/fpvectorial/src/fpvectorial.pas

fpvectorial: Repositions the field Name to avoid confusing fcl-passrc, Name cannot come after Method + Public
------------------------------------------------------------------------
------------------------------------------------------------------------
r18221 | sekelsenmat | 2011-08-16 17:06:45 +0200 (Tue, 16 Aug 2011) | 1 line
Changed paths:
M /trunk/packages/fpvectorial/src/fpvectorial.pas

fpvectorial: Updates the comments
------------------------------------------------------------------------
------------------------------------------------------------------------
r18240 | sekelsenmat | 2011-08-17 13:03:06 +0200 (Wed, 17 Aug 2011) | 1 line
Changed paths:
M /trunk/packages/fpvectorial/examples/fpvwritetest.pas

fpvectorial: Fixes example compilation
------------------------------------------------------------------------
------------------------------------------------------------------------
r18250 | sekelsenmat | 2011-08-17 16:59:08 +0200 (Wed, 17 Aug 2011) | 1 line
Changed paths:
M /trunk/packages/fpvectorial/src/epsvectorialreader.pas
M /trunk/packages/fpvectorial/src/fpvectorial.pas

fpvectorial: Adds support for guessing the document size and zoom level
------------------------------------------------------------------------
------------------------------------------------------------------------
r18258 | sekelsenmat | 2011-08-18 11:13:47 +0200 (Thu, 18 Aug 2011) | 1 line
Changed paths:
M /trunk/packages/fpvectorial/src/dxfvectorialreader.pas
M /trunk/packages/fpvectorial/src/fpvectorial.pas
M /trunk/packages/fpvectorial/src/fpvtocanvas.pas

fpvectorial: Removes unused Z coordinates and makes the entity classes smarter, adds support for searching for elements
------------------------------------------------------------------------
------------------------------------------------------------------------
r18260 | sekelsenmat | 2011-08-18 13:41:22 +0200 (Thu, 18 Aug 2011) | 1 line
Changed paths:
M /trunk/packages/fpvectorial/src/fpvectorial.pas
M /trunk/packages/fpvectorial/src/fpvtocanvas.pas
M /trunk/packages/fpvectorial/src/svgvectorialwriter.pas

fpvectorial: Adds multiline support for text, adds a new translate function to entities
------------------------------------------------------------------------

git-svn-id: branches/fixes_2_6@18829 -

marco 14 years ago
parent
commit
de4984d985

+ 3 - 3
packages/fpvectorial/examples/fpvwritetest.pas

@@ -161,7 +161,7 @@ begin
     Vec.StartPath(0, 20);
     Vec.AddLineToPath(30, 30);
     Vec.SetPenWidth(10);
-    Vec.SetPenColor(RGBToVColor(255, 0, 0));
+    Vec.SetPenColor(RGBToFPColor(255, 0, 0));
     Vec.EndPath();
     Vec.StartPath(0, 0);
     Vec.AddLineToPath(100, 0);
@@ -169,14 +169,14 @@ begin
     Vec.AddLineToPath(0, 100);
     Vec.AddLineToPath(0, 0);
     Vec.SetPenWidth(10);
-    Vec.SetPenColor(RGBToVColor(0, 255, 0));
+    Vec.SetPenColor(RGBToFPColor(0, 255, 0));
     Vec.EndPath();
     Vec.StartPath(0, 0);
     Vec.AddLineToPath(10, 10);
     Vec.AddBezierToPath(10, 20, 20, 20, 20, 10);
     Vec.AddLineToPath(30, 0);
     Vec.SetPenWidth(10);
-    Vec.SetPenColor(RGBToVColor(0, 0, 255));
+    Vec.SetPenColor(RGBToFPColor(0, 0, 255));
     Vec.EndPath();
     Vec.WriteToFile('pen_test_2' + cExtension, cFormat);
   finally

+ 6 - 8
packages/fpvectorial/src/dxfvectorialreader.pas

@@ -590,7 +590,7 @@ begin
   WriteLn(Format('Adding Arc Center=%f,%f Radius=%f StartAngle=%f EndAngle=%f',
     [CenterX, CenterY, Radius, StartAngle, EndAngle]));
   {$endif}
-  AData.AddCircularArc(CenterX, CenterY, CenterZ, Radius, StartAngle, EndAngle, LColor);
+  AData.AddCircularArc(CenterX, CenterY, Radius, StartAngle, EndAngle, LColor);
 end;
 
 {
@@ -638,8 +638,7 @@ begin
   CircleCenterX := CircleCenterX - DOC_OFFSET.X;
   CircleCenterY := CircleCenterY - DOC_OFFSET.Y;
 
-  AData.AddCircle(CircleCenterX, CircleCenterY,
-    CircleCenterZ, CircleRadius);
+  AData.AddCircle(CircleCenterX, CircleCenterY, CircleRadius);
 end;
 
 {
@@ -845,7 +844,7 @@ begin
   CenterY := CenterY - DOC_OFFSET.Y;
 
   //
-  AData.AddEllipse(CenterX, CenterY, CenterZ, MajorHalfAxis, MinorHalfAxis, Angle);
+  AData.AddEllipse(CenterX, CenterY, MajorHalfAxis, MinorHalfAxis, Angle);
 end;
 
 {
@@ -916,7 +915,7 @@ begin
   PosY := PosY - DOC_OFFSET.Y;
 
   //
-  AData.AddText(PosX, PosY, PosZ, '', Round(FontSize), Str);
+  AData.AddText(PosX, PosY, '', Round(FontSize), Str);
 end;
 
 {.$define FPVECTORIALDEBUG_LWPOLYLINE}
@@ -1141,7 +1140,7 @@ begin
   PosY := PosY - DOC_OFFSET.Y;
 
   //
-  AData.AddText(PosX, PosY, PosZ, '', Round(FontSize), Str);
+  AData.AddText(PosX, PosY, '', Round(FontSize), Str);
 end;
 
 procedure TvDXFVectorialReader.ReadENTITIES_POINT(ATokens: TDXFTokens;
@@ -1179,8 +1178,7 @@ begin
   CircleCenterX := CircleCenterX - DOC_OFFSET.X;
   CircleCenterY := CircleCenterY - DOC_OFFSET.Y;
 
-  AData.AddCircle(CircleCenterX, CircleCenterY,
-    CircleCenterZ, CircleRadius);
+  AData.AddCircle(CircleCenterX, CircleCenterY, CircleRadius);
 end;
 
 function TvDXFVectorialReader.GetCoordinateValue(AStr: shortstring): Double;

+ 4 - 0
packages/fpvectorial/src/epsvectorialreader.pas

@@ -2035,6 +2035,10 @@ begin
 
   // Make sure we have at least one path
   AData.EndPath();
+
+  // PostScript has no document size information, so lets calculate it ourselves
+  AData.GuessDocumentSize();
+  AData.GuessGoodZoomLevel()
 end;
 
 initialization

+ 224 - 64
packages/fpvectorial/src/fpvectorial.pas

@@ -64,7 +64,7 @@ type
     {@@
       Font orientation is measured in degrees and uses the
       same direction as the LCL TFont.orientation, which is counter-clockwise.
-      Zero is the normal, horizontal, orientation.
+      Zero is the normal, horizontal, orientation, directed to the right.
     }
     Orientation: Double;
   end;
@@ -139,6 +139,8 @@ type
     X3, Y3, Z3: Double;
   end;
 
+  TvFindEntityResult = (vfrNotFound, vfrFound, vfrSubpartFound);
+
   { Now all elements }
 
   {@@
@@ -146,8 +148,11 @@ type
     they might contain.
   }
 
+  { TvEntity }
+
   TvEntity = class
   public
+    X, Y: Double;
     {@@ The global Pen for the entire entity. In the case of paths, individual
         elements might be able to override this setting. }
     Pen: TvPen;
@@ -155,6 +160,10 @@ type
         elements might be able to override this setting. }
     Brush: TvBrush;
     constructor Create; virtual;
+    procedure CalculateBoundingBox(var ALeft, ATop, ARight, ABottom: Double); virtual;
+    procedure ExpandBoundingBox(var ALeft, ATop, ARight, ABottom: Double);
+    function TryToSelect(APos: TPoint): TvFindEntityResult; virtual;
+    procedure Translate(ADeltaX, ADeltaY: Integer); virtual;
   end;
 
   TvClipMode = (vcmNonzeroWindingRule, vcmEvenOddRule);
@@ -169,33 +178,37 @@ type
     procedure Assign(ASource: TPath);
     procedure PrepareForSequentialReading;
     function Next(): TPathSegment;
+    procedure CalculateBoundingBox(var ALeft, ATop, ARight, ABottom: Double); override;
+    procedure AppendSegment(ASegment: TPathSegment);
   end;
 
   {@@
-    TvText represents a text in memory.
-
-    At the moment fonts are unsupported, only simple texts
-    up to 255 chars are supported.
+    TvText represents a text entity.
   }
+
+  { TvText }
+
   TvText = class(TvEntity)
   public
-    X, Y, Z: Double; // Z is ignored in 2D formats
-    Value: utf8string;
+    Value: TStringList;
     Font: TvFont;
+    constructor Create; override;
+    destructor Destroy; override;
+    function TryToSelect(APos: TPoint): TvFindEntityResult; override;
   end;
 
   {@@
   }
   TvCircle = class(TvEntity)
   public
-    CenterX, CenterY, CenterZ, Radius: Double;
+    Radius: Double;
   end;
 
   {@@
   }
   TvCircularArc = class(TvEntity)
   public
-    CenterX, CenterY, CenterZ, Radius: Double;
+    Radius: Double;
     {@@ The Angle is measured in degrees in relation to the positive X axis }
     StartAngle, EndAngle: Double;
   end;
@@ -205,7 +218,7 @@ type
   TvEllipse = class(TvEntity)
   public
     // Mandatory fields
-    CenterX, CenterY, CenterZ, MajorHalfAxis, MinorHalfAxis: Double;
+    MajorHalfAxis, MinorHalfAxis: Double;
     {@@ The Angle is measured in degrees in relation to the positive X axis }
     Angle: Double;
     // Calculated fields
@@ -266,10 +279,14 @@ type
     procedure ClearTmpPath();
     procedure AppendSegmentToTmpPath(ASegment: TPathSegment);
   public
-    Name: string;
     Width, Height: Double; // in millimeters
+    Name: string;
+    // User-Interface information
+    ZoomLevel: Double; // 1 = 100%
+    { Selection fields }
+    SelectedvElement: TvEntity;
     { Base methods }
-    constructor Create;
+    constructor Create; virtual;
     destructor Destroy; override;
     procedure Assign(ASource: TvVectorialDocument);
     procedure AssignTo(ADest: TvVectorialDocument);
@@ -283,15 +300,18 @@ type
     procedure ReadFromStrings(AStrings: TStrings; AFormat: TvVectorialFormat);
     class function GetFormatFromExtension(AFileName: string): TvVectorialFormat;
     function  GetDetailedFileFormat(): string;
+    procedure GuessDocumentSize();
+    procedure GuessGoodZoomLevel(AScreenSize: Integer = 500);
     { Data reading methods }
     function  GetPath(ANum: Cardinal): TPath;
     function  GetPathCount: Integer;
     function  GetEntity(ANum: Cardinal): TvEntity;
     function  GetEntitiesCount: Integer;
+    function  FindAndSelectEntity(Pos: TPoint): TvFindEntityResult;
     { Data removing methods }
-    procedure Clear;
+    procedure Clear; virtual;
     { Data writing methods }
-    procedure AddEntity(AEntity: TvEntity);
+    function AddEntity(AEntity: TvEntity): Integer;
     procedure AddPathCopyMem(APath: TPath);
     procedure StartPath(AX, AY: Double); overload;
     procedure StartPath(); overload;
@@ -309,11 +329,11 @@ type
     procedure SetPenWidth(AWidth: Integer);
     procedure SetClipPath(AClipPath: TPath; AClipMode: TvClipMode);
     procedure EndPath();
-    procedure AddText(AX, AY, AZ: Double; FontName: string; FontSize: integer; AText: utf8string); overload;
-    procedure AddText(AX, AY, AZ: Double; AStr: utf8string); overload;
-    procedure AddCircle(ACenterX, ACenterY, ACenterZ, ARadius: Double);
-    procedure AddCircularArc(ACenterX, ACenterY, ACenterZ, ARadius, AStartAngle, AEndAngle: Double; AColor: TFPColor);
-    procedure AddEllipse(CenterX, CenterY, CenterZ, MajorHalfAxis, MinorHalfAxis, Angle: Double);
+    procedure AddText(AX, AY: Double; FontName: string; FontSize: integer; AText: utf8string); overload;
+    procedure AddText(AX, AY: Double; AStr: utf8string); overload;
+    procedure AddCircle(ACenterX, ACenterY, ARadius: Double);
+    procedure AddCircularArc(ACenterX, ACenterY, ARadius, AStartAngle, AEndAngle: Double; AColor: TFPColor);
+    procedure AddEllipse(CenterX, CenterY, MajorHalfAxis, MinorHalfAxis, Angle: Double);
     // Dimensions
     procedure AddAlignedDimension(BaseLeft, BaseRight, DimLeft, DimRight: T3DPoint);
     { properties }
@@ -470,6 +490,31 @@ begin
   Result.Z := 0;
 end;
 
+{ TvText }
+
+constructor TvText.Create;
+begin
+  inherited Create;
+  Value := TStringList.Create;
+end;
+
+destructor TvText.Destroy;
+begin
+  Value.Free;
+  inherited Destroy;
+end;
+
+function TvText.TryToSelect(APos: TPoint): TvFindEntityResult;
+var
+  lProximityFactor: Integer;
+begin
+  lProximityFactor := 5;
+  if (APos.X > X - lProximityFactor) and (APos.X < X + lProximityFactor)
+    and (APos.Y > Y - lProximityFactor) and (APos.Y < Y + lProximityFactor) then
+    Result := vfrFound
+  else Result := vfrNotFound;
+end;
+
 { TvEntity }
 
 constructor TvEntity.Create;
@@ -480,6 +525,36 @@ begin
   Brush.Color := colBlue;
 end;
 
+procedure TvEntity.CalculateBoundingBox(var ALeft, ATop, ARight, ABottom: Double);
+begin
+  ALeft := 0;
+  ATop := 0;
+  ARight := 0;
+  ABottom := 0;
+end;
+
+procedure TvEntity.ExpandBoundingBox(var ALeft, ATop, ARight, ABottom: Double);
+var
+  lLeft, lTop, lRight, lBottom: Double;
+begin
+  CalculateBoundingBox(lLeft, lTop, lRight, lBottom);
+  if lLeft < ALeft then ALeft := lLeft;
+  if lTop < ATop then ATop := lTop;
+  if lRight > ARight then ARight := lRight;
+  if lBottom > ABottom then ABottom := lBottom;
+end;
+
+function TvEntity.TryToSelect(APos: TPoint): TvFindEntityResult;
+begin
+  Result := vfrNotFound;
+end;
+
+procedure TvEntity.Translate(ADeltaX, ADeltaY: Integer);
+begin
+  X := X + ADeltaX;
+  Y := Y + ADeltaY;
+end;
+
 { TvEllipse }
 
 procedure TvEllipse.CalculateBoundingRectangle;
@@ -508,7 +583,7 @@ begin
     tan(t) = b*cot(phi)/a
   }
   t := cotan(-MinorHalfAxis*tan(Angle)/MajorHalfAxis);
-  tmp := CenterX + MajorHalfAxis*cos(t)*cos(Angle) - MinorHalfAxis*sin(t)*sin(Angle);
+  tmp := X + MajorHalfAxis*cos(t)*cos(Angle) - MinorHalfAxis*sin(t)*sin(Angle);
   BoundingRect.Right := Round(tmp);
 end;
 
@@ -580,7 +655,7 @@ end;
   Should be followed by zero or more calls to AddPointToPath
   and by a call to EndPath to effectively add the data.
 
-  @see    StartPath, AddPointToPath
+  @see    EndPath, AddPointToPath
 }
 procedure TvVectorialDocument.StartPath(AX, AY: Double);
 var
@@ -766,46 +841,43 @@ begin
   ClearTmpPath();
 end;
 
-procedure TvVectorialDocument.AddText(AX, AY, AZ: Double; FontName: string; FontSize: integer; AText: utf8string);
+procedure TvVectorialDocument.AddText(AX, AY: Double; FontName: string; FontSize: integer; AText: utf8string);
 var
   lText: TvText;
 begin
   lText := TvText.Create;
-  lText.Value := AText;
+  lText.Value.Text := AText;
   lText.X := AX;
   lText.Y := AY;
-  lText.Z := AZ;
   lText.Font.Name := FontName;
   lText.Font.Size := FontSize;
   AddEntity(lText);
 end;
 
-procedure TvVectorialDocument.AddText(AX, AY, AZ: Double; AStr: utf8string);
+procedure TvVectorialDocument.AddText(AX, AY: Double; AStr: utf8string);
 begin
-  AddText(AX, AY, AZ, '', 10, AStr);
+  AddText(AX, AY, '', 10, AStr);
 end;
 
-procedure TvVectorialDocument.AddCircle(ACenterX, ACenterY, ACenterZ, ARadius: Double);
+procedure TvVectorialDocument.AddCircle(ACenterX, ACenterY, ARadius: Double);
 var
   lCircle: TvCircle;
 begin
   lCircle := TvCircle.Create;
-  lCircle.CenterX := ACenterX;
-  lCircle.CenterY := ACenterY;
-  lCircle.CenterZ := ACenterZ;
+  lCircle.X := ACenterX;
+  lCircle.Y := ACenterY;
   lCircle.Radius := ARadius;
   AddEntity(lCircle);
 end;
 
-procedure TvVectorialDocument.AddCircularArc(ACenterX, ACenterY, ACenterZ,
+procedure TvVectorialDocument.AddCircularArc(ACenterX, ACenterY,
   ARadius, AStartAngle, AEndAngle: Double; AColor: TFPColor);
 var
   lCircularArc: TvCircularArc;
 begin
   lCircularArc := TvCircularArc.Create;
-  lCircularArc.CenterX := ACenterX;
-  lCircularArc.CenterY := ACenterY;
-  lCircularArc.CenterZ := ACenterZ;
+  lCircularArc.X := ACenterX;
+  lCircularArc.Y := ACenterY;
   lCircularArc.Radius := ARadius;
   lCircularArc.StartAngle := AStartAngle;
   lCircularArc.EndAngle := AEndAngle;
@@ -813,15 +885,14 @@ begin
   AddEntity(lCircularArc);
 end;
 
-procedure TvVectorialDocument.AddEllipse(CenterX, CenterY, CenterZ,
+procedure TvVectorialDocument.AddEllipse(CenterX, CenterY,
   MajorHalfAxis, MinorHalfAxis, Angle: Double);
 var
   lEllipse: TvEllipse;
 begin
   lEllipse := TvEllipse.Create;
-  lEllipse.CenterX := CenterX;
-  lEllipse.CenterY := CenterY;
-  lEllipse.CenterZ := CenterZ;
+  lEllipse.X := CenterX;
+  lEllipse.Y := CenterY;
   lEllipse.MajorHalfAxis := MajorHalfAxis;
   lEllipse.MinorHalfAxis := MinorHalfAxis;
   lEllipse.Angle := Angle;
@@ -829,10 +900,11 @@ begin
 end;
 
 {@@
-  Don't free the passed TvText because it will be added directly to the list
+  Adds an entity to the document and returns it's current index
 }
-procedure TvVectorialDocument.AddEntity(AEntity: TvEntity);
+function TvVectorialDocument.AddEntity(AEntity: TvEntity): Integer;
 begin
+  Result := FEntities.Count;
   FEntities.Add(Pointer(AEntity));
 end;
 
@@ -908,28 +980,8 @@ begin
 end;
 
 procedure TvVectorialDocument.AppendSegmentToTmpPath(ASegment: TPathSegment);
-var
-  L: Integer;
 begin
-  // Check if we are the first segment in the tmp path
-  if FTmpPath.PointsEnd = nil then
-  begin
-    if FTmpPath.Len <> 0 then
-      Exception.Create('[TvVectorialDocument.AppendSegmentToTmpPath]' + Str_Error_Nil_Path);
-
-    FTmpPath.Points := ASegment;
-    FTmpPath.PointsEnd := ASegment;
-    FTmpPath.Len := 1;
-    Exit;
-  end;
-
-  L := FTmpPath.Len;
-  Inc(FTmpPath.Len);
-
-  // Adds the element to the end of the list
-  FTmpPath.PointsEnd.Next := ASegment;
-  ASegment.Previous := FTmpPath.PointsEnd;
-  FTmpPath.PointsEnd := ASegment;
+  FTmpPath.AppendSegment(ASegment);
 end;
 
 {@@
@@ -991,7 +1043,7 @@ end;
 {@@
   Reads the document from a file.
 
-  Any current contents will be removed.
+  Any current contents in this object will be removed.
 }
 procedure TvVectorialDocument.ReadFromFile(AFileName: string;
   AFormat: TvVectorialFormat);
@@ -1009,7 +1061,7 @@ begin
 end;
 
 {@@
-  Reads the document from a file.  A variant that auto-detects the format from the extension.
+  Reads the document from a file.  A variant that auto-detects the format from the extension and other factors.
 }
 procedure TvVectorialDocument.ReadFromFile(AFileName: string);
 var
@@ -1022,7 +1074,7 @@ end;
 {@@
   Reads the document from a stream.
 
-  Any current contents will be removed.
+  Any current contents in this object will be removed.
 }
 procedure TvVectorialDocument.ReadFromStream(AStream: TStream;
   AFormat: TvVectorialFormat);
@@ -1076,6 +1128,32 @@ begin
 
 end;
 
+procedure TvVectorialDocument.GuessDocumentSize();
+var
+  i: Integer;
+  lEntity: TvEntity;
+  lLeft, lTop, lRight, lBottom: Double;
+begin
+  lLeft := 0;
+  lTop := 0;
+  lRight := 0;
+  lBottom := 0;
+
+  for i := 0 to GetEntitiesCount() - 1 do
+  begin
+    lEntity := GetEntity(I);
+    lEntity.ExpandBoundingBox(lLeft, lTop, lRight, lBottom);
+  end;
+
+  Width := lRight - lLeft;
+  Height := lBottom - lTop;
+end;
+
+procedure TvVectorialDocument.GuessGoodZoomLevel(AScreenSize: Integer);
+begin
+  ZoomLevel := AScreenSize / Height;
+end;
+
 function TvVectorialDocument.GetPath(ANum: Cardinal): TPath;
 var
   i: Integer;
@@ -1119,6 +1197,27 @@ begin
   Result := FEntities.Count;
 end;
 
+function TvVectorialDocument.FindAndSelectEntity(Pos: TPoint): TvFindEntityResult;
+var
+  lEntity: TvEntity;
+  i: Integer;
+begin
+  Result := vfrNotFound;
+
+  for i := 0 to GetEntitiesCount() - 1 do
+  begin
+    lEntity := GetEntity(i);
+
+    Result := lEntity.TryToSelect(Pos);
+
+    if Result <> vfrNotFound then
+    begin
+      SelectedvElement := lEntity;
+      Exit;
+    end;
+  end;
+end;
+
 {@@
   Clears all data in the document
 }
@@ -1260,6 +1359,67 @@ begin
   CurPoint := Result;
 end;
 
+procedure TPath.CalculateBoundingBox(var ALeft, ATop, ARight, ABottom: Double);
+var
+  lSegment: TPathSegment;
+  l2DSegment: T2DSegment;
+  lFirstValue: Boolean = True;
+begin
+  inherited CalculateBoundingBox(ALeft, ATop, ARight, ABottom);
+
+  PrepareForSequentialReading();
+  lSegment := Next();
+  while lSegment <> nil do
+  begin
+    if lSegment is T2DSegment then
+    begin
+      l2DSegment := T2DSegment(lSegment);
+      if lFirstValue then
+      begin
+        ALeft := l2DSegment.X;
+        ATop := l2DSegment.Y;
+        ARight := l2DSegment.X;
+        ABottom := l2DSegment.Y;
+        lFirstValue := False;
+      end
+      else
+      begin
+        if l2DSegment.X < ALeft then ALeft := l2DSegment.X;
+        if l2DSegment.Y < ATop then ATop := l2DSegment.Y;
+        if l2DSegment.X > ARight then ARight := l2DSegment.X;
+        if l2DSegment.Y > ABottom then ABottom := l2DSegment.Y;
+      end;
+    end;
+
+    lSegment := Next();
+  end;
+end;
+
+procedure TPath.AppendSegment(ASegment: TPathSegment);
+var
+  L: Integer;
+begin
+  // Check if we are the first segment in the tmp path
+  if PointsEnd = nil then
+  begin
+    if Len <> 0 then
+      Exception.Create('[TPath.AppendSegment] Assertion failed Len <> 0 with PointsEnd = nil');
+
+    Points := ASegment;
+    PointsEnd := ASegment;
+    Len := 1;
+    Exit;
+  end;
+
+  L := Len;
+  Inc(Len);
+
+  // Adds the element to the end of the list
+  PointsEnd.Next := ASegment;
+  ASegment.Previous := PointsEnd;
+  PointsEnd := ASegment;
+end;
+
 finalization
 
   SetLength(GvVectorialFormats, 0);

+ 18 - 12
packages/fpvectorial/src/fpvtocanvas.pas

@@ -65,8 +65,8 @@ begin
   y2 := CurEllipse.BoundingRect.Bottom;
 
   dk := Round(0.654 * Abs(y2-y1));
-  f.x := Round(CurEllipse.CenterX);
-  f.y := Round(CurEllipse.CenterY - 1);
+  f.x := Round(CurEllipse.X);
+  f.y := Round(CurEllipse.Y - 1);
   PointList[0] := Rotate2DPoint(Point(x1, f.y), f, CurEllipse.Angle) ;  // Startpoint
   PointList[1] := Rotate2DPoint(Point(x1,  f.y - dk), f, CurEllipse.Angle);
   //Controlpoint of Startpoint first part
@@ -353,10 +353,10 @@ begin
   begin
     CurCircle := CurEntity as TvCircle;
     ADest.Ellipse(
-      CoordToCanvasX(CurCircle.CenterX - CurCircle.Radius),
-      CoordToCanvasY(CurCircle.CenterY - CurCircle.Radius),
-      CoordToCanvasX(CurCircle.CenterX + CurCircle.Radius),
-      CoordToCanvasY(CurCircle.CenterY + CurCircle.Radius)
+      CoordToCanvasX(CurCircle.X - CurCircle.Radius),
+      CoordToCanvasY(CurCircle.Y - CurCircle.Radius),
+      CoordToCanvasX(CurCircle.X + CurCircle.Radius),
+      CoordToCanvasY(CurCircle.Y + CurCircle.Radius)
       );
   end
   else if CurEntity is TvEllipse then
@@ -370,10 +370,10 @@ begin
     {$ifdef USE_LCL_CANVAS}
     // ToDo: Consider a X axis inversion
     // If the Y axis is inverted, then we need to mirror our angles as well
-    BoundsLeft := CoordToCanvasX(CurArc.CenterX - CurArc.Radius);
-    BoundsTop := CoordToCanvasY(CurArc.CenterY - CurArc.Radius);
-    BoundsRight := CoordToCanvasX(CurArc.CenterX + CurArc.Radius);
-    BoundsBottom := CoordToCanvasY(CurArc.CenterY + CurArc.Radius);
+    BoundsLeft := CoordToCanvasX(CurArc.X - CurArc.Radius);
+    BoundsTop := CoordToCanvasY(CurArc.Y - CurArc.Radius);
+    BoundsRight := CoordToCanvasX(CurArc.X + CurArc.Radius);
+    BoundsBottom := CoordToCanvasY(CurArc.Y + CurArc.Radius);
     {if AMulY > 0 then
     begin}
       FinalStartAngle := CurArc.StartAngle;
@@ -548,8 +548,14 @@ begin
   ALCLDest.Font.Orientation := Round(CurText.Font.Orientation * 16);
   {$endif}
 
-  LowerDim.Y := CurText.Y + CurText.Font.Size;
-  ADest.TextOut(CoordToCanvasX(CurText.X), CoordToCanvasY(LowerDim.Y), CurText.Value);
+  // TvText supports multiple lines
+  for i := 0 to CurText.Value.Count - 1 do
+  begin
+    if CurText.Font.Size = 0 then LowerDim.Y := CurText.Y - 12 * (i + 1)
+    else LowerDim.Y := CurText.Y - CurText.Font.Size * (i + 1);
+
+    ADest.TextOut(CoordToCanvasX(CurText.X), CoordToCanvasY(LowerDim.Y), CurText.Value.Strings[i]);
+  end;
 end;
 
 end.

+ 1 - 1
packages/fpvectorial/src/svgvectorialwriter.pas

@@ -232,7 +232,7 @@ begin
   ConvertFPVCoordinatesToSVGCoordinates(
       AData, lText.X, lText.Y, PtX, PtY);
 
-  TextStr := lText.Value;
+  TextStr := lText.Value.Text;
   FontSize:= ceil(lText.Font.Size / FLOAT_MILIMETERS_PER_PIXEL);
   SVGFontFamily := 'Arial, sans-serif';//lText.FontName;