2
0

GLFileDXF.pas 28 KB

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