Browse Source

Fixes the svg coordinates and svg path generation

git-svn-id: trunk@15915 -
sekelsenmat 15 years ago
parent
commit
51f23db4bd

+ 22 - 2
packages/fpvectorial/examples/fpvwritetest.pas

@@ -29,23 +29,43 @@ const
   cExtension = '.svg';
 var
   Vec: TvVectorialDocument;
+
+{$R *.res}
+
 begin
   Vec := TvVectorialDocument.Create;
   try
+    // All documents are 10cm x 10cm
+    Vec.Width := 100;
+    Vec.Height := 100;
+
     // single_line_1    One line from (0, 20) to (30, 30)
     Vec.StartPath(0, 20);
     Vec.AddLineToPath(30, 30);
     Vec.EndPath();
     Vec.WriteToFile('single_line_1' + cExtension, cFormat);
 
-    //    single_line_2    One line from (20, 30) to (30, 20)
+    // single_line_2    One line from (20, 30) to (30, 20)
     Vec.Clear;
     Vec.StartPath(20, 30);
     Vec.AddLineToPath(30, 20);
     Vec.EndPath();
     Vec.WriteToFile('single_line_2' + cExtension, cFormat);
 
-    //    polyline_1       One line from (0, 0) to (10, 10) to (20, 30) to (30, 20)
+    // single_line_3    One line from (0, 20) to (30, 30) + frame
+    Vec.Clear;
+    Vec.StartPath(0, 20);
+    Vec.AddLineToPath(30, 30);
+    Vec.EndPath();
+    Vec.StartPath(0, 0);
+    Vec.AddLineToPath(100, 0);
+    Vec.AddLineToPath(100, 100);
+    Vec.AddLineToPath(0, 100);
+    Vec.AddLineToPath(0, 0);
+    Vec.EndPath();
+    Vec.WriteToFile('single_line_3' + cExtension, cFormat);
+
+    // polyline_1       One line from (0, 0) to (10, 10) to (20, 30) to (30, 20)
     Vec.Clear;
     Vec.StartPath(0, 0);
     Vec.AddLineToPath(10, 10);

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

@@ -25,6 +25,9 @@ type
     procedure WriteDocumentSize(AStrings: TStrings; AData: TvVectorialDocument);
     procedure WriteDocumentName(AStrings: TStrings; AData: TvVectorialDocument);
     procedure WritePaths(AStrings: TStrings; AData: TvVectorialDocument);
+    procedure ConvertFPVCoordinatesToSVGCoordinates(
+      const AData: TvVectorialDocument;
+      const ASrcX, ASrcY: Double; var ADestX, ADestY: double);
   public
     { General reading methods }
     procedure WriteToStrings(AStrings: TStrings; AData: TvVectorialDocument); override;
@@ -32,6 +35,9 @@ type
 
 implementation
 
+const
+  FLOAT_MILIMETERS_PER_PIXEL = 0.3528;
+
 { TvSVGVectorialWriter }
 
 procedure TvSVGVectorialWriter.WriteDocumentSize(AStrings: TStrings; AData: TvVectorialDocument);
@@ -46,11 +52,15 @@ begin
 end;
 
 {@@
-  SVG Coordinate system measures things in whatever unit we pass to it, so we
-  choose to pass in millimiters (mm), like FPVectorial uses.
+  SVG Coordinate system measures things only in pixels, so that we have to
+  hardcode a DPI value for the screen, which is usually 72.
+  FPVectorial uses only milimeters (mm).
 
-  The initial point is in the bottom-left corner of the document and it grows
-  to the top and to the right, just like in FPVectorial.
+  The initial point in FPVectorial is in the bottom-left corner of the document
+  and it grows to the top and to the right. In SVG, on the other hand, the
+  initial point is in the top-left corner, growing to the bottom and right.
+  Besides that, coordinates in SVG are also lengths in comparison to the
+  previous point and not absolute coordinates.
 
   SVG uses commas "," to separate the X,Y coordinates, so it always uses points
   "." as decimal separators and uses no thousand separators
@@ -60,20 +70,31 @@ var
   i, j: Integer;
   PathStr: string;
   lPath: TPath;
-  PtX, PtY: double;
+  PtX, PtY, OldPtX, OldPtY: double;
 begin
   for i := 0 to AData.GetPathCount() - 1 do
   begin
+    OldPtX := 0;
+    OldPtY := 0;
+
     PathStr := 'm ';
     lPath := AData.GetPath(i);
     for j := 0 to lPath.Len - 1 do
     begin
       if lPath.Points[j].SegmentType <> st2DLine then Break; // unsupported line type
 
-      PtX := lPath.Points[j].X;
-      PtY := lPath.Points[j].Y;
-      PathStr := PathStr + FloatToStr(PtX, FPointSeparator) + 'mm,'
-        + FloatToStr(PtY, FPointSeparator) + 'mm ';
+      // Coordinate conversion from fpvectorial to SVG
+      ConvertFPVCoordinatesToSVGCoordinates(
+        AData, lPath.Points[j].X, lPath.Points[j].Y, PtX, PtY);
+      PtX := PtX - OldPtX;
+      PtY := PtY - OldPtY;
+
+      PathStr := PathStr + FloatToStr(PtX, FPointSeparator) + ','
+        + FloatToStr(PtY, FPointSeparator) + ' ';
+
+      // Store the current position for future points
+      OldPtX := OldPtX + PtX;
+      OldPtY := OldPtY + PtY;
     end;
 
     AStrings.Add('  <path');
@@ -83,6 +104,14 @@ begin
   end;
 end;
 
+procedure TvSVGVectorialWriter.ConvertFPVCoordinatesToSVGCoordinates(
+  const AData: TvVectorialDocument; const ASrcX, ASrcY: Double; var ADestX,
+  ADestY: double);
+begin
+  ADestX := ASrcX / FLOAT_MILIMETERS_PER_PIXEL;
+  ADestY := (AData.Height - ASrcY) / FLOAT_MILIMETERS_PER_PIXEL;
+end;
+
 procedure TvSVGVectorialWriter.WriteToStrings(AStrings: TStrings;
   AData: TvVectorialDocument);
 begin