GXS.FileDXF.pas 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.FileDXF;
  5. (*
  6. Support-Code to load DXF (Drawing eXchange Files) TgxFreeForm or
  7. TgxActor Components.
  8. Note that you must manually add this unit to one of your project's uses
  9. to enable support for DXF at run-time.
  10. Turn on TwoSideLighting in your Buffer! DXF-Faces have no defined winding order
  11. *)
  12. interface
  13. uses
  14. System.Classes,
  15. System.SysUtils,
  16. Stage.VectorTypes,
  17. GXS.ApplicationFileIO,
  18. Stage.VectorGeometry,
  19. GXS.VectorLists,
  20. GXS.Scene,
  21. GXS.Texture,
  22. GXS.VectorFileObjects,
  23. GXS.Material;
  24. type
  25. TgxDXFVectorFile = class(TgxVectorFile)
  26. private
  27. FSourceStream: TStream; // Load from this stream
  28. FBuffer: String; // Buffer and current line
  29. FLineNo: Integer; // current Line number - for error messages
  30. FEof: Boolean; // Stream done?
  31. FBufPos: Integer; // Position in the buffer
  32. HasPushedCode: Boolean;
  33. PushedCode: Integer;
  34. FLayers: TStringList;
  35. FBlocks: TStringList;
  36. FLastpercentdone: BYTE;
  37. protected
  38. procedure PushCode(code: Integer);
  39. function GetCode: Integer;
  40. procedure SkipTable;
  41. procedure SkipSection;
  42. // procedure DoProgress (Stage: TgxProgressStage; PercentDone: single; RedrawNow: Boolean; const Msg: string);
  43. function NeedMesh(basemesh: TgxBaseMesh; layer: STRING): TgxMeshObject;
  44. function NeedFaceGroup(m: TgxMeshObject; fgmode: TgxFaceGroupMeshMode;
  45. fgmat: STRING): TgxFGVertexIndexList;
  46. procedure NeedMeshAndFaceGroup(basemesh: TgxBaseMesh; layer: STRING;
  47. fgmode: TgxFaceGroupMeshMode; fgmat: STRING; var m: TgxMeshObject;
  48. var fg: TgxFGVertexIndexList);
  49. function ReadLine: STRING;
  50. // Read a single line of text from the source stream, set FEof to true when done.
  51. function ReadInt: Integer;
  52. function ReadDouble: double;
  53. procedure ReadTables;
  54. procedure ReadLayer;
  55. procedure ReadLayerTable;
  56. procedure ReadBlocks;
  57. procedure ReadInsert(basemesh: TgxBaseMesh);
  58. procedure ReadEntity3Dface(basemesh: TgxBaseMesh);
  59. procedure ReadEntityPolyLine(basemesh: TgxBaseMesh);
  60. procedure ReadEntities(basemesh: TgxBaseMesh);
  61. public
  62. class function Capabilities: TDataFileCapabilities; override;
  63. procedure LoadFromStream(aStream: TStream); override;
  64. end;
  65. //========================================================================
  66. implementation
  67. //========================================================================
  68. procedure BuildNormals(m: TgxMeshObject); FORWARD;
  69. const
  70. DXFcolorsRGB: ARRAY [1 .. 255] OF LONGINT = ($FF0000, $FFFF00, $00FF00,
  71. $00FFFF, $0000FF, $FF00FF, $000000, $000000, $000000, $FF0000, $FF8080,
  72. $A60000, $A65353, $800000, $804040, $4D0000, $4D2626, $260000, $261313,
  73. $FF4000, $FF9F80, $A62900, $A66853, $802000, $805040, $4D1300, $4D3026,
  74. $260A00, $261813, $FF8000, $FFBF80, $A65300, $A67C53, $804000, $806040,
  75. $4D2600, $4D3926, $261300, $261D13, $FFBF00, $FFDF80, $A67C00, $A69153,
  76. $806000, $807040, $4D3900, $4D4326, $261D00, $262113, $FFFF00, $FFFF80,
  77. $A6A600, $A6A653, $808000, $808040, $4D4D00, $4D4D26, $262600, $262613,
  78. $BFFF00, $DFFF80, $7CA600, $91A653, $608000, $708040, $394D00, $434D26,
  79. $1D2600, $212613, $80FF00, $BFFF80, $53A600, $7CA653, $408000, $608040,
  80. $264D00, $394D26, $132600, $1D2613, $40FF00, $9FFF80, $29A600, $68A653,
  81. $208000, $508040, $134D00, $304D26, $0A2600, $182613, $00FF00, $80FF80,
  82. $00A600, $53A653, $008000, $408040, $004D00, $264D26, $002600, $132613,
  83. $00FF40, $80FF9F, $00A629, $53A668, $008020, $408050, $004D13, $264D30,
  84. $00260A, $132618, $00FF80, $80FFBF, $00A653, $53A67C, $008040, $408060,
  85. $004D26, $264D39, $002613, $13261D, $00FFBF, $80FFDF, $00A67C, $53A691,
  86. $008060, $408070, $004D39, $264D43, $00261D, $132621, $00FFFF, $80FFFF,
  87. $00A6A6, $53A6A6, $008080, $408080, $004D4D, $264D4D, $002626, $132626,
  88. $00BFFF, $80DFFF, $007CA6, $5391A6, $006080, $407080, $00394D, $26434D,
  89. $001D26, $132126, $0080FF, $80BFFF, $0053A6, $537CA6, $004080, $406080,
  90. $00264D, $26394D, $001326, $131D26, $0040FF, $809FFF, $0029A6, $5368A6,
  91. $002080, $405080, $00134D, $26304D, $000A26, $131826, $0000FF, $8080FF,
  92. $0000A6, $5353A6, $000080, $404080, $00004D, $26264D, $000026, $131326,
  93. $4000FF, $9F80FF, $2900A6, $6853A6, $200080, $504080, $13004D, $30264D,
  94. $0A0026, $181326, $8000FF, $BF80FF, $5300A6, $7C53A6, $400080, $604080,
  95. $26004D, $39264D, $130026, $1D1326, $BF00FF, $DF80FF, $7C00A6, $9153A6,
  96. $600080, $704080, $39004D, $43264D, $1D0026, $211326, $FF00FF, $FF80FF,
  97. $A600A6, $A653A6, $800080, $804080, $4D004D, $4D264D, $260026, $261326,
  98. $FF00BF, $FF80DF, $A6007C, $A65391, $800060, $804070, $4D0039, $4D2643,
  99. $26001D, $261321, $FF0080, $FF80BF, $A60053, $A6537C, $800040, $804060,
  100. $4D0026, $4D2639, $260013, $26131D, $FF0040, $FF809F, $A60029, $A65368,
  101. $800020, $804050, $4D0013, $4D2630, $26000A, $261318, $545454, $767676,
  102. $989898, $BBBBBB, $DDDDDD, $FFFFFF);
  103. const
  104. BufSize = 65536; { Load input data in chunks of BufSize Bytes. }
  105. LineLen = 100; { Allocate memory for the current line in chunks }
  106. function RGB2BGR(bgr: LONGINT): LONGINT;
  107. begin
  108. result := ((bgr SHR 16) and $FF) or (bgr AND $FF00) or
  109. ((bgr SHL 16) and $FF0000)
  110. end;
  111. function StreamEOF(S: TStream): Boolean;
  112. begin // Is the stream at its end?
  113. result := (S.Position >= S.Size);
  114. end;
  115. class function TgxDXFVectorFile.Capabilities: TDataFileCapabilities;
  116. begin
  117. result := [dfcRead];
  118. end;
  119. function TgxDXFVectorFile.ReadLine: STRING;
  120. var
  121. j: Integer;
  122. FLine: STRING;
  123. NewlineChar: CHAR;
  124. procedure FillBuffer;
  125. var
  126. l: Integer;
  127. begin
  128. l := FSourceStream.Size - FSourceStream.Position;
  129. if l > BufSize then
  130. l := BufSize;
  131. SetLength(FBuffer, l);
  132. FSourceStream.Read(FBuffer[1], l);
  133. FBufPos := 1;
  134. end;
  135. begin
  136. Inc(FLineNo);
  137. if FBufPos < 1 then
  138. FillBuffer;
  139. j := 1;
  140. while True do
  141. begin
  142. if FBufPos > Length(FBuffer) then
  143. begin
  144. if StreamEOF(FSourceStream) then
  145. begin
  146. FEof := True;
  147. break;
  148. end
  149. else
  150. FillBuffer
  151. end
  152. else
  153. begin
  154. case FBuffer[FBufPos] of
  155. #10, #13:
  156. begin
  157. NewlineChar := FBuffer[FBufPos];
  158. Inc(FBufPos);
  159. if FBufPos > Length(FBuffer) then
  160. if StreamEOF(FSourceStream) then
  161. break
  162. else
  163. FillBuffer;
  164. if ((FBuffer[FBufPos] = #10) or (FBuffer[FBufPos] = #13)) and
  165. (FBuffer[FBufPos] <> NewlineChar) then
  166. Inc(FBufPos);
  167. break;
  168. end;
  169. else
  170. if j > Length(FLine) then
  171. SetLength(FLine, Length(FLine) + LineLen);
  172. if FBuffer[FBufPos] = #9 then
  173. FLine[j] := #32
  174. else
  175. FLine[j] := FBuffer[FBufPos];
  176. Inc(FBufPos);
  177. Inc(j);
  178. end;
  179. end;
  180. end;
  181. SetLength(FLine, j - 1);
  182. ReadLine := Trim(FLine);
  183. end;
  184. {
  185. procedure TgxDXFVectorFile.DoProgress (Stage: TgxProgressStage; PercentDone: single; RedrawNow: Boolean; const Msg: string);
  186. var perc:BYTE;
  187. begin
  188. // If the following line stops your compiler, just comment this function
  189. if @owner.OnProgress<>NIL then
  190. begin
  191. perc:=round(percentdone);
  192. if (perc<>Flastpercentdone) or (msg<>'') or redrawnow then
  193. owner.OnProgress (owner,stage,perc,redrawnow,msg);
  194. Flastpercentdone:=perc;
  195. end;
  196. end;
  197. }
  198. procedure TgxDXFVectorFile.PushCode(code: Integer);
  199. begin
  200. PushedCode := code;
  201. HasPushedCode := True;
  202. end;
  203. function TgxDXFVectorFile.GetCode: Integer;
  204. var
  205. S: STRING;
  206. begin
  207. if HasPushedCode then
  208. begin
  209. GetCode := PushedCode;
  210. HasPushedCode := FALSE;
  211. end
  212. else
  213. begin
  214. S := ReadLine;
  215. result := StrToIntDef(S, -1);
  216. if result = -1 then
  217. raise Exception.create('Invalid DXF Code ' + S + ' on Line #' +
  218. IntToStr(FLineNo));
  219. end;
  220. end;
  221. function TgxDXFVectorFile.ReadDouble: double;
  222. var
  223. S: String;
  224. c: CHAR;
  225. begin
  226. c := FormatSettings.DecimalSeparator;
  227. FormatSettings.DecimalSeparator := '.';
  228. S := Trim(ReadLine);
  229. result := StrToFloat(S);
  230. FormatSettings.DecimalSeparator := c;
  231. end;
  232. function TgxDXFVectorFile.ReadInt: Integer;
  233. var
  234. S: String;
  235. begin
  236. S := Trim(ReadLine);
  237. result := StrToInt(S);
  238. end;
  239. procedure TgxDXFVectorFile.SkipSection;
  240. var
  241. S: String;
  242. code: Integer;
  243. begin
  244. repeat
  245. code := GetCode;
  246. S := ReadLine;
  247. until (code = 0) and (S = 'ENDSEC');
  248. end;
  249. procedure TgxDXFVectorFile.SkipTable;
  250. var
  251. S: String;
  252. code: Integer;
  253. begin
  254. repeat
  255. code := GetCode;
  256. S := ReadLine;
  257. until (code = 0) and (S = 'ENDTAB');
  258. end;
  259. procedure TgxDXFVectorFile.ReadLayer;
  260. var
  261. layername, color: String;
  262. code: Integer;
  263. begin
  264. color := '1';
  265. repeat
  266. code := GetCode;
  267. case code of
  268. 0:
  269. ;
  270. 2:
  271. layername := ReadLine;
  272. 70:
  273. ReadLine; // freeze and lock flags
  274. 62:
  275. color := ReadLine;
  276. else
  277. ReadLine;
  278. end;
  279. until code = 0;
  280. PushCode(0);
  281. FLayers.AddObject(layername, POINTER(StrToIntDef(color, 1)));
  282. end;
  283. procedure TgxDXFVectorFile.ReadLayerTable;
  284. var
  285. S: STRING;
  286. code: Integer;
  287. begin
  288. repeat
  289. code := GetCode;
  290. S := ReadLine;
  291. if (code = 0) and (S = 'LAYER') then
  292. ReadLayer;
  293. until (code = 0) and (S = 'ENDTAB');
  294. end;
  295. procedure TgxDXFVectorFile.ReadTables;
  296. var
  297. S: String;
  298. code: Integer;
  299. begin
  300. repeat
  301. code := GetCode;
  302. S := ReadLine;
  303. if (code = 0) and (S = 'TABLE') then
  304. begin
  305. code := GetCode;
  306. S := ReadLine;
  307. if (code = 2) then
  308. if S = 'LAYER' then
  309. ReadLayerTable
  310. else
  311. SkipTable; // LTYPE, STYLE, UCS, and more currently skipped
  312. end
  313. until (code = 0) and (S = 'ENDSEC');
  314. end;
  315. procedure TgxDXFVectorFile.ReadBlocks;
  316. var
  317. S: String;
  318. code: Integer;
  319. blockname: String;
  320. blockmesh: TgxFreeForm;
  321. begin
  322. // This code reads blocks into orphaned TgxFreeForms.
  323. // ReadInsert then either copies or parents this object to its parent
  324. // unused blocks are freed upon completion
  325. repeat
  326. code := GetCode;
  327. S := ReadLine;
  328. if (code = 0) and (S = 'BLOCK') then
  329. begin
  330. blockmesh := TgxFreeForm.create(owner);
  331. blockmesh.IgnoreMissingTextures := True;
  332. blockmesh.MaterialLibrary := owner.MaterialLibrary;
  333. blockmesh.OnProgress := NIL;
  334. blockname := 'DXFBLOCK' + IntToStr(FBlocks.count);
  335. repeat
  336. code := GetCode;
  337. case code of
  338. 0:
  339. ;
  340. 2:
  341. blockname := ReadLine;
  342. else
  343. S := ReadLine;
  344. end;
  345. until code = 0;
  346. PushCode(0);
  347. FBlocks.AddObject(blockname, blockmesh);
  348. ReadEntities(blockmesh);
  349. // basemesh.Direction.SetVector(0,1,0);
  350. // code:=GetCode;
  351. // s:=ReadLine;
  352. // asm nop end;
  353. end;
  354. until (code = 0) and (S = 'ENDSEC');
  355. end;
  356. procedure TgxDXFVectorFile.ReadInsert(basemesh: TgxBaseMesh);
  357. var
  358. code, idx, indexoffset: Integer;
  359. i, j, k: Integer;
  360. blockname, S: STRING;
  361. pt, insertpoint, scale: TAffineVector;
  362. blockmesh: TgxBaseMesh;
  363. // blockproxy :TgxProxyObject;
  364. mo_block: TgxMeshObject;
  365. mo_base: TgxMeshObject;
  366. fg_block, fg_base: TgxFGVertexIndexList;
  367. begin
  368. blockname := '';
  369. insertpoint := NullVector;
  370. scale := XYZvector;
  371. repeat // see ReadBlocks for details
  372. code := GetCode;
  373. case code of
  374. 0:
  375. ;
  376. 2:
  377. blockname := ReadLine;
  378. 10:
  379. insertpoint.X := ReadDouble;
  380. 20:
  381. insertpoint.Y := ReadDouble;
  382. 30:
  383. insertpoint.Z := ReadDouble;
  384. 41:
  385. scale.X := ReadDouble;
  386. 42:
  387. scale.Y := ReadDouble;
  388. 43:
  389. scale.Z := ReadDouble;
  390. else
  391. S := ReadLine;
  392. end;
  393. until code = 0;
  394. idx := FBlocks.IndexOf(blockname);
  395. if idx >= 0 then
  396. begin
  397. blockmesh := FBlocks.Objects[idx] as TgxBaseMesh;
  398. // FLAT STRUCTURES
  399. // Insert a block into its parent by copying the contents.
  400. // the blockmesh will be freed upon completion, leaving only the copies.
  401. for i := 0 to blockmesh.MeshObjects.count - 1 do
  402. begin
  403. mo_block := blockmesh.MeshObjects[i];
  404. mo_base := NeedMesh(basemesh, mo_block.name);
  405. indexoffset := mo_base.vertices.count;
  406. for j := 0 to mo_block.vertices.count - 1 do
  407. begin
  408. pt := mo_block.vertices[j];
  409. ScaleVector(pt, scale);
  410. AddVector(pt, insertpoint);
  411. mo_base.vertices.Add(pt);
  412. end;
  413. for j := 0 to mo_block.FaceGroups.count - 1 do
  414. begin
  415. fg_block := mo_block.FaceGroups[j] as TgxFGVertexIndexList;
  416. fg_base := NeedFaceGroup(mo_base, fg_block.mode,
  417. fg_block.MaterialName);
  418. for k := 0 to fg_block.VertexIndices.count - 1 do
  419. begin
  420. fg_base.VertexIndices.Add(fg_block.VertexIndices[k] +
  421. indexoffset);
  422. end;
  423. end;
  424. end;
  425. // TREE STRUCTURES
  426. // Instead of copying the contents of the block, they are parented to the
  427. // base mesh. If the block already has a parent, a proxy object is created.
  428. // WARNING: THE CODE BELOW DOES NOT WORK.
  429. (*
  430. if blockmesh.Parent =NIL then
  431. begin
  432. blockmesh.Position.AsAffineVector:=insertpoint;
  433. blockmesh.ShowAxes:=TRUE;
  434. basemesh.AddChild(blockmesh);
  435. for i:=0 to blockmesh.MeshObjects.Count-1 do
  436. BuildNormals(blockmesh.MeshObjects[i]);
  437. end
  438. else
  439. begin
  440. blockproxy:=TgxproxyObject.CreateAsChild(basemesh);
  441. blockproxy.MasterObject:=blockmesh;
  442. blockproxy.Position.AsAffineVector:=insertpoint;
  443. blockproxy.ShowAxes:=TRUE;
  444. end;
  445. *)
  446. end;
  447. PushCode(0);
  448. end;
  449. function TgxDXFVectorFile.NeedMesh(basemesh: TgxBaseMesh; layer: STRING)
  450. : TgxMeshObject;
  451. var
  452. i: Integer;
  453. begin
  454. i := 0;
  455. while (i < basemesh.MeshObjects.count) and
  456. not(basemesh.MeshObjects[i].name = layer) do
  457. Inc(i);
  458. if i < basemesh.MeshObjects.count then
  459. result := basemesh.MeshObjects[i]
  460. else
  461. begin
  462. result := TgxMeshObject.CreateOwned(basemesh.MeshObjects);
  463. result.mode := momFaceGroups;
  464. result.name := layer;
  465. end;
  466. end;
  467. function TgxDXFVectorFile.NeedFaceGroup(m: TgxMeshObject;
  468. fgmode: TgxFaceGroupMeshMode; fgmat: STRING): TgxFGVertexIndexList;
  469. var
  470. i: Integer;
  471. acadcolor: LONGINT;
  472. libmat: TgxLibMaterial;
  473. fg: TgxFGVertexIndexList;
  474. begin
  475. i := 0;
  476. while (i < m.FaceGroups.count) and
  477. not((m.FaceGroups[i] is TgxFGVertexIndexList) and
  478. ((m.FaceGroups[i] as TgxFGVertexIndexList).mode = fgmode) and
  479. (m.FaceGroups[i].MaterialName = fgmat)) do
  480. Inc(i);
  481. if i < m.FaceGroups.count then
  482. fg := m.FaceGroups[i] as TgxFGVertexIndexList
  483. else
  484. begin
  485. fg := TgxFGVertexIndexList.CreateOwned(m.FaceGroups);
  486. fg.mode := fgmode;
  487. fg.MaterialName := fgmat;
  488. if owner.MaterialLibrary <> NIL then
  489. begin
  490. libmat := owner.MaterialLibrary.Materials.GetLibMaterialByName(fgmat);
  491. if libmat = NIL then // create a colored material
  492. begin
  493. acadcolor := StrToIntDef(fgmat, 0);
  494. if acadcolor in [1 .. 255] then
  495. begin
  496. libmat := owner.MaterialLibrary.Materials.Add;
  497. libmat.name := fgmat;
  498. libmat.Material.FrontProperties.Diffuse.AsWinColor :=
  499. RGB2BGR(DXFcolorsRGB[acadcolor]);
  500. libmat.Material.BackProperties.Diffuse.AsWinColor :=
  501. RGB2BGR(DXFcolorsRGB[acadcolor]);
  502. libmat.Material.FaceCulling := fcNoCull;
  503. end;
  504. end;
  505. end;
  506. end;
  507. result := fg;
  508. end;
  509. procedure TgxDXFVectorFile.NeedMeshAndFaceGroup(basemesh: TgxBaseMesh;
  510. layer: STRING; fgmode: TgxFaceGroupMeshMode; fgmat: STRING;
  511. var m: TgxMeshObject; var fg: TgxFGVertexIndexList);
  512. begin
  513. m := NeedMesh(basemesh, layer);
  514. fg := NeedFaceGroup(m, fgmode, fgmat);
  515. end;
  516. procedure TgxDXFVectorFile.ReadEntity3Dface(basemesh: TgxBaseMesh);
  517. var
  518. code, i: Integer;
  519. pts: ARRAY [0 .. 3] of TAffineVector;
  520. isquad: Boolean;
  521. fg: TgxFGVertexIndexList;
  522. color, layer: STRING;
  523. m: TgxMeshObject;
  524. begin
  525. color := '';
  526. layer := '';
  527. isquad := FALSE;
  528. for i := 0 to 3 do
  529. pts[i] := NullVector;
  530. repeat
  531. code := GetCode;
  532. case code of
  533. 0:
  534. ;
  535. 8:
  536. layer := ReadLine; // Layer
  537. 10:
  538. pts[0].X := ReadDouble;
  539. 11:
  540. pts[1].X := ReadDouble;
  541. 12:
  542. pts[2].X := ReadDouble;
  543. 13:
  544. begin
  545. pts[3].X := ReadDouble;
  546. isquad := True
  547. end;
  548. 20:
  549. pts[0].Y := ReadDouble;
  550. 21:
  551. pts[1].Y := ReadDouble;
  552. 22:
  553. pts[2].Y := ReadDouble;
  554. 23:
  555. begin
  556. pts[3].Y := ReadDouble;
  557. isquad := True
  558. end;
  559. 30:
  560. pts[0].Z := ReadDouble;
  561. 31:
  562. pts[1].Z := ReadDouble;
  563. 32:
  564. pts[2].Z := ReadDouble;
  565. 33:
  566. begin
  567. pts[3].Z := ReadDouble;
  568. isquad := True
  569. end;
  570. 62:
  571. color := ReadLine; // Color
  572. else
  573. ReadLine;
  574. end;
  575. until code = 0;
  576. PushCode(0);
  577. isquad := isquad and ((pts[2].X <> pts[3].X) or (pts[2].Y <> pts[3].Y) or
  578. (pts[2].Z <> pts[3].Z));
  579. if isquad then
  580. NeedMeshAndFaceGroup(basemesh, layer, fgmmQuads, color, m, fg)
  581. else
  582. NeedMeshAndFaceGroup(basemesh, layer, fgmmTriangles, color, m, fg);
  583. fg.Add(m.vertices.FindOrAdd(pts[0]));
  584. fg.Add(m.vertices.FindOrAdd(pts[1]));
  585. fg.Add(m.vertices.FindOrAdd(pts[2]));
  586. if isquad then
  587. fg.Add(m.vertices.FindOrAdd(pts[3]));
  588. end;
  589. procedure TgxDXFVectorFile.ReadEntityPolyLine(basemesh: TgxBaseMesh);
  590. procedure ReadPolylineVertex(m: TgxMeshObject; vertexindexbase: Integer);
  591. var
  592. color: STRING;
  593. pt: TAffineVector;
  594. fg: TgxFGVertexIndexList;
  595. code, idx, i70, i71, i72, i73, i74: Integer;
  596. begin
  597. color := '';
  598. pt := NullVector;
  599. i70 := 0;
  600. i71 := 0;
  601. i72 := 0;
  602. i73 := 0;
  603. i74 := 0;
  604. repeat
  605. code := GetCode;
  606. case code of
  607. 0:
  608. ;
  609. 5:
  610. ReadLine; // ID :=ReadHex16;
  611. 8:
  612. ReadLine; // ignore per vertex layer. Polyline vertices cannot cross layers!
  613. 10:
  614. pt.X := ReadDouble;
  615. 20:
  616. pt.Y := ReadDouble;
  617. 30:
  618. pt.Z := ReadDouble;
  619. 62:
  620. color := ReadLine;
  621. 70:
  622. i70 := ReadInt;
  623. 71:
  624. i71 := abs(ReadInt);
  625. // negative values should hide points... we cannot
  626. 72:
  627. i72 := abs(ReadInt);
  628. 73:
  629. i73 := abs(ReadInt);
  630. 74:
  631. i74 := abs(ReadInt);
  632. 100:
  633. ReadLine; // Subclass Marker
  634. 330:
  635. ReadLine; // Soft Pointer?
  636. else
  637. ReadLine;
  638. end;
  639. until code = 0;
  640. PushCode(0);
  641. if (color = '') or (color = '256') or (color = 'BYLAYER') then
  642. begin
  643. idx := FLayers.IndexOf(m.name);
  644. if idx >= 0 then
  645. color := IntToStr(LONGINT(FLayers.Objects[idx]));
  646. end;
  647. if i70 and 192 = 192 then
  648. begin
  649. m.vertices.Add(pt);
  650. end
  651. else if i70 and 192 = 128 then
  652. begin
  653. i71 := i71 - 1 + vertexindexbase;
  654. i72 := i72 - 1 + vertexindexbase;
  655. i73 := i73 - 1 + vertexindexbase;
  656. if i74 = 0 then
  657. begin
  658. fg := NeedFaceGroup(m, fgmmTriangles, color);
  659. fg.Add(i71);
  660. fg.Add(i72);
  661. fg.Add(i73);
  662. end
  663. else
  664. begin
  665. i74 := i74 - 1 + vertexindexbase;
  666. fg := NeedFaceGroup(m, fgmmQuads, color);
  667. fg.Add(i71);
  668. fg.Add(i72);
  669. fg.Add(i73);
  670. fg.Add(i74);
  671. end
  672. end
  673. else
  674. // hmm?
  675. end;
  676. var
  677. m: TgxMeshObject;
  678. code, vertexindexbase: Integer;
  679. S, layer: STRING;
  680. begin
  681. m := NIL;
  682. vertexindexbase := 0;
  683. repeat
  684. code := GetCode;
  685. S := ReadLine;
  686. if (code = 8) then
  687. begin
  688. layer := S;
  689. m := NeedMesh(basemesh, layer);
  690. vertexindexbase := m.vertices.count;
  691. end;
  692. if (code = 0) and (S = 'VERTEX') and (m <> NIL) then
  693. ReadPolylineVertex(m, vertexindexbase);
  694. until (code = 0) and (S = 'SEQEND');
  695. repeat
  696. code := GetCode;
  697. if code <> 0 then
  698. ReadLine;
  699. until (code = 0);
  700. PushCode(0);
  701. end;
  702. procedure TgxDXFVectorFile.ReadEntities(basemesh: TgxBaseMesh);
  703. var
  704. code: Integer;
  705. S: STRING;
  706. begin
  707. repeat
  708. code := GetCode;
  709. /// DoProgress (psRunning,FSourceStream.Position/FSourceStream.Size*100,false,'');
  710. case code of
  711. 0:
  712. begin
  713. S := ReadLine;
  714. if S = 'POLYLINE' then
  715. ReadEntityPolyLine(basemesh)
  716. else if S = '3DFACE' then
  717. ReadEntity3Dface(basemesh)
  718. else if S = 'INSERT' then
  719. ReadInsert(basemesh)
  720. else if S = 'ENDSEC' then
  721. begin
  722. end
  723. else if S = 'ENDBLK' then
  724. begin
  725. end
  726. else
  727. { TODO : E1025 Unsupported language feature: 'ASM' }
  728. (*
  729. asm
  730. nop
  731. end *) (* put breakpoint here to catch other entities *)
  732. end;
  733. else
  734. S := ReadLine;
  735. end;
  736. until (code = 0) and ((S = 'ENDSEC') or (S = 'ENDBLK'));
  737. end;
  738. // build normals
  739. procedure BuildNormals(m: TgxMeshObject);
  740. var
  741. i, j: Integer;
  742. v1, v2, v3, v4, n: TAffineVector;
  743. begin
  744. for i := 0 to m.vertices.count - 1 do
  745. m.Normals.Add(0, 0, 0);
  746. for i := 0 to m.FaceGroups.count - 1 do
  747. if m.FaceGroups[i] is TgxFGVertexIndexList then
  748. with m.FaceGroups[i] as TgxFGVertexIndexList do
  749. case mode of
  750. fgmmTriangles:
  751. begin
  752. for j := 0 to (VertexIndices.count div 3) - 1 do
  753. begin
  754. v1 := m.vertices[VertexIndices[j * 3]];
  755. v2 := m.vertices[VertexIndices[j * 3 + 1]];
  756. v3 := m.vertices[VertexIndices[j * 3 + 2]];
  757. n := CalcPlaneNormal(v1, v2, v3);
  758. m.Normals.items[VertexIndices[j * 3]] :=
  759. VectorAdd(m.Normals.items[VertexIndices[j * 3]], n);
  760. m.Normals.items[VertexIndices[j * 3 + 1]] :=
  761. VectorAdd(m.Normals.items[VertexIndices[j * 3 + 1]], n);
  762. m.Normals.items[VertexIndices[j * 3 + 2]] :=
  763. VectorAdd(m.Normals.items[VertexIndices[j * 3 + 2]], n);
  764. end;
  765. end;
  766. fgmmQuads:
  767. begin
  768. for j := 0 to (VertexIndices.count div 4) - 1 do
  769. begin
  770. v1 := m.vertices[VertexIndices[j * 4]];
  771. v2 := m.vertices[VertexIndices[j * 4 + 1]];
  772. v3 := m.vertices[VertexIndices[j * 4 + 2]];
  773. v4 := m.vertices[VertexIndices[j * 4 + 3]];
  774. n := CalcPlaneNormal(v1, v2, v3);
  775. m.Normals.items[VertexIndices[j * 4]] :=
  776. VectorAdd(m.Normals.items[VertexIndices[j * 4]], n);
  777. m.Normals.items[VertexIndices[j * 4 + 1]] :=
  778. VectorAdd(m.Normals.items[VertexIndices[j * 4 + 1]], n);
  779. m.Normals.items[VertexIndices[j * 4 + 2]] :=
  780. VectorAdd(m.Normals.items[VertexIndices[j * 4 + 2]], n);
  781. m.Normals.items[VertexIndices[j * 4 + 3]] :=
  782. VectorAdd(m.Normals.items[VertexIndices[j * 4 + 3]], n);
  783. end;
  784. end;
  785. end;
  786. for i := 0 to m.Normals.count - 1 do
  787. m.Normals.items[i] := VectorNormalize(m.Normals.items[i]);
  788. end;
  789. procedure TgxDXFVectorFile.LoadFromStream(aStream: TStream);
  790. var
  791. S: STRING;
  792. code, i: Integer;
  793. begin
  794. FLastpercentdone := 1;
  795. /// DoProgress (psStarting,0,false,'Starting');
  796. FEof := FALSE;
  797. FSourceStream := aStream;
  798. FLineNo := 0;
  799. HasPushedCode := FALSE;
  800. FLayers := TStringList.create;
  801. FBlocks := TStringList.create;
  802. while not FEof do
  803. begin
  804. /// DoProgress (psStarting,FSourceStream.Position/FSourceStream.Size*90,false,'');
  805. code := GetCode;
  806. if (code = 0) then
  807. begin
  808. S := ReadLine;
  809. if S = 'EOF' then
  810. break
  811. else if S = 'SECTION' then
  812. begin
  813. code := GetCode;
  814. if code <> 2 then
  815. raise Exception.create('Name must follow Section' + ' on Line #' +
  816. IntToStr(FLineNo))
  817. else
  818. begin
  819. S := ReadLine;
  820. if S = 'HEADER' then
  821. SkipSection
  822. else if S = 'BLOCKS' then
  823. ReadBlocks
  824. else if S = 'ENTITIES' then
  825. ReadEntities(owner)
  826. else if S = 'CLASSES' then
  827. SkipSection
  828. else if S = 'TABLES' then
  829. ReadTables
  830. else if S = 'OBJECTS' then
  831. SkipSection
  832. else
  833. SkipSection;
  834. end
  835. end
  836. else if S = 'ENDSEC' then
  837. raise Exception.create('SECTION/ENDSEC Mismatch' + ' on Line #' +
  838. IntToStr(FLineNo))
  839. end
  840. else
  841. S := ReadLine; // raise Exception.create ('Invalid Group Code');
  842. end;
  843. // calc normals
  844. FLayers.free;
  845. for i := FBlocks.count - 1 downto 0 do
  846. (FBlocks.Objects[i] as TgxFreeForm).free;
  847. FBlocks.free;
  848. for i := 0 to owner.MeshObjects.count - 1 do
  849. BuildNormals(owner.MeshObjects[i]);
  850. /// DoProgress (psEnding,100,false,'');
  851. end;
  852. initialization
  853. RegisterVectorFileFormat('dxf', 'AutoCAD Exchange Format', TgxDXFVectorFile);
  854. end.