2011-01-14 14:49:45 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
|
|
2011-01-25 14:13:33 +00:00
|
|
|
after all sections there is:
|
2011-01-14 14:49:45 +00:00
|
|
|
|
|
|
|
EOF
|
|
|
|
|
|
|
|
}
|
|
|
|
unit dxfvectorialreader;
|
|
|
|
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
|
|
|
Classes, SysUtils,
|
|
|
|
fpvectorial;
|
|
|
|
|
|
|
|
type
|
|
|
|
|
|
|
|
{ Used by tcutils.SeparateString }
|
|
|
|
T10Strings = array[0..9] of shortstring;
|
|
|
|
|
2011-01-25 14:13:33 +00:00
|
|
|
TDXFToken = class;
|
|
|
|
|
|
|
|
TDXFTokens = TFPList;// TDXFToken;
|
|
|
|
|
|
|
|
TDXFToken = class
|
|
|
|
GroupCode: Integer;
|
|
|
|
StrValue: string;
|
|
|
|
FloatValue: double;
|
|
|
|
IntValue: Integer;
|
|
|
|
Childs: TDXFTokens;
|
|
|
|
constructor Create;
|
|
|
|
Destructor Destroy; override;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ TDXFTokenizer }
|
|
|
|
|
|
|
|
TDXFTokenizer = class
|
|
|
|
public
|
|
|
|
Tokens: TDXFTokens;
|
|
|
|
constructor Create;
|
|
|
|
Destructor Destroy; override;
|
|
|
|
procedure ReadFromStrings(AStrings: TStrings);
|
|
|
|
function IsENTITIES_Subsection(AStr: string): Boolean;
|
|
|
|
end;
|
|
|
|
|
2011-01-14 14:49:45 +00:00
|
|
|
{ TvDXFVectorialReader }
|
|
|
|
|
|
|
|
TvDXFVectorialReader = class(TvCustomVectorialReader)
|
|
|
|
private
|
2011-01-28 15:25:55 +00:00
|
|
|
FPointSeparator: TFormatSettings;
|
2011-01-30 14:37:28 +00:00
|
|
|
// HEADER data
|
|
|
|
ANGBASE: Double;
|
|
|
|
ANGDIR: Integer;
|
2011-01-25 16:51:57 +00:00
|
|
|
//
|
2011-01-14 14:49:45 +00:00
|
|
|
function SeparateString(AString: string; ASeparator: Char): T10Strings;
|
2011-01-30 14:37:28 +00:00
|
|
|
procedure ReadHEADER(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
2011-01-25 14:13:33 +00:00
|
|
|
procedure ReadENTITIES(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
2011-01-25 16:51:57 +00:00
|
|
|
procedure ReadENTITIES_LINE(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
2011-01-26 16:05:00 +00:00
|
|
|
procedure ReadENTITIES_ARC(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
2011-01-25 16:51:57 +00:00
|
|
|
procedure ReadENTITIES_CIRCLE(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
|
|
|
procedure ReadENTITIES_ELLIPSE(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
|
|
|
procedure ReadENTITIES_TEXT(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
2011-01-14 14:49:45 +00:00
|
|
|
function GetCoordinateValue(AStr: shortstring): Double;
|
|
|
|
public
|
|
|
|
{ General reading methods }
|
2011-01-25 14:13:33 +00:00
|
|
|
Tokenizer: TDXFTokenizer;
|
2011-01-25 14:43:07 +00:00
|
|
|
constructor Create; override;
|
2011-01-25 14:13:33 +00:00
|
|
|
Destructor Destroy; override;
|
2011-01-14 14:49:45 +00:00
|
|
|
procedure ReadFromStrings(AStrings: TStrings; AData: TvVectorialDocument); override;
|
|
|
|
end;
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
2011-01-29 21:32:39 +00:00
|
|
|
{$ifndef Windows}
|
2011-01-14 14:49:45 +00:00
|
|
|
{$define FPVECTORIALDEBUG}
|
2011-01-29 21:32:39 +00:00
|
|
|
{$endif}
|
2011-01-14 14:49:45 +00:00
|
|
|
|
|
|
|
const
|
2011-01-30 15:35:48 +00:00
|
|
|
// Items in the HEADER section
|
|
|
|
|
|
|
|
// $ACADVER
|
|
|
|
DXF_AUTOCAD_R10 = 'AC1006'; // 1988
|
|
|
|
DXF_AUTOCAD_R11_and_R12 = 'AC1009'; // 1990
|
|
|
|
DXF_AUTOCAD_R13 = 'AC1012'; // 1994
|
|
|
|
DXF_AUTOCAD_R14 = 'AC1009'; // 1997 http://www.autodesk.com/techpubs/autocad/acadr14/dxf/index.htm
|
|
|
|
DXF_AUTOCAD_2000 = 'AC1500'; // 1999 http://www.autodesk.com/techpubs/autocad/acad2000/dxf/
|
2011-01-30 14:37:28 +00:00
|
|
|
|
2011-01-25 14:13:33 +00:00
|
|
|
// Group Codes for ENTITIES
|
|
|
|
DXF_ENTITIES_TYPE = 0;
|
|
|
|
DXF_ENTITIES_HANDLE = 5;
|
2011-01-29 21:32:39 +00:00
|
|
|
DXF_ENTITIES_LINETYPE_NAME = 6;
|
2011-01-25 14:13:33 +00:00
|
|
|
DXF_ENTITIES_APPLICATION_GROUP = 102;
|
|
|
|
DXF_ENTITIES_AcDbEntity = 100;
|
|
|
|
DXF_ENTITIES_MODEL_OR_PAPER_SPACE = 67; // default=0=model, 1=paper
|
|
|
|
DXF_ENTITIES_VISIBILITY = 60; // default=0 = Visible, 1 = Invisible
|
|
|
|
|
|
|
|
{ TDXFToken }
|
|
|
|
|
|
|
|
constructor TDXFToken.Create;
|
|
|
|
begin
|
|
|
|
inherited Create;
|
|
|
|
|
|
|
|
Childs := TDXFTokens.Create;
|
|
|
|
end;
|
|
|
|
|
|
|
|
destructor TDXFToken.Destroy;
|
|
|
|
begin
|
|
|
|
Childs.Free;
|
2011-01-14 14:49:45 +00:00
|
|
|
|
2011-01-25 14:13:33 +00:00
|
|
|
inherited Destroy;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ TDXFTokenizer }
|
|
|
|
|
|
|
|
constructor TDXFTokenizer.Create;
|
|
|
|
begin
|
|
|
|
inherited Create;
|
|
|
|
|
|
|
|
Tokens := TDXFTokens.Create;
|
|
|
|
end;
|
|
|
|
|
|
|
|
destructor TDXFTokenizer.Destroy;
|
|
|
|
begin
|
|
|
|
Tokens.Free;
|
2011-01-14 14:49:45 +00:00
|
|
|
|
2011-01-25 14:13:33 +00:00
|
|
|
inherited Destroy;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TDXFTokenizer.ReadFromStrings(AStrings: TStrings);
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
StrSectionGroupCode, StrSectionName: string;
|
|
|
|
IntSectionGroupCode: Integer;
|
2011-01-25 14:43:07 +00:00
|
|
|
CurTokenBase, NextTokenBase, SectionTokenBase: TDXFTokens;
|
2011-01-25 14:13:33 +00:00
|
|
|
NewToken: TDXFToken;
|
|
|
|
ParserState: Integer;
|
|
|
|
begin
|
|
|
|
// Tokens.ForEachCall(); deletecallback
|
|
|
|
Tokens.Clear;
|
|
|
|
|
|
|
|
CurTokenBase := Tokens;
|
|
|
|
NextTokenBase := Tokens;
|
|
|
|
i := 0;
|
|
|
|
ParserState := 0;
|
|
|
|
|
|
|
|
while i < AStrings.Count - 1 do
|
|
|
|
begin
|
|
|
|
CurTokenBase := NextTokenBase;
|
|
|
|
|
|
|
|
// Now read and process the section name
|
|
|
|
StrSectionGroupCode := AStrings.Strings[i];
|
|
|
|
IntSectionGroupCode := StrToInt(Trim(StrSectionGroupCode));
|
|
|
|
StrSectionName := AStrings.Strings[i+1];
|
|
|
|
|
|
|
|
NewToken := TDXFToken.Create;
|
|
|
|
NewToken.GroupCode := IntSectionGroupCode;
|
|
|
|
NewToken.StrValue := StrSectionName;
|
|
|
|
|
|
|
|
// Waiting for a section
|
|
|
|
if ParserState = 0 then
|
|
|
|
begin
|
|
|
|
if (StrSectionName = 'SECTION') then
|
|
|
|
begin
|
|
|
|
ParserState := 1;
|
|
|
|
NextTokenBase := NewToken.Childs;
|
|
|
|
end
|
2011-01-25 14:43:07 +00:00
|
|
|
else if (StrSectionName = 'EOF') then
|
|
|
|
begin
|
|
|
|
Exit;
|
|
|
|
end
|
2011-01-25 14:13:33 +00:00
|
|
|
else
|
|
|
|
begin
|
|
|
|
raise Exception.Create(Format(
|
|
|
|
'TDXFTokenizer.ReadFromStrings: Expected SECTION, but got: %s', [StrSectionname]));
|
|
|
|
end;
|
|
|
|
end
|
|
|
|
// Processing the section name
|
|
|
|
else if ParserState = 1 then
|
|
|
|
begin
|
|
|
|
if (StrSectionName = 'HEADER') or
|
|
|
|
(StrSectionName = 'CLASSES') or
|
|
|
|
(StrSectionName = 'TABLES') or
|
|
|
|
(StrSectionName = 'BLOCKS') or
|
|
|
|
(StrSectionName = 'OBJECTS') or
|
|
|
|
(StrSectionName = 'THUMBNAILIMAGE') then
|
|
|
|
begin
|
|
|
|
ParserState := 2;
|
2011-01-25 14:43:07 +00:00
|
|
|
SectionTokenBase := CurTokenBase;
|
2011-01-25 14:13:33 +00:00
|
|
|
end
|
|
|
|
else if (StrSectionName = 'ENTITIES') then
|
|
|
|
begin
|
|
|
|
ParserState := 3;
|
2011-01-25 14:43:07 +00:00
|
|
|
SectionTokenBase := CurTokenBase;
|
2011-01-25 14:13:33 +00:00
|
|
|
end
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
raise Exception.Create(Format(
|
|
|
|
'TDXFTokenizer.ReadFromStrings: Invalid section name: %s', [StrSectionname]));
|
|
|
|
end;
|
|
|
|
end
|
|
|
|
// Reading a generic section
|
|
|
|
else if ParserState = 2 then
|
|
|
|
begin
|
|
|
|
if StrSectionName = 'ENDSEC' then
|
|
|
|
begin
|
|
|
|
ParserState := 0;
|
2011-01-25 14:43:07 +00:00
|
|
|
CurTokenBase := SectionTokenBase;
|
2011-01-25 14:13:33 +00:00
|
|
|
NextTokenBase := Tokens;
|
|
|
|
end;
|
|
|
|
end
|
|
|
|
// Reading the ENTITIES section
|
|
|
|
else if ParserState = 3 then
|
|
|
|
begin
|
|
|
|
if IsENTITIES_Subsection(StrSectionName) then
|
|
|
|
begin
|
2011-01-25 14:43:07 +00:00
|
|
|
CurTokenBase := SectionTokenBase;
|
2011-01-25 14:13:33 +00:00
|
|
|
NextTokenBase := NewToken.Childs;
|
|
|
|
end
|
2011-01-25 14:43:07 +00:00
|
|
|
else if StrSectionName = 'ENDSEC' then
|
|
|
|
begin
|
|
|
|
ParserState := 0;
|
|
|
|
CurTokenBase := SectionTokenBase;
|
|
|
|
NextTokenBase := Tokens;
|
|
|
|
end;
|
2011-01-25 14:13:33 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
CurTokenBase.Add(NewToken);
|
|
|
|
|
|
|
|
Inc(i, 2);
|
|
|
|
end;
|
|
|
|
end;
|
2011-01-14 14:49:45 +00:00
|
|
|
|
2011-01-25 14:13:33 +00:00
|
|
|
function TDXFTokenizer.IsENTITIES_Subsection(AStr: string): Boolean;
|
|
|
|
begin
|
|
|
|
Result :=
|
|
|
|
(AStr = '3DFACE') or
|
|
|
|
(AStr = '3DSOLID') or
|
|
|
|
(AStr = 'ACAD_PROXY_ENTITY') or
|
|
|
|
(AStr = 'ARC') or
|
|
|
|
(AStr = 'ATTDEF') or
|
|
|
|
(AStr = 'ATTRIB') or
|
|
|
|
(AStr = 'BODY') or
|
|
|
|
(AStr = 'CIRCLE') or
|
|
|
|
(AStr = 'DIMENSION') or
|
|
|
|
(AStr = 'ELLIPSE') or
|
|
|
|
(AStr = 'HATCH') or
|
|
|
|
(AStr = 'IMAGE') or
|
|
|
|
(AStr = 'INSERT') or
|
|
|
|
(AStr = 'LEADER') or
|
|
|
|
(AStr = 'LINE') or
|
|
|
|
(AStr = 'LWPOLYLINE') or
|
|
|
|
(AStr = 'MLINE') or
|
|
|
|
(AStr = 'MTEXT') or
|
|
|
|
(AStr = 'OLEFRAME') or
|
|
|
|
(AStr = 'OLE2FRAME') or
|
|
|
|
(AStr = 'POINT') or
|
|
|
|
(AStr = 'POLYLINE') or
|
|
|
|
(AStr = 'RAY') or
|
|
|
|
(AStr = 'REGION') or
|
|
|
|
(AStr = 'SEQEND') or
|
|
|
|
(AStr = 'SHAPE') or
|
|
|
|
(AStr = 'SOLID') or
|
|
|
|
(AStr = 'SPLINE') or
|
|
|
|
(AStr = 'TEXT') or
|
|
|
|
(AStr = 'TOLERANCE') or
|
|
|
|
(AStr = 'TRACE') or
|
|
|
|
(AStr = 'VERTEX') or
|
|
|
|
(AStr = 'VIEWPORT') or
|
|
|
|
(AStr = 'XLINE');
|
|
|
|
end;
|
2011-01-14 14:49:45 +00:00
|
|
|
|
2011-01-25 14:13:33 +00:00
|
|
|
{ TvDXFVectorialReader }
|
2011-01-14 14:49:45 +00:00
|
|
|
|
|
|
|
{@@
|
|
|
|
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;
|
|
|
|
|
2011-01-30 14:37:28 +00:00
|
|
|
procedure TvDXFVectorialReader.ReadHEADER(ATokens: TDXFTokens;
|
|
|
|
AData: TvVectorialDocument);
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
CurToken: TDXFToken;
|
|
|
|
begin
|
|
|
|
i := 0;
|
|
|
|
while i < ATokens.Count do
|
|
|
|
begin
|
|
|
|
CurToken := TDXFToken(ATokens.Items[i]);
|
|
|
|
if CurToken.StrValue = '$ANGBASE' then
|
|
|
|
begin
|
|
|
|
CurToken := TDXFToken(ATokens.Items[i+1]);
|
|
|
|
ANGBASE := StrToFloat(CurToken.StrValue, FPointSeparator);
|
|
|
|
Inc(i);
|
|
|
|
end
|
|
|
|
else if CurToken.StrValue = '$ANGDIR' then
|
|
|
|
begin
|
|
|
|
CurToken := TDXFToken(ATokens.Items[i+1]);
|
|
|
|
ANGDIR := StrToInt(CurToken.StrValue);
|
|
|
|
Inc(i);
|
|
|
|
end;
|
|
|
|
|
|
|
|
Inc(i);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2011-01-25 14:13:33 +00:00
|
|
|
procedure TvDXFVectorialReader.ReadENTITIES(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
2011-01-14 14:49:45 +00:00
|
|
|
var
|
2011-01-25 14:13:33 +00:00
|
|
|
i: Integer;
|
|
|
|
CurToken: TDXFToken;
|
2011-01-14 14:49:45 +00:00
|
|
|
begin
|
2011-01-25 14:13:33 +00:00
|
|
|
for i := 0 to ATokens.Count - 1 do
|
2011-01-14 14:49:45 +00:00
|
|
|
begin
|
2011-01-25 14:13:33 +00:00
|
|
|
CurToken := TDXFToken(ATokens.Items[i]);
|
2011-01-26 20:40:56 +00:00
|
|
|
if CurToken.StrValue = 'ARC' then ReadENTITIES_ARC(CurToken.Childs, AData)
|
|
|
|
else if CurToken.StrValue = 'CIRCLE' then ReadENTITIES_CIRCLE(CurToken.Childs, AData)
|
2011-01-26 16:05:00 +00:00
|
|
|
else if CurToken.StrValue = 'ELLIPSE' then ReadENTITIES_ELLIPSE(CurToken.Childs, AData)
|
|
|
|
else if CurToken.StrValue = 'LINE' then ReadENTITIES_LINE(CurToken.Childs, AData)
|
2011-01-25 14:13:33 +00:00
|
|
|
else if CurToken.StrValue = 'TEXT' then
|
|
|
|
begin
|
|
|
|
// ...
|
2011-01-14 14:49:45 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2011-01-25 16:51:57 +00:00
|
|
|
procedure TvDXFVectorialReader.ReadENTITIES_LINE(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
2011-01-14 14:49:45 +00:00
|
|
|
var
|
2011-01-25 14:43:07 +00:00
|
|
|
CurToken: TDXFToken;
|
|
|
|
i: Integer;
|
2011-01-26 16:05:00 +00:00
|
|
|
// LINE
|
|
|
|
LineStartX, LineStartY, LineStartZ: Double;
|
|
|
|
LineEndX, LineEndY, LineEndZ: Double;
|
2011-01-14 14:49:45 +00:00
|
|
|
begin
|
2011-01-26 16:05:00 +00:00
|
|
|
// Initial values
|
|
|
|
LineStartX := 0;
|
|
|
|
LineStartY := 0;
|
|
|
|
LineStartZ := 0;
|
|
|
|
LineEndX := 0;
|
|
|
|
LineEndY := 0;
|
|
|
|
LineEndZ := 0;
|
|
|
|
|
2011-01-25 14:43:07 +00:00
|
|
|
for i := 0 to ATokens.Count - 1 do
|
2011-01-14 14:49:45 +00:00
|
|
|
begin
|
2011-01-25 14:43:07 +00:00
|
|
|
// Now read and process the item name
|
|
|
|
CurToken := TDXFToken(ATokens.Items[i]);
|
2011-01-25 14:46:25 +00:00
|
|
|
|
|
|
|
// Avoid an exception by previously checking if the conversion can be made
|
2011-01-29 21:32:39 +00:00
|
|
|
if CurToken.GroupCode in [10, 20, 30, 11, 21, 31] then
|
|
|
|
begin
|
|
|
|
CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue), FPointSeparator);
|
|
|
|
end;
|
2011-01-25 14:43:07 +00:00
|
|
|
|
|
|
|
case CurToken.GroupCode of
|
|
|
|
10: LineStartX := CurToken.FloatValue;
|
|
|
|
20: LineStartY := CurToken.FloatValue;
|
|
|
|
30: LineStartZ := CurToken.FloatValue;
|
|
|
|
11: LineEndX := CurToken.FloatValue;
|
|
|
|
21: LineEndY := CurToken.FloatValue;
|
|
|
|
31: LineEndZ := CurToken.FloatValue;
|
2011-01-14 14:49:45 +00:00
|
|
|
end;
|
2011-01-25 14:43:07 +00:00
|
|
|
end;
|
2011-01-26 16:05:00 +00:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
{
|
|
|
|
100 Subclass marker (AcDbCircle)
|
|
|
|
39 Thickness (optional; default = 0)
|
|
|
|
10 Center point (in OCS) DXF: X value; APP: 3D point
|
|
|
|
20, 30 DXF: Y and Z values of center point (in OCS)
|
|
|
|
40 Radius
|
|
|
|
100 Subclass marker (AcDbArc)
|
2011-01-26 20:40:56 +00:00
|
|
|
50 Start angle (degrees)
|
|
|
|
51 End angle (degrees)
|
2011-01-26 16:05:00 +00:00
|
|
|
210 Extrusion direction. (optional; default = 0, 0, 1) DXF: X value; APP: 3D vector
|
|
|
|
220, 230 DXF: Y and Z values of extrusion direction (optional)
|
|
|
|
}
|
|
|
|
procedure TvDXFVectorialReader.ReadENTITIES_ARC(ATokens: TDXFTokens;
|
|
|
|
AData: TvVectorialDocument);
|
|
|
|
var
|
|
|
|
CurToken: TDXFToken;
|
|
|
|
i: Integer;
|
|
|
|
CenterX, CenterY, CenterZ, Radius, StartAngle, EndAngle: Double;
|
|
|
|
begin
|
|
|
|
CenterX := 0.0;
|
|
|
|
CenterY := 0.0;
|
|
|
|
CenterZ := 0.0;
|
|
|
|
Radius := 0.0;
|
|
|
|
StartAngle := 0.0;
|
|
|
|
EndAngle := 0.0;
|
|
|
|
|
|
|
|
for i := 0 to ATokens.Count - 1 do
|
|
|
|
begin
|
|
|
|
// Now read and process the item name
|
|
|
|
CurToken := TDXFToken(ATokens.Items[i]);
|
|
|
|
|
|
|
|
// Avoid an exception by previously checking if the conversion can be made
|
2011-01-29 21:32:39 +00:00
|
|
|
if CurToken.GroupCode in [10, 20, 30, 40, 50, 51] then
|
|
|
|
begin
|
|
|
|
CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue), FPointSeparator);
|
|
|
|
end;
|
2011-01-26 16:05:00 +00:00
|
|
|
|
|
|
|
case CurToken.GroupCode of
|
|
|
|
10: CenterX := CurToken.FloatValue;
|
|
|
|
20: CenterY := CurToken.FloatValue;
|
|
|
|
30: CenterZ := CurToken.FloatValue;
|
|
|
|
40: Radius := CurToken.FloatValue;
|
2011-01-26 20:40:56 +00:00
|
|
|
50: StartAngle := CurToken.FloatValue;
|
|
|
|
51: EndAngle := CurToken.FloatValue;
|
2011-01-26 16:05:00 +00:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
AData.AddCircularArc(CenterX, CenterY, CenterZ, Radius, StartAngle, EndAngle);
|
2011-01-14 14:49:45 +00:00
|
|
|
end;
|
|
|
|
|
2011-01-25 16:51:57 +00:00
|
|
|
{
|
|
|
|
Group codes Description
|
|
|
|
100 Subclass marker (AcDbCircle)
|
|
|
|
39 Thickness (optional; default = 0)
|
|
|
|
10 Center point (in OCS) DXF: X value; APP: 3D point
|
|
|
|
20, 30 DXF: Y and Z values of center point (in OCS)
|
|
|
|
40 Radius
|
|
|
|
210 Extrusion direction (optional; default = 0, 0, 1) DXF: X value; APP: 3D vector
|
|
|
|
220, 230 DXF: Y and Z values of extrusion direction (optional)
|
|
|
|
}
|
|
|
|
procedure TvDXFVectorialReader.ReadENTITIES_CIRCLE(ATokens: TDXFTokens;
|
|
|
|
AData: TvVectorialDocument);
|
|
|
|
var
|
|
|
|
CurToken: TDXFToken;
|
|
|
|
i: Integer;
|
2011-01-26 16:05:00 +00:00
|
|
|
CircleCenterX, CircleCenterY, CircleCenterZ, CircleRadius: Double;
|
2011-01-25 16:51:57 +00:00
|
|
|
begin
|
2011-01-26 16:05:00 +00:00
|
|
|
CircleCenterX := 0.0;
|
|
|
|
CircleCenterY := 0.0;
|
|
|
|
CircleCenterZ := 0.0;
|
|
|
|
CircleRadius := 0.0;
|
|
|
|
|
2011-01-25 16:51:57 +00:00
|
|
|
for i := 0 to ATokens.Count - 1 do
|
|
|
|
begin
|
|
|
|
// Now read and process the item name
|
|
|
|
CurToken := TDXFToken(ATokens.Items[i]);
|
|
|
|
|
|
|
|
// Avoid an exception by previously checking if the conversion can be made
|
2011-01-29 21:32:39 +00:00
|
|
|
if CurToken.GroupCode in [10, 20, 30, 40] then
|
|
|
|
begin
|
|
|
|
CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue), FPointSeparator);
|
|
|
|
end;
|
2011-01-25 16:51:57 +00:00
|
|
|
|
|
|
|
case CurToken.GroupCode of
|
|
|
|
10: CircleCenterX := CurToken.FloatValue;
|
|
|
|
20: CircleCenterY := CurToken.FloatValue;
|
|
|
|
30: CircleCenterZ := CurToken.FloatValue;
|
|
|
|
40: CircleRadius := CurToken.FloatValue;
|
|
|
|
end;
|
|
|
|
end;
|
2011-01-26 16:05:00 +00:00
|
|
|
|
|
|
|
AData.AddCircle(CircleCenterX, CircleCenterY,
|
|
|
|
CircleCenterZ, CircleRadius);
|
2011-01-25 16:51:57 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
{
|
|
|
|
100 Subclass marker (AcDbEllipse)
|
|
|
|
10 Center point (in WCS) DXF: X value; APP: 3D point
|
|
|
|
20, 30 DXF: Y and Z values of center point (in WCS)
|
|
|
|
11 Endpoint of major axis, relative to the center (in WCS) DXF: X value; APP: 3D point
|
|
|
|
21, 31 DXF: Y and Z values of endpoint of major axis, relative to the center (in WCS)
|
|
|
|
210 Extrusion direction (optional; default = 0, 0, 1) DXF: X value; APP: 3D vector
|
|
|
|
220, 230 DXF: Y and Z values of extrusion direction (optional)
|
|
|
|
40 Ratio of minor axis to major axis
|
|
|
|
41 Start parameter (this value is 0.0 for a full ellipse)
|
|
|
|
42 End parameter (this value is 2pi for a full ellipse)
|
|
|
|
}
|
|
|
|
procedure TvDXFVectorialReader.ReadENTITIES_ELLIPSE(ATokens: TDXFTokens;
|
|
|
|
AData: TvVectorialDocument);
|
|
|
|
var
|
|
|
|
CurToken: TDXFToken;
|
|
|
|
i: Integer;
|
2011-01-26 16:05:00 +00:00
|
|
|
CenterX, CenterY, CenterZ, MajorHalfAxis, MinorHalfAxis, Angle: Double;
|
2011-01-25 16:51:57 +00:00
|
|
|
begin
|
|
|
|
for i := 0 to ATokens.Count - 1 do
|
|
|
|
begin
|
|
|
|
// Now read and process the item name
|
|
|
|
CurToken := TDXFToken(ATokens.Items[i]);
|
|
|
|
|
|
|
|
// Avoid an exception by previously checking if the conversion can be made
|
2011-01-29 21:32:39 +00:00
|
|
|
if CurToken.GroupCode in [10, 20, 30] then
|
|
|
|
begin
|
|
|
|
CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue), FPointSeparator);
|
|
|
|
end;
|
2011-01-25 16:51:57 +00:00
|
|
|
|
|
|
|
case CurToken.GroupCode of
|
|
|
|
10: CenterX := CurToken.FloatValue;
|
|
|
|
20: CenterY := CurToken.FloatValue;
|
|
|
|
30: CenterZ := CurToken.FloatValue;
|
|
|
|
end;
|
|
|
|
end;
|
2011-01-26 16:05:00 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
AData.AddEllipse(CenterX, CenterY, CenterZ, MajorHalfAxis, MinorHalfAxis, Angle);
|
2011-01-25 16:51:57 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
{
|
|
|
|
100 Subclass marker (AcDbText)
|
|
|
|
39 Thickness (optional; default = 0)
|
|
|
|
10 First alignment point (in OCS) DXF: X value; APP: 3D point
|
|
|
|
20, 30 DXF: Y and Z values of first alignment point (in OCS)
|
|
|
|
40 Text height
|
|
|
|
1 Default value (the string itself)
|
|
|
|
50 Text rotation (optional; default = 0)
|
|
|
|
41 Relative X scale factor-width (optional; default = 1)
|
|
|
|
This value is also adjusted when fit-type text is used.
|
|
|
|
51 Oblique angle (optional; default = 0)
|
|
|
|
7 Text style name (optional, default = STANDARD)
|
|
|
|
71 Text generation flags (optional, default = 0):
|
|
|
|
2 = Text is backward (mirrored in X).
|
|
|
|
4 = Text is upside down (mirrored in Y).
|
|
|
|
72 Horizontal text justification type (optional, default = 0) integer codes (not bit-coded)
|
|
|
|
0 = Left; 1= Center; 2 = Right
|
|
|
|
3 = Aligned (if vertical alignment = 0)
|
|
|
|
4 = Middle (if vertical alignment = 0)
|
|
|
|
5 = Fit (if vertical alignment = 0)
|
|
|
|
See the Group 72 and 73 integer codes table for clarification.
|
|
|
|
11 Second alignment point (in OCS) (optional)
|
|
|
|
DXF: X value; APP: 3D point
|
|
|
|
This value is meaningful only if the value of a 72 or 73 group is nonzero (if the justification is anything other than baseline/left).
|
|
|
|
21, 31 DXF: Y and Z values of second alignment point (in OCS) (optional)
|
|
|
|
210 Extrusion direction (optional; default = 0, 0, 1)
|
|
|
|
DXF: X value; APP: 3D vector
|
|
|
|
220, 230 DXF: Y and Z values of extrusion direction (optional)
|
|
|
|
73 Vertical text justification type (optional, default = 0): integer codes (not bit- coded):
|
|
|
|
0 = Baseline; 1 = Bottom; 2 = Middle; 3 = Top
|
|
|
|
See the Group 72 and 73 integer codes table for clarification.
|
|
|
|
}
|
|
|
|
procedure TvDXFVectorialReader.ReadENTITIES_TEXT(ATokens: TDXFTokens;
|
|
|
|
AData: TvVectorialDocument);
|
2011-01-26 16:05:00 +00:00
|
|
|
var
|
|
|
|
CurToken: TDXFToken;
|
|
|
|
i: Integer;
|
2011-01-30 15:35:48 +00:00
|
|
|
PosX: Double = 0.0;
|
|
|
|
PosY: Double = 0.0;
|
|
|
|
PosZ: Double = 0.0;
|
|
|
|
FontSize: Double = 10.0;
|
|
|
|
Str: string = '';
|
2011-01-14 14:49:45 +00:00
|
|
|
begin
|
2011-01-26 16:05:00 +00:00
|
|
|
for i := 0 to ATokens.Count - 1 do
|
|
|
|
begin
|
|
|
|
// Now read and process the item name
|
|
|
|
CurToken := TDXFToken(ATokens.Items[i]);
|
|
|
|
|
|
|
|
// Avoid an exception by previously checking if the conversion can be made
|
2011-01-30 15:35:48 +00:00
|
|
|
if CurToken.GroupCode in [10, 20, 30, 40] then
|
2011-01-29 21:32:39 +00:00
|
|
|
begin
|
|
|
|
CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue), FPointSeparator);
|
|
|
|
end;
|
2011-01-26 16:05:00 +00:00
|
|
|
|
|
|
|
case CurToken.GroupCode of
|
|
|
|
1: Str := CurToken.StrValue;
|
|
|
|
10: PosX := CurToken.FloatValue;
|
|
|
|
20: PosY := CurToken.FloatValue;
|
|
|
|
30: PosZ := CurToken.FloatValue;
|
2011-01-30 15:35:48 +00:00
|
|
|
40: FontSize := CurToken.FloatValue;
|
2011-01-26 16:05:00 +00:00
|
|
|
end;
|
|
|
|
end;
|
2011-01-14 14:49:45 +00:00
|
|
|
|
2011-01-26 16:05:00 +00:00
|
|
|
//
|
2011-01-30 15:35:48 +00:00
|
|
|
AData.AddText(PosX, PosY, PosZ, '', Round(FontSize), Str);
|
2011-01-14 14:49:45 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
function TvDXFVectorialReader.GetCoordinateValue(AStr: shortstring): Double;
|
|
|
|
begin
|
|
|
|
Result := 0.0;
|
|
|
|
|
2011-01-25 14:13:33 +00:00
|
|
|
{ if Length(AStr) <= 1 then Exit;
|
2011-01-14 14:49:45 +00:00
|
|
|
|
2011-01-25 14:13:33 +00:00
|
|
|
Result := StrToFloat(Copy(AStr, 2, Length(AStr) - 1));}
|
|
|
|
end;
|
|
|
|
|
|
|
|
constructor TvDXFVectorialReader.Create;
|
|
|
|
begin
|
|
|
|
inherited Create;
|
|
|
|
|
2011-01-28 15:25:55 +00:00
|
|
|
FPointSeparator := DefaultFormatSettings;
|
|
|
|
FPointSeparator.DecimalSeparator := '.';
|
|
|
|
FPointSeparator.ThousandSeparator := '#';// disable the thousand separator
|
|
|
|
|
2011-01-30 14:37:28 +00:00
|
|
|
// Default HEADER data
|
|
|
|
ANGBASE := 0.0; // Starts pointing to the right / east
|
|
|
|
ANGDIR := 0; // counter-clock wise
|
|
|
|
|
2011-01-25 14:13:33 +00:00
|
|
|
Tokenizer := TDXFTokenizer.Create;
|
|
|
|
end;
|
|
|
|
|
|
|
|
destructor TvDXFVectorialReader.Destroy;
|
|
|
|
begin
|
|
|
|
Tokenizer.Free;
|
|
|
|
|
|
|
|
inherited Destroy;
|
2011-01-14 14:49:45 +00:00
|
|
|
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;
|
2011-01-25 14:13:33 +00:00
|
|
|
CurToken, CurTokenFirstChild: TDXFToken;
|
2011-01-14 14:49:45 +00:00
|
|
|
begin
|
2011-01-25 14:13:33 +00:00
|
|
|
Tokenizer.ReadFromStrings(AStrings);
|
|
|
|
|
|
|
|
for i := 0 to Tokenizer.Tokens.Count - 1 do
|
|
|
|
begin
|
|
|
|
CurToken := TDXFToken(Tokenizer.Tokens.Items[i]);
|
|
|
|
CurTokenFirstChild := TDXFToken(CurToken.Childs.Items[0]);
|
|
|
|
|
2011-01-30 14:37:28 +00:00
|
|
|
if CurTokenFirstChild.StrValue = 'HEADER' then
|
|
|
|
ReadHEADER(CurToken.Childs, AData)
|
|
|
|
else if CurTokenFirstChild.StrValue = 'ENTITIES' then
|
2011-01-25 14:13:33 +00:00
|
|
|
ReadENTITIES(CurToken.Childs, AData);
|
|
|
|
end;
|
2011-01-14 14:49:45 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
initialization
|
|
|
|
|
|
|
|
RegisterVectorialReader(TvDXFVectorialReader, vfDXF);
|
|
|
|
|
|
|
|
end.
|
|
|
|
|