From d67eefba96eefb79b623b9b08e9049d0fe9e686a Mon Sep 17 00:00:00 2001 From: sekelsenmat Date: Tue, 25 Jan 2011 14:13:33 +0000 Subject: [PATCH] Implements the new DXF Tokenizer git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1458 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- applications/fpvviewer/dxftokentotree.pas | 42 ++ .../fpvectorialsrc/dxfvectorialreader.pas | 400 ++++++++++++------ applications/fpvviewer/fpvv_mainform.lfm | 64 ++- applications/fpvviewer/fpvv_mainform.pas | 34 +- applications/fpvviewer/fpvviewer.lpi | 10 +- applications/fpvviewer/fpvviewer.lpr | 2 +- 6 files changed, 398 insertions(+), 154 deletions(-) create mode 100644 applications/fpvviewer/dxftokentotree.pas diff --git a/applications/fpvviewer/dxftokentotree.pas b/applications/fpvviewer/dxftokentotree.pas new file mode 100644 index 000000000..6b970780c --- /dev/null +++ b/applications/fpvviewer/dxftokentotree.pas @@ -0,0 +1,42 @@ +unit dxftokentotree; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, ComCtrls, + dxfvectorialreader; + +procedure ConvertDXFTokensToTreeView(ATokens: TDXFTokens; ATreeView: TTreeView); +procedure ConvertDXFTokensToTreeNodes(ATokens: TDXFTokens; ATreeNodes: TTreeNodes; ABaseNode: TTreeNode); + +implementation + +procedure ConvertDXFTokensToTreeView(ATokens: TDXFTokens; ATreeView: TTreeView); +begin + ATreeView.Items.Clear; + ConvertDXFTokensToTreeNodes(ATokens, ATreeView.Items, ATreeView.Items.GetFirstNode); +end; + +procedure ConvertDXFTokensToTreeNodes(ATokens: TDXFTokens; + ATreeNodes: TTreeNodes; ABaseNode: TTreeNode); +var + AToken: TDXFToken; + NodeStr: string; + NewNode: TTreeNode; + i: Integer; +begin + if ATokens = nil then Exit; + + for i := 0 to ATokens.Count - 1 do + begin + AToken := TDXFToken(ATokens.Items[i]); + NodeStr := Format('(%d %s)', [AToken.GroupCode, AToken.StrValue]); + NewNode := ATreeNodes.AddChild(ABaseNode, NodeStr); + ConvertDXFTokensToTreeNodes(AToken.Childs, NewNode.TreeNodes, NewNode); + end; +end; + +end. + diff --git a/applications/fpvviewer/fpvectorialsrc/dxfvectorialreader.pas b/applications/fpvviewer/fpvectorialsrc/dxfvectorialreader.pas index a983332b6..f3b82c86a 100644 --- a/applications/fpvviewer/fpvectorialsrc/dxfvectorialreader.pas +++ b/applications/fpvviewer/fpvectorialsrc/dxfvectorialreader.pas @@ -17,7 +17,7 @@ SECTION_NAME ENDSEC 0 -after all section end there is: +after all sections there is: EOF @@ -37,6 +37,31 @@ 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) @@ -44,13 +69,15 @@ type 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; + procedure ReadENTITIES(ATokens: TDXFTokens; AData: TvVectorialDocument); + 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 } + Tokenizer: TDXFTokenizer; + constructor Create; + Destructor Destroy; override; procedure ReadFromStrings(AStrings: TStrings; AData: TvVectorialDocument); override; end; @@ -59,23 +86,182 @@ 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, ENTITIESTokenBase: 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 + 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; + end + else if (StrSectionName = 'ENTITIES') then + begin + ParserState := 3; + ENTITIESTokenBase := CurTokenBase; + end + else if (StrSectionName = 'EOF') then + begin + Exit; + 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; + NextTokenBase := Tokens; + end; + end + // Reading the ENTITIES section + else if ParserState = 3 then + begin + if IsENTITIES_Subsection(StrSectionName) then + begin + CurTokenBase := ENTITIESTokenBase; + NextTokenBase := NewToken.Childs; + 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,116 +296,44 @@ 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 = 'ELLIPSE' then begin - if AStrings.Strings[i] = 'ENDSEC' then - begin - AIndex := i + 1; - Exit; - end; + // ... + end + else if CurToken.StrValue = '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 + else if CurToken.StrValue = 'TEXT' then + begin + // ... 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; @@ -232,11 +346,11 @@ var begin Result := False; - // Now read and process the item name +{ // Now read and process the item name StrSectionNum := AStrings.Strings[AIndex]; StrSectionValue := AStrings.Strings[AIndex+1]; - if (StrSectionValue = 'LINE') or + if IsENTITIES_Subsection(StrSectionValue) or (StrSectionValue = 'ENDSEC') then begin Exit(True); @@ -256,26 +370,40 @@ begin 21: LineEndY := FloatSectionValue; 31: LineEndZ := FloatSectionValue; end; - end; + end;} end; function TvDXFVectorialReader.GetCoordinate(AStr: shortstring): Integer; begin - Result := INT_COORDINATE_NONE; +{ 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; + 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 +414,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 diff --git a/applications/fpvviewer/fpvv_mainform.lfm b/applications/fpvviewer/fpvv_mainform.lfm index 2b17bb057..612327411 100644 --- a/applications/fpvviewer/fpvv_mainform.lfm +++ b/applications/fpvviewer/fpvv_mainform.lfm @@ -1,11 +1,11 @@ object frmFPVViewer: TfrmFPVViewer - Left = 234 - Height = 433 - Top = 172 - Width = 342 + Left = 186 + Height = 441 + Top = 137 + Width = 336 Caption = 'frmFPVViewer' - ClientHeight = 433 - ClientWidth = 342 + ClientHeight = 441 + ClientWidth = 336 LCLVersion = '0.9.31' object editFileName: TFileNameEdit Left = 8 @@ -44,21 +44,15 @@ object frmFPVViewer: TfrmFPVViewer Left = 8 Height = 18 Top = 79 - Width = 61 + Width = 58 Caption = 'Scale by:' ParentColor = False end - object imageView: TImage - Left = 11 - Height = 296 - Top = 128 - Width = 325 - end object Label2: TLabel Left = 8 Height = 18 Top = 104 - Width = 82 + Width = 76 Caption = 'Start Pos X:' ParentColor = False end @@ -80,8 +74,48 @@ object frmFPVViewer: TfrmFPVViewer Left = 152 Height = 18 Top = 104 - Width = 79 + Width = 73 Caption = 'Start Pos Y:' ParentColor = False end + object Button1: TButton + Left = 112 + Height = 25 + Top = 41 + Width = 128 + Caption = 'View DXF Tokens' + OnClick = Button1Click + TabOrder = 5 + end + object notebook: TNotebook + Left = 0 + Height = 313 + Top = 128 + Width = 336 + PageIndex = 1 + TabOrder = 6 + TabStop = True + object Page1: TPage + ClientWidth = 336 + ClientHeight = 313 + object imageView: TImage + Left = 8 + Height = 296 + Top = 8 + Width = 325 + end + end + object Page2: TPage + ClientWidth = 336 + ClientHeight = 313 + object DXFTreeView: TTreeView + Left = 8 + Height = 313 + Top = 0 + Width = 321 + DefaultItemHeight = 19 + TabOrder = 0 + end + end + end end diff --git a/applications/fpvviewer/fpvv_mainform.pas b/applications/fpvviewer/fpvv_mainform.pas index de5766cb2..1a295f65d 100644 --- a/applications/fpvviewer/fpvv_mainform.pas +++ b/applications/fpvviewer/fpvv_mainform.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, EditBtn, - StdCtrls, Spin, ExtCtrls; + StdCtrls, Spin, ExtCtrls, ComCtrls; type @@ -14,15 +14,21 @@ type TfrmFPVViewer = class(TForm) btnVisualize: TButton; + Button1: TButton; editFileName: TFileNameEdit; imageView: TImage; Label2: TLabel; Label3: TLabel; + notebook: TNotebook; + Page1: TPage; + Page2: TPage; spinStartX: TSpinEdit; spinStartY: TSpinEdit; spinScale: TFloatSpinEdit; Label1: TLabel; + DXFTreeView: TTreeView; procedure btnVisualizeClick(Sender: TObject); + procedure Button1Click(Sender: TObject); private { private declarations } public @@ -37,7 +43,8 @@ implementation uses fpvectorial, cdrvectorialreader, svgvectorialwriter, pdfvectorialreader, dxfvectorialreader, - fpvtocanvas; + fpvtocanvas, + dxftokentotree; {$R *.lfm} @@ -50,6 +57,8 @@ begin // First check the in input //if not CheckInput() then Exit; + notebook.PageIndex := 0; + Vec := TvVectorialDocument.Create; try Vec.ReadFromFile(editFileName.FileName, vfDXF); @@ -61,5 +70,26 @@ begin end; end; +procedure TfrmFPVViewer.Button1Click(Sender: TObject); +var + Reader: TvDXFVectorialReader; + Vec: TvVectorialDocument; +begin + // First check the in input + //if not CheckInput() then Exit; + + notebook.PageIndex := 1; + + Reader := TvDXFVectorialReader.Create; + Vec := TvVectorialDocument.Create; + try + Reader.ReadFromFile(editFileName.FileName, Vec); + ConvertDXFTokensToTreeView(Reader.Tokenizer.Tokens, DXFTreeView); + finally + Reader.Free; + Vec.Free; + end; +end; + end. diff --git a/applications/fpvviewer/fpvviewer.lpi b/applications/fpvviewer/fpvviewer.lpi index c29f28924..75c729b67 100644 --- a/applications/fpvviewer/fpvviewer.lpi +++ b/applications/fpvviewer/fpvviewer.lpi @@ -3,9 +3,6 @@ - - - @@ -37,7 +34,7 @@ - + @@ -50,6 +47,11 @@ + + + + + diff --git a/applications/fpvviewer/fpvviewer.lpr b/applications/fpvviewer/fpvviewer.lpr index d0081b499..d75de4970 100644 --- a/applications/fpvviewer/fpvviewer.lpr +++ b/applications/fpvviewer/fpvviewer.lpr @@ -7,7 +7,7 @@ uses cthreads, {$ENDIF}{$ENDIF} Interfaces, // this includes the LCL widgetset - Forms, fpvv_mainform + Forms, fpvv_mainform, dxftokentotree { you can add units after this }; {$R *.res}