Browse Source

Initial transformation of fpvectorial segments in classes, as well as making the number of segments dynamic

git-svn-id: trunk@16202 -
sekelsenmat 15 years ago
parent
commit
cc2da23316

+ 14 - 12
packages/fpvectorial/examples/fpvc_mainform.lfm

@@ -10,26 +10,28 @@ object formVectorialConverter: TformVectorialConverter
   LCLVersion = '0.9.29'
   LCLVersion = '0.9.29'
   object Label1: TLabel
   object Label1: TLabel
     Left = 8
     Left = 8
-    Height = 14
-    Top = 104
-    Width = 123
+    Height = 17
+    Top = 112
+    Width = 160
     Caption = 'Location of the Input file:'
     Caption = 'Location of the Input file:'
     ParentColor = False
     ParentColor = False
   end
   end
   object Label2: TLabel
   object Label2: TLabel
     Left = 11
     Left = 11
-    Height = 96
+    Height = 104
     Top = 8
     Top = 8
-    Width = 224
+    Width = 229
     AutoSize = False
     AutoSize = False
     Caption = 'This converter application use the fpvectorial library to convert between various different vectorial graphics formats. The type is detected from the extension and the supported types are: PDF (*.pdf), SVG (*.svg) and Corel Draw file (*.cdr).'
     Caption = 'This converter application use the fpvectorial library to convert between various different vectorial graphics formats. The type is detected from the extension and the supported types are: PDF (*.pdf), SVG (*.svg) and Corel Draw file (*.cdr).'
+    Font.Height = -12
     ParentColor = False
     ParentColor = False
+    ParentFont = False
     WordWrap = True
     WordWrap = True
   end
   end
   object editInput: TFileNameEdit
   object editInput: TFileNameEdit
     Left = 8
     Left = 8
-    Height = 21
-    Top = 120
+    Height = 22
+    Top = 128
     Width = 192
     Width = 192
     DialogOptions = []
     DialogOptions = []
     FilterIndex = 0
     FilterIndex = 0
@@ -41,16 +43,16 @@ object formVectorialConverter: TformVectorialConverter
   end
   end
   object Label3: TLabel
   object Label3: TLabel
     Left = 8
     Left = 8
-    Height = 14
-    Top = 144
-    Width = 132
+    Height = 17
+    Top = 152
+    Width = 173
     Caption = 'Full path of the Output file:'
     Caption = 'Full path of the Output file:'
     ParentColor = False
     ParentColor = False
   end
   end
   object editOutput: TFileNameEdit
   object editOutput: TFileNameEdit
     Left = 8
     Left = 8
-    Height = 21
-    Top = 160
+    Height = 22
+    Top = 168
     Width = 192
     Width = 192
     DialogOptions = []
     DialogOptions = []
     FilterIndex = 0
     FilterIndex = 0

+ 5 - 1
packages/fpvectorial/examples/fpvectorialconverter.lpi

@@ -8,6 +8,7 @@
         <AlwaysBuild Value="False"/>
         <AlwaysBuild Value="False"/>
       </Flags>
       </Flags>
       <SessionStorage Value="InProjectDir"/>
       <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
       <Title Value="fpvectorialconverter"/>
       <Title Value="fpvectorialconverter"/>
       <UseXPManifest Value="True"/>
       <UseXPManifest Value="True"/>
       <Icon Value="0"/>
       <Icon Value="0"/>
@@ -18,6 +19,9 @@
     <VersionInfo>
     <VersionInfo>
       <StringTable ProductVersion=""/>
       <StringTable ProductVersion=""/>
     </VersionInfo>
     </VersionInfo>
+    <BuildModes Count="1">
+      <Item1 Name="default" Default="True"/>
+    </BuildModes>
     <PublishOptions>
     <PublishOptions>
       <Version Value="2"/>
       <Version Value="2"/>
       <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
       <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
@@ -55,7 +59,7 @@
       <Filename Value="fpvectorialconverter"/>
       <Filename Value="fpvectorialconverter"/>
     </Target>
     </Target>
     <SearchPaths>
     <SearchPaths>
-      <IncludeFiles Value="$(ProjOutDir)\"/>
+      <IncludeFiles Value="$(ProjOutDir)"/>
       <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
       <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
     </SearchPaths>
     </SearchPaths>
     <Linking>
     <Linking>

