fpvectorial: Starts adding support for BLOCK and INSERT entities from DXF

git-svn-id: trunk@39023 -
This commit is contained in:
sekelsenmat 2012-10-09 14:21:45 +00:00
parent e6a407ceed
commit 8659c6e351
4 changed files with 344 additions and 25 deletions

View File

@ -71,6 +71,7 @@ type
constructor Create;
Destructor Destroy; override;
procedure ReadFromStrings(AStrings: TStrings);
function IsBLOCKS_Subsection(AStr: string): Boolean;
function IsENTITIES_Subsection(AStr: string): Boolean;
end;
@ -91,13 +92,17 @@ type
Polyline: array of TPolylineElement;
//
procedure ReadHEADER(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument);
procedure ReadBLOCKS(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument);
procedure ReadBLOCKS_BLOCK(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument);
procedure ReadBLOCKS_ENDBLK(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument);
procedure ReadENTITIES(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument);
procedure ReadENTITIES_LINE(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument);
function ReadENTITIES_LINE(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument): TPath;
procedure ReadENTITIES_ARC(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument);
procedure ReadENTITIES_CIRCLE(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument);
procedure ReadENTITIES_DIMENSION(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument);
procedure ReadENTITIES_ELLIPSE(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument);
procedure ReadENTITIES_TEXT(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument);
function ReadENTITIES_INSERT(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument): TvInsert;
function ReadENTITIES_TEXT(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument): TvText;
procedure ReadENTITIES_LWPOLYLINE(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument);
procedure ReadENTITIES_SPLINE(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument);
procedure ReadENTITIES_POLYLINE(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument);
@ -486,7 +491,7 @@ var
i: Integer;
StrSectionGroupCode, StrSectionName: string;
IntSectionGroupCode: Integer;
CurTokenBase, NextTokenBase, SectionTokenBase: TDXFTokens;
CurTokenBase, NextTokenBase, SectionTokenBase, LastBlockToken: TDXFTokens;
NewToken: TDXFToken;
ParserState: Integer;
begin
@ -535,13 +540,17 @@ 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 = 'BLOCKS') then
begin
ParserState := 4;
SectionTokenBase := CurTokenBase;
end
else if (StrSectionName = 'ENTITIES') then
begin
ParserState := 3;
@ -577,6 +586,29 @@ begin
CurTokenBase := SectionTokenBase;
NextTokenBase := Tokens;
end;
end
// Reading the BLOCKS section
else if ParserState = 4 then
begin
// This orders the blocks themselves
if IsBLOCKS_Subsection(StrSectionName) then
begin
CurTokenBase := SectionTokenBase;
NextTokenBase := NewToken.Childs;
LastBlockToken := NewToken.Childs;
end
// This orders the entities inside blocks
else if IsENTITIES_Subsection(StrSectionName) and (LastBlockToken <> nil) then
begin
CurTokenBase := LastBlockToken;
NextTokenBase := NewToken.Childs;
end
else if StrSectionName = 'ENDSEC' then
begin
ParserState := 0;
CurTokenBase := SectionTokenBase;
NextTokenBase := Tokens;
end;
end;
CurTokenBase.Add(NewToken);
@ -585,6 +617,13 @@ begin
end;
end;
function TDXFTokenizer.IsBLOCKS_Subsection(AStr: string): Boolean;
begin
Result :=
(AStr = 'BLOCK') or
(AStr = 'ENDBLK');
end;
function TDXFTokenizer.IsENTITIES_Subsection(AStr: string): Boolean;
begin
Result :=
@ -723,6 +762,112 @@ begin
end;
end;
procedure TvDXFVectorialReader.ReadBLOCKS(ATokens: TDXFTokens;
AData: TvVectorialPage; ADoc: TvVectorialDocument);
var
i: Integer;
CurToken: TDXFToken;
begin
for i := 0 to ATokens.Count - 1 do
begin
CurToken := TDXFToken(ATokens.Items[i]);
if CurToken.StrValue = 'BLOCK' then ReadBLOCKS_BLOCK(CurToken.Childs, AData, ADoc)
else if CurToken.StrValue = 'ENDBLK' then ReadBLOCKS_ENDBLK(CurToken.Childs, AData, ADoc)
else
begin
// ...
end;
end;
end;
(*
The following group codes apply to block entities. For information about abbreviations and formatting used in this table, see "Formatting Conventions in This Reference."
Block group codes Group codes Description
0 Entity type (BLOCK)
5 Handle
102 (optional) Start of application-defined group "{application_name". For example, "{ACAD_REACTORS" indicates the start of the AutoCAD persistent reactors group.
application-defined codes (optional) Codes and values within the 102 groups are application defined
102 (optional) End of group, "}"
330 Soft-pointer ID/handle to owner object
100 Subclass marker (AcDbEntity)
8 Layer name
100 Subclass marker (AcDbBlockBegin)
2 Block name
70 Block-type flags (bit coded values, may be combined):
1 = This is an anonymous block generated by hatching, associative dimensioning, other internal operations, or an application.
2 = This block has non-constant attribute definitions (this bit is not set if the block has any attribute definitions that are constant, or has no attribute definitions at all).
4 = This block is an external reference (xref).
8 = This block is an xref overlay.
16 = This block is externally dependent.
32 = This is a resolved external reference, or dependent of an external reference (ignored on input).
64 = This definition is a referenced external reference (ignored
on input).
10 Base point DXF: X value; APP: 3D point
20, 30 DXF: Y and Z values of base point
3 Block name
1 Xref path name
4 Block description (optional)
*)
procedure TvDXFVectorialReader.ReadBLOCKS_BLOCK(ATokens: TDXFTokens;
AData: TvVectorialPage; ADoc: TvVectorialDocument);
var
CurToken: TDXFToken;
i: Integer;
// BLOCK data
lName: string;
PosX, PosY, PosZ: Double;
lBlock: TvBlock = nil;
lEntity: TvEntity = nil;
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 in [10, 20, 30] then
begin
CurToken.FloatValue := StrToFloat(Trim(CurToken.StrValue), FPointSeparator);
end;
case CurToken.GroupCode of
2: lName := CurToken.StrValue;
10: PosX := CurToken.FloatValue;
20: PosY := CurToken.FloatValue;
30: PosZ := CurToken.FloatValue;
0:
begin
if lBlock = nil then
lBlock := AData.AddBlock(lName, PosX, PosY, PosZ);
lEntity := nil;
case CurToken.StrValue of
{'ARC': lEntity := ReadENTITIES_ARC(CurToken.Childs, nil, ADoc);
'CIRCLE': lEntity := ReadENTITIES_CIRCLE(CurToken.Childs, nil, ADoc);
'DIMENSION': lEntity := ReadENTITIES_DIMENSION(CurToken.Childs, nil, ADoc);
'ELLIPSE': lEntity := ReadENTITIES_ELLIPSE(CurToken.Childs, nil, ADoc);}
'LINE': lEntity := ReadENTITIES_LINE(CurToken.Childs, nil, ADoc);
'TEXT': lEntity := ReadENTITIES_TEXT(CurToken.Childs, nil, ADoc);
{'LWPOLYLINE':lEntity := ReadENTITIES_LWPOLYLINE(CurToken.Childs, nil, ADoc);
'SPLINE': lEntity := ReadENTITIES_SPLINE(CurToken.Childs, nil, ADoc);
'POINT': lEntity := ReadENTITIES_POINT(CurToken.Childs, nil, ADoc);
'MTEXT': lEntity := ReadENTITIES_MTEXT(CurToken.Childs, nil, ADoc);
'LEADER': lEntity := ReadENTITIES_LEADER(CurToken.Childs, nil, ADoc);}
end;
if lEntity <> nil then
lBlock.AddEntity(lEntity);
end;
end;
end;
end;
procedure TvDXFVectorialReader.ReadBLOCKS_ENDBLK(ATokens: TDXFTokens;
AData: TvVectorialPage; ADoc: TvVectorialDocument);
begin
end;
procedure TvDXFVectorialReader.ReadENTITIES(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument);
var
i: Integer;
@ -737,6 +882,7 @@ begin
else if CurToken.StrValue = 'CIRCLE' then ReadENTITIES_CIRCLE(CurToken.Childs, AData, ADoc)
else if CurToken.StrValue = 'DIMENSION' then ReadENTITIES_DIMENSION(CurToken.Childs, AData, ADoc)
else if CurToken.StrValue = 'ELLIPSE' then ReadENTITIES_ELLIPSE(CurToken.Childs, AData, ADoc)
else if CurToken.StrValue = 'INSERT' then ReadENTITIES_INSERT(CurToken.Childs, AData, ADoc)
else if CurToken.StrValue = 'LINE' then ReadENTITIES_LINE(CurToken.Childs, AData, ADoc)
else if CurToken.StrValue = 'TEXT' then ReadENTITIES_TEXT(CurToken.Childs, AData, ADoc)
else if CurToken.StrValue = 'LWPOLYLINE' then ReadENTITIES_LWPOLYLINE(CurToken.Childs, AData, ADoc)
@ -763,7 +909,7 @@ begin
end;
end;
procedure TvDXFVectorialReader.ReadENTITIES_LINE(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument);
function TvDXFVectorialReader.ReadENTITIES_LINE(ATokens: TDXFTokens; AData: TvVectorialPage; ADoc: TvVectorialDocument): TPath;
var
CurToken: TDXFToken;
i: Integer;
@ -772,6 +918,8 @@ var
LineEndX, LineEndY, LineEndZ: Double;
LLineColor: TFPColor;
begin
Result := nil;
// Initial values
LineStartX := 0;
LineStartY := 0;
@ -813,9 +961,18 @@ begin
{$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, LLineColor);
AData.EndPath();
if AData = nil then
begin
Result := TPath.Create;
Result.AppendMoveToSegment(LineStartX, LineStartY);
Result.AppendLineToSegment(LineEndX, LineEndY);
end
else
begin
AData.StartPath(LineStartX, LineStartY);
AData.AddLineToPath(LineEndX, LineEndY, LLineColor);
AData.EndPath();
end;
end;
{
@ -1139,6 +1296,12 @@ begin
AData.AddEllipse(CenterX, CenterY, MajorHalfAxis, MinorHalfAxis, Angle);
end;
function TvDXFVectorialReader.ReadENTITIES_INSERT(ATokens: TDXFTokens;
AData: TvVectorialPage; ADoc: TvVectorialDocument): TvInsert;
begin
end;
{
100 Subclass marker (AcDbText)
39 Thickness (optional; default = 0)
@ -1171,8 +1334,8 @@ end;
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: TvVectorialPage; ADoc: TvVectorialDocument);
function TvDXFVectorialReader.ReadENTITIES_TEXT(ATokens: TDXFTokens;
AData: TvVectorialPage; ADoc: TvVectorialDocument): TvText;
var
CurToken: TDXFToken;
i: Integer;
@ -1210,7 +1373,16 @@ begin
Str := ConvertDXFStringToUTF8(Str);
//
AData.AddText(PosX, PosY, 0, '', Round(FontSize), Str);
if AData = nil then
begin
Result := TvText.Create;
Result.Value.Text := Str;
Result.X := PosX;
Result.Y := PosY;
Result.Font.Size := Round(FontSize);
end
else
Result := AData.AddText(PosX, PosY, 0, '', Round(FontSize), Str);
end;
{.$define FPVECTORIALDEBUG_LWPOLYLINE}
@ -1617,6 +1789,8 @@ begin
if CurTokenFirstChild.StrValue = 'HEADER' then
ReadHEADER(CurToken.Childs, lPage, AData)
else if CurTokenFirstChild.StrValue = 'BLOCKS' then
ReadBLOCKS(CurToken.Childs, lPage, AData)
else if CurTokenFirstChild.StrValue = 'ENTITIES' then
ReadENTITIES(CurToken.Childs, lPage, AData);
end;

View File

@ -249,6 +249,8 @@ type
function Next(): TPathSegment;
procedure CalculateBoundingBox(ADest: TFPCustomCanvas; var ALeft, ATop, ARight, ABottom: Double); override;
procedure AppendSegment(ASegment: TPathSegment);
procedure AppendMoveToSegment(AX, AY: Double);
procedure AppendLineToSegment(AX, AY: Double);
procedure Render(ADest: TFPCustomCanvas; ADestX: Integer = 0;
ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0); override;
end;
@ -467,6 +469,39 @@ type
function GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer): Pointer; override;
end;
{@@
A block is a group of other elements. It is not rendered directly into the drawing,
but instead is rendered via another item, called TvInsert
}
{ TvBlock }
TvBlock = class(TvEntity)
private
FCurIndex: Integer;
procedure CallbackDeleteElement(data,arg:pointer);
protected
FElements: TFPList; // of TvEntity
public
Name: string;
constructor Create; override;
destructor Destroy; override;
//
function GetFirstEntity: TvEntity;
function GetNextEntity: TvEntity;
procedure AddEntity(AEntity: TvEntity);
procedure Clear;
end;
{@@
A "Insert" inserts a block into the drawing in the specified position
}
TvInsert = class(TvEntity)
public
Block: TvBlock; // The block to be inserted
end;
{ TvVectorialDocument }
TvVectorialDocument = class
@ -563,12 +598,14 @@ type
procedure SetPenWidth(AWidth: Integer);
procedure SetClipPath(AClipPath: TPath; AClipMode: TvClipMode);
procedure EndPath();
procedure AddText(AX, AY, AZ: Double; FontName: string; FontSize: integer; AText: utf8string); overload;
procedure AddText(AX, AY: Double; AStr: utf8string); overload;
procedure AddText(AX, AY, AZ: Double; AStr: utf8string); overload;
function AddText(AX, AY, AZ: Double; FontName: string; FontSize: integer; AText: utf8string): TvText; overload;
function AddText(AX, AY: Double; AStr: utf8string): TvText; overload;
function AddText(AX, AY, AZ: Double; AStr: utf8string): TvText; overload;
procedure AddCircle(ACenterX, ACenterY, ARadius: Double);
procedure AddCircularArc(ACenterX, ACenterY, ARadius, AStartAngle, AEndAngle: Double; AColor: TFPColor);
procedure AddEllipse(CenterX, CenterY, HorzHalfAxis, VertHalfAxis, Angle: Double);
function AddBlock(AName: string; AX, AY, AZ: Double): TvBlock;
function AddInsert(AX, AY, AZ: Double; ABlock: TvBlock): TvInsert;
// Dimensions
procedure AddAlignedDimension(BaseLeft, BaseRight, DimLeft, DimRight: T3DPoint);
//
@ -961,6 +998,28 @@ begin
PointsEnd := ASegment;
end;
procedure TPath.AppendMoveToSegment(AX, AY: Double);
var
segment: T2DSegment;
begin
segment := T2DSegment.Create;
segment.SegmentType := stMoveTo;
segment.X := AX;
segment.Y := AY;
AppendSegment(segment);
end;
procedure TPath.AppendLineToSegment(AX, AY: Double);
var
segment: T2DSegment;
begin
segment := T2DSegment.Create;
segment.SegmentType := st2DLine;
segment.X := AX;
segment.Y := AY;
AppendSegment(segment);
end;
procedure TPath.Render(ADest: TFPCustomCanvas; ADestX: Integer;
ADestY: Integer; AMulX: Double; AMulY: Double);
@ -2152,6 +2211,50 @@ begin
end;
end;
{ TvBlock }
procedure TvBlock.CallbackDeleteElement(data, arg: pointer);
begin
TvFormulaElement(data).Free;
end;
constructor TvBlock.Create;
begin
inherited Create;
FElements := TFPList.Create;
end;
destructor TvBlock.Destroy;
begin
FElements.Free;
inherited Destroy;
end;
function TvBlock.GetFirstEntity: TvEntity;
begin
if FElements.Count = 0 then Exit(nil);
Result := FElements.Items[0];
FCurIndex := 1;
end;
function TvBlock.GetNextEntity: TvEntity;
begin
if FElements.Count <= FCurIndex then Exit(nil);
Result := FElements.Items[FCurIndex];
Inc(FCurIndex);
end;
procedure TvBlock.AddEntity(AEntity: TvEntity);
begin
FElements.Add(AEntity);
end;
procedure TvBlock.Clear;
begin
FElements.ForEachCall(CallbackDeleteElement, nil);
FElements.Clear;
end;
{ TvVectorialPage }
procedure TvVectorialPage.ClearTmpPath;
@ -2495,8 +2598,8 @@ begin
ClearTmpPath();
end;
procedure TvVectorialPage.AddText(AX, AY, AZ: Double; FontName: string;
FontSize: integer; AText: utf8string);
function TvVectorialPage.AddText(AX, AY, AZ: Double; FontName: string;
FontSize: integer; AText: utf8string): TvText;
var
lText: TvText;
begin
@ -2508,16 +2611,17 @@ begin
lText.Font.Name := FontName;
lText.Font.Size := FontSize;
AddEntity(lText);
Result := lText;
end;
procedure TvVectorialPage.AddText(AX, AY: Double; AStr: utf8string);
function TvVectorialPage.AddText(AX, AY: Double; AStr: utf8string): TvText;
begin
AddText(AX, AY, 0, '', 10, AStr);
Result := AddText(AX, AY, 0, '', 10, AStr);
end;
procedure TvVectorialPage.AddText(AX, AY, AZ: Double; AStr: utf8string);
function TvVectorialPage.AddText(AX, AY, AZ: Double; AStr: utf8string): TvText;
begin
AddText(AX, AY, AZ, '', 10, AStr);
Result := AddText(AX, AY, AZ, '', 10, AStr);
end;
procedure TvVectorialPage.AddCircle(ACenterX, ACenterY, ARadius: Double);
@ -2560,6 +2664,30 @@ begin
AddEntity(lEllipse);
end;
function TvVectorialPage.AddBlock(AName: string; AX, AY, AZ: Double): TvBlock;
var
lBlock: TvBlock;
begin
lBlock := TvBlock.Create;
lBlock.X := AX;
lBlock.Y := AY;
lBlock.Name := AName;
AddEntity(lBlock);
Result := lBlock;
end;
function TvVectorialPage.AddInsert(AX, AY, AZ: Double; ABlock: TvBlock): TvInsert;
var
lInsert: TvInsert;
begin
lInsert := TvInsert.Create;
lInsert.X := AX;
lInsert.Y := AY;
lInsert.Block := ABlock;
AddEntity(lInsert);
Result := lInsert;
end;
procedure TvVectorialPage.AddAlignedDimension(BaseLeft, BaseRight, DimLeft,
DimRight: T3DPoint);

