mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-06 10:50:31 +02:00
Large improvements to the DXF reader and adds a new circle entity to fpvectorial
git-svn-id: trunk@16816 -
This commit is contained in:
parent
ed1485c33e
commit
6bad2fa169
@ -7,12 +7,12 @@ object formVectorialConverter: TformVectorialConverter
|
||||
Caption = 'FP Vectorial Converter'
|
||||
ClientHeight = 439
|
||||
ClientWidth = 240
|
||||
LCLVersion = '0.9.29'
|
||||
LCLVersion = '0.9.31'
|
||||
object Label1: TLabel
|
||||
Left = 8
|
||||
Height = 17
|
||||
Height = 18
|
||||
Top = 112
|
||||
Width = 160
|
||||
Width = 172
|
||||
Caption = 'Location of the Input file:'
|
||||
ParentColor = False
|
||||
end
|
||||
@ -30,7 +30,7 @@ object formVectorialConverter: TformVectorialConverter
|
||||
end
|
||||
object editInput: TFileNameEdit
|
||||
Left = 8
|
||||
Height = 22
|
||||
Height = 25
|
||||
Top = 128
|
||||
Width = 192
|
||||
DialogOptions = []
|
||||
@ -43,15 +43,15 @@ object formVectorialConverter: TformVectorialConverter
|
||||
end
|
||||
object Label3: TLabel
|
||||
Left = 8
|
||||
Height = 17
|
||||
Height = 18
|
||||
Top = 152
|
||||
Width = 173
|
||||
Width = 184
|
||||
Caption = 'Full path of the Output file:'
|
||||
ParentColor = False
|
||||
end
|
||||
object editOutput: TFileNameEdit
|
||||
Left = 8
|
||||
Height = 22
|
||||
Height = 25
|
||||
Top = 168
|
||||
Width = 192
|
||||
DialogOptions = []
|
||||
|
@ -3,12 +3,8 @@ program fpvectorialconverter;
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
uses
|
||||
{$IFDEF UNIX}{$IFDEF UseCThreads}
|
||||
cthreads,
|
||||
{$ENDIF}{$ENDIF}
|
||||
Interfaces, // this includes the LCL widgetset
|
||||
Forms, fpvc_mainform
|
||||
{ you can add units after this };
|
||||
Forms, fpvc_mainform;
|
||||
|
||||
{$R *.res}
|
||||
|
||||
|
@ -17,7 +17,7 @@ SECTION_NAME
|
||||
ENDSEC
|
||||
0
|
||||
|
||||
after all section end there is:
|
||||
after all sections there is:
|
||||
|
||||
EOF
|
||||
|
||||
@ -37,20 +37,53 @@ type
|
||||
{ Used by tcutils.SeparateString }
|
||||
T10Strings = array[0..9] of shortstring;
|
||||
|
||||
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;
|
||||
|
||||
{ TvDXFVectorialReader }
|
||||
|
||||
TvDXFVectorialReader = class(TvCustomVectorialReader)
|
||||
private
|
||||
// CIRCLE
|
||||
CircleCenterX, CircleCenterY, CircleCenterZ, CircleRadius: Double;
|
||||
// LINE
|
||||
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;
|
||||
procedure ReadENTITIES(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
||||
procedure ReadENTITIES_LINE(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
||||
procedure ReadENTITIES_CIRCLE(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
||||
procedure ReadENTITIES_ELLIPSE(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
||||
procedure ReadENTITIES_TEXT(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
||||
function GetCoordinateValue(AStr: shortstring): Double;
|
||||
public
|
||||
{ General reading methods }
|
||||
Tokenizer: TDXFTokenizer;
|
||||
constructor Create; override;
|
||||
Destructor Destroy; override;
|
||||
procedure ReadFromStrings(AStrings: TStrings; AData: TvVectorialDocument); override;
|
||||
end;
|
||||
|
||||
@ -59,23 +92,190 @@ implementation
|
||||
{$define FPVECTORIALDEBUG}
|
||||
|
||||
const
|
||||
{ Coordinate constants }
|
||||
// Group Codes for ENTITIES
|
||||
DXF_ENTITIES_TYPE = 0;
|
||||
DXF_ENTITIES_HANDLE = 5;
|
||||
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
|
||||
|
||||
INT_COORDINATE_NONE = 0;
|
||||
INT_COORDINATE_X = 1;
|
||||
INT_COORDINATE_Y = 2;
|
||||
INT_COORDINATE_Z = 3;
|
||||
{ TDXFToken }
|
||||
|
||||
{ GCode constants }
|
||||
constructor TDXFToken.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
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';
|
||||
Childs := TDXFTokens.Create;
|
||||
end;
|
||||
|
||||
{ TvAvisoCNCGCodeReader }
|
||||
destructor TDXFToken.Destroy;
|
||||
begin
|
||||
Childs.Free;
|
||||
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
{ TDXFTokenizer }
|
||||
|
||||
constructor TDXFTokenizer.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
Tokens := TDXFTokens.Create;
|
||||
end;
|
||||
|
||||
destructor TDXFTokenizer.Destroy;
|
||||
begin
|
||||
Tokens.Free;
|
||||
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TDXFTokenizer.ReadFromStrings(AStrings: TStrings);
|
||||
var
|
||||
i: Integer;
|
||||
StrSectionGroupCode, StrSectionName: string;
|
||||
IntSectionGroupCode: Integer;
|
||||
CurTokenBase, NextTokenBase, SectionTokenBase: TDXFTokens;
|
||||
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
|
||||
else if (StrSectionName = 'EOF') then
|
||||
begin
|
||||
Exit;
|
||||
end
|
||||
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;
|
||||
SectionTokenBase := CurTokenBase;
|
||||
end
|
||||
else if (StrSectionName = 'ENTITIES') then
|
||||
begin
|
||||
ParserState := 3;
|
||||
SectionTokenBase := CurTokenBase;
|
||||
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;
|
||||
CurTokenBase := SectionTokenBase;
|
||||
NextTokenBase := Tokens;
|
||||
end;
|
||||
end
|
||||
// Reading the ENTITIES section
|
||||
else if ParserState = 3 then
|
||||
begin
|
||||
if IsENTITIES_Subsection(StrSectionName) then
|
||||
begin
|
||||
CurTokenBase := SectionTokenBase;
|
||||
NextTokenBase := NewToken.Childs;
|
||||
end
|
||||
else if StrSectionName = 'ENDSEC' then
|
||||
begin
|
||||
ParserState := 0;
|
||||
CurTokenBase := SectionTokenBase;
|
||||
NextTokenBase := Tokens;
|
||||
end;
|
||||
end;
|
||||
|
||||
CurTokenBase.Add(NewToken);
|
||||
|
||||
Inc(i, 2);
|
||||
end;
|
||||
end;
|
||||
|
||||
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;
|
||||
|
||||
{ TvDXFVectorialReader }
|
||||
|
||||
{@@
|
||||
Reads a string and separates it in substring
|
||||
@ -110,172 +310,219 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
{@@
|
||||
returns If an end of file marker was found
|
||||
}
|
||||
function TvDXFVectorialReader.ReadSection(
|
||||
AStrings: TStrings; var AIndex: Integer; AData: TvVectorialDocument): Boolean;
|
||||
procedure TvDXFVectorialReader.ReadENTITIES(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
||||
var
|
||||
DestX, DestY, DestZ: Double;
|
||||
StrSectionNum, StrSectionName: string;
|
||||
IntSectionNum, i: Integer;
|
||||
i: Integer;
|
||||
CurToken: TDXFToken;
|
||||
begin
|
||||
Result := False;
|
||||
|
||||
// Check if there is minimal space for a section
|
||||
if AIndex+5 > AStrings.Count then
|
||||
for i := 0 to ATokens.Count - 1 do
|
||||
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
|
||||
CurToken := TDXFToken(ATokens.Items[i]);
|
||||
if CurToken.StrValue = 'CIRCLE' then
|
||||
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;
|
||||
CircleCenterX := 0.0;
|
||||
CircleCenterY := 0.0;
|
||||
CircleCenterZ := 0.0;
|
||||
CircleRadius := 0.0;
|
||||
|
||||
function TvDXFVectorialReader.ReadENTITIES(AStrings: TStrings;
|
||||
var AIndex: Integer; AData: TvVectorialDocument): Boolean;
|
||||
var
|
||||
StrSectionNum, StrSectionName: string;
|
||||
IntSectionNum, i: Integer;
|
||||
begin
|
||||
Result := False;
|
||||
ReadENTITIES_CIRCLE(CurToken.Childs, AData);
|
||||
|
||||
// Now read and process the item name
|
||||
StrSectionName := AStrings.Strings[AIndex+1];
|
||||
AData.AddCircle(CircleCenterX, CircleCenterY,
|
||||
CircleCenterZ, CircleRadius);
|
||||
end
|
||||
else if CurToken.StrValue = 'ELLIPSE' then
|
||||
begin
|
||||
// ...
|
||||
ReadENTITIES_ELLIPSE(CurToken.Childs, AData);
|
||||
end
|
||||
else if CurToken.StrValue = 'LINE' then
|
||||
begin
|
||||
// Initial values
|
||||
LineStartX := 0;
|
||||
LineStartY := 0;
|
||||
LineStartZ := 0;
|
||||
LineEndX := 0;
|
||||
LineEndY := 0;
|
||||
LineEndZ := 0;
|
||||
|
||||
{$ifdef FPVECTORIALDEBUG}
|
||||
WriteLn('TvDXFVectorialReader.ReadENTITIES ', StrSectionName);
|
||||
{$endif}
|
||||
// Read the data of the line
|
||||
ReadENTITIES_LINE(CurToken.Childs, AData);
|
||||
|
||||
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;
|
||||
// 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
|
||||
else if CurToken.StrValue = 'TEXT' then
|
||||
begin
|
||||
// ...
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TvDXFVectorialReader.GetCoordinate(AStr: shortstring): Integer;
|
||||
procedure TvDXFVectorialReader.ReadENTITIES_LINE(ATokens: TDXFTokens; AData: TvVectorialDocument);
|
||||
var
|
||||
CurToken: TDXFToken;
|
||||
i: Integer;
|
||||
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
|
||||
if (CurToken.GroupCode = DXF_ENTITIES_HANDLE) or
|
||||
(CurToken.GroupCode = DXF_ENTITIES_AcDbEntity) then Continue;
|
||||
|
||||
CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue));
|
||||
|
||||
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;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
{
|
||||
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;
|
||||
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
|
||||
if (CurToken.GroupCode = DXF_ENTITIES_HANDLE) or
|
||||
(CurToken.GroupCode = DXF_ENTITIES_AcDbEntity) then Continue;
|
||||
|
||||
CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue));
|
||||
|
||||
case CurToken.GroupCode of
|
||||
10: CircleCenterX := CurToken.FloatValue;
|
||||
20: CircleCenterY := CurToken.FloatValue;
|
||||
30: CircleCenterZ := CurToken.FloatValue;
|
||||
40: CircleRadius := CurToken.FloatValue;
|
||||
end;
|
||||
end;
|
||||
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;
|
||||
CenterX, CenterY, CenterZ: Double;
|
||||
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
|
||||
if (CurToken.GroupCode = DXF_ENTITIES_HANDLE) or
|
||||
(CurToken.GroupCode = DXF_ENTITIES_AcDbEntity) then Continue;
|
||||
|
||||
CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue));
|
||||
|
||||
case CurToken.GroupCode of
|
||||
10: CenterX := CurToken.FloatValue;
|
||||
20: CenterY := CurToken.FloatValue;
|
||||
30: CenterZ := CurToken.FloatValue;
|
||||
end;
|
||||
end;
|
||||
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);
|
||||
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;
|
||||
{ if Length(AStr) <= 1 then Exit;
|
||||
|
||||
Result := StrToFloat(Copy(AStr, 2, Length(AStr) - 1));
|
||||
Result := StrToFloat(Copy(AStr, 2, Length(AStr) - 1));}
|
||||
end;
|
||||
|
||||
constructor TvDXFVectorialReader.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
Tokenizer := TDXFTokenizer.Create;
|
||||
end;
|
||||
|
||||
destructor TvDXFVectorialReader.Destroy;
|
||||
begin
|
||||
Tokenizer.Free;
|
||||
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
{@@
|
||||
@ -286,10 +533,18 @@ procedure TvDXFVectorialReader.ReadFromStrings(AStrings: TStrings;
|
||||
AData: TvVectorialDocument);
|
||||
var
|
||||
i: Integer;
|
||||
CurToken, CurTokenFirstChild: TDXFToken;
|
||||
begin
|
||||
i := 0;
|
||||
while i < AStrings.Count - 1 do
|
||||
if ReadSection(AStrings, i, AData) then Break;
|
||||
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]);
|
||||
|
||||
if CurTokenFirstChild.StrValue = 'ENTITIES' then
|
||||
ReadENTITIES(CurToken.Childs, AData);
|
||||
end;
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
@ -121,6 +121,15 @@ type
|
||||
Value: utf8string;
|
||||
end;
|
||||
|
||||
TvEntity = class
|
||||
public
|
||||
end;
|
||||
|
||||
TvCircle = class(TvEntity)
|
||||
public
|
||||
X, Y, Z, Radius: Double;
|
||||
end;
|
||||
|
||||
type
|
||||
|
||||
TvCustomVectorialWriter = class;
|
||||
@ -132,6 +141,7 @@ type
|
||||
private
|
||||
FPaths: TFPList;
|
||||
FTexts: TFPList;
|
||||
FEntities: TFPList;
|
||||
FTmpPath: TPath;
|
||||
FTmpText: TvText;
|
||||
procedure RemoveCallback(data, arg: pointer);
|
||||
@ -158,6 +168,8 @@ type
|
||||
function GetPathCount: Integer;
|
||||
function GetText(ANum: Cardinal): TvText;
|
||||
function GetTextCount: Integer;
|
||||
function GetEntity(ANum: Cardinal): TvEntity;
|
||||
function GetEntityCount: Integer;
|
||||
{ Data removing methods }
|
||||
procedure Clear;
|
||||
procedure RemoveAllPaths;
|
||||
@ -172,6 +184,7 @@ type
|
||||
procedure EndPath();
|
||||
procedure AddText(AX, AY, AZ: Double; FontName: string; FontSize: integer; AText: utf8string); overload;
|
||||
procedure AddText(AX, AY, AZ: Double; AStr: utf8string); overload;
|
||||
procedure AddCircle(AX, AY, AZ, ARadius: Double);
|
||||
{ properties }
|
||||
property PathCount: Integer read GetPathCount;
|
||||
property Paths[Index: Cardinal]: TPath read GetPath;
|
||||
@ -186,6 +199,7 @@ type
|
||||
TvCustomVectorialReader = class
|
||||
public
|
||||
{ General reading methods }
|
||||
constructor Create; virtual;
|
||||
procedure ReadFromFile(AFileName: string; AData: TvVectorialDocument); virtual;
|
||||
procedure ReadFromStream(AStream: TStream; AData: TvVectorialDocument); virtual;
|
||||
procedure ReadFromStrings(AStrings: TStrings; AData: TvVectorialDocument); virtual;
|
||||
@ -202,6 +216,7 @@ type
|
||||
TvCustomVectorialWriter = class
|
||||
public
|
||||
{ General writing methods }
|
||||
constructor Create; virtual;
|
||||
procedure WriteToFile(AFileName: string; AData: TvVectorialDocument); virtual;
|
||||
procedure WriteToStream(AStream: TStream; AData: TvVectorialDocument); virtual;
|
||||
procedure WriteToStrings(AStrings: TStrings; AData: TvVectorialDocument); virtual;
|
||||
@ -339,6 +354,7 @@ begin
|
||||
|
||||
FPaths := TFPList.Create;
|
||||
FTexts := TFPList.Create;
|
||||
FEntities := TFPList.Create;
|
||||
FTmpPath := TPath.Create;
|
||||
end;
|
||||
|
||||
@ -351,6 +367,7 @@ begin
|
||||
|
||||
FPaths.Free;
|
||||
FTexts.Free;
|
||||
FEntities.Free;
|
||||
|
||||
inherited Destroy;
|
||||
end;
|
||||
@ -520,6 +537,18 @@ begin
|
||||
AddText(AX, AY, AZ, '', 10, AStr);
|
||||
end;
|
||||
|
||||
procedure TvVectorialDocument.AddCircle(AX, AY, AZ, ARadius: Double);
|
||||
var
|
||||
lCircle: TvCircle;
|
||||
begin
|
||||
lCircle := TvCircle.Create;
|
||||
lCircle.X := AX;
|
||||
lCircle.Y := AY;
|
||||
lCircle.Z := AZ;
|
||||
lCircle.Radius := ARadius;
|
||||
FEntities.Add(lCircle);
|
||||
end;
|
||||
|
||||
{@@
|
||||
Convenience method which creates the correct
|
||||
writer object for a given vector graphics document format.
|
||||
@ -747,6 +776,20 @@ begin
|
||||
Result := FTexts.Count;
|
||||
end;
|
||||
|
||||
function TvVectorialDocument.GetEntity(ANum: Cardinal): TvEntity;
|
||||
begin
|
||||
if ANum >= FEntities.Count then raise Exception.Create('TvVectorialDocument.GetEntity: Entity number out of bounds');
|
||||
|
||||
if FEntities.Items[ANum] = nil then raise Exception.Create('TvVectorialDocument.GetEntity: Invalid Entity number');
|
||||
|
||||
Result := TvEntity(FEntities.Items[ANum]);
|
||||
end;
|
||||
|
||||
function TvVectorialDocument.GetEntityCount: Integer;
|
||||
begin
|
||||
Result := FEntities.Count;
|
||||
end;
|
||||
|
||||
{@@
|
||||
Clears all data in the document
|
||||
}
|
||||
@ -758,6 +801,11 @@ end;
|
||||
|
||||
{ TvCustomVectorialReader }
|
||||
|
||||
constructor TvCustomVectorialReader.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
end;
|
||||
|
||||
procedure TvCustomVectorialReader.ReadFromFile(AFileName: string; AData: TvVectorialDocument);
|
||||
var
|
||||
FileStream: TFileStream;
|
||||
@ -806,6 +854,11 @@ end;
|
||||
|
||||
{ TsCustomSpreadWriter }
|
||||
|
||||
constructor TvCustomVectorialWriter.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
end;
|
||||
|
||||
{@@
|
||||
Default file writting method.
|
||||
|
||||
|
@ -40,6 +40,9 @@ var
|
||||
CurX, CurY: Integer; // Not modified by ADestX, etc
|
||||
CurveLength: Integer;
|
||||
t: Double;
|
||||
// For entities
|
||||
CurEntity: TvEntity;
|
||||
CurCircle: TvCircle;
|
||||
begin
|
||||
{$ifdef FPVECTORIALDEBUG}
|
||||
WriteLn(':>DrawFPVectorialToCanvas');
|
||||
@ -100,6 +103,21 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
for i := 0 to ASource.GetEntityCount - 1 do
|
||||
begin
|
||||
CurEntity := ASource.GetEntity(i);
|
||||
CurCircle := CurEntity as TvCircle;
|
||||
if CurEntity is TvCircle then
|
||||
begin
|
||||
ADest.Ellipse(
|
||||
Round(ADestX + AmulX * (CurCircle.X - CurCircle.Radius)),
|
||||
Round(ADestY + AMulY * (CurCircle.Y - CurCircle.Radius)),
|
||||
Round(ADestX + AmulX * (CurCircle.X + CurCircle.Radius)),
|
||||
Round(ADestY + AMulY * (CurCircle.Y + CurCircle.Radius))
|
||||
);
|
||||
end;
|
||||
end;
|
||||
|
||||
{$ifdef FPVECTORIALDEBUG}
|
||||
WriteLn(':<DrawFPVectorialToCanvas');
|
||||
{$endif}
|
||||
|
Loading…
Reference in New Issue
Block a user