+ 195 - 66
packages/fpvectorial/src/fpvectorial.pas

@@ -48,20 +48,64 @@ type
     the starting point is in the bottom-left corner of the document.
     the starting point is in the bottom-left corner of the document.
     The X grows to the right and the Y grows to the top.
     The X grows to the right and the Y grows to the top.
   }
   }
-  TPathSegment = record
+  { TPathSegment }
+
+  TPathSegment = class
+  public
     SegmentType: TSegmentType;
     SegmentType: TSegmentType;
-    X, Y, Z: Double; // Z is ignored in 2D segments
-    X2, Y2, Z2: Double; // Z is ignored in 2D segments
-    X3, Y3, Z3: Double; // Z is ignored in 2D segments
+    // Fields for linking the list
+    Previous: TPathSegment;
+    Next: TPathSegment;
   end;
   end;
 
 
-  TPath = record
-    Len: Integer;
-    // ToDo: make the array dynamic
-    Points: array[0..255] of TPathSegment;
+  {@@
+    In a 2D segment, the X and Y coordinates represent usually the
+    final point of the segment, being that it starts where the previous
+    segment ends. The exception is for the first segment of all, which simply
+    holds the starting point for the drawing and should always be of the type
+    stMoveTo.
+  }
+  T2DSegment = class(TPathSegment)
+  public
+    X, Y: Double;
+  end;
+
+  {@@
+    In Bezier segments, we remain using the X and Y coordinates for the ending point.
+    The starting point is where the previous segment ended, so that the intermediary
+    bezier control points are [X2, Y2] and [X3, Y3].
+  }
+  T2DBezierSegment = class(T2DSegment)
+  public
+    X2, Y2: Double;
+    X3, Y3: Double;
   end;
   end;
 
 