View File

@ -136,6 +136,7 @@ type
{$endif}
procedure ReadVariableLengthRecords(AStream: TStream);
procedure DoProgress(AProgress: Byte; AData: TvVectorialDocument);
function ReadLAZPoint0(AStream: TStream): TLASPointDataRecordFormat0;
public
// Public Header
PublicHeaderBlock_1_0: TLASPublicHeaderBlock_1_0;
@ -355,6 +356,12 @@ begin
if @AData.OnProgress <> nil then AData.OnProgress(AProgress);
end;
function TvLASVectorialReader.ReadLAZPoint0(AStream: TStream
): TLASPointDataRecordFormat0;
begin
end;
procedure TvLASVectorialReader.ReadFromStream(AStream: TStream;
AData: TvVectorialDocument);
var
@ -421,6 +428,15 @@ begin
lClassification := lRecord1.Classification;
lPoint := lPage.AddPoint(lRecord1.X, lRecord1.Y, lRecord1.Z);
end;
130:
begin
lRecord0 := ReadLAZPoint0(AStream);
lClassification := lRecord0.Classification;
lPoint := lPage.AddPoint(lRecord0.X, lRecord0.Y, lRecord0.Z);
end;
else
raise Exception.Create('[TvLASVectorialReader.ReadFromStream] Error reading LAS point: Unknown point type number='
+ IntToStr(PublicHeaderBlock_1_0.PointDataFormatID));
end;
// Correct the min and max
@ -477,6 +493,7 @@ initialization
RegisterVectorialReader(TvLASVectorialReader, vfLAS);
RegisterVectorialWriter(TvLASVectorialWriter, vfLAS);
RegisterVectorialReader(TvLASVectorialReader, vfLAZ);
end.

View File

@ -42,12 +42,12 @@ type
TvLAZVectorialReader = class(TvLASVectorialReader)
public
{ General reading methods }
procedure ReadFromStream(AStream: TStream; AData: TvVectorialDocument); override;
//procedure ReadFromStream(AStream: TStream; AData: TvVectorialDocument); override;
end;
implementation
procedure TvLAZVectorialReader.ReadFromStream(AStream: TStream;
(*procedure TvLAZVectorialReader.ReadFromStream(AStream: TStream;
AData: TvVectorialDocument);
var
lPage: TvVectorialPage;
@ -162,12 +162,12 @@ begin
end;
lPoint.Pen.Color := lColor;
end;*)
end;
end;
end;*)
initialization
RegisterVectorialReader(TvLAZVectorialReader, vfLAZ);
// RegisterVectorialReader(TvLAZVectorialReader, vfLAZ);
// RegisterVectorialWriter(TvLAZVectorialWriter, vfLAZ);
end.