You've already forked lazarus-ccr
301 lines
7.3 KiB
ObjectPascal
301 lines
7.3 KiB
ObjectPascal
![]() |
{
|
||
|
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.
|
||
|
|