diff --git a/packages/fpvectorial/examples/cdr2svg_mainform.lfm b/packages/fpvectorial/examples/cdr2svg_mainform.lfm
index aa720d40e2..526e178ad8 100644
--- a/packages/fpvectorial/examples/cdr2svg_mainform.lfm
+++ b/packages/fpvectorial/examples/cdr2svg_mainform.lfm
@@ -1,10 +1,11 @@
-object Form1: TForm1
+object formCDR2SVG: TformCDR2SVG
Left = 216
- Height = 240
+ Height = 439
Top = 192
Width = 240
+ BorderStyle = bsSingle
Caption = 'cdr2svg'
- ClientHeight = 240
+ ClientHeight = 439
ClientWidth = 240
LCLVersion = '0.9.29'
object Label1: TLabel
@@ -60,21 +61,36 @@ object Form1: TForm1
TabOrder = 1
end
object buttonConvert: TButton
- Left = 32
+ Left = 87
Height = 25
Top = 200
- Width = 75
+ Width = 67
Caption = 'Convert'
OnClick = buttonConvertClick
TabOrder = 2
end
object buttonQuit: TButton
- Left = 136
+ Left = 176
Height = 25
Top = 200
- Width = 75
+ Width = 59
Caption = 'Quit'
OnClick = buttonQuitClick
TabOrder = 3
end
+ object imagePreview: TImage
+ Left = 8
+ Height = 202
+ Top = 232
+ Width = 224
+ end
+ object buttonVisualize: TButton
+ Left = 8
+ Height = 25
+ Top = 200
+ Width = 59
+ Caption = 'Visualize'
+ OnClick = buttonVisualizeClick
+ TabOrder = 4
+ end
end
diff --git a/packages/fpvectorial/examples/cdr2svg_mainform.pas b/packages/fpvectorial/examples/cdr2svg_mainform.pas
index 9096afe2e2..62a9f393d7 100644
--- a/packages/fpvectorial/examples/cdr2svg_mainform.pas
+++ b/packages/fpvectorial/examples/cdr2svg_mainform.pas
@@ -6,57 +6,85 @@ interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
- EditBtn;
+ EditBtn, ExtCtrls;
type
- { TForm1 }
+ { TformCDR2SVG }
- TForm1 = class(TForm)
+ TformCDR2SVG = class(TForm)
+ buttonVisualize: TButton;
buttonConvert: TButton;
buttonQuit: TButton;
editInput: TFileNameEdit;
editOutput: TFileNameEdit;
+ imagePreview: TImage;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
procedure buttonConvertClick(Sender: TObject);
procedure buttonQuitClick(Sender: TObject);
+ procedure buttonVisualizeClick(Sender: TObject);
private
{ private declarations }
+ function CheckInput(): Boolean;
public
{ public declarations }
end;
var
- Form1: TForm1;
+ formCDR2SVG: TformCDR2SVG;
implementation
uses
- fpvectorial, cdrvectorialreader, svgvectorialwriter;
+ fpvectorial, cdrvectorialreader, svgvectorialwriter, pdfvectorialreader,
+ fpvtocanvas;
{$R *.lfm}
-{ TForm1 }
+{ TformCDR2SVG }
-procedure TForm1.buttonQuitClick(Sender: TObject);
+procedure TformCDR2SVG.buttonQuitClick(Sender: TObject);
begin
Close;
end;
-procedure TForm1.buttonConvertClick(Sender: TObject);
+procedure TformCDR2SVG.buttonVisualizeClick(Sender: TObject);
var
Vec: TvVectorialDocument;
begin
// First check the in input
+ if not CheckInput() then Exit;
+
+ Vec := TvVectorialDocument.Create;
+ try
+ Vec.ReadFromFile(editInput.FileName, vfPDF);
+ imagePreview.Canvas.Brush.Color := clWhite;
+ imagePreview.Canvas.FillRect(0, 0, imagePreview.Width, imagePreview.Height);
+ DrawFPVectorialToCanvas(Vec, imagePreview.Canvas, 0, 0, 0.25, 0.25);
+ finally
+ Vec.Free;
+ end;
+end;
+
+function TformCDR2SVG.CheckInput(): Boolean;
+begin
// todo...
+end;
+
+procedure TformCDR2SVG.buttonConvertClick(Sender: TObject);
+var
+ Vec: TvVectorialDocument;
+begin
+ // First check the in input
+ if not CheckInput() then Exit;
// Now convert
Vec := TvVectorialDocument.Create;
try
Vec.ReadFromFile(editInput.FileName, vfPDF);
- Vec.WriteToFile(editOutPut.FileName, vfGCodeAvisoCNCPrototipoV5);
+ Vec.WriteToFile(editOutPut.FileName, vfSVG);
finally
Vec.Free;
end;
diff --git a/packages/fpvectorial/examples/cdr2svg_visual.lpi b/packages/fpvectorial/examples/cdr2svg_visual.lpi
index add68249c1..338b07f8ef 100644
--- a/packages/fpvectorial/examples/cdr2svg_visual.lpi
+++ b/packages/fpvectorial/examples/cdr2svg_visual.lpi
@@ -4,6 +4,9 @@
+
+
+
@@ -39,7 +42,7 @@
-
+
@@ -70,7 +73,7 @@
-
+
@@ -80,6 +83,9 @@
+
+
+
diff --git a/packages/fpvectorial/examples/cdr2svg_visual.lpr b/packages/fpvectorial/examples/cdr2svg_visual.lpr
index aef4846c5f..3551fefa2b 100644
--- a/packages/fpvectorial/examples/cdr2svg_visual.lpr
+++ b/packages/fpvectorial/examples/cdr2svg_visual.lpr
@@ -14,7 +14,7 @@ uses
begin
Application.Initialize;
- Application.CreateForm(TForm1, Form1);
+ Application.CreateForm(TformCDR2SVG, formCDR2SVG);
Application.Run;
end.
diff --git a/packages/fpvectorial/src/fpvectorial.pas b/packages/fpvectorial/src/fpvectorial.pas
index 0b18f768d5..d2a50a2a9d 100644
--- a/packages/fpvectorial/src/fpvectorial.pas
+++ b/packages/fpvectorial/src/fpvectorial.pas
@@ -38,6 +38,11 @@ type
st2DLine, st2DBezier,
st3DLine, st3DBezier);
+ {@
+ The coordinates in fpvectorial are given in millimiters and
+ the starting point is in the top-left corner of the document
+ and it grows to the bottom and to the right.
+ }
TPathSegment = record
SegmentType: TSegmentType;
X, Y, Z: Double; // Z is ignored in 2D segments
@@ -617,10 +622,21 @@ begin
end;
end;
+{@@
+ The default stream writer just uses WriteToStrings
+}
procedure TvCustomVectorialWriter.WriteToStream(AStream: TStream;
AData: TvVectorialDocument);
+var
+ lStringList: TStringList;
begin
-
+ lStringList := TStringList.Create;
+ try
+ WriteToStrings(lStringList, AData);
+ lStringList.SaveToStream(AStream);
+ finally
+ lStringList.Free;
+ end;
end;
procedure TvCustomVectorialWriter.WriteToStrings(AStrings: TStrings;
diff --git a/packages/fpvectorial/src/fpvtocanvas.pas b/packages/fpvectorial/src/fpvtocanvas.pas
index c7b5ff1a4a..a75c7dc8bf 100644
--- a/packages/fpvectorial/src/fpvtocanvas.pas
+++ b/packages/fpvectorial/src/fpvtocanvas.pas
@@ -10,12 +10,12 @@ uses
fpvectorial;
procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument; ADest: TFPCustomCanvas;
- ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Integer = 1; AMulY: Integer = 1);
+ ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
implementation
procedure DrawFPVectorialToCanvas(ASource: TvVectorialDocument; ADest: TFPCustomCanvas;
- ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Integer = 1; AMulY: Integer = 1);
+ ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
var
i, j, k: Integer;
PosX, PosY: Integer; // Not modified by ADestX, etc
@@ -47,8 +47,8 @@ begin
PosX := Round(CurSegment.X);
PosY := Round(CurSegment.Y);
ADest.LineTo(
- ADestX + AMulX * PosX,
- ADestY + AMulY * PosY
+ Round(ADestX + AMulX * PosX),
+ Round(ADestY + AMulY * PosY)
);
end;
{ To draw a bezier we need to divide the interval in parts and make
@@ -66,8 +66,8 @@ begin
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);
ADest.LineTo(
- ADestX + AMulX * CurX,
- ADestY + AMulY * CurY);
+ Round(ADestX + AMulX * CurX),
+ Round(ADestY + AMulY * CurY));
end;
PosX := Round(CurSegment.X);
PosY := Round(CurSegment.Y);
diff --git a/packages/fpvectorial/src/pdfvrsemantico.pas b/packages/fpvectorial/src/pdfvrsemantico.pas
index 421e0d6175..bf2c80edfe 100644
--- a/packages/fpvectorial/src/pdfvrsemantico.pas
+++ b/packages/fpvectorial/src/pdfvrsemantico.pas
@@ -8,11 +8,16 @@ uses
Classes, SysUtils, pdfvrlexico, fpvectorial;
type
+
+ { AnSemantico }
+
AnSemantico = class
public
+ FPointSeparator, FCommaSeparator: TFormatSettings;
close_path_x: String;
close_path_y: String;
cm_a, cm_b, cm_c, cm_d, cm_e, cm_f: Real; // coordinate spaces constants
+ function StringToFloat(AStr: string): Double;
function generate(c: Command; AData: TvVectorialDocument): String;
function convert(x: String; y: String; Axis: Char): String;
function startMachine(): String;
@@ -22,6 +27,14 @@ type
implementation
+{ PDF doesn't seam very consistent when it comes to using commas or
+ points as decimal separator, so we just try both }
+function AnSemantico.StringToFloat(AStr: string): Double;
+begin
+ if Pos('.', AStr) > 0 then Result := StrToFloat(AStr, FPointSeparator)
+ else Result := StrToFloat(AStr, FCommaSeparator);
+end;
+
function AnSemantico.generate(c: Command; AData: TvVectorialDocument): String;
var
enter_line : String;
@@ -29,6 +42,7 @@ begin
{$ifdef FPVECTORIALDEBUG}
WriteLn(':> AnSemantico.generate');
{$endif}
+
enter_line:= LineEnding; //chr(13) + chr(10); // CR and LF
if ((c.code = cc_H_CLOSE_PATH) or (c.code = cc_hS_CLOSE_AND_END_PATH)) then // command h or s
@@ -69,7 +83,7 @@ begin
// Correcao para programas de desenho que geram um novo inicio no
// fim do desenho, terminamos qualquer desenho inacabado
AData.EndPath();
- AData.StartPath(StrToFloat(c.cord_x), StrToFloat(c.cord_y));
+ AData.StartPath(StringToFloat(c.cord_x), StringToFloat(c.cord_y));
close_path_x:=c.cord_x;
close_path_y:=c.cord_y;
@@ -81,7 +95,7 @@ begin
{$endif}
// Result:='G01' + ' ' + 'X' + c.cord_x + ' ' + 'Y' + c.cord_y;
- AData.AddLineToPath(StrToFloat(c.cord_x), StrToFloat(c.cord_y));
+ AData.AddLineToPath(StringToFloat(c.cord_x), StringToFloat(c.cord_y));
end;
cc_h_CLOSE_PATH: // command h
begin
@@ -90,7 +104,7 @@ begin
{$endif}
//Result:='G01' + ' ' + 'X' + c.cord_x + ' ' + 'Y' + c.cord_y;
- AData.AddLineToPath(StrToFloat(c.cord_x), StrToFloat(c.cord_y));
+ AData.AddLineToPath(StringToFloat(c.cord_x), StringToFloat(c.cord_y));
end;
cc_S_END_PATH: // command S
begin
@@ -108,7 +122,7 @@ begin
//Result:='G01' + ' ' + 'X' + c.cord_x + ' ' + 'Y' + c.cord_y + enter_line
// +'G01 Z0 // Sobe a cabeça de gravação' + enter_line;
- AData.AddLineToPath(StrToFloat(c.cord_x), StrToFloat(c.cord_y));
+ AData.AddLineToPath(StringToFloat(c.cord_x), StringToFloat(c.cord_y));
AData.EndPath();
end;
cc_c_BEZIER_TO_X_Y_USING_X2_Y2_AND_X3_Y3: // command c
@@ -120,9 +134,9 @@ begin
// +'G01 Z0 // Sobe a cabeça de gravação' + enter_line;
AData.AddBezierToPath(
- StrToFloat(c.cord_x3), StrToFloat(c.cord_y3),
- StrToFloat(c.cord_x2), StrToFloat(c.cord_y2),
- StrToFloat(c.cord_x), StrToFloat(c.cord_y)
+ StringToFloat(c.cord_x3), StringToFloat(c.cord_y3),
+ StringToFloat(c.cord_x2), StringToFloat(c.cord_y2),
+ StringToFloat(c.cord_x), StringToFloat(c.cord_y)
);
end;
cc_CONCATENATE_MATRIX: // command cm
@@ -131,12 +145,12 @@ begin
WriteLn(':> AnSemantico.cc_CONCATENATE_MATRIX');
{$endif}
- cm_a := StrToFloat(c.cord_x3);
- cm_b := StrToFloat(c.cord_y3);
- cm_c := StrToFloat(c.cord_x2);
- cm_d := StrToFloat(c.cord_y2);
- cm_e := StrToFloat(c.cord_x);
- cm_f := StrToFloat(c.cord_y);
+ cm_a := StringToFloat(c.cord_x3);
+ cm_b := StringToFloat(c.cord_y3);
+ cm_c := StringToFloat(c.cord_x2);
+ cm_d := StringToFloat(c.cord_y2);
+ cm_e := StringToFloat(c.cord_x);
+ cm_f := StringToFloat(c.cord_y);
end;
cc_RESTORE_MATRIX: // command Q
begin
@@ -169,13 +183,13 @@ begin
if (Axis = 'y') then
begin
// y' = b * x + d * y + f
- Result:=FloatToStr((cm_b*StrToFloat(x)+cm_d*StrToFloat(y)+cm_f)*(25.40/72));
+ Result:=FloatToStr((cm_b*StringToFloat(x)+cm_d*StringToFloat(y)+cm_f)*(25.40/72));
end
else
// Axis = 'x'
begin
// x' = a * x + c * y + e
- Result:=FloatToStr((cm_a*StrToFloat(x)+cm_c*StrToFloat(y)+cm_e)*(25.40/72));
+ Result:=FloatToStr((cm_a*StringToFloat(x)+cm_c*StringToFloat(y)+cm_e)*(25.40/72));
end;
end;
@@ -209,12 +223,21 @@ end;
constructor AnSemantico.Create;
begin
inherited Create;
+
cm_a:=1;
cm_b:=0;
cm_c:=0;
cm_d:=1;
cm_e:=0;
cm_f:=0;
+
+ // Format seetings to convert a string to a float
+ FPointSeparator := DefaultFormatSettings;
+ FPointSeparator.DecimalSeparator := '.';
+ FPointSeparator.ThousandSeparator := '#';// disable the thousand separator
+ FCommaSeparator := DefaultFormatSettings;
+ FCommaSeparator.DecimalSeparator := ',';
+ FCommaSeparator.ThousandSeparator := '#';// disable the thousand separator
end;
end.
diff --git a/packages/fpvectorial/src/svgvectorialwriter.pas b/packages/fpvectorial/src/svgvectorialwriter.pas
index cafd26c782..782590afe6 100644
--- a/packages/fpvectorial/src/svgvectorialwriter.pas
+++ b/packages/fpvectorial/src/svgvectorialwriter.pas
@@ -20,19 +20,102 @@ type
{ TvSVGVectorialWriter }
TvSVGVectorialWriter = class(TvCustomVectorialWriter)
+ private
+ FPointSeparator, FCommaSeparator: TFormatSettings;
+ procedure WriteDocumentSize(AStrings: TStrings; AData: TvVectorialDocument);
+ procedure WriteDocumentName(AStrings: TStrings; AData: TvVectorialDocument);
+ procedure WritePaths(AStrings: TStrings; AData: TvVectorialDocument);
public
{ General reading methods }
- procedure WriteToStream(AStream: TStream; AData: TvVectorialDocument); virtual;
+ procedure WriteToStrings(AStrings: TStrings; AData: TvVectorialDocument); override;
end;
implementation
{ TvSVGVectorialWriter }
-procedure TvSVGVectorialWriter.WriteToStream(AStream: TStream;
+procedure TvSVGVectorialWriter.WriteDocumentSize(AStrings: TStrings; AData: TvVectorialDocument);
+begin
+ AStrings.Add(' width="744.09448819"');
+ AStrings.Add(' height="1052.3622047"');
+end;
+
+procedure TvSVGVectorialWriter.WriteDocumentName(AStrings: TStrings; AData: TvVectorialDocument);
+begin
+ AStrings.Add(' sodipodi:docname="New document 1">');
+end;
+
+{@@
+ SVG Coordinate system measures things in millimiters.
+ The initial point is in the bottom-left corner of the document and it grows
+ to the top and to the right.
+
+ SVG uses commas "," to separate the X,Y coordinates, so it always uses points
+ "." as decimal separators and uses no thousand separators
+}
+procedure TvSVGVectorialWriter.WritePaths(AStrings: TStrings; AData: TvVectorialDocument);
+var
+ i, j: Integer;
+ PathStr: string;
+ lPath: TPath;
+ PtX, PtY: double;
+begin
+ for i := 0 to AData.GetPathCount() - 1 do
+ begin
+ 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;
+ PtY := AData.Height - PtY;
+ PathStr := PathStr + FloatToStr(PtX, FPointSeparator) + ','
+ + FloatToStr(PtY, FPointSeparator) + ' ';
+ end;
+
+ AStrings.Add(' ');
+ end;
+end;
+
+procedure TvSVGVectorialWriter.WriteToStrings(AStrings: TStrings;
AData: TvVectorialDocument);
begin
+ // Format seetings to convert a string to a float
+ FPointSeparator := DefaultFormatSettings;
+ FPointSeparator.DecimalSeparator := '.';
+ FPointSeparator.ThousandSeparator := '#';// disable the thousand separator
+ FCommaSeparator := DefaultFormatSettings;
+ FCommaSeparator.DecimalSeparator := ',';
+ FCommaSeparator.ThousandSeparator := '#';// disable the thousand separator
+ // Headers
+ AStrings.Add('');
+ AStrings.Add('');
+ AStrings.Add('');
+ AStrings.Add('');
end;
initialization