GLS.FileDXF.pas 27 KB

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