-  PPath = ^TPath;
+  T3DSegment = class(TPathSegment)
+  public
+    {@@
+      Coordinates of the end of the segment.
+      For the first segment, this is the starting point.
+    }
+    X, Y, Z: Double;
+  end;
+
+  T3DBezierSegment = class(T3DSegment)
+  public
+    X2, Y2, Z2: Double;
+    X3, Y3, Z3: Double;
+  end;
+
+  TPath = class
+    Len: Integer;
+    Points: TPathSegment; // Beginning of the double-linked list
+    PointsEnd: TPathSegment; // End of the double-linked list
+    CurPoint: TPathSegment; // Used in PrepareForSequentialReading and Next
+    procedure Assign(APath: TPath);
+    function Count(): TPathSegment;
+    procedure PrepareForSequentialReading;
+    function Next(): TPathSegment;
+  end;
 
 
   {@@
   {@@
     TvText represents a text in memory.
     TvText represents a text in memory.
@@ -69,16 +113,14 @@ type
     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 = record
+  TvText = class
+  public
     X, Y, Z: Double; // Z is ignored in 2D formats
     X, Y, Z: Double; // Z is ignored in 2D formats
     FontSize: integer;
     FontSize: integer;
     FontName: utf8string;
     FontName: utf8string;
     Value: utf8string;
     Value: utf8string;
   end;
   end;
 
 
-  PText = ^TvText;
-
 type
 type
 
 
   TvCustomVectorialWriter = class;
   TvCustomVectorialWriter = class;
@@ -95,6 +137,8 @@ type
     procedure RemoveCallback(data, arg: pointer);
     procedure RemoveCallback(data, arg: pointer);
     function CreateVectorialWriter(AFormat: TvVectorialFormat): TvCustomVectorialWriter;
     function CreateVectorialWriter(AFormat: TvVectorialFormat): TvCustomVectorialWriter;
     function CreateVectorialReader(AFormat: TvVectorialFormat): TvCustomVectorialReader;
     function CreateVectorialReader(AFormat: TvVectorialFormat): TvCustomVectorialReader;
+    procedure ClearTmpPath();
+    procedure AppendSegmentToTmpPath(ASegment: TPathSegment);
   public
   public
     Name: string;
     Name: string;
     Width, Height: Double; // in millimeters
     Width, Height: Double; // in millimeters
@@ -185,6 +229,9 @@ procedure RegisterVectorialWriter(
 
 
 implementation
 implementation
 
 
+const
+  Str_Error_Nil_Path = ' The program attempted to add a segment before creating a path';
+
 {@@
 {@@
   Registers a new reader for a format
   Registers a new reader for a format
 }
 }
@@ -276,7 +323,11 @@ end;
 }
 }
 procedure TvVectorialDocument.RemoveCallback(data, arg: pointer);
 procedure TvVectorialDocument.RemoveCallback(data, arg: pointer);
 begin
 begin
-  if data <> nil then FreeMem(data);
+{  if data <> nil then
+  begin
+    ldata := PObject(data);
+    ldata^.Free;
+  end;}
 end;
 end;
 
 
 {@@
 {@@
@@ -288,6 +339,7 @@ begin
 
 
   FPaths := TFPList.Create;
   FPaths := TFPList.Create;
   FTexts := TFPList.Create;
   FTexts := TFPList.Create;
+  FTmpPath := TPath.Create;
 end;
 end;
 
 
 {@@
 {@@
@@ -308,28 +360,27 @@ end;
 }
 }
 procedure TvVectorialDocument.RemoveAllPaths;
 procedure TvVectorialDocument.RemoveAllPaths;
 begin
 begin
-  FPaths.ForEachCall(RemoveCallback, nil);
+//  FPaths.ForEachCall(RemoveCallback, nil);
   FPaths.Clear;
   FPaths.Clear;
 end;
 end;
 
 
 procedure TvVectorialDocument.RemoveAllTexts;
 procedure TvVectorialDocument.RemoveAllTexts;
 begin
 begin
-  FTexts.ForEachCall(RemoveCallback, nil);
+//  FTexts.ForEachCall(RemoveCallback, nil);
   FTexts.Clear;
   FTexts.Clear;
 end;
 end;
 
 
 procedure TvVectorialDocument.AddPath(APath: TPath);
 procedure TvVectorialDocument.AddPath(APath: TPath);
 var
 var
-  Path: PPath;
+  lPath: TPath;
   Len: Integer;
   Len: Integer;
 begin
 begin
-  Len := SizeOf(TPath);
+  lPath := TPath.Create;
+  lPath.Assign(APath);
+  FPaths.Add(Pointer(lPath));
   //WriteLn(':>TvVectorialDocument.AddPath 1 Len = ', Len);
   //WriteLn(':>TvVectorialDocument.AddPath 1 Len = ', Len);
-  Path := GetMem(Len);
   //WriteLn(':>TvVectorialDocument.AddPath 2');
   //WriteLn(':>TvVectorialDocument.AddPath 2');
-  Move(APath, Path^, Len);
   //WriteLn(':>TvVectorialDocument.AddPath 3');
   //WriteLn(':>TvVectorialDocument.AddPath 3');
-  FPaths.Add(Path);
   //WriteLn(':>TvVectorialDocument.AddPath 4');
   //WriteLn(':>TvVectorialDocument.AddPath 4');
 end;
 end;
 
 
@@ -341,11 +392,19 @@ end;
   @see    StartPath, AddPointToPath
   @see    StartPath, AddPointToPath
 }
 }
 procedure TvVectorialDocument.StartPath(AX, AY: Double);
 procedure TvVectorialDocument.StartPath(AX, AY: Double);
+var
+  segment: T2DSegment;
 begin
 begin
+  ClearTmpPath();
+
   FTmpPath.Len := 1;
   FTmpPath.Len := 1;
-  FTmpPath.Points[0].SegmentType := stMoveTo;
-  FTmpPath.Points[0].X := AX;
-  FTmpPath.Points[0].Y := AY;
+  segment := T2DSegment.Create;
+  segment.SegmentType := stMoveTo;
+  segment.X := AX;
+  segment.Y := AY;
+
+  FTmpPath.Points := segment;
+  FTmpPath.PointsEnd := segment;
 end;
 end;
 
 
 {@@
 {@@
@@ -360,60 +419,69 @@ end;
 }
 }
 procedure TvVectorialDocument.AddLineToPath(AX, AY: Double);
 procedure TvVectorialDocument.AddLineToPath(AX, AY: Double);
 var
 var
-  L: Integer;
+  segment: T2DSegment;
 begin
 begin
-  L := FTmpPath.Len;
-  Inc(FTmpPath.Len);
-  FTmpPath.Points[L].SegmentType := st2DLine;
-  FTmpPath.Points[L].X := AX;
-  FTmpPath.Points[L].Y := AY;
+  segment := T2DSegment.Create;
+  segment.SegmentType := st2DLine;
+  segment.X := AX;
+  segment.Y := AY;
+
+  AppendSegmentToTmpPath(segment);
 end;
 end;
 
 
 procedure TvVectorialDocument.AddLineToPath(AX, AY, AZ: Double);
 procedure TvVectorialDocument.AddLineToPath(AX, AY, AZ: Double);
 var
 var
-  L: Integer;
+  segment: T3DSegment;
 begin
 begin
-  L := FTmPPath.Len;
-  Inc(FTmPPath.Len);
-  FTmPPath.Points[L].SegmentType := st3DLine;
-  FTmPPath.Points[L].X := AX;
-  FTmPPath.Points[L].Y := AY;
-  FTmPPath.Points[L].Z := AZ;
+  segment := T3DSegment.Create;
+  segment.SegmentType := st3DLine;
+  segment.X := AX;
+  segment.Y := AY;
+  segment.Z := AZ;
+
+  AppendSegmentToTmpPath(segment);
 end;
 end;
 
 
+{@@
+  Adds a bezier element to the path. It starts where the previous element ended
+  and it goes throw the control points [AX1, AY1] and [AX2, AY2] and ends
+  in [AX3, AY3].
+}
 procedure TvVectorialDocument.AddBezierToPath(AX1, AY1, AX2, AY2, AX3,
 procedure TvVectorialDocument.AddBezierToPath(AX1, AY1, AX2, AY2, AX3,
   AY3: Double);
   AY3: Double);
 var
 var
-  L: Integer;
+  segment: T2DBezierSegment;
 begin
 begin
-  L := FTmPPath.Len;
-  Inc(FTmPPath.Len);
-  FTmPPath.Points[L].SegmentType := st2DBezier;
-  FTmPPath.Points[L].X := AX3;
-  FTmPPath.Points[L].Y := AY3;
-  FTmPPath.Points[L].X2 := AX1;
-  FTmPPath.Points[L].Y2 := AY1;
-  FTmPPath.Points[L].X3 := AX2;
-  FTmPPath.Points[L].Y3 := AY2;
+  segment := T2DBezierSegment.Create;
+  segment.SegmentType := st2DBezier;
+  segment.X := AX3;
+  segment.Y := AY3;
+  segment.X2 := AX1;
+  segment.Y2 := AY1;
+  segment.X3 := AX2;
+  segment.Y3 := AY2;
+
+  AppendSegmentToTmpPath(segment);
 end;
 end;
 
 
 procedure TvVectorialDocument.AddBezierToPath(AX1, AY1, AZ1, AX2, AY2, AZ2,
 procedure TvVectorialDocument.AddBezierToPath(AX1, AY1, AZ1, AX2, AY2, AZ2,
   AX3, AY3, AZ3: Double);
   AX3, AY3, AZ3: Double);
 var
 var
-  L: Integer;
+  segment: T3DBezierSegment;
 begin
 begin
-  L := FTmPPath.Len;
-  Inc(FTmPPath.Len);
-  FTmPPath.Points[L].SegmentType := st3DBezier;
-  FTmPPath.Points[L].X := AX3;
-  FTmPPath.Points[L].Y := AY3;
-  FTmPPath.Points[L].Z := AZ3;
-  FTmPPath.Points[L].X2 := AX1;
-  FTmPPath.Points[L].Y2 := AY1;
-  FTmPPath.Points[L].Z2 := AZ1;
-  FTmPPath.Points[L].X3 := AX2;
-  FTmPPath.Points[L].Y3 := AY2;
-  FTmPPath.Points[L].Z3 := AZ2;
+  segment := T3DBezierSegment.Create;
+  segment.SegmentType := st3DBezier;
+  segment.X := AX3;
+  segment.Y := AY3;
+  segment.Z := AZ3;
+  segment.X2 := AX1;
+  segment.Y2 := AY1;
+  segment.Z2 := AZ1;
+  segment.X3 := AX2;
+  segment.Y3 := AY2;
+  segment.Z3 := AZ2;
+
+  AppendSegmentToTmpPath(segment);
 end;
 end;
 
 
 {@@
 {@@
@@ -430,15 +498,14 @@ procedure TvVectorialDocument.EndPath();
 begin
 begin
   if FTmPPath.Len = 0 then Exit;
   if FTmPPath.Len = 0 then Exit;
   AddPath(FTmPPath);
   AddPath(FTmPPath);
-  FTmPPath.Len := 0;
+  ClearTmpPath();
 end;
 end;
 
 
 procedure TvVectorialDocument.AddText(AX, AY, AZ: Double; FontName: string; FontSize: integer; AText: utf8string);
 procedure TvVectorialDocument.AddText(AX, AY, AZ: Double; FontName: string; FontSize: integer; AText: utf8string);
 var
 var
-  lText: PText;
+  lText: TvText;
 begin
 begin
-  lText := GetMem(SizeOf(TvText));
-  FillChar(lText^, SizeOf(TvText), 0);
+  lText := TvText.Create;
   lText.Value := AText;
   lText.Value := AText;
   lText.X := AX;
   lText.X := AX;
   lText.Y := AY;
   lText.Y := AY;
@@ -495,6 +562,40 @@ begin
   if Result = nil then raise Exception.Create('Unsuported vector graphics format.');
   if Result = nil then raise Exception.Create('Unsuported vector graphics format.');
 end;
 end;
 
 
+procedure TvVectorialDocument.ClearTmpPath();
+var
+  segment, oldsegment: TPathSegment;
+begin
+//  segment := FTmpPath.Points;
+// Don't free segments, because they are used when the path is added
+//  while segment <> nil do
+//  begin
+//    oldsegment := segment;
+//    segment := segment^.Next;
+//    oldsegment^.Free;
+//  end;
+
+  FTmpPath.Points := nil;
+  FTmpPath.PointsEnd := nil;
+  FTmpPath.Len := 0;
+end;
+
+procedure TvVectorialDocument.AppendSegmentToTmpPath(ASegment: TPathSegment);
+var
+  L: Integer;
+begin
+  if FTmpPath.PointsEnd = nil then
+    Exception.Create('[TvVectorialDocument.AppendSegmentToTmpPath]' + Str_Error_Nil_Path);
+
+  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;
+end;
+
 {@@
 {@@
   Writes the document to a file.
   Writes the document to a file.
 
 
@@ -624,7 +725,7 @@ begin
 
 
   if FPaths.Items[ANum] = nil then raise Exception.Create('TvVectorialDocument.GetPath: Invalid Path number');
   if FPaths.Items[ANum] = nil then raise Exception.Create('TvVectorialDocument.GetPath: Invalid Path number');
 
 
-  Result := PPath(FPaths.Items[ANum])^;
+  Result := TPath(FPaths.Items[ANum]);
 end;
 end;
 
 
 function TvVectorialDocument.GetPathCount: Integer;
 function TvVectorialDocument.GetPathCount: Integer;
@@ -638,7 +739,7 @@ begin
 
 
   if FTexts.Items[ANum] = nil then raise Exception.Create('TvVectorialDocument.GetText: Invalid Text number');
   if FTexts.Items[ANum] = nil then raise Exception.Create('TvVectorialDocument.GetText: Invalid Text number');
 
 
-  Result := PText(FTexts.Items[ANum])^;
+  Result := TvText(FTexts.Items[ANum]);
 end;
 end;
 
 
 function TvVectorialDocument.GetTextCount: Integer;
 function TvVectorialDocument.GetTextCount: Integer;
@@ -751,6 +852,34 @@ begin
 
 
 end;
 end;
 
 
+{ TPath }
+
+procedure TPath.Assign(APath: TPath);
+begin
+  Len := APath.Len;
+  Points := APath.Points;
+  PointsEnd := APath.PointsEnd;
+  CurPoint := APath.CurPoint;
+end;
+
+function TPath.Count(): TPathSegment;
+begin
+
+end;
+
+procedure TPath.PrepareForSequentialReading;
+begin
+  CurPoint := nil;
+end;
+
+function TPath.Next(): TPathSegment;
+begin
+  if CurPoint = nil then Result := Points
+  else Result := CurPoint.Next;
+
+  CurPoint := Result;
+end;
+
 finalization
 finalization
 
 
   SetLength(GvVectorialFormats, 0);
   SetLength(GvVectorialFormats, 0);

+ 16 - 11
packages/fpvectorial/src/fpvtocanvas.pas

@@ -34,6 +34,8 @@ var
   i, j, k: Integer;
   i, j, k: Integer;
   PosX, PosY: Integer; // Not modified by ADestX, etc
   PosX, PosY: Integer; // Not modified by ADestX, etc
   CurSegment: TPathSegment;
   CurSegment: TPathSegment;
+  Cur2DSegment: T2DSegment absolute CurSegment;
+  Cur2DBSegment: T2DBezierSegment absolute CurSegment;
   // For bezier
   // For bezier
   CurX, CurY: Integer; // Not modified by ADestX, etc
   CurX, CurY: Integer; // Not modified by ADestX, etc
   CurveLength: Integer;
   CurveLength: Integer;
@@ -51,15 +53,18 @@ begin
   for i := 0 to ASource.PathCount - 1 do
   for i := 0 to ASource.PathCount - 1 do
   begin
   begin
     //WriteLn('i = ', i);
     //WriteLn('i = ', i);
-    for j := 0 to Length(ASource.Paths[i].Points) - 1 do
+    ASource.Paths[i].PrepareForSequentialReading;
+
+    for j := 0 to ASource.Paths[i].Len - 1 do
     begin
     begin
       //WriteLn('j = ', j);
       //WriteLn('j = ', j);
-      CurSegment := ASource.Paths[i].Points[j];
+      CurSegment := TPathSegment(ASource.Paths[i].Next());
+
       case CurSegment.SegmentType of
       case CurSegment.SegmentType of
       st2DLine, st3DLine:
       st2DLine, st3DLine:
       begin
       begin
-        PosX := Round(CurSegment.X);
-        PosY := Round(CurSegment.Y);
+        PosX := Round(Cur2DSegment.X);
+        PosY := Round(Cur2DSegment.Y);
         ADest.LineTo(
         ADest.LineTo(
           Round(ADestX + AMulX * PosX),
           Round(ADestX + AMulX * PosX),
           Round(ADestY + AMulY * PosY)
           Round(ADestY + AMulY * PosY)
@@ -70,21 +75,21 @@ begin
       st2DBezier, st3DBezier:
       st2DBezier, st3DBezier:
       begin
       begin
         CurveLength :=
         CurveLength :=
-          Round(sqrt(sqr(CurSegment.X3 - PosX) + sqr(CurSegment.Y3 - PosY))) +
-          Round(sqrt(sqr(CurSegment.X2 - CurSegment.X3) + sqr(CurSegment.Y2 - CurSegment.Y3))) +
-          Round(sqrt(sqr(CurSegment.X - CurSegment.X3) + sqr(CurSegment.Y - CurSegment.Y3)));
+          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
         for k := 1 to CurveLength do
         begin
         begin
           t := k / CurveLength;
           t := k / CurveLength;
-          CurX := Round(sqr(1 - t) * (1 - t) * PosX + 3 * t * sqr(1 - t) * CurSegment.X2 + 3 * t * t * (1 - t) * CurSegment.X3 + t * t * t * CurSegment.X);
-          CurY := Round(sqr(1 - t) * (1 - t) * PosY + 3 * t * sqr(1 - t) * CurSegment.Y2 + 3 * t * t * (1 - t) * CurSegment.Y3 + t * t * t * CurSegment.Y);
+          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(
           ADest.LineTo(
             Round(ADestX + AMulX * CurX),
             Round(ADestX + AMulX * CurX),
             Round(ADestY + AMulY * CurY));
             Round(ADestY + AMulY * CurY));
         end;
         end;
-        PosX := Round(CurSegment.X);
-        PosY := Round(CurSegment.Y);
+        PosX := Round(Cur2DBSegment.X);
+        PosY := Round(Cur2DBSegment.Y);
       end;
       end;
       end;
       end;
     end;
     end;

+ 16 - 9
packages/fpvectorial/src/svgvectorialwriter.pas

@@ -81,6 +81,9 @@ var
   lPath: TPath;
   lPath: TPath;
   PtX, PtY, OldPtX, OldPtY: double;
   PtX, PtY, OldPtX, OldPtY: double;
   BezierCP1X, BezierCP1Y, BezierCP2X, BezierCP2Y: double;
   BezierCP1X, BezierCP1Y, BezierCP2X, BezierCP2Y: double;
+  segment: TPathSegment;
+  l2DSegment: T2DSegment absolute segment;
+  l2DBSegment: T2DBezierSegment absolute segment;
 begin
 begin
   for i := 0 to AData.GetPathCount() - 1 do
   for i := 0 to AData.GetPathCount() - 1 do
   begin
   begin
@@ -89,38 +92,42 @@ begin
 
 
     PathStr := '';
     PathStr := '';
     lPath := AData.GetPath(i);
     lPath := AData.GetPath(i);
+    lPath.PrepareForSequentialReading;
+
     for j := 0 to lPath.Len - 1 do
     for j := 0 to lPath.Len - 1 do
     begin
     begin
-      if (lPath.Points[j].SegmentType <> st2DLine)
-        and (lPath.Points[j].SegmentType <> stMoveTo)
-        and (lPath.Points[j].SegmentType <> st2DBezier)
+      segment := TPathSegment(lPath.Next());
+
+      if (segment.SegmentType <> st2DLine)
+        and (segment.SegmentType <> stMoveTo)
+        and (segment.SegmentType <> st2DBezier)
         then Break; // unsupported line type
         then Break; // unsupported line type
 
 
       // Coordinate conversion from fpvectorial to SVG
       // Coordinate conversion from fpvectorial to SVG
       ConvertFPVCoordinatesToSVGCoordinates(
       ConvertFPVCoordinatesToSVGCoordinates(
-        AData, lPath.Points[j].X, lPath.Points[j].Y, PtX, PtY);
+        AData, l2DSegment.X, l2DSegment.Y, PtX, PtY);
       PtX := PtX - OldPtX;
       PtX := PtX - OldPtX;
       PtY := PtY - OldPtY;
       PtY := PtY - OldPtY;
 
 
-      if (lPath.Points[j].SegmentType = stMoveTo) then
+      if (segment.SegmentType = stMoveTo) then
       begin
       begin
         PathStr := PathStr + 'm '
         PathStr := PathStr + 'm '
           + FloatToStr(PtX, FPointSeparator) + ','
           + FloatToStr(PtX, FPointSeparator) + ','
           + FloatToStr(PtY, FPointSeparator) + ' ';
           + FloatToStr(PtY, FPointSeparator) + ' ';
       end
       end
-      else if (lPath.Points[j].SegmentType = st2DLine) then
+      else if (segment.SegmentType = st2DLine) then
       begin
       begin
         PathStr := PathStr + 'l '
         PathStr := PathStr + 'l '
           + FloatToStr(PtX, FPointSeparator) + ','
           + FloatToStr(PtX, FPointSeparator) + ','
           + FloatToStr(PtY, FPointSeparator) + ' ';
           + FloatToStr(PtY, FPointSeparator) + ' ';
       end
       end
-      else if (lPath.Points[j].SegmentType = st2DBezier) then
+      else if (segment.SegmentType = st2DBezier) then
       begin
       begin
         // Converts all coordinates to absolute values
         // Converts all coordinates to absolute values
         ConvertFPVCoordinatesToSVGCoordinates(
         ConvertFPVCoordinatesToSVGCoordinates(
-          AData, lPath.Points[j].X2, lPath.Points[j].Y2, BezierCP1X, BezierCP1Y);
+          AData, l2DBSegment.X2, l2DBSegment.Y2, BezierCP1X, BezierCP1Y);
         ConvertFPVCoordinatesToSVGCoordinates(
         ConvertFPVCoordinatesToSVGCoordinates(
-          AData, lPath.Points[j].X3, lPath.Points[j].Y3, BezierCP2X, BezierCP2Y);
+          AData, l2DBSegment.X3, l2DBSegment.Y3, BezierCP2X, BezierCP2Y);
 
 
         // Transforms them into values relative to the initial point
         // Transforms them into values relative to the initial point
         BezierCP1X := BezierCP1X - OldPtX;
         BezierCP1X := BezierCP1X - OldPtX;