Browse Source

fpvectorial: Major rework, joined all 3 lists of elements into a single list in order to use it to keep the Z-Order

git-svn-id: trunk@17765 -
sekelsenmat 14 years ago
parent
commit
b65d397249

+ 16 - 16
packages/fpvectorial/src/dxfvectorialreader.pas

@@ -148,22 +148,22 @@ const
   // Valid for DXF up to AutoCad 2004, after that RGB is available
   // Valid for DXF up to AutoCad 2004, after that RGB is available
   AUTOCAD_COLOR_PALETTE: array[0..15] of TFPColor =
   AUTOCAD_COLOR_PALETTE: array[0..15] of TFPColor =
   (
   (
-    (Red: $0000; Green: $0000; Blue: $0000; Alpha: FPValphaOpaque), // 0 - Black
-    (Red: $0000; Green: $0000; Blue: $8080; Alpha: FPValphaOpaque), // 1 - Dark blue
-    (Red: $0000; Green: $8080; Blue: $0000; Alpha: FPValphaOpaque), // 2 - Dark green
-    (Red: $0000; Green: $8080; Blue: $8080; Alpha: FPValphaOpaque), // 3 - Dark cyan
-    (Red: $8080; Green: $0000; Blue: $0000; Alpha: FPValphaOpaque), // 4 - Dark red
-    (Red: $8080; Green: $0000; Blue: $8080; Alpha: FPValphaOpaque), // 5 - Dark Magenta
-    (Red: $8080; Green: $8080; Blue: $0000; Alpha: FPValphaOpaque), // 6 - Dark
-    (Red: $c0c0; Green: $c0c0; Blue: $c0c0; Alpha: FPValphaOpaque), // 7 - Light Gray
-    (Red: $8080; Green: $8080; Blue: $8080; Alpha: FPValphaOpaque), // 8 - Medium Gray
-    (Red: $0000; Green: $0000; Blue: $ffff; Alpha: FPValphaOpaque), // 9 - Light blue
-    (Red: $0000; Green: $ffff; Blue: $0000; Alpha: FPValphaOpaque), // 10 - Light green
-    (Red: $0000; Green: $ffff; Blue: $ffff; Alpha: FPValphaOpaque), // 11 - Light cyan
-    (Red: $ffff; Green: $0000; Blue: $0000; Alpha: FPValphaOpaque), // 12 - Light red
-    (Red: $ffff; Green: $0000; Blue: $ffff; Alpha: FPValphaOpaque), // 13 - Light Magenta
-    (Red: $ffff; Green: $ffff; Blue: $0000; Alpha: FPValphaOpaque), // 14 - Light Yellow
-    (Red: $ffff; Green: $ffff; Blue: $ffff; Alpha: FPValphaOpaque)  // 15 - White
+    (Red: $0000; Green: $0000; Blue: $0000; Alpha: alphaOpaque), // 0 - Black
+    (Red: $0000; Green: $0000; Blue: $8080; Alpha: alphaOpaque), // 1 - Dark blue
+    (Red: $0000; Green: $8080; Blue: $0000; Alpha: alphaOpaque), // 2 - Dark green
+    (Red: $0000; Green: $8080; Blue: $8080; Alpha: alphaOpaque), // 3 - Dark cyan
+    (Red: $8080; Green: $0000; Blue: $0000; Alpha: alphaOpaque), // 4 - Dark red
+    (Red: $8080; Green: $0000; Blue: $8080; Alpha: alphaOpaque), // 5 - Dark Magenta
+    (Red: $8080; Green: $8080; Blue: $0000; Alpha: alphaOpaque), // 6 - Dark
+    (Red: $c0c0; Green: $c0c0; Blue: $c0c0; Alpha: alphaOpaque), // 7 - Light Gray
+    (Red: $8080; Green: $8080; Blue: $8080; Alpha: alphaOpaque), // 8 - Medium Gray
+    (Red: $0000; Green: $0000; Blue: $ffff; Alpha: alphaOpaque), // 9 - Light blue
+    (Red: $0000; Green: $ffff; Blue: $0000; Alpha: alphaOpaque), // 10 - Light green
+    (Red: $0000; Green: $ffff; Blue: $ffff; Alpha: alphaOpaque), // 11 - Light cyan
+    (Red: $ffff; Green: $0000; Blue: $0000; Alpha: alphaOpaque), // 12 - Light red
+    (Red: $ffff; Green: $0000; Blue: $ffff; Alpha: alphaOpaque), // 13 - Light Magenta
+    (Red: $ffff; Green: $ffff; Blue: $0000; Alpha: alphaOpaque), // 14 - Light Yellow
+    (Red: $ffff; Green: $ffff; Blue: $ffff; Alpha: alphaOpaque)  // 15 - White
   );
   );
 
 
 { TDXFToken }
 { TDXFToken }

+ 95 - 106
packages/fpvectorial/src/fpvectorial.pas

@@ -44,6 +44,8 @@ const
   STR_ENCAPSULATEDPOSTSCRIPT_EXTENSION = '.eps';
   STR_ENCAPSULATEDPOSTSCRIPT_EXTENSION = '.eps';
 
 
 type
 type
+  { Pen, Brush and Font }
+
   TvPen = record
   TvPen = record
     Color: TFPColor;
     Color: TFPColor;
     Style: TFPPenStyle;
     Style: TFPPenStyle;
@@ -55,11 +57,20 @@ type
     Style: TFPBrushStyle;
     Style: TFPBrushStyle;
   end;
   end;
 
 
-const
-  FPValphaTransparent = $00;
-  FPValphaOpaque = $FF;
+  TvFont = record
+    Color: TFPColor;
+    Size: integer;
+    Name: utf8string;
+    {@@
+      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.
+    }
+    Orientation: Double;
+  end;
+
+  { Coordinates and polyline segments }
 
 
-type
   T3DPoint = record
   T3DPoint = record
     X, Y, Z: Double;
     X, Y, Z: Double;
   end;
   end;
@@ -128,60 +139,47 @@ type
     X3, Y3, Z3: Double;
     X3, Y3, Z3: Double;
   end;
   end;
 
 
-  TPath = class
+  { Now all elements }
+
+  {@@
+    All elements should derive from TvEntity, regardless of whatever properties
+    they might contain.
+  }
+
+  TvEntity = class
+  public
+    {@@ The global Pen for the entire entity. In the case of paths, individual
+        elements might be able to override this setting. }
+    Pen: TvPen;
+    {@@ The global Brush for the entire entity. In the case of paths, individual
+        elements might be able to override this setting. }
+    Brush: TvBrush;
+    constructor Create; virtual;
+  end;
+
+  TPath = class(TvEntity)
     Len: Integer;
     Len: Integer;
     Points: TPathSegment; // Beginning of the double-linked list
     Points: TPathSegment; // Beginning of the double-linked list
     PointsEnd: TPathSegment; // End of the double-linked list
     PointsEnd: TPathSegment; // End of the double-linked list
     CurPoint: TPathSegment; // Used in PrepareForSequentialReading and Next
     CurPoint: TPathSegment; // Used in PrepareForSequentialReading and Next
-    {@@ The global Pen for the entire path. This Pen might be overriden by
-        individual elements of the polyline. }
-    Pen: TvPen;
-    {@@ Sets a Brush to paint the inner area inside the path.
-        There is no inner area if Brush.Style = bsClear, which is the default. }
-    Brush: TvBrush;
-    constructor Create();
-    procedure Assign(APath: TPath);
+    procedure Assign(ASource: TPath);
     procedure PrepareForSequentialReading;
     procedure PrepareForSequentialReading;
     function Next(): TPathSegment;
     function Next(): TPathSegment;
   end;
   end;
 
 
-  TvFont = record
-    Color: TFPColor;
-    Size: integer;
-    Name: utf8string;
-    {@@
-      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.
-    }
-    Orientation: Double;
-  end;
-
   {@@
   {@@
     TvText represents a text in memory.
     TvText represents a text in memory.
 
 
     At the moment fonts are unsupported, only simple texts
     At the moment fonts are unsupported, only simple texts
     up to 255 chars are supported.
     up to 255 chars are supported.
   }
   }
-  TvText = class
+  TvText = class(TvEntity)
   public
   public
     X, Y, Z: Double; // Z is ignored in 2D formats
     X, Y, Z: Double; // Z is ignored in 2D formats
     Value: utf8string;
     Value: utf8string;
     Font: TvFont;
     Font: TvFont;
   end;
   end;
 
 
-  {@@
-  }
-
-  { TvEntity }
-
-  TvEntity = class
-  public
-    Pen: TvPen;
-    Brush: TvBrush;
-    constructor Create; virtual;
-  end;
-
   {@@
   {@@
   }
   }
   TvCircle = class(TvEntity)
   TvCircle = class(TvEntity)
@@ -200,9 +198,6 @@ type
 
 
   {@@
   {@@
   }
   }
-
-  { TvEllipse }
-
   TvEllipse = class(TvEntity)
   TvEllipse = class(TvEntity)
   public
   public
     // Mandatory fields
     // Mandatory fields
@@ -215,6 +210,8 @@ type
   end;
   end;
 
 
   {@@
   {@@
+   The brush has no effect in this class
+
    DimensionLeft ---text--- DimensionRight
    DimensionLeft ---text--- DimensionRight
                  |        |
                  |        |
                  |        | BaseRight
                  |        | BaseRight
@@ -239,8 +236,6 @@ type
 
 
   TvVectorialDocument = class
   TvVectorialDocument = class
   private
   private
-    FPaths: TFPList;
-    FTexts: TFPList;
     FEntities: TFPList;
     FEntities: TFPList;
     FTmpPath: TPath;
     FTmpPath: TPath;
     FTmpText: TvText;
     FTmpText: TvText;
@@ -255,6 +250,8 @@ type
     { Base methods }
     { Base methods }
     constructor Create;
     constructor Create;
     destructor Destroy; override;
     destructor Destroy; override;
+    procedure Assign(ASource: TvVectorialDocument);
+    procedure AssignTo(ADest: TvVectorialDocument);
     procedure WriteToFile(AFileName: string; AFormat: TvVectorialFormat); overload;
     procedure WriteToFile(AFileName: string; AFormat: TvVectorialFormat); overload;
     procedure WriteToFile(AFileName: string); overload;
     procedure WriteToFile(AFileName: string); overload;
     procedure WriteToStream(AStream: TStream; AFormat: TvVectorialFormat);
     procedure WriteToStream(AStream: TStream; AFormat: TvVectorialFormat);
@@ -268,16 +265,13 @@ type
     { Data reading methods }
     { Data reading methods }
     function  GetPath(ANum: Cardinal): TPath;
     function  GetPath(ANum: Cardinal): TPath;
     function  GetPathCount: Integer;
     function  GetPathCount: Integer;
-    function  GetText(ANum: Cardinal): TvText;
-    function  GetTextCount: Integer;
     function  GetEntity(ANum: Cardinal): TvEntity;
     function  GetEntity(ANum: Cardinal): TvEntity;
-    function  GetEntityCount: Integer;
+    function  GetEntitiesCount: Integer;
     { Data removing methods }
     { Data removing methods }
     procedure Clear;
     procedure Clear;
-    procedure RemoveAllPaths;
-    procedure RemoveAllTexts;
     { Data writing methods }
     { Data writing methods }
-    procedure AddPath(APath: TPath);
+    procedure AddEntity(AEntity: TvEntity);
+    procedure AddPathCopyMem(APath: TPath);
     procedure StartPath(AX, AY: Double); overload;
     procedure StartPath(AX, AY: Double); overload;
     procedure StartPath(); overload;
     procedure StartPath(); overload;
     procedure AddMoveToPath(AX, AY: Double);
     procedure AddMoveToPath(AX, AY: Double);
@@ -517,8 +511,6 @@ constructor TvVectorialDocument.Create;
 begin
 begin
   inherited Create;
   inherited Create;
 
 
-  FPaths := TFPList.Create;
-  FTexts := TFPList.Create;
   FEntities := TFPList.Create;
   FEntities := TFPList.Create;
   FTmpPath := TPath.Create;
   FTmpPath := TPath.Create;
 end;
 end;
@@ -530,40 +522,35 @@ destructor TvVectorialDocument.Destroy;
 begin
 begin
   Clear;
   Clear;
 
 
-  FPaths.Free;
-  FTexts.Free;
   FEntities.Free;
   FEntities.Free;
 
 
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 
-{@@
-  Clears the list of Vectors and releases their memory.
-}
-procedure TvVectorialDocument.RemoveAllPaths;
+procedure TvVectorialDocument.Assign(ASource: TvVectorialDocument);
+var
+  i: Integer;
 begin
 begin
-//  FPaths.ForEachCall(RemoveCallback, nil);
-  FPaths.Clear;
+  Clear;
+
+  for i := 0 to ASource.GetEntitiesCount - 1 do
+    Self.AddEntity(ASource.GetEntity(i));
 end;
 end;
 
 
-procedure TvVectorialDocument.RemoveAllTexts;
+procedure TvVectorialDocument.AssignTo(ADest: TvVectorialDocument);
 begin
 begin
-//  FTexts.ForEachCall(RemoveCallback, nil);
-  FTexts.Clear;
+  ADest.Assign(Self);
 end;
 end;
 
 
-procedure TvVectorialDocument.AddPath(APath: TPath);
+procedure TvVectorialDocument.AddPathCopyMem(APath: TPath);
 var
 var
   lPath: TPath;
   lPath: TPath;
   Len: Integer;
   Len: Integer;
 begin
 begin
   lPath := TPath.Create;
   lPath := TPath.Create;
   lPath.Assign(APath);
   lPath.Assign(APath);
-  FPaths.Add(Pointer(lPath));
+  AddEntity(lPath);
   //WriteLn(':>TvVectorialDocument.AddPath 1 Len = ', Len);
   //WriteLn(':>TvVectorialDocument.AddPath 1 Len = ', Len);
-  //WriteLn(':>TvVectorialDocument.AddPath 2');
-  //WriteLn(':>TvVectorialDocument.AddPath 3');
-  //WriteLn(':>TvVectorialDocument.AddPath 4');
 end;
 end;
 
 
 {@@
 {@@
@@ -746,7 +733,7 @@ end;
 procedure TvVectorialDocument.EndPath();
 procedure TvVectorialDocument.EndPath();
 begin
 begin
   if FTmPPath.Len = 0 then Exit;
   if FTmPPath.Len = 0 then Exit;
-  AddPath(FTmPPath);
+  AddPathCopyMem(FTmPPath);
   ClearTmpPath();
   ClearTmpPath();
 end;
 end;
 
 
@@ -761,7 +748,7 @@ begin
   lText.Z := AZ;
   lText.Z := AZ;
   lText.Font.Name := FontName;
   lText.Font.Name := FontName;
   lText.Font.Size := FontSize;
   lText.Font.Size := FontSize;
-  FTexts.Add(lText);
+  AddEntity(lText);
 end;
 end;
 
 
 procedure TvVectorialDocument.AddText(AX, AY, AZ: Double; AStr: utf8string);
 procedure TvVectorialDocument.AddText(AX, AY, AZ: Double; AStr: utf8string);
@@ -778,7 +765,7 @@ begin
   lCircle.CenterY := ACenterY;
   lCircle.CenterY := ACenterY;
   lCircle.CenterZ := ACenterZ;
   lCircle.CenterZ := ACenterZ;
   lCircle.Radius := ARadius;
   lCircle.Radius := ARadius;
-  FEntities.Add(lCircle);
+  AddEntity(lCircle);
 end;
 end;
 
 
 procedure TvVectorialDocument.AddCircularArc(ACenterX, ACenterY, ACenterZ,
 procedure TvVectorialDocument.AddCircularArc(ACenterX, ACenterY, ACenterZ,
@@ -794,7 +781,7 @@ begin
   lCircularArc.StartAngle := AStartAngle;
   lCircularArc.StartAngle := AStartAngle;
   lCircularArc.EndAngle := AEndAngle;
   lCircularArc.EndAngle := AEndAngle;
   lCircularArc.Pen.Color := AColor;
   lCircularArc.Pen.Color := AColor;
-  FEntities.Add(lCircularArc);
+  AddEntity(lCircularArc);
 end;
 end;
 
 
 procedure TvVectorialDocument.AddEllipse(CenterX, CenterY, CenterZ,
 procedure TvVectorialDocument.AddEllipse(CenterX, CenterY, CenterZ,
@@ -809,7 +796,15 @@ begin
   lEllipse.MajorHalfAxis := MajorHalfAxis;
   lEllipse.MajorHalfAxis := MajorHalfAxis;
   lEllipse.MinorHalfAxis := MinorHalfAxis;
   lEllipse.MinorHalfAxis := MinorHalfAxis;
   lEllipse.Angle := Angle;
   lEllipse.Angle := Angle;
-  FEntities.Add(lEllipse);
+  AddEntity(lEllipse);
+end;
+
+{@@
+  Don't free the passed TvText because it will be added directly to the list
+}
+procedure TvVectorialDocument.AddEntity(AEntity: TvEntity);
+begin
+  FEntities.Add(Pointer(AEntity));
 end;
 end;
 
 
 procedure TvVectorialDocument.AddAlignedDimension(BaseLeft, BaseRight,
 procedure TvVectorialDocument.AddAlignedDimension(BaseLeft, BaseRight,
@@ -822,7 +817,7 @@ begin
   lDim.BaseRight := BaseRight;
   lDim.BaseRight := BaseRight;
   lDim.DimensionLeft := DimLeft;
   lDim.DimensionLeft := DimLeft;
   lDim.DimensionRight := DimRight;
   lDim.DimensionRight := DimRight;
-  FEntities.Add(lDim);
+  AddEntity(lDim);
 end;
 end;
 
 
 {@@
 {@@
@@ -1062,31 +1057,32 @@ begin
 end;
 end;
 
 
 function TvVectorialDocument.GetPath(ANum: Cardinal): TPath;
 function TvVectorialDocument.GetPath(ANum: Cardinal): TPath;
+var
+  i: Integer;
+  Index: Integer = - 1;
 begin
 begin
-  if ANum >= FPaths.Count then raise Exception.Create('TvVectorialDocument.GetPath: Path number out of bounds');
+  Result := nil;
 
 
-  if FPaths.Items[ANum] = nil then raise Exception.Create('TvVectorialDocument.GetPath: Invalid Path number');
+  if ANum >= FEntities.Count then raise Exception.Create('TvVectorialDocument.GetPath: Path number out of bounds');
 
 
-  Result := TPath(FPaths.Items[ANum]);
+  for i := 0 to FEntities.Count - 1 do
+  begin
+    if TvEntity(FEntities.Items[i]) is TPath then
+    begin
+      Inc(Index);
+      if Index = ANum then Result := TPath(FEntities.Items[i]);
+    end;
+  end;
 end;
 end;
 
 
 function TvVectorialDocument.GetPathCount: Integer;
 function TvVectorialDocument.GetPathCount: Integer;
+var
+  i: Integer;
 begin
 begin
-  Result := FPaths.Count;
-end;
-
-function TvVectorialDocument.GetText(ANum: Cardinal): TvText;
-begin
-  if ANum >= FTexts.Count then raise Exception.Create('TvVectorialDocument.GetText: Text number out of bounds');
-
-  if FTexts.Items[ANum] = nil then raise Exception.Create('TvVectorialDocument.GetText: Invalid Text number');
-
-  Result := TvText(FTexts.Items[ANum]);
-end;
+  Result := 0;
 
 
-function TvVectorialDocument.GetTextCount: Integer;
-begin
-  Result := FTexts.Count;
+  for i := 0 to FEntities.Count - 1 do
+    if TvEntity(FEntities.Items[i]) is TPath then Inc(Result);
 end;
 end;
 
 
 function TvVectorialDocument.GetEntity(ANum: Cardinal): TvEntity;
 function TvVectorialDocument.GetEntity(ANum: Cardinal): TvEntity;
@@ -1098,7 +1094,7 @@ begin
   Result := TvEntity(FEntities.Items[ANum]);
   Result := TvEntity(FEntities.Items[ANum]);
 end;
 end;
 
 
-function TvVectorialDocument.GetEntityCount: Integer;
+function TvVectorialDocument.GetEntitiesCount: Integer;
 begin
 begin
   Result := FEntities.Count;
   Result := FEntities.Count;
 end;
 end;
@@ -1108,8 +1104,7 @@ end;
 }
 }
 procedure TvVectorialDocument.Clear;
 procedure TvVectorialDocument.Clear;
 begin
 begin
-  RemoveAllPaths();
-  RemoveAllTexts();
+  FEntities.Clear();
 end;
 end;
 
 
 { TvCustomVectorialReader }
 { TvCustomVectorialReader }
@@ -1220,20 +1215,14 @@ end;
 
 
 { TPath }
 { TPath }
 
 
-constructor TPath.Create();
-begin
-  Brush.Style := bsClear;
-  inherited Create();
-end;
-
-procedure TPath.Assign(APath: TPath);
+procedure TPath.Assign(ASource: TPath);
 begin
 begin
-  Len := APath.Len;
-  Points := APath.Points;
-  PointsEnd := APath.PointsEnd;
-  CurPoint := APath.CurPoint;
-  Pen := APath.Pen;
-  Brush := APath.Brush;
+  Len := ASource.Len;
+  Points := ASource.Points;
+  PointsEnd := ASource.PointsEnd;
+  CurPoint := ASource.CurPoint;
+  Pen := ASource.Pen;
+  Brush := ASource.Brush;
 end;
 end;
 
 
 procedure TPath.PrepareForSequentialReading;
 procedure TPath.PrepareForSequentialReading;

+ 260 - 272
packages/fpvectorial/src/fpvtocanvas.pas

@@ -10,23 +10,22 @@ uses
   Classes, SysUtils, Math,
   Classes, SysUtils, Math,
   {$ifdef USE_LCL_CANVAS}
   {$ifdef USE_LCL_CANVAS}
   Graphics, LCLIntf,
   Graphics, LCLIntf,
-  {$else}
-  fpcanvas,
   {$endif}
   {$endif}
+  fpcanvas,
   fpimage,
   fpimage,
   fpvectorial;
   fpvectorial;
 
 
 procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument;
 procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument;
-  {$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
+  ADest: TFPCustomCanvas;
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
-procedure DrawFPVPathsToCanvas(ASource: TvVectorialDocument;
-  {$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
+procedure DrawFPVPathToCanvas(ASource: TvVectorialDocument; CurPath: TPath;
+  ADest: TFPCustomCanvas;
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
-procedure DrawFPVEntitiesToCanvas(ASource: TvVectorialDocument;
-  {$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
+procedure DrawFPVEntityToCanvas(ASource: TvVectorialDocument; CurEntity: TvEntity;
+  ADest: TFPCustomCanvas;
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
-procedure DrawFPVTextToCanvas(ASource: TvVectorialDocument;
-  {$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
+procedure DrawFPVTextToCanvas(ASource: TvVectorialDocument; CurText: TvText;
+  ADest: TFPCustomCanvas;
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
 
 
 implementation
 implementation
@@ -47,17 +46,16 @@ begin
 end;
 end;
 
 
 procedure DrawRotatedEllipse(
 procedure DrawRotatedEllipse(
-  {$ifdef USE_LCL_CANVAS}
-  ADest: TCanvas;
-  {$else}
   ADest: TFPCustomCanvas;
   ADest: TFPCustomCanvas;
-  {$endif}
   CurEllipse: TvEllipse;
   CurEllipse: TvEllipse;
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
 var
 var
   PointList: array[0..6] of TPoint;
   PointList: array[0..6] of TPoint;
   f: TPoint;
   f: TPoint;
   dk, x1, x2, y1, y2: Integer;
   dk, x1, x2, y1, y2: Integer;
+  {$ifdef USE_LCL_CANVAS}
+  ALCLDest: TCanvas absolute ADest;
+  {$endif}
 begin
 begin
   {$ifdef USE_LCL_CANVAS}
   {$ifdef USE_LCL_CANVAS}
   CurEllipse.CalculateBoundingRectangle();
   CurEllipse.CalculateBoundingRectangle();
@@ -82,7 +80,7 @@ begin
   // Conrollpoint of secondpart endpoint
   // Conrollpoint of secondpart endpoint
   PointList[6] := PointList[0];   // Endpoint of
   PointList[6] := PointList[0];   // Endpoint of
    // Back to the startpoint
    // Back to the startpoint
-  ADest.PolyBezier(Pointlist[0]);
+  ALCLDest.PolyBezier(Pointlist[0]);
   {$endif}
   {$endif}
 end;
 end;
 
 
@@ -102,24 +100,32 @@ end;
 }
 }
 {.$define FPVECTORIAL_TOCANVAS_DEBUG}
 {.$define FPVECTORIAL_TOCANVAS_DEBUG}
 procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument;
 procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument;
-  {$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
+  ADest: TFPCustomCanvas;
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
+var
+  i: Integer;
+  CurEntity: TvEntity;
 begin
 begin
   {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
   {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
   WriteLn(':>DrawFPVectorialToCanvas');
   WriteLn(':>DrawFPVectorialToCanvas');
   {$endif}
   {$endif}
 
 
-  DrawFPVPathsToCanvas(ASource, ADest, ADestX, ADestY, AMulX, AMulY);
-  DrawFPVEntitiesToCanvas(ASource, ADest, ADestX, ADestY, AMulX, AMulY);
-  DrawFPVTextToCanvas(ASource, ADest, ADestX, ADestY, AMulX, AMulY);
+  for i := 0 to ASource.GetEntitiesCount - 1 do
+  begin
+    CurEntity := ASource.GetEntity(i);
+
+    if CurEntity is TPath then DrawFPVPathToCanvas(ASource, TPath(CurEntity), ADest, ADestX, ADestY, AMulX, AMulY)
+    else if CurEntity is TvText then DrawFPVTextToCanvas(ASource, TvText(CurEntity), ADest, ADestX, ADestY, AMulX, AMulY)
+    else DrawFPVEntityToCanvas(ASource, CurEntity, ADest, ADestX, ADestY, AMulX, AMulY);
+  end;
 
 
   {$ifdef FPVECTORIALDEBUG}
   {$ifdef FPVECTORIALDEBUG}
   WriteLn(':<DrawFPVectorialToCanvas');
   WriteLn(':<DrawFPVectorialToCanvas');
   {$endif}
   {$endif}
 end;
 end;
 
 
-procedure DrawFPVPathsToCanvas(ASource: TvVectorialDocument;
-  {$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
+procedure DrawFPVPathToCanvas(ASource: TvVectorialDocument; CurPath: TPath;
+  ADest: TFPCustomCanvas;
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
 
 
   function CoordToCanvasX(ACoord: Double): Integer;
   function CoordToCanvasX(ACoord: Double): Integer;
@@ -133,9 +139,8 @@ procedure DrawFPVPathsToCanvas(ASource: TvVectorialDocument;
   end;
   end;
 
 
 var
 var
-  i, j, k: Integer;
+  j, k: Integer;
   PosX, PosY: Integer; // Not modified by ADestX, etc
   PosX, PosY: Integer; // Not modified by ADestX, etc
-  CurPath: TPath;
   CurSegment: TPathSegment;
   CurSegment: TPathSegment;
   Cur2DSegment: T2DSegment absolute CurSegment;
   Cur2DSegment: T2DSegment absolute CurSegment;
   Cur2DBSegment: T2DBezierSegment absolute CurSegment;
   Cur2DBSegment: T2DBezierSegment absolute CurSegment;
@@ -150,86 +155,80 @@ begin
 
 
   ADest.MoveTo(ADestX, ADestY);
   ADest.MoveTo(ADestX, ADestY);
 
 
-  // Draws all paths
-  for i := 0 to ASource.PathCount - 1 do
+  CurPath.PrepareForSequentialReading;
+
+  // Set the path Pen and Brush options
+  ADest.Pen.Style := CurPath.Pen.Style;
+  ADest.Pen.Width := CurPath.Pen.Width;
+  ADest.Brush.Style := CurPath.Brush.Style;
+  ADest.Pen.FPColor := CurPath.Pen.Color;
+  ADest.Brush.FPColor := CurPath.Brush.Color;
+
+  {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
+  Write(Format('[Path] ID=%d', [i]));
+  {$endif}
+
+  for j := 0 to CurPath.Len - 1 do
   begin
   begin
-    //WriteLn('i = ', i);
-    CurPath := ASource.Paths[i];
-    CurPath.PrepareForSequentialReading;
-
-    // Set the path Pen and Brush options
-    ADest.Pen.Style := CurPath.Pen.Style;
-    ADest.Pen.Width := CurPath.Pen.Width;
-    ADest.Brush.Style := CurPath.Brush.Style;
-    ADest.Pen.FPColor := CurPath.Pen.Color;
-    ADest.Brush.FPColor := CurPath.Brush.Color;
-
-    {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
-    Write(Format('[Path] ID=%d', [i]));
-    {$endif}
+    //WriteLn('j = ', j);
+    CurSegment := TPathSegment(CurPath.Next());
 
 
-    for j := 0 to CurPath.Len - 1 do
+    case CurSegment.SegmentType of
+    stMoveTo:
+    begin
+      ADest.MoveTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
+      {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
+      Write(Format(' M%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
+      {$endif}
+    end;
+    // This element can override temporarely the Pen
+    st2DLineWithPen:
     begin
     begin
-      //WriteLn('j = ', j);
-      CurSegment := TPathSegment(CurPath.Next());
+      ADest.Pen.FPColor := T2DSegmentWithPen(Cur2DSegment).Pen.Color;
 
 
-      case CurSegment.SegmentType of
-      stMoveTo:
-      begin
-        ADest.MoveTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
-        {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
-        Write(Format(' M%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
-        {$endif}
-      end;
-      // This element can override temporarely the Pen
-      st2DLineWithPen:
-      begin
-        ADest.Pen.FPColor := T2DSegmentWithPen(Cur2DSegment).Pen.Color;
+      ADest.LineTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
 
 
-        ADest.LineTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
+      ADest.Pen.FPColor := CurPath.Pen.Color;
 
 
-        ADest.Pen.FPColor := CurPath.Pen.Color;
+      {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
+      Write(Format(' L%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
+      {$endif}
+    end;
+    st2DLine, st3DLine:
+    begin
+      ADest.LineTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
+      {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
+      Write(Format(' L%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
+      {$endif}
+    end;
+    { To draw a bezier we need to divide the interval in parts and make
+      lines between this parts }
+    st2DBezier, st3DBezier:
+    begin
+      CurveLength :=
+        Round(sqrt(sqr(Cur2DBSegment.X3 - PosX) + sqr(Cur2DBSegment.Y3 - PosY))) +
+        Round(sqrt(sqr(Cur2DBSegment.X2 - Cur2DBSegment.X3) + sqr(Cur2DBSegment.Y2 - Cur2DBSegment.Y3))) +
+        Round(sqrt(sqr(Cur2DBSegment.X - Cur2DBSegment.X3) + sqr(Cur2DBSegment.Y - Cur2DBSegment.Y3)));
 
 
-        {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
-        Write(Format(' L%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
-        {$endif}
-      end;
-      st2DLine, st3DLine:
+      for k := 1 to CurveLength do
       begin
       begin
-        ADest.LineTo(CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y));
-        {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
-        Write(Format(' L%d,%d', [CoordToCanvasX(Cur2DSegment.X), CoordToCanvasY(Cur2DSegment.Y)]));
-        {$endif}
-      end;
-      { To draw a bezier we need to divide the interval in parts and make
-        lines between this parts }
-      st2DBezier, st3DBezier:
-      begin
-        CurveLength :=
-          Round(sqrt(sqr(Cur2DBSegment.X3 - PosX) + sqr(Cur2DBSegment.Y3 - PosY))) +
-          Round(sqrt(sqr(Cur2DBSegment.X2 - Cur2DBSegment.X3) + sqr(Cur2DBSegment.Y2 - Cur2DBSegment.Y3))) +
-          Round(sqrt(sqr(Cur2DBSegment.X - Cur2DBSegment.X3) + sqr(Cur2DBSegment.Y - Cur2DBSegment.Y3)));
-
-        for k := 1 to CurveLength do
-        begin
-          t := k / CurveLength;
-          CurX := Round(sqr(1 - t) * (1 - t) * PosX + 3 * t * sqr(1 - t) * Cur2DBSegment.X2 + 3 * t * t * (1 - t) * Cur2DBSegment.X3 + t * t * t * Cur2DBSegment.X);
-          CurY := Round(sqr(1 - t) * (1 - t) * PosY + 3 * t * sqr(1 - t) * Cur2DBSegment.Y2 + 3 * t * t * (1 - t) * Cur2DBSegment.Y3 + t * t * t * Cur2DBSegment.Y);
-          ADest.LineTo(CoordToCanvasX(CurX), CoordToCanvasY(CurY));
-        end;
-        PosX := Round(Cur2DBSegment.X);
-        PosY := Round(Cur2DBSegment.Y);
-      end;
+        t := k / CurveLength;
+        CurX := Round(sqr(1 - t) * (1 - t) * PosX + 3 * t * sqr(1 - t) * Cur2DBSegment.X2 + 3 * t * t * (1 - t) * Cur2DBSegment.X3 + t * t * t * Cur2DBSegment.X);
+        CurY := Round(sqr(1 - t) * (1 - t) * PosY + 3 * t * sqr(1 - t) * Cur2DBSegment.Y2 + 3 * t * t * (1 - t) * Cur2DBSegment.Y3 + t * t * t * Cur2DBSegment.Y);
+        ADest.LineTo(CoordToCanvasX(CurX), CoordToCanvasY(CurY));
       end;
       end;
+      PosX := Round(Cur2DBSegment.X);
+      PosY := Round(Cur2DBSegment.Y);
+    end;
     end;
     end;
-    {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
-    WriteLn('');
-    {$endif}
   end;
   end;
+  {$ifdef FPVECTORIAL_TOCANVAS_DEBUG}
+  WriteLn('');
+  {$endif}
 end;
 end;
 
 
-procedure DrawFPVEntitiesToCanvas(ASource: TvVectorialDocument;
-  {$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
+procedure DrawFPVEntityToCanvas(ASource: TvVectorialDocument; CurEntity: TvEntity;
+  ADest: TFPCustomCanvas;
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
 
 
   function CoordToCanvasX(ACoord: Double): Integer;
   function CoordToCanvasX(ACoord: Double): Integer;
@@ -244,8 +243,10 @@ procedure DrawFPVEntitiesToCanvas(ASource: TvVectorialDocument;
 
 
 var
 var
   i: Integer;
   i: Integer;
+  {$ifdef USE_LCL_CANVAS}
+  ALCLDest: TCanvas;
+  {$endif}
   // For entities
   // For entities
-  CurEntity: TvEntity;
   CurCircle: TvCircle;
   CurCircle: TvCircle;
   CurEllipse: TvEllipse;
   CurEllipse: TvEllipse;
   //
   //
@@ -258,192 +259,182 @@ var
   Points: array of TPoint;
   Points: array of TPoint;
   UpperDim, LowerDim: T3DPoint;
   UpperDim, LowerDim: T3DPoint;
 begin
 begin
-  // Draws all entities
-  for i := 0 to ASource.GetEntityCount - 1 do
-  begin
-    CurEntity := ASource.GetEntity(i);
+  {$ifdef USE_LCL_CANVAS}
+  ALCLDest := TCanvas(ADest);
+  {$endif}
 
 
-    ADest.Brush.Style := CurEntity.Brush.Style;
-    ADest.Pen.Style := CurEntity.Pen.Style;
-    ADest.Pen.FPColor := CurEntity.Pen.Color;
-    ADest.Brush.FPColor := CurEntity.Brush.Color;
+  ADest.Brush.Style := CurEntity.Brush.Style;
+  ADest.Pen.Style := CurEntity.Pen.Style;
+  ADest.Pen.FPColor := CurEntity.Pen.Color;
+  ADest.Brush.FPColor := CurEntity.Brush.Color;
 
 
-    if CurEntity is TvCircle then
+  if CurEntity is TvCircle then
+  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)
+      );
+  end
+  else if CurEntity is TvEllipse then
+  begin
+    CurEllipse := CurEntity as TvEllipse;
+    DrawRotatedEllipse(ADest, CurEllipse);
+  end
+  else if CurEntity is TvCircularArc then
+  begin
+    CurArc := CurEntity as TvCircularArc;
+    {$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);
+    {if AMulY > 0 then
+    begin}
+      FinalStartAngle := CurArc.StartAngle;
+      FinalEndAngle := CurArc.EndAngle;
+    {end
+    else // AMulY is negative
     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)
-        );
-    end
-    else if CurEntity is TvEllipse then
+      // Inverting the angles generates the correct result for Y axis inversion
+      if CurArc.EndAngle = 0 then FinalStartAngle := 0
+      else FinalStartAngle := 360 - 1* CurArc.EndAngle;
+      if CurArc.StartAngle = 0 then FinalEndAngle := 0
+      else FinalEndAngle := 360 - 1* CurArc.StartAngle;
+    end;}
+    IntStartAngle := Round(16*FinalStartAngle);
+    IntAngleLength := Round(16*(FinalEndAngle - FinalStartAngle));
+    // On Gtk2 and Carbon, the Left really needs to be to the Left of the Right position
+    // The same for the Top and Bottom
+    // On Windows it works fine either way
+    // On Gtk2 if the positions are inverted then the arcs are screwed up
+    // In Carbon if the positions are inverted, then the arc is inverted
+    if BoundsLeft > BoundsRight then
     begin
     begin
-      CurEllipse := CurEntity as TvEllipse;
-      DrawRotatedEllipse(ADest, CurEllipse);
-    end
-    else if CurEntity is TvCircularArc then
+      IntTmp := BoundsLeft;
+      BoundsLeft := BoundsRight;
+      BoundsRight := IntTmp;
+    end;
+    if BoundsTop > BoundsBottom then
     begin
     begin
-      CurArc := CurEntity as TvCircularArc;
-      {$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);
-      {if AMulY > 0 then
-      begin}
-        FinalStartAngle := CurArc.StartAngle;
-        FinalEndAngle := CurArc.EndAngle;
-      {end
-      else // AMulY is negative
-      begin
-        // Inverting the angles generates the correct result for Y axis inversion
-        if CurArc.EndAngle = 0 then FinalStartAngle := 0
-        else FinalStartAngle := 360 - 1* CurArc.EndAngle;
-        if CurArc.StartAngle = 0 then FinalEndAngle := 0
-        else FinalEndAngle := 360 - 1* CurArc.StartAngle;
-      end;}
-      IntStartAngle := Round(16*FinalStartAngle);
-      IntAngleLength := Round(16*(FinalEndAngle - FinalStartAngle));
-      // On Gtk2 and Carbon, the Left really needs to be to the Left of the Right position
-      // The same for the Top and Bottom
-      // On Windows it works fine either way
-      // On Gtk2 if the positions are inverted then the arcs are screwed up
-      // In Carbon if the positions are inverted, then the arc is inverted
-      if BoundsLeft > BoundsRight then
-      begin
-        IntTmp := BoundsLeft;
-        BoundsLeft := BoundsRight;
-        BoundsRight := IntTmp;
-      end;
-      if BoundsTop > BoundsBottom then
-      begin
-        IntTmp := BoundsTop;
-        BoundsTop := BoundsBottom;
-        BoundsBottom := IntTmp;
-      end;
-      // Arc(ALeft, ATop, ARight, ABottom, Angle16Deg, Angle16DegLength: Integer);
-      {$ifdef FPVECTORIALDEBUG}
-      WriteLn(Format('Drawing Arc Center=%f,%f Radius=%f StartAngle=%f AngleLength=%f',
-        [CurArc.CenterX, CurArc.CenterY, CurArc.Radius, IntStartAngle/16, IntAngleLength/16]));
-      {$endif}
-      ADest.Pen.FPColor := CurArc.Pen.Color;
-      ADest.Arc(
-        BoundsLeft, BoundsTop, BoundsRight, BoundsBottom,
-        IntStartAngle, IntAngleLength
-        );
-      ADest.Pen.Color := clBlack;
-      // Debug info
+      IntTmp := BoundsTop;
+      BoundsTop := BoundsBottom;
+      BoundsBottom := IntTmp;
+    end;
+    // Arc(ALeft, ATop, ARight, ABottom, Angle16Deg, Angle16DegLength: Integer);
+    {$ifdef FPVECTORIALDEBUG}
+    WriteLn(Format('Drawing Arc Center=%f,%f Radius=%f StartAngle=%f AngleLength=%f',
+      [CurArc.CenterX, CurArc.CenterY, CurArc.Radius, IntStartAngle/16, IntAngleLength/16]));
+    {$endif}
+    ADest.Pen.FPColor := CurArc.Pen.Color;
+    ALCLDest.Arc(
+      BoundsLeft, BoundsTop, BoundsRight, BoundsBottom,
+      IntStartAngle, IntAngleLength
+      );
+    ADest.Pen.FPColor := colBlack;
+    // Debug info
 //      {$define FPVECTORIALDEBUG}
 //      {$define FPVECTORIALDEBUG}
 //      {$ifdef FPVECTORIALDEBUG}
 //      {$ifdef FPVECTORIALDEBUG}
 //      WriteLn(Format('Drawing Arc x1y1=%d,%d x2y2=%d,%d start=%d end=%d',
 //      WriteLn(Format('Drawing Arc x1y1=%d,%d x2y2=%d,%d start=%d end=%d',
 //        [BoundsLeft, BoundsTop, BoundsRight, BoundsBottom, IntStartAngle, IntAngleLength]));
 //        [BoundsLeft, BoundsTop, BoundsRight, BoundsBottom, IntStartAngle, IntAngleLength]));
 //      {$endif}
 //      {$endif}
 {      ADest.TextOut(CoordToCanvasX(CurArc.CenterX), CoordToCanvasY(CurArc.CenterY),
 {      ADest.TextOut(CoordToCanvasX(CurArc.CenterX), CoordToCanvasY(CurArc.CenterY),
-        Format('R=%d S=%d L=%d', [Round(CurArc.Radius*AMulX), Round(FinalStartAngle),
-        Abs(Round((FinalEndAngle - FinalStartAngle)))]));
-      ADest.Pen.Color := TColor($DDDDDD);
-      ADest.Rectangle(
-        BoundsLeft, BoundsTop, BoundsRight, BoundsBottom);
-      ADest.Pen.Color := clBlack;}
-      {$endif}
+      Format('R=%d S=%d L=%d', [Round(CurArc.Radius*AMulX), Round(FinalStartAngle),
+      Abs(Round((FinalEndAngle - FinalStartAngle)))]));
+    ADest.Pen.Color := TColor($DDDDDD);
+    ADest.Rectangle(
+      BoundsLeft, BoundsTop, BoundsRight, BoundsBottom);
+    ADest.Pen.Color := clBlack;}
+    {$endif}
+  end
+  else if CurEntity is TvAlignedDimension then
+  begin
+    CurDim := CurEntity as TvAlignedDimension;
+    //
+    // Draws this shape:
+    // vertical     horizontal
+    // ___
+    // | |     or   ---| X cm
+    //   |           --|
+    // Which marks the dimension
+    ADest.MoveTo(CoordToCanvasX(CurDim.BaseRight.X), CoordToCanvasY(CurDim.BaseRight.Y));
+    ADest.LineTo(CoordToCanvasX(CurDim.DimensionRight.X), CoordToCanvasY(CurDim.DimensionRight.Y));
+    ADest.LineTo(CoordToCanvasX(CurDim.DimensionLeft.X), CoordToCanvasY(CurDim.DimensionLeft.Y));
+    ADest.LineTo(CoordToCanvasX(CurDim.BaseLeft.X), CoordToCanvasY(CurDim.BaseLeft.Y));
+    // Now the arrows
+    // horizontal
+    SetLength(Points, 3);
+    if CurDim.DimensionRight.Y = CurDim.DimensionLeft.Y then
+    begin
+      ADest.Brush.FPColor := colBlack;
+      ADest.Brush.Style := bsSolid;
+      // Left arrow
+      Points[0] := Point(CoordToCanvasX(CurDim.DimensionLeft.X), CoordToCanvasY(CurDim.DimensionLeft.Y));
+      Points[1] := Point(Points[0].X + 7, Points[0].Y - 3);
+      Points[2] := Point(Points[0].X + 7, Points[0].Y + 3);
+      ADest.Polygon(Points);
+      // Right arrow
+      Points[0] := Point(CoordToCanvasX(CurDim.DimensionRight.X), CoordToCanvasY(CurDim.DimensionRight.Y));
+      Points[1] := Point(Points[0].X - 7, Points[0].Y - 3);
+      Points[2] := Point(Points[0].X - 7, Points[0].Y + 3);
+      ADest.Polygon(Points);
+      ADest.Brush.Style := bsClear;
+      // Dimension text
+      Points[0].X := CoordToCanvasX((CurDim.DimensionLeft.X+CurDim.DimensionRight.X)/2);
+      Points[0].Y := CoordToCanvasY(CurDim.DimensionLeft.Y);
+      LowerDim.X := CurDim.DimensionRight.X-CurDim.DimensionLeft.X;
+      ADest.Font.Size := 10;
+      ADest.TextOut(Points[0].X, Points[0].Y, Format('%.1f', [LowerDim.X]));
     end
     end
-    else if CurEntity is TvAlignedDimension then
+    else
     begin
     begin
-      CurDim := CurEntity as TvAlignedDimension;
-      //
-      // Draws this shape:
-      // vertical     horizontal
-      // ___
-      // | |     or   ---| X cm
-      //   |           --|
-      // Which marks the dimension
-      ADest.MoveTo(CoordToCanvasX(CurDim.BaseRight.X), CoordToCanvasY(CurDim.BaseRight.Y));
-      ADest.LineTo(CoordToCanvasX(CurDim.DimensionRight.X), CoordToCanvasY(CurDim.DimensionRight.Y));
-      ADest.LineTo(CoordToCanvasX(CurDim.DimensionLeft.X), CoordToCanvasY(CurDim.DimensionLeft.Y));
-      ADest.LineTo(CoordToCanvasX(CurDim.BaseLeft.X), CoordToCanvasY(CurDim.BaseLeft.Y));
-      // Now the arrows
-      // horizontal
-      SetLength(Points, 3);
-      if CurDim.DimensionRight.Y = CurDim.DimensionLeft.Y then
+      ADest.Brush.FPColor := colBlack;
+      ADest.Brush.Style := bsSolid;
+      // There is no upper/lower preference for DimensionLeft/Right, so we need to check
+      if CurDim.DimensionLeft.Y > CurDim.DimensionRight.Y then
       begin
       begin
-        {$ifdef USE_LCL_CANVAS}
-        ADest.Brush.Color := clBlack;
-        {$else}
-        ADest.Brush.FPColor := colBlack;
-        {$endif}
-        ADest.Brush.Style := bsSolid;
-        // Left arrow
-        Points[0] := Point(CoordToCanvasX(CurDim.DimensionLeft.X), CoordToCanvasY(CurDim.DimensionLeft.Y));
-        Points[1] := Point(Points[0].X + 7, Points[0].Y - 3);
-        Points[2] := Point(Points[0].X + 7, Points[0].Y + 3);
-        ADest.Polygon(Points);
-        // Right arrow
-        Points[0] := Point(CoordToCanvasX(CurDim.DimensionRight.X), CoordToCanvasY(CurDim.DimensionRight.Y));
-        Points[1] := Point(Points[0].X - 7, Points[0].Y - 3);
-        Points[2] := Point(Points[0].X - 7, Points[0].Y + 3);
-        ADest.Polygon(Points);
-        ADest.Brush.Style := bsClear;
-        // Dimension text
-        Points[0].X := CoordToCanvasX((CurDim.DimensionLeft.X+CurDim.DimensionRight.X)/2);
-        Points[0].Y := CoordToCanvasY(CurDim.DimensionLeft.Y);
-        LowerDim.X := CurDim.DimensionRight.X-CurDim.DimensionLeft.X;
-        ADest.Font.Size := 10;
-        ADest.TextOut(Points[0].X, Points[0].Y, Format('%.1f', [LowerDim.X]));
+        UpperDim := CurDim.DimensionLeft;
+        LowerDim := CurDim.DimensionRight;
       end
       end
       else
       else
       begin
       begin
-        {$ifdef USE_LCL_CANVAS}
-        ADest.Brush.Color := clBlack;
-        {$else}
-        ADest.Brush.FPColor := colBlack;
-        {$endif}
-        ADest.Brush.Style := bsSolid;
-        // There is no upper/lower preference for DimensionLeft/Right, so we need to check
-        if CurDim.DimensionLeft.Y > CurDim.DimensionRight.Y then
-        begin
-          UpperDim := CurDim.DimensionLeft;
-          LowerDim := CurDim.DimensionRight;
-        end
-        else
-        begin
-          UpperDim := CurDim.DimensionRight;
-          LowerDim := CurDim.DimensionLeft;
-        end;
-        // Upper arrow
-        Points[0] := Point(CoordToCanvasX(UpperDim.X), CoordToCanvasY(UpperDim.Y));
-        Points[1] := Point(Points[0].X + Round(AMulX), Points[0].Y - Round(AMulY*3));
-        Points[2] := Point(Points[0].X - Round(AMulX), Points[0].Y - Round(AMulY*3));
-        ADest.Polygon(Points);
-        // Lower arrow
-        Points[0] := Point(CoordToCanvasX(LowerDim.X), CoordToCanvasY(LowerDim.Y));
-        Points[1] := Point(Points[0].X + Round(AMulX), Points[0].Y + Round(AMulY*3));
-        Points[2] := Point(Points[0].X - Round(AMulX), Points[0].Y + Round(AMulY*3));
-        ADest.Polygon(Points);
-        ADest.Brush.Style := bsClear;
-        // Dimension text
-        Points[0].X := CoordToCanvasX(CurDim.DimensionLeft.X);
-        Points[0].Y := CoordToCanvasY((CurDim.DimensionLeft.Y+CurDim.DimensionRight.Y)/2);
-        LowerDim.Y := CurDim.DimensionRight.Y-CurDim.DimensionLeft.Y;
-        if LowerDim.Y < 0 then LowerDim.Y := -1 * LowerDim.Y;
-        ADest.Font.Size := 10;
-        ADest.TextOut(Points[0].X, Points[0].Y, Format('%.1f', [LowerDim.Y]));
+        UpperDim := CurDim.DimensionRight;
+        LowerDim := CurDim.DimensionLeft;
       end;
       end;
-      SetLength(Points, 0);
-{      // Debug info
-      ADest.TextOut(CoordToCanvasX(CurDim.BaseRight.X), CoordToCanvasY(CurDim.BaseRight.Y), 'BR');
-      ADest.TextOut(CoordToCanvasX(CurDim.DimensionRight.X), CoordToCanvasY(CurDim.DimensionRight.Y), 'DR');
-      ADest.TextOut(CoordToCanvasX(CurDim.DimensionLeft.X), CoordToCanvasY(CurDim.DimensionLeft.Y), 'DL');
-      ADest.TextOut(CoordToCanvasX(CurDim.BaseLeft.X), CoordToCanvasY(CurDim.BaseLeft.Y), 'BL');}
+      // Upper arrow
+      Points[0] := Point(CoordToCanvasX(UpperDim.X), CoordToCanvasY(UpperDim.Y));
+      Points[1] := Point(Points[0].X + Round(AMulX), Points[0].Y - Round(AMulY*3));
+      Points[2] := Point(Points[0].X - Round(AMulX), Points[0].Y - Round(AMulY*3));
+      ADest.Polygon(Points);
+      // Lower arrow
+      Points[0] := Point(CoordToCanvasX(LowerDim.X), CoordToCanvasY(LowerDim.Y));
+      Points[1] := Point(Points[0].X + Round(AMulX), Points[0].Y + Round(AMulY*3));
+      Points[2] := Point(Points[0].X - Round(AMulX), Points[0].Y + Round(AMulY*3));
+      ADest.Polygon(Points);
+      ADest.Brush.Style := bsClear;
+      // Dimension text
+      Points[0].X := CoordToCanvasX(CurDim.DimensionLeft.X);
+      Points[0].Y := CoordToCanvasY((CurDim.DimensionLeft.Y+CurDim.DimensionRight.Y)/2);
+      LowerDim.Y := CurDim.DimensionRight.Y-CurDim.DimensionLeft.Y;
+      if LowerDim.Y < 0 then LowerDim.Y := -1 * LowerDim.Y;
+      ADest.Font.Size := 10;
+      ADest.TextOut(Points[0].X, Points[0].Y, Format('%.1f', [LowerDim.Y]));
     end;
     end;
+    SetLength(Points, 0);
+{      // Debug info
+    ADest.TextOut(CoordToCanvasX(CurDim.BaseRight.X), CoordToCanvasY(CurDim.BaseRight.Y), 'BR');
+    ADest.TextOut(CoordToCanvasX(CurDim.DimensionRight.X), CoordToCanvasY(CurDim.DimensionRight.Y), 'DR');
+    ADest.TextOut(CoordToCanvasX(CurDim.DimensionLeft.X), CoordToCanvasY(CurDim.DimensionLeft.Y), 'DL');
+    ADest.TextOut(CoordToCanvasX(CurDim.BaseLeft.X), CoordToCanvasY(CurDim.BaseLeft.Y), 'BL');}
   end;
   end;
 end;
 end;
 
 
-procedure DrawFPVTextToCanvas(ASource: TvVectorialDocument;
-  {$ifdef USE_LCL_CANVAS}ADest: TCanvas;{$else}ADest: TFPCustomCanvas;{$endif}
+procedure DrawFPVTextToCanvas(ASource: TvVectorialDocument; CurText: TvText;
+  ADest: TFPCustomCanvas;
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
   ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
 
 
   function CoordToCanvasX(ACoord: Double): Integer;
   function CoordToCanvasX(ACoord: Double): Integer;
@@ -458,29 +449,26 @@ procedure DrawFPVTextToCanvas(ASource: TvVectorialDocument;
 
 
 var
 var
   i: Integer;
   i: Integer;
-  // For text
-  CurText: TvText;
+  {$ifdef USE_LCL_CANVAS}
+  ALCLDest: TCanvas;
+  {$endif}
   //
   //
   LowerDim: T3DPoint;
   LowerDim: T3DPoint;
 begin
 begin
-  // Draws all text
-  for i := 0 to ASource.GetTextCount - 1 do
-  begin
-    CurText := ASource.GetText(i);
+  {$ifdef USE_LCL_CANVAS}
+  ALCLDest := TCanvas(ADest);
+  {$endif}
 
 
-    ADest.Font.Size := Round(AmulX * CurText.Font.Size);
-    ADest.Pen.Style := psSolid;
-    {$ifdef USE_LCL_CANVAS}
-    ADest.Pen.Color := clBlack;
-    {$else}
-    ADest.Pen.FPColor := colBlack;
-    {$endif}
-    ADest.Brush.Style := bsClear;
-    ADest.Font.Orientation := Round(CurText.Font.Orientation * 16);
+  ADest.Font.Size := Round(AmulX * CurText.Font.Size);
+  ADest.Pen.Style := psSolid;
+  ADest.Pen.FPColor := colBlack;
+  ADest.Brush.Style := bsClear;
+  {$ifdef USE_LCL_CANVAS}
+  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);
-  end;
+  LowerDim.Y := CurText.Y + CurText.Font.Size;
+  ADest.TextOut(CoordToCanvasX(CurText.X), CoordToCanvasY(LowerDim.Y), CurText.Value);
 end;
 end;
 
 
 end.
 end.

+ 32 - 7
packages/fpvectorial/src/fpvutils.pas

@@ -27,10 +27,16 @@ type
 // Color Conversion routines
 // Color Conversion routines
 function FPColorToRGBHexString(AColor: TFPColor): string;
 function FPColorToRGBHexString(AColor: TFPColor): string;
 function RGBToFPColor(AR, AG, AB: byte): TFPColor; inline;
 function RGBToFPColor(AR, AG, AB: byte): TFPColor; inline;
+// Other routine
+function CanvasCoordsToFPVectorial(AY: Integer; AHeight: Integer): Integer; inline;
+function CanvasTextPosToFPVectorial(AY: Integer; ACanvasHeight, ATextHeight: Integer): Integer;
 function SeparateString(AString: string; ASeparator: char): T10Strings;
 function SeparateString(AString: string; ASeparator: char): T10Strings;
 
 
 implementation
 implementation
 
 
+{@@ This function is utilized by the SVG writer and some other places, so
+    it shouldn't be changed.
+}
 function FPColorToRGBHexString(AColor: TFPColor): string;
 function FPColorToRGBHexString(AColor: TFPColor): string;
 begin
 begin
   Result := Format('%.2x%.2x%.2x', [AColor.Red shr 8, AColor.Green shr 8, AColor.Blue shr 8]);
   Result := Format('%.2x%.2x%.2x', [AColor.Red shr 8, AColor.Green shr 8, AColor.Blue shr 8]);
@@ -38,16 +44,35 @@ end;
 
 
 function RGBToFPColor(AR, AG, AB: byte): TFPColor; inline;
 function RGBToFPColor(AR, AG, AB: byte): TFPColor; inline;
 begin
 begin
-  if AR > $100 then Result.Red := (AR shl 8) + $FF
-  else Result.Red := AR shl 8;
+  Result.Red := (AR shl 8) + AR;
+  Result.Green := (AG shl 8) + AG;
+  Result.Blue := (AB shl 8) + AB;
+  Result.Alpha := $FFFF;
+end;
 
 
-  if AR > $100 then Result.Green := (AG shl 8) + $FF
-  else Result.Green := AG shl 8;
+{@@ Converts the coordinate system from a TCanvas to FPVectorial
+    The basic difference is that the Y axis is positioned differently and
+    points upwards in FPVectorial and downwards in TCanvas.
+    The X axis doesn't change. The fix is trivial and requires only the Height of
+    the Canvas as extra info.
 
 
-  if AR > $100 then Result.Blue := (AB shl 8) + $FF
-  else Result.Blue := AB shl 8;
+    @param AHeight Should receive TCanvas.Height
+}
+function CanvasCoordsToFPVectorial(AY: Integer; AHeight: Integer): Integer; inline;
+begin
+  Result := AHeight - AY;
+end;
 
 
-  Result.Alpha := $FFFF;
+{@@
+  LCL Text is positioned based on the top-left corner of the text.
+  Besides that, one also needs to take the general coordinate change into account too.
+
+  @param ACanvasHeight Should receive TCanvas.Height
+  @param ATextHeight   Should receive TFont.Size
+}
+function CanvasTextPosToFPVectorial(AY: Integer; ACanvasHeight, ATextHeight: Integer): Integer;
+begin
+  Result := CanvasCoordsToFPVectorial(AY, ACanvasHeight) - ATextHeight;
 end;
 end;
 
 
 {@@
 {@@

+ 32 - 36
packages/fpvectorial/src/svgvectorialwriter.pas

@@ -23,9 +23,9 @@ type
     FPointSeparator, FCommaSeparator: TFormatSettings;
     FPointSeparator, FCommaSeparator: TFormatSettings;
     procedure WriteDocumentSize(AStrings: TStrings; AData: TvVectorialDocument);
     procedure WriteDocumentSize(AStrings: TStrings; AData: TvVectorialDocument);
     procedure WriteDocumentName(AStrings: TStrings; AData: TvVectorialDocument);
     procedure WriteDocumentName(AStrings: TStrings; AData: TvVectorialDocument);
-    procedure WritePaths(AStrings: TStrings; AData: TvVectorialDocument);
     procedure WritePath(AIndex: Integer; APath: TPath; AStrings: TStrings; AData: TvVectorialDocument);
     procedure WritePath(AIndex: Integer; APath: TPath; AStrings: TStrings; AData: TvVectorialDocument);
-    procedure WriteTexts(AStrings: TStrings; AData: TvVectorialDocument);
+    procedure WriteText(AStrings: TStrings; lText: TvText; AData: TvVectorialDocument);
+    procedure WriteEntities(AStrings: TStrings; AData: TvVectorialDocument);
     procedure ConvertFPVCoordinatesToSVGCoordinates(
     procedure ConvertFPVCoordinatesToSVGCoordinates(
       const AData: TvVectorialDocument;
       const AData: TvVectorialDocument;
       const ASrcX, ASrcY: Double; var ADestX, ADestY: double);
       const ASrcX, ASrcY: Double; var ADestX, ADestY: double);
@@ -61,19 +61,6 @@ begin
   AStrings.Add('  sodipodi:docname="New document 1">');
   AStrings.Add('  sodipodi:docname="New document 1">');
 end;
 end;
 
 
-procedure TvSVGVectorialWriter.WritePaths(AStrings: TStrings; AData: TvVectorialDocument);
-var
-  i: Integer;
-  lPath: TPath;
-begin
-  for i := 0 to AData.GetPathCount() - 1 do
-  begin
-    lPath := AData.GetPath(i);
-    lPath.PrepareForSequentialReading;
-    WritePath(i ,lPath, AStrings, AData);
-  end;
-end;
-
 {@@
 {@@
   SVG Coordinate system measures things only in pixels, so that we have to
   SVG Coordinate system measures things only in pixels, so that we have to
   hardcode a DPI value for the screen, which is usually 72.
   hardcode a DPI value for the screen, which is usually 72.
@@ -227,43 +214,52 @@ begin
 
 
   // Now data
   // Now data
   AStrings.Add('  <g id="layer1">');
   AStrings.Add('  <g id="layer1">');
-  WritePaths(AStrings, AData);
-  WriteTexts(AStrings, AData);
+  WriteEntities(AStrings, AData);
   AStrings.Add('  </g>');
   AStrings.Add('  </g>');
 
 
   // finalization
   // finalization
   AStrings.Add('</svg>');
   AStrings.Add('</svg>');
 end;
 end;
 
 
-procedure TvSVGVectorialWriter.WriteTexts(AStrings: TStrings; AData: TvVectorialDocument);
+procedure TvSVGVectorialWriter.WriteText(AStrings: TStrings; lText: TvText; AData: TvVectorialDocument);
 var
 var
   i, j, FontSize: Integer;
   i, j, FontSize: Integer;
   TextStr, FontName, SVGFontFamily: string;
   TextStr, FontName, SVGFontFamily: string;
-  lText: TvText;
   PtX, PtY: double;
   PtX, PtY: double;
 begin
 begin
-  for i := 0 to AData.GetTextCount() - 1 do
-  begin
-    TextStr := '';
-    lText := AData.GetText(i);
+  TextStr := '';
 
 
-    ConvertFPVCoordinatesToSVGCoordinates(
-        AData, lText.X, lText.Y, PtX, PtY);
+  ConvertFPVCoordinatesToSVGCoordinates(
+      AData, lText.X, lText.Y, PtX, PtY);
 
 
-    TextStr := lText.Value;
-    FontSize:= ceil(lText.Font.Size / FLOAT_MILIMETERS_PER_PIXEL);
-    SVGFontFamily := 'Arial, sans-serif';//lText.FontName;
+  TextStr := lText.Value;
+  FontSize:= ceil(lText.Font.Size / FLOAT_MILIMETERS_PER_PIXEL);
+  SVGFontFamily := 'Arial, sans-serif';//lText.FontName;
 
 
-    AStrings.Add('  <text ');
-    AStrings.Add('    x="' + FloatToStr(PtX, FPointSeparator) + '"');
-    AStrings.Add('    y="' + FloatToStr(PtY, FPointSeparator) + '"');
+  AStrings.Add('  <text ');
+  AStrings.Add('    x="' + FloatToStr(PtX, FPointSeparator) + '"');
+  AStrings.Add('    y="' + FloatToStr(PtY, FPointSeparator) + '"');
 //    AStrings.Add('    font-size="' + IntToStr(FontSize) + '"'); Doesn't seam to work, we need to use the tspan
 //    AStrings.Add('    font-size="' + IntToStr(FontSize) + '"'); Doesn't seam to work, we need to use the tspan
-    AStrings.Add('    font-family="' + SVGFontFamily + '">');
-    AStrings.Add('    <tspan ');
-    AStrings.Add('      style="font-size:' + IntToStr(FontSize) + '" ');
+  AStrings.Add('    font-family="' + SVGFontFamily + '">');
+  AStrings.Add('    <tspan ');
+  AStrings.Add('      style="font-size:' + IntToStr(FontSize) + '" ');
 //    AStrings.Add('      id="tspan2828" ');
 //    AStrings.Add('      id="tspan2828" ');
-    AStrings.Add('    >');
-    AStrings.Add(TextStr + '</tspan></text>');
+  AStrings.Add('    >');
+  AStrings.Add(TextStr + '</tspan></text>');
+end;
+
+procedure TvSVGVectorialWriter.WriteEntities(AStrings: TStrings;
+  AData: TvVectorialDocument);
+var
+  lEntity: TvEntity;
+  i: Integer;
+begin
+  for i := 0 to AData.GetEntitiesCount() - 1 do
+  begin
+    lEntity := AData.GetEntity(i);
+
+    if lEntity is TPath then WritePath(i, TPath(lEntity), AStrings, AData)
+    else if lEntity is TvText then WriteText(AStrings, TvText(lEntity), AData);
   end;
   end;
 end;
 end;