Преглед изворни кода

Adds a DXF reader and fixes an error in the Canvas output

git-svn-id: trunk@16765 -
sekelsenmat пре 14 година
родитељ
комит
d260e8b2ee
3 измењених фајлова са 322 додато и 16 уклоњено
  1. 13 12
      .gitattributes
  2. 300 0
      packages/fpvectorial/src/dxfvectorialreader.pas
  3. 9 4
      packages/fpvectorial/src/fpvtocanvas.pas

+ 13 - 12
.gitattributes

@@ -2507,18 +2507,19 @@ packages/fpvectorial/examples/fpvectorialconverter.lpr svneol=native#text/plain
 packages/fpvectorial/examples/fpvwritetest.lpi svneol=native#text/plain
 packages/fpvectorial/examples/fpvwritetest.pas svneol=native#text/plain
 packages/fpvectorial/fpmake.pp svneol=native#text/plain
-packages/fpvectorial/src/avisocncgcodereader.pas svneol=native#text/plain
-packages/fpvectorial/src/avisocncgcodewriter.pas svneol=native#text/plain
-packages/fpvectorial/src/avisozlib.pas svneol=native#text/plain
-packages/fpvectorial/src/cdrvectorialreader.pas svneol=native#text/plain
-packages/fpvectorial/src/fpvectbuildunit.pas svneol=native#text/plain
-packages/fpvectorial/src/fpvectorial.pas svneol=native#text/plain
-packages/fpvectorial/src/fpvtocanvas.pas svneol=native#text/plain
-packages/fpvectorial/src/pdfvectorialreader.pas svneol=native#text/plain
-packages/fpvectorial/src/pdfvrlexico.pas svneol=native#text/plain
-packages/fpvectorial/src/pdfvrsemantico.pas svneol=native#text/plain
-packages/fpvectorial/src/pdfvrsintatico.pas svneol=native#text/plain
-packages/fpvectorial/src/svgvectorialwriter.pas svneol=native#text/plain
+packages/fpvectorial/src/avisocncgcodereader.pas svneol=native#text/pascal
+packages/fpvectorial/src/avisocncgcodewriter.pas svneol=native#text/pascal
+packages/fpvectorial/src/avisozlib.pas svneol=native#text/pascal
+packages/fpvectorial/src/cdrvectorialreader.pas svneol=native#text/pascal
+packages/fpvectorial/src/dxfvectorialreader.pas svneol=native#text/pascal
+packages/fpvectorial/src/fpvectbuildunit.pas svneol=native#text/pascal
+packages/fpvectorial/src/fpvectorial.pas svneol=native#text/pascal
+packages/fpvectorial/src/fpvtocanvas.pas svneol=native#text/pascal
+packages/fpvectorial/src/pdfvectorialreader.pas svneol=native#text/pascal
+packages/fpvectorial/src/pdfvrlexico.pas svneol=native#text/pascal
+packages/fpvectorial/src/pdfvrsemantico.pas svneol=native#text/pascal
+packages/fpvectorial/src/pdfvrsintatico.pas svneol=native#text/pascal
+packages/fpvectorial/src/svgvectorialwriter.pas svneol=native#text/pascal
 packages/fuse/Makefile svneol=native#text/plain
 packages/fuse/Makefile.fpc svneol=native#text/plain
 packages/fuse/fpmake_disabled.pp svneol=native#text/plain

+ 300 - 0
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.
+

+ 9 - 4
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