GLS.FileVOR.pas 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. //
  2. // The graphics platform GLScene https://github.com/glscene
  3. //
  4. unit GLS.FileVOR;
  5. (*
  6. Supports to import TetGen files from http://wias-berlin.de/software/tetgen/fformats.html
  7. combined in a VOR ASCII file for Voronoi polyhedralization.
  8. *)
  9. interface
  10. uses
  11. System.Classes,
  12. System.SysUtils,
  13. GLS.ApplicationFileIO,
  14. GLS.VectorTypes,
  15. GLS.VectorGeometry,
  16. GLS.VectorLists,
  17. GLS.VectorFileObjects,
  18. GLS.Utils;
  19. type
  20. TVORHeader = packed record
  21. dummy : array[0..79] of byte;
  22. nbFaces : Longint;
  23. end;
  24. TVORVertex = TAffineVector;
  25. TVORFace = packed record
  26. normal : TVORVertex; // facet surface normal
  27. v1 : TVORVertex; // vertex 1
  28. v2 : TVORVertex; // vertex 2
  29. v3 : TVORVertex; // vertex 3
  30. padding : array[0..1] of byte;
  31. end;
  32. type
  33. TGLVORVectorFile = class(TGLVectorFile)
  34. public
  35. class function Capabilities: TGLDataFileCapabilities; override;
  36. procedure LoadFromStream(aStream: TStream); override;
  37. procedure SaveToStream(aStream: TStream); override;
  38. end;
  39. {$IFDEF USE_MULTITHREAD}
  40. threadvar
  41. {$ELSE}
  42. var
  43. {$ENDIF}
  44. VORUseEmbeddedColors: Boolean;
  45. // ------------------------------------------------------------------
  46. implementation
  47. // ------------------------------------------------------------------
  48. const
  49. cNODE_LABEL = 'node';
  50. cEDGE_LABEL = 'edge';
  51. cFACE_LABEL = 'face';
  52. cCELL_LABEL = 'cell';
  53. // ------------------
  54. // ------------------ TGLVectorFile ------------------
  55. // ------------------
  56. class function TGLVORVectorFile.Capabilities: TGLDataFileCapabilities;
  57. begin
  58. Result := [dfcRead, dfcWrite];
  59. end;
  60. procedure TGLVORVectorFile.LoadFromStream(aStream: TStream);
  61. var
  62. Sl: TStringList;
  63. procedure _DecodeVORNormals(const aString: String; var aNormal: TVORVertex);
  64. begin
  65. Sl.CommaText := aString;
  66. if Sl.Count <> 5 then
  67. raise Exception.Create('Invalid Normal')
  68. else
  69. begin
  70. aNormal.X := GLStrToFloatDef(Sl[2], 0);
  71. aNormal.Y := GLStrToFloatDef(Sl[3], 0);
  72. aNormal.Z := GLStrToFloatDef(Sl[4], 0);
  73. end;
  74. end;
  75. procedure _DecodeVORVertex(const aString: String; var aVertex: TVORVertex);
  76. begin
  77. Sl.CommaText := aString;
  78. if (Sl.Count <> 4) or (CompareText(Sl[0], cNODE_LABEL) <> 0) then
  79. raise Exception.Create('Invalid Vertex')
  80. else
  81. begin
  82. aVertex.X := GLStrToFloatDef(Sl[1], 0);
  83. aVertex.Y := GLStrToFloatDef(Sl[2], 0);
  84. aVertex.Z := GLStrToFloatDef(Sl[3], 0);
  85. end;
  86. end;
  87. var
  88. R: Byte;
  89. G: Byte;
  90. B: Byte;
  91. I: Integer;
  92. L: Integer;
  93. CurLine: string;
  94. Mesh: TGLMeshObject;
  95. DataFace: TVORFace;
  96. Header: TVORHeader;
  97. FileContent: TStringList;
  98. CalcNormal: TAffineVector;
  99. // NOTE ABOUT VOR:
  100. // The minimum size of an empty ASCII file is 15 bytes.
  101. // Each facet contains:
  102. // - Normals: 3 floats (4 bytes)
  103. // - Vertices: 3x floats (4 byte each, 12 bytes total)
  104. // - AttributeCount: 1 short (2 bytes)
  105. // Total: 50 bytes per facet
  106. begin
  107. // create mesh object
  108. Mesh := TGLMeshObject.CreateOwned(Owner.MeshObjects);
  109. try
  110. Mesh.Mode := momTriangles;
  111. begin
  112. // ASCII VOR READER
  113. FileContent := TStringList.Create;
  114. Sl := TStringList.Create;
  115. try
  116. FileContent.LoadFromStream(AStream);
  117. I := 0;
  118. CurLine := Trim(UpperCase(FileContent[I]));
  119. if Pos(cNODE_LABEL, CurLine) = 1 then
  120. begin
  121. Mesh.Vertices.Capacity := (FileContent.Count - 2) div 7;
  122. Mesh.Normals.Capacity := (FileContent.Count -2) div 7;
  123. Inc(I);
  124. CurLine := Trim(UpperCase(FileContent[I]));
  125. while I < FileContent.Count do
  126. begin
  127. if Pos(cEDGE_LABEL, CurLine) = 1 then
  128. begin
  129. _DecodeVORNormals(CurLine, DataFace.normal);
  130. Inc(I);
  131. CurLine := Trim(UpperCase(FileContent[I]));
  132. if Pos(cFACE_LABEL, CurLine) = 1 then
  133. begin
  134. Inc(I);
  135. CurLine := Trim(FileContent[I]);
  136. _DecodeVORVertex(CurLine, DataFace.v1);
  137. Inc(I);
  138. CurLine := Trim(FileContent[I]);
  139. _DecodeVORVertex(CurLine, DataFace.v2);
  140. Inc(I);
  141. CurLine := Trim(FileContent[I]);
  142. _DecodeVORVertex(CurLine, DataFace.v3);
  143. end;
  144. Inc(I);
  145. CurLine := Trim(UpperCase(FileContent[I]));
  146. if Pos(cCELL_LABEL, CurLine) <> 1 then
  147. raise Exception.Create('End of Loop Not Found')
  148. else
  149. begin
  150. CalcNormal := CalcPlaneNormal(DataFace.v1, DataFace.v2, DataFace.v3);
  151. if VectorDotProduct(CalcNormal, DataFace.normal) > 0 then
  152. Mesh.Vertices.Add(DataFace.v1, DataFace.v2, DataFace.v3)
  153. else
  154. Mesh.Vertices.Add(DataFace.v3, DataFace.v2, DataFace.v1);
  155. Mesh.Normals.Add(DataFace.normal, DataFace.normal, DataFace.normal);
  156. end;
  157. end;
  158. Inc(I);
  159. CurLine := Trim(UpperCase(FileContent[I]));
  160. if Pos(cCELL_LABEL, curLine) <> 1 then
  161. raise Exception.Create('End of Facet Not found');
  162. Inc(I);
  163. CurLine := Trim(UpperCase(FileContent[I]));
  164. if Pos(cNODE_LABEL, curLine) = 1 then Break;
  165. end;
  166. end;
  167. finally
  168. Sl.Free;
  169. FileContent.Free;
  170. end;
  171. end;
  172. except
  173. on E: Exception do
  174. Mesh.Free;
  175. end;
  176. end;
  177. procedure TGLVORVectorFile.SaveToStream(aStream: TStream);
  178. var
  179. I: Integer;
  180. DataFace: TVORFace;
  181. Header: TVORHeader;
  182. List: TGLAffineVectorList;
  183. const
  184. cHeaderTag = 'VOR export';
  185. begin
  186. List := Owner.MeshObjects.ExtractTriangles;
  187. try
  188. FillChar(Header.dummy[0], SizeOf(Header.dummy), 0);
  189. Move(cHeaderTag, Header.dummy[0], Length(cHeaderTag));
  190. Header.nbFaces := List.Count div 3;
  191. aStream.Write(Header, SizeOf(Header));
  192. I := 0;
  193. while I <list.Count do
  194. begin
  195. DataFace.normal := CalcPlaneNormal(List[I], List[I + 1], List[I + 2]);
  196. DataFace.v1 := List[I];
  197. DataFace.v2 := List[I + 1];
  198. DataFace.v3 := List[I + 2];
  199. aStream.Write(DataFace, SizeOf(DataFace));
  200. Inc(I, 3);
  201. end;
  202. finally
  203. list.Free;
  204. end;
  205. end;
  206. // ------------------------------------------------------------------
  207. initialization
  208. // ------------------------------------------------------------------
  209. VORUseEmbeddedColors := False;
  210. RegisterVectorFileFormat('voronoi', 'Voronoi files', TGLVORVectorFile);
  211. end.