diff options
| author | sekelsenmat <sekelsenmat@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2011-01-14 14:45:03 +0000 |
|---|---|---|
| committer | sekelsenmat <sekelsenmat@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2011-01-14 14:45:03 +0000 |
| commit | 355f1c0fe2f5e494682e501c5dd25098fe335773 (patch) | |
| tree | c9f7a1a5612868704958214cea0d8a7acaad3ed1 /packages/fpvectorial | |
| parent | 52e8206918f0a8490e46106b42075b0b9028daef (diff) | |
| download | fpc-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.pas | 300 | ||||
| -rw-r--r-- | packages/fpvectorial/src/fpvtocanvas.pas | 13 |
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 |
