Starts implementing svg writer and improves test app and pdf reader

git-svn-id: trunk@15799 -
This commit is contained in:
sekelsenmat 2010-08-13 14:56:40 +00:00
parent eb2581946c
commit 6403d462d2
8 changed files with 215 additions and 43 deletions

View File

@ -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

View File

@ -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;

View File

@ -4,6 +4,9 @@
<Version Value="9"/>
<PathDelim Value="\"/>
<General>
<Flags>
<AlwaysBuild Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<Title Value="cdr2svg_visual"/>
<UseXPManifest Value="True"/>
@ -39,7 +42,7 @@
<Unit1>
<Filename Value="cdr2svg_mainform.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="Form1"/>
<ComponentName Value="formCDR2SVG"/>
<ResourceBaseClass Value="Form"/>
<UnitName Value="cdr2svg_mainform"/>
</Unit1>
@ -70,7 +73,7 @@
</Other>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Exceptions Count="4">
<Item1>
<Name Value="EAbort"/>
</Item1>
@ -80,6 +83,9 @@
<Item3>
<Name Value="EFOpenError"/>
</Item3>
<Item4>
<Name Value="EConvertError"/>
</Item4>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -14,7 +14,7 @@ uses
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TformCDR2SVG, formCDR2SVG);
Application.Run;
end.

View File

@ -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;

View File

@ -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);

View File

@ -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.

View File

@ -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(' <path');
AStrings.Add(' style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"');
AStrings.Add(' d="' + PathStr + '"');
AStrings.Add(' id="path' + IntToStr(i) + '" />');
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('<?xml version="1.0" encoding="UTF-8" standalone="no"?>');
AStrings.Add('<!-- Created with fpVectorial (http://wiki.lazarus.freepascal.org/fpvectorial) -->');
AStrings.Add('');
AStrings.Add('<svg');
AStrings.Add(' xmlns:dc="http://purl.org/dc/elements/1.1/"');
AStrings.Add(' xmlns:cc="http://creativecommons.org/ns#"');
AStrings.Add(' xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"');
AStrings.Add(' xmlns:svg="http://www.w3.org/2000/svg"');
AStrings.Add(' xmlns="http://www.w3.org/2000/svg"');
AStrings.Add(' xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"');
WriteDocumentSize(AStrings, AData);
AStrings.Add(' id="svg2"');
AStrings.Add(' version="1.1"');
WriteDocumentName(AStrings, AData);
// Now data
AStrings.Add(' <g id="layer1">');
WritePaths(AStrings, AData);
AStrings.Add(' </g>');
// finalization
AStrings.Add('</svg>');
end;
initialization