summaryrefslogtreecommitdiff
path: root/packages/fpvectorial
diff options
context:
space:
mode:
authorsekelsenmat <sekelsenmat@3ad0048d-3df7-0310-abae-a5850022a9f2>2011-01-14 14:45:03 +0000
committersekelsenmat <sekelsenmat@3ad0048d-3df7-0310-abae-a5850022a9f2>2011-01-14 14:45:03 +0000
commit355f1c0fe2f5e494682e501c5dd25098fe335773 (patch)
treec9f7a1a5612868704958214cea0d8a7acaad3ed1 /packages/fpvectorial
parent52e8206918f0a8490e46106b42075b0b9028daef (diff)
downloadfpc-355f1c0fe2f5e494682e501c5dd25098fe335773.tar.gz
Adds a DXF reader and fixes an error in the Canvas output
git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@16765 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'packages/fpvectorial')
-rw-r--r--packages/fpvectorial/src/dxfvectorialreader.pas300
-rw-r--r--packages/fpvectorial/src/fpvtocanvas.pas13
2 files changed, 309 insertions, 4 deletions
diff --git a/packages/fpvectorial/src/dxfvectorialreader.pas b/packages/fpvectorial/src/dxfvectorialreader.pas
new file mode 100644
index 0000000000..a983332b64
--- /dev/null
+++ b/packages/fpvectorial/src/dxfvectorialreader.pas
@@ -0,0 +1,300 @@
+{
+Reads DXF files
+
+License: The same modified LGPL as the Free Pascal RTL
+ See the file COPYING.modifiedLGPL for more details
+
+AUTHORS: Felipe Monteiro de Carvalho
+
+DXF is composed by records written in ASCII with the following structure:
+
+0
+SECTION
+section_number
+SECTION_NAME
+<data>
+0
+ENDSEC
+0
+
+after all section end there is:
+
+EOF
+
+}
+unit dxfvectorialreader;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils,
+ fpvectorial;
+
+type
+
+ { Used by tcutils.SeparateString }
+ T10Strings = array[0..9] of shortstring;
+
+ { TvDXFVectorialReader }
+
+ TvDXFVectorialReader = class(TvCustomVectorialReader)
+ private
+ LineStartX, LineStartY, LineStartZ: Double;
+ LineEndX, LineEndY, LineEndZ: Double;
+ function SeparateString(AString: string; ASeparator: Char): T10Strings;
+ function ReadSection(AStrings: TStrings; var AIndex: Integer; AData: TvVectorialDocument): Boolean;
+ function ReadENTITIES(AStrings: TStrings; var AIndex: Integer; AData: TvVectorialDocument): Boolean;
+ function ReadENTITIES_LINE(AStrings: TStrings; var AIndex: Integer; AData: TvVectorialDocument): Boolean;
+ function GetCoordinate(AStr: shortstring): Integer;
+ function GetCoordinateValue(AStr: shortstring): Double;
+ public
+ { General reading methods }
+ procedure ReadFromStrings(AStrings: TStrings; AData: TvVectorialDocument); override;
+ end;
+
+implementation
+
+{$define FPVECTORIALDEBUG}
+
+const
+ { Coordinate constants }
+
+ INT_COORDINATE_NONE = 0;
+ INT_COORDINATE_X = 1;
+ INT_COORDINATE_Y = 2;
+ INT_COORDINATE_Z = 3;
+
+ { GCode constants }
+
+ STR_GCODE_LINEAR_MOVE = 'G01';
+ STR_GCODE_STEPPER_MOVE = 'S01';
+ STR_GCODE_2DBEZIER_MOVE = 'B02';
+ STR_GCODE_3DBEZIER_MOVE = 'B03';
+ STR_GCODE_DRILL_UP = 'P01';
+ STR_GCODE_DRILL_DOWN = 'P02';
+
+{ TvAvisoCNCGCodeReader }
+
+{@@
+ Reads a string and separates it in substring
+ using ASeparator to delimite them.
+
+ Limits:
+
+ Number of substrings: 10 (indexed 0 to 9)
+ Length of each substring: 255 (they are shortstrings)
+}
+function TvDXFVectorialReader.SeparateString(AString: string; ASeparator: Char): T10Strings;
+var
+ i, CurrentPart: Integer;
+begin
+ CurrentPart := 0;
+
+ { Clears the result }
+ for i := 0 to 9 do Result[i] := '';
+
+ { Iterates througth the string, filling strings }
+ for i := 1 to Length(AString) do
+ begin
+ if Copy(AString, i, 1) = ASeparator then
+ begin
+ Inc(CurrentPart);
+
+ { Verifies if the string capacity wasn't exceeded }
+ if CurrentPart > 9 then Exit;
+ end
+ else
+ Result[CurrentPart] := Result[CurrentPart] + Copy(AString, i, 1);
+ end;
+end;
+
+{@@
+ returns If an end of file marker was found
+}
+function TvDXFVectorialReader.ReadSection(
+ AStrings: TStrings; var AIndex: Integer; AData: TvVectorialDocument): Boolean;
+var
+ DestX, DestY, DestZ: Double;
+ StrSectionNum, StrSectionName: string;
+ IntSectionNum, i: Integer;
+begin
+ Result := False;
+
+ // Check if there is minimal space for a section
+ if AIndex+5 > AStrings.Count then
+ begin
+ {$ifdef FPVECTORIALDEBUG}
+ WriteLn('Not enough space for a section');
+ {$endif}
+ Exit(True);
+ end;
+
+ // Check of the EOF marker
+ StrSectionName := Trim(AStrings.Strings[AIndex+1]);
+ if StrSectionName = 'EOF' then
+ begin
+ {$ifdef FPVECTORIALDEBUG}
+ WriteLn('EOF found');
+ {$endif}
+ Exit(True);
+ end;
+
+ // Now read and process the section name
+ StrSectionNum := AStrings.Strings[AIndex+2];
+ IntSectionNum := StrToInt(Trim(StrSectionNum));
+ StrSectionName := AStrings.Strings[AIndex+3];
+
+ {$ifdef FPVECTORIALDEBUG}
+ WriteLn('TvDXFVectorialReader.ReadSection ' + StrSectionName);
+ {$endif}
+
+ if (StrSectionName = 'HEADER') or
+ (StrSectionName = 'CLASSES') or
+ (StrSectionName = 'TABLES') or
+ (StrSectionName = 'BLOCKS') or
+ (StrSectionName = 'OBJECTS') or
+ (StrSectionName = 'THUMBNAILIMAGE') then
+ begin
+ // We don't care about contents here, so let's just find the last section and get out of here.
+ for i := AIndex + 4 to AStrings.Count - 1 do
+ begin
+ if AStrings.Strings[i] = 'ENDSEC' then
+ begin
+ AIndex := i + 1;
+ Exit;
+ end;
+ end;
+ // If we reached here, the section in incomplete
+ raise Exception.Create('TvDXFVectorialReader.ReadSection: ENDSEC was not found in the SECTION');
+ end
+ else if StrSectionName = 'ENTITIES' then
+ begin
+ AIndex := AIndex + 4;
+ while not ReadENTITIES(AStrings, AIndex, AData) do ;
+ end;
+ {else
+ begin
+ end;}
+end;
+
+function TvDXFVectorialReader.ReadENTITIES(AStrings: TStrings;
+ var AIndex: Integer; AData: TvVectorialDocument): Boolean;
+var
+ StrSectionNum, StrSectionName: string;
+ IntSectionNum, i: Integer;
+begin
+ Result := False;
+
+ // Now read and process the item name
+ StrSectionName := AStrings.Strings[AIndex+1];
+
+ {$ifdef FPVECTORIALDEBUG}
+ WriteLn('TvDXFVectorialReader.ReadENTITIES ', StrSectionName);
+ {$endif}
+
+ if StrSectionName = 'ENDSEC' then
+ begin
+ Inc(AIndex, 2);
+ Exit(True);
+ end
+ else if StrSectionName = 'LINE' then
+ begin
+ // Initial values
+ LineStartX := 0;
+ LineStartY := 0;
+ LineStartZ := 0;
+ LineEndX := 0;
+ LineEndY := 0;
+ LineEndZ := 0;
+
+ // Read the data of the line
+ Inc(AIndex, 2);
+ while not ReadENTITIES_LINE(AStrings, AIndex, AData) do ;
+
+ // And now write it
+ {$ifdef FPVECTORIALDEBUG}
+ WriteLn(Format('Adding Line from %f,%f to %f,%f', [LineStartX, LineStartY, LineEndX, LineEndY]));
+ {$endif}
+ AData.StartPath(LineStartX, LineStartY);
+ AData.AddLineToPath(LineEndX, LineEndY);
+ AData.EndPath();
+ end;
+end;
+
+function TvDXFVectorialReader.ReadENTITIES_LINE(AStrings: TStrings;
+ var AIndex: Integer; AData: TvVectorialDocument): Boolean;
+var
+ StrSectionNum, StrSectionValue: string;
+ IntSectionNum: Integer;
+ FloatSectionValue: double;
+begin
+ Result := False;
+
+ // Now read and process the item name
+ StrSectionNum := AStrings.Strings[AIndex];
+ StrSectionValue := AStrings.Strings[AIndex+1];
+
+ if (StrSectionValue = 'LINE') or
+ (StrSectionValue = 'ENDSEC') then
+ begin
+ Exit(True);
+ end
+ else
+ begin
+ Inc(AIndex, 2);
+
+ IntSectionNum := StrToInt(Trim(StrSectionNum));
+ FloatSectionValue := StrToFloat(Trim(StrSectionValue));
+
+ case IntSectionNum of
+ 10: LineStartX := FloatSectionValue;
+ 20: LineStartY := FloatSectionValue;
+ 30: LineStartZ := FloatSectionValue;
+ 11: LineEndX := FloatSectionValue;
+ 21: LineEndY := FloatSectionValue;
+ 31: LineEndZ := FloatSectionValue;
+ end;
+ end;
+end;
+
+function TvDXFVectorialReader.GetCoordinate(AStr: shortstring): Integer;
+begin
+ Result := INT_COORDINATE_NONE;
+
+ if AStr = '' then Exit
+ else if AStr[1] = 'X' then Result := INT_COORDINATE_X
+ else if AStr[1] = 'Y' then Result := INT_COORDINATE_Y
+ else if AStr[1] = 'Z' then Result := INT_COORDINATE_Z;
+end;
+
+function TvDXFVectorialReader.GetCoordinateValue(AStr: shortstring): Double;
+begin
+ Result := 0.0;
+
+ if Length(AStr) <= 1 then Exit;
+
+ Result := StrToFloat(Copy(AStr, 2, Length(AStr) - 1));
+end;
+
+{@@
+ The information of each separate path is lost in G-Code files
+ Only one path uniting all of them is created when reading G-Code
+}
+procedure TvDXFVectorialReader.ReadFromStrings(AStrings: TStrings;
+ AData: TvVectorialDocument);
+var
+ i: Integer;
+begin
+ i := 0;
+ while i < AStrings.Count - 1 do
+ if ReadSection(AStrings, i, AData) then Break;
+end;
+
+initialization
+
+ RegisterVectorialReader(TvDXFVectorialReader, vfDXF);
+
+end.
+
diff --git a/packages/fpvectorial/src/fpvtocanvas.pas b/packages/fpvectorial/src/fpvtocanvas.pas
index d5977019a1..48429f0930 100644
--- a/packages/fpvectorial/src/fpvtocanvas.pas
+++ b/packages/fpvectorial/src/fpvtocanvas.pas
@@ -61,13 +61,18 @@ begin
CurSegment := TPathSegment(ASource.Paths[i].Next());
case CurSegment.SegmentType of
+ stMoveTo:
+ begin
+ ADest.MoveTo(
+ Round(ADestX + AMulX * Cur2DSegment.X),
+ Round(ADestY + AMulY * Cur2DSegment.Y)
+ );
+ end;
st2DLine, st3DLine:
begin
- PosX := Round(Cur2DSegment.X);
- PosY := Round(Cur2DSegment.Y);
ADest.LineTo(
- Round(ADestX + AMulX * PosX),
- Round(ADestY + AMulY * PosY)
+ Round(ADestX + AMulX * Cur2DSegment.X),
+ Round(ADestY + AMulY * Cur2DSegment.Y)
);
end;
{ To draw a bezier we need to divide the interval in parts and make