GXS.Isosurface.pas 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.Isosurface;
  5. (*
  6. Polygonising a scalar field by construction of isosurfaces
  7. Algorithms
  8. ----------
  9. Marching Cubes
  10. - Exploits a coarser Mesh then Marching Tetrahedra but produces less triangles
  11. - based on "Marching Cubes: A High Resolution 3D Surface
  12. Construction Algorithm" by W.E.Lorensen and H.E.Cline
  13. - patent free since 2005
  14. Marching Tetrahedra
  15. - Finer Mesh, better feature preservation
  16. - based on "A new tetrahedral tesselation scheme for isosurface generation"
  17. by S.L.Chan and E.O.Purisima
  18. - patent free
  19. Lookuptables
  20. - by Paul Bourke (http://paulbourke.net/geometry/polygonise/)
  21. Overall
  22. - Simple Data Structures to store Mesh. Vertices are calculated and stored twice
  23. or even more often.
  24. *)
  25. interface
  26. // uncomment next line to memorize vertex Density value to further use
  27. // (i.e. mesh color generation)
  28. {.$Define UseDensity}
  29. uses
  30. Stage.VectorGeometry,
  31. GXS.VectorLists,
  32. Stage.VectorTypes,
  33. Stage.VectorTypesExt,
  34. GXS.Mesh,
  35. GXS.VectorFileObjects;
  36. const
  37. ALLOC_SIZE = 65536;
  38. type
  39. TgxMarchingCube = class(TObject)
  40. private
  41. FIsoValue: TScalarValue;
  42. // sliceSize:Longword;
  43. PVertsX: PIntegerArray;
  44. PVertsY: PIntegerArray;
  45. PVertsZ: PIntegerArray;
  46. _Nverts: Integer;
  47. _Ntrigs: Integer;
  48. _Sverts: Integer;
  49. _Strigs: Integer;
  50. PVertices: PVertArray;
  51. PTriangles: PTriangleRecArray;
  52. _i, _j, _k: Longword;
  53. _Cube: array [0 .. 7] of TVoxelRec;
  54. _lut_entry: Byte;
  55. // _case:Byte;
  56. // _config:Byte;
  57. // _subconfig:Byte;
  58. procedure Init_temps;
  59. procedure Init_all;
  60. procedure Init_space;
  61. procedure Clean_temps;
  62. procedure Clean_all(keepFacets: Boolean = False);
  63. procedure Clean_space;
  64. procedure Test_vertex_addiction;
  65. protected
  66. FOriginalMC: Boolean; // now only original MC is implemented
  67. FSizeX: Integer;
  68. FSizeY: Integer;
  69. FSizeZ: Integer;
  70. FxMin: Single;
  71. FxMax: Single;
  72. FyMin: Single;
  73. FyMax: Single;
  74. FzMin: Single;
  75. FzMax: Single;
  76. FStepX: Single;
  77. FStepY: Single;
  78. FStepZ: Single;
  79. VoxelData: PVoxelData;
  80. procedure Process_cube;
  81. (* function test_face(face:byte):Boolean;
  82. function test_interior(s:Byte):boolean *)
  83. procedure Compute_Intersection_Points;
  84. procedure Add_Triangle(trig: array of Integer; N: Byte; v12: Integer = -1);
  85. function Add_x_vertex: Integer;
  86. function Add_y_vertex: Integer;
  87. function Add_z_vertex: Integer;
  88. function Add_c_vertex: Integer;
  89. function Get_x_grad(i, j, k: Integer): Single;
  90. function Get_y_grad(i, j, k: Integer): Single;
  91. function Get_z_grad(i, j, k: Integer): Single;
  92. function Get_x_vert(i, j, k: Integer): Integer;
  93. function Get_y_vert(i, j, k: Integer): Integer;
  94. function Get_z_vert(i, j, k: Integer): Integer;
  95. procedure Set_x_vert(a_val, i, j, k: Integer);
  96. procedure Set_y_vert(a_val, i, j, k: Integer);
  97. procedure Set_z_vert(a_val, i, j, k: Integer);
  98. function GetVoxelValue(i, j, k: Integer): TScalarValue;
  99. procedure SetVoxelValue(i, j, k: Integer; HfValue: TScalarValue);
  100. function GetVoxelData(i, j, k: Integer): TVoxelRec;
  101. function Voxel(i, j, k: Integer): PVoxelRec;
  102. function calc_u(v1, v2: Single): Extended; virtual;
  103. public
  104. ScalarField: TScalarField;
  105. constructor Create; overload; virtual;
  106. constructor Create(SizeX, SizeY, SizeZ: Integer;
  107. AIsoValue: TScalarValue = 0.0; xMin: Single = -0.5; xMax: Single = 0.5;
  108. yMin: Single = -0.5; yMax: Single = 0.5; zMin: Single = -0.5;
  109. zMax: Single = 0.5); overload; virtual;
  110. procedure ReDim(ASizeX, ASizeY, ASizeZ: Integer;
  111. xMin, xMax, yMin, yMax, zMin, zMax: Single); virtual;
  112. destructor Destroy; override;
  113. procedure Run; overload;
  114. procedure Run(IsoValue: TScalarValue); overload;
  115. function Internal(AValue: TScalarValue): Boolean; virtual;
  116. procedure FillVoxelData; overload; virtual;
  117. procedure FillVoxelData(AIsoValue: TScalarValue;
  118. AScalarField: TScalarField = nil); overload; virtual;
  119. procedure FillVoxelData(AIsoValue: TScalarValue;
  120. AScalarField: TScalarFieldInt); overload; virtual;
  121. procedure CalcVertices(Vertices: TgxVertexList; Alpha: Single = 1);
  122. procedure CalcMeshObject(AMeshObject: TgxMeshObject; Alpha: Single = 1);
  123. property IsoValue: TScalarValue read FIsoValue write FIsoValue; // TODO
  124. end;
  125. (* 3D isosurface extractor class. This class allows to calculate and exctract
  126. isosurfaces from scalar field voxel models using a given isovalue *)
  127. TIsoSurfaceExtractor = class(TObject)
  128. private
  129. Data: TArray3DExt;
  130. Dimensions: array ['x' .. 'z'] of Integer;
  131. { Build Index depending on whether the edges are outside or inside the surface }
  132. function BuildIndex(var ADatavals: array of Single; Isovalue: Single): word;
  133. function Interpolate(const V0, V1: TAffineVector;
  134. var Val0, Val1, Isovalue: Single; isPolished: boolean): TVertex;
  135. public
  136. constructor Create(); overload;
  137. constructor Create(Xdim, Ydim, Zdim: Integer;
  138. var AData: TArray3DExt); overload;
  139. destructor Destroy(); override;
  140. procedure AssignData(Xdim, Ydim, Zdim: Integer; var AData: TArray3DExt);
  141. // Launch Marching Cubes
  142. procedure MarchingCubes(Isovalue: Single; out Vertices: TVertexArray;
  143. out Triangles: TIntegerArray; isPolished: boolean);
  144. { Launch Marching Tetrahedra }
  145. procedure MarchingTetrahedra(Isovalue: Single; out Vertices: TVertexArray;
  146. out Triangles: TIntegerArray; isPolished: boolean);
  147. end;
  148. // Sphere surface
  149. function SFSphere(X, Y, Z: Extended): TScalarValue;
  150. // Minkowski space (http://mathworld.wolfram.com)
  151. function SFMinkowski(X, Y, Z: Extended): TScalarValue;
  152. // Klein Bottle (http://mathworld.wolfram.com)
  153. function SFKleinBottle(X, Y, Z: Extended): TScalarValue;
  154. // Chmutov-surface-1 (http://mathworld.wolfram.com)
  155. function SFChmutov1(X, Y, Z: Extended): TScalarValue;
  156. // Chmutov-surface-2 (http://mathworld.wolfram.com)
  157. function SFChmutov2(X, Y, Z: Extended): TScalarValue;
  158. // Toroidal surface (phantasy!)
  159. function SFToroidal(X, Y, Z: Extended): TScalarValue;
  160. // Double torus Surface (phantasy!)
  161. function SFDoubleTorus(X, Y, Z: Extended): TScalarValue;
  162. // -------------------------------------------------------------------------
  163. implementation
  164. // -------------------------------------------------------------------------
  165. const
  166. // Classic Cases for Marching Cube TriTable
  167. //
  168. (*
  169. 4----4------5
  170. /| /|
  171. 7 | 5 |
  172. / | / |
  173. 7-----6----6 |
  174. | 8 | 9
  175. | | | |
  176. | 0----0--|---1
  177. 11 / 10 /
  178. | 3 | 1
  179. |/ |/
  180. 3-----2-----2
  181. *)
  182. MC_TRITABLE: array [0 .. 255, 0 .. 15] of Integer = (
  183. (* 0: *) ( -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  184. (* 1: 0, *) ( 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  185. (* 2: 1, *) ( 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  186. (* 3: 0, 1, *) ( 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  187. (* 4: 2, *) ( 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  188. (* 5: 0, 2, *) ( 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  189. (* 6: 1, 2, *) ( 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  190. (* 7: 0, 1, 2, *) ( 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 ),
  191. (* 8: 3, *) ( 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  192. (* 9: 0, 3, *) ( 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  193. (* 10: 1, 3, *) ( 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  194. (* 11: 0, 1, 3, *) ( 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 ),
  195. (* 12: 2, 3, *) ( 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  196. (* 13: 0, 2, 3, *) ( 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 ),
  197. (* 14: 1, 2, 3, *) ( 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 ),
  198. (* 15: 0, 1, 2, 3, *) ( 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  199. (* 16: 4, *) ( 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  200. (* 17: 0, 4, *) ( 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  201. (* 18: 1, 4, *) ( 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  202. (* 19: 0, 1, 4, *) ( 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 ),
  203. (* 20: 2, 4, *) ( 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  204. (* 21: 0, 2, 4, *) ( 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1 ),
  205. (* 22: 1, 2, 4, *) ( 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 ),
  206. (* 23: 0, 1, 2, 4, *) ( 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1 ),
  207. (* 24: 3, 4, *) ( 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  208. (* 25: 0, 3, 4, *) ( 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1 ),
  209. (* 26: 1, 3, 4, *) ( 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 ),
  210. (* 27: 0, 1, 3, 4, *) ( 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1 ),
  211. (* 28: 2, 3, 4, *) ( 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1 ),
  212. (* 29: 0, 2, 3, 4, *) ( 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1 ),
  213. (* 30: 1, 2, 3, 4, *) ( 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1 ),
  214. (* 31: 0, 1, 2, 3, 4, *) ( 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1 ),
  215. (* 32: 5, *) ( 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  216. (* 33: 0, 5, *) ( 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  217. (* 34: 1, 5, *) ( 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  218. (* 35: 0, 1, 5, *) ( 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1 ),
  219. (* 36: 2, 5, *) ( 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  220. (* 37: 0, 2, 5, *) ( 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 ),
  221. (* 38: 1, 2, 5, *) ( 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 ),
  222. (* 39: 0, 1, 2, 5, *) ( 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 ),
  223. (* 40: 3, 5, *) ( 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  224. (* 41: 0, 3, 5, *) ( 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 ),
  225. (* 42: 1, 3, 5, *) ( 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 ),
  226. (* 43: 0, 1, 3, 5, *) ( 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1 ),
  227. (* 44: 2, 3, 5, *) ( 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1 ),
  228. (* 45: 0, 2, 3, 5, *) ( 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1 ),
  229. (* 46: 1, 2, 3, 5, *) ( 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1 ),
  230. (* 47: 0, 1, 2, 3, 5, *) ( 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1 ),
  231. (* 48: 4, 5, *) ( 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  232. (* 49: 0, 4, 5, *) ( 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1 ),
  233. (* 50: 1, 4, 5, *) ( 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1 ),
  234. (* 51: 0, 1, 4, 5, *) ( 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  235. (* 52: 2, 4, 5, *) ( 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1 ),
  236. (* 53: 0, 2, 4, 5, *) ( 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 ),
  237. (* 54: 1, 2, 4, 5, *) ( 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 ),
  238. (* 55: 0, 1, 2, 4, 5, *) ( 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 ),
  239. (* 56: 3, 4, 5, *) ( 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 ),
  240. (* 57: 0, 3, 4, 5, *) ( 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 ),
  241. (* 58: 1, 3, 4, 5, *) ( 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1 ),
  242. (* 59: 0, 1, 3, 4, 5, *) ( 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1 ),
  243. (* 60: 2, 3, 4, 5, *) ( 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1 ),
  244. (* 61: 0, 2, 3, 4, 5, *) ( 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1 ),
  245. (* 62: 1, 2, 3, 4, 5, *) ( 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1 ),
  246. (* 63: 0, 1, 2, 3, 4, 5, *) ( 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  247. (* 64: 6, *) ( 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  248. (* 65: 0, 6, *) ( 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  249. (* 66: 1, 6, *) ( 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  250. (* 67: 0, 1, 6, *) ( 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 ),
  251. (* 68: 2, 6, *) ( 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  252. (* 69: 0, 2, 6, *) ( 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1 ),
  253. (* 70: 1, 2, 6, *) ( 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 ),
  254. (* 71: 0, 1, 2, 6, *) ( 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 ),
  255. (* 72: 3, 6, *) ( 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  256. (* 73: 0, 3, 6, *) ( 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 ),
  257. (* 74: 1, 3, 6, *) ( 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 ),
  258. (* 75: 0, 1, 3, 6, *) ( 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1 ),
  259. (* 76: 2, 3, 6, *) ( 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1 ),
  260. (* 77: 0, 2, 3, 6, *) ( 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1 ),
  261. (* 78: 1, 2, 3, 6, *) ( 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1 ),
  262. (* 79: 0, 1, 2, 3, 6, *) ( 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1 ),
  263. (* 80: 4, 6, *) ( 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  264. (* 81: 0, 4, 6, *) ( 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1 ),
  265. (* 82: 1, 4, 6, *) ( 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 ),
  266. (* 83: 0, 1, 4, 6, *) ( 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 ),
  267. (* 84: 2, 4, 6, *) ( 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 ),
  268. (* 85: 0, 2, 4, 6, *) ( 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1 ),
  269. (* 86: 1, 2, 4, 6, *) ( 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1 ),
  270. (* 87: 0, 1, 2, 4, 6, *) ( 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1 ),
  271. (* 88: 3, 4, 6, *) ( 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 ),
  272. (* 89: 0, 3, 4, 6, *) ( 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1 ),
  273. (* 90: 1, 3, 4, 6, *) ( 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 ),
  274. (* 91: 0, 1, 3, 4, 6, *) ( 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 ),
  275. (* 92: 2, 3, 4, 6, *) ( 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1 ),
  276. (* 93: 0, 2, 3, 4, 6, *) ( 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1 ),
  277. (* 94: 1, 2, 3, 4, 6, *) ( 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1 ),
  278. (* 95: 0, 1, 2, 3, 4, 6, *) ( 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1 ),
  279. (* 96: 5, 6, *) ( 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  280. (* 97: 0, 5, 6, *) ( 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1 ),
  281. (* 98: 1, 5, 6, *) ( 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1 ),
  282. (* 99: 0, 1, 5, 6, *) ( 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 ),
  283. (* 100: 2, 5, 6, *) ( 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 ),
  284. (* 101: 0, 2, 5, 6, *) ( 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 ),
  285. (* 102: 1, 2, 5, 6, *) ( 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  286. (* 103: 0, 1, 2, 5, 6, *) ( 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1 ),
  287. (* 104: 3, 5, 6, *) ( 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1 ),
  288. (* 105: 0, 3, 5, 6, *) ( 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1 ),
  289. (* 106: 1, 3, 5, 6, *) ( 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1 ),
  290. (* 107: 0, 1, 3, 5, 6, *) ( 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1 ),
  291. (* 108: 2, 3, 5, 6, *) ( 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1 ),
  292. (* 109: 0, 2, 3, 5, 6, *) ( 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 ),
  293. (* 110: 1, 2, 3, 5, 6, *) ( 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 ),
  294. (* 111: 0, 1, 2, 3, 5, 6, *) ( 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  295. (* 112: 4, 5, 6, *) ( 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 ),
  296. (* 113: 0, 4, 5, 6, *) ( 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 ),
  297. (* 114: 1, 4, 5, 6, *) ( 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 ),
  298. (* 115: 0, 1, 4, 5, 6, *) ( 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1 ),
  299. (* 116: 2, 4, 5, 6, *) ( 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1 ),
  300. (* 117: 0, 2, 4, 5, 6, *) ( 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1 ),
  301. (* 118: 1, 2, 4, 5, 6, *) ( 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1 ),
  302. (* 119: 0, 1, 2, 4, 5, 6, *) ( 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  303. (* 120: 3, 4, 5, 6, *) ( 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1 ),
  304. (* 121: 0, 3, 4, 5, 6, *) ( 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 ),
  305. (* 122: 1, 3, 4, 5, 6, *) ( 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 ),
  306. (* 123: 0, 1, 3, 4, 5, 6, *) ( 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 ),
  307. (* 124: 2, 3, 4, 5, 6, *) ( 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 ),
  308. (* 125: 0, 2, 3, 4, 5, 6, *) ( 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  309. (* 126: 1, 2, 3, 4, 5, 6, *) ( 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1 ),
  310. (* 127: 0, 1, 2, 3, 4, 5, 6, *) ( 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  311. (* 128: 7, *) ( 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  312. (* 129: 0, 7, *) ( 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  313. (* 130: 1, 7, *) ( 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  314. (* 131: 0, 1, 7, *) ( 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 ),
  315. (* 132: 2, 7, *) ( 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  316. (* 133: 0, 2, 7, *) ( 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 ),
  317. (* 134: 1, 2, 7, *) ( 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 ),
  318. (* 135: 0, 1, 2, 7, *) ( 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1 ),
  319. (* 136: 3, 7, *) ( 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  320. (* 137: 0, 3, 7, *) ( 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1 ),
  321. (* 138: 1, 3, 7, *) ( 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1 ),
  322. (* 139: 0, 1, 3, 7, *) ( 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 ),
  323. (* 140: 2, 3, 7, *) ( 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 ),
  324. (* 141: 0, 2, 3, 7, *) ( 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 ),
  325. (* 142: 1, 2, 3, 7, *) ( 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1 ),
  326. (* 143: 0, 1, 2, 3, 7, *) ( 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1 ),
  327. (* 144: 4, 7, *) ( 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  328. (* 145: 0, 4, 7, *) ( 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1 ),
  329. (* 146: 1, 4, 7, *) ( 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1 ),
  330. (* 147: 0, 1, 4, 7, *) ( 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1 ),
  331. (* 148: 2, 4, 7, *) ( 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1 ),
  332. (* 149: 0, 2, 4, 7, *) ( 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1 ),
  333. (* 150: 1, 2, 4, 7, *) ( 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1 ),
  334. (* 151: 0, 1, 2, 4, 7, *) ( 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 ),
  335. (* 152: 3, 4, 7, *) ( 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 ),
  336. (* 153: 0, 3, 4, 7, *) ( 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  337. (* 154: 1, 3, 4, 7, *) ( 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 ),
  338. (* 155: 0, 1, 3, 4, 7, *) ( 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1 ),
  339. (* 156: 2, 3, 4, 7, *) ( 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1 ),
  340. (* 157: 0, 2, 3, 4, 7, *) ( 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1 ),
  341. (* 158: 1, 2, 3, 4, 7, *) ( 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1 ),
  342. (* 159: 0, 1, 2, 3, 4, 7, *) ( 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  343. (* 160: 5, 7, *) ( 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  344. (* 161: 0, 5, 7, *) ( 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 ),
  345. (* 162: 1, 5, 7, *) ( 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 ),
  346. (* 163: 0, 1, 5, 7, *) ( 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1 ),
  347. (* 164: 2, 5, 7, *) ( 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 ),
  348. (* 165: 0, 2, 5, 7, *) ( 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 ),
  349. (* 166: 1, 2, 5, 7, *) ( 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 ),
  350. (* 167: 0, 1, 2, 5, 7, *) ( 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1 ),
  351. (* 168: 3, 5, 7, *) ( 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1 ),
  352. (* 169: 0, 3, 5, 7, *) ( 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1 ),
  353. (* 170: 1, 3, 5, 7, *) ( 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1 ),
  354. (* 171: 0, 1, 3, 5, 7, *) ( 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 ),
  355. (* 172: 2, 3, 5, 7, *) ( 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 ),
  356. (* 173: 0, 2, 3, 5, 7, *) ( 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 ),
  357. (* 174: 1, 2, 3, 5, 7, *) ( 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 ),
  358. (* 175: 0, 1, 2, 3, 5, 7, *) ( 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1 ),
  359. (* 176: 4, 5, 7, *) ( 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1 ),
  360. (* 177: 0, 4, 5, 7, *) ( 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1 ),
  361. (* 178: 1, 4, 5, 7, *) ( 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1 ),
  362. (* 179: 0, 1, 4, 5, 7, *) ( 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1 ),
  363. (* 180: 2, 4, 5, 7, *) ( 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1 ),
  364. (* 181: 0, 2, 4, 5, 7, *) ( 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1 ),
  365. (* 182: 1, 2, 4, 5, 7, *) ( 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 ),
  366. (* 183: 0, 1, 2, 4, 5, 7, *) ( 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 ),
  367. (* 184: 3, 4, 5, 7, *) ( 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 ),
  368. (* 185: 0, 3, 4, 5, 7, *) ( 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 ),
  369. (* 186: 1, 3, 4, 5, 7, *) ( 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1 ),
  370. (* 187: 0, 1, 3, 4, 5, 7, *) ( 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  371. (* 188: 2, 3, 4, 5, 7, *) ( 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1 ),
  372. (* 189: 0, 2, 3, 4, 5, 7, *) ( 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1 ),
  373. (* 190: 1, 2, 3, 4, 5, 7, *) ( 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  374. (* 191: 0, 1, 2, 3, 4, 5, 7, *) ( 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  375. (* 192: 6, 7, *) ( 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  376. (* 193: 0, 6, 7, *) ( 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1 ),
  377. (* 194: 1, 6, 7, *) ( 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1 ),
  378. (* 195: 0, 1, 6, 7, *) ( 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1 ),
  379. (* 196: 2, 6, 7, *) ( 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1 ),
  380. (* 197: 0, 2, 6, 7, *) ( 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 ),
  381. (* 198: 1, 2, 6, 7, *) ( 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 ),
  382. (* 199: 0, 1, 2, 6, 7, *) ( 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1 ),
  383. (* 200: 3, 6, 7, *) ( 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1 ),
  384. (* 201: 0, 3, 6, 7, *) ( 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1 ),
  385. (* 202: 1, 3, 6, 7, *) ( 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1 ),
  386. (* 203: 0, 1, 3, 6, 7, *) ( 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1 ),
  387. (* 204: 2, 3, 6, 7, *) ( 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  388. (* 205: 0, 2, 3, 6, 7, *) ( 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 ),
  389. (* 206: 1, 2, 3, 6, 7, *) ( 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 ),
  390. (* 207: 0, 1, 2, 3, 6, 7, *) ( 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  391. (* 208: 4, 6, 7, *) ( 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 ),
  392. (* 209: 0, 4, 6, 7, *) ( 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 ),
  393. (* 210: 1, 4, 6, 7, *) ( 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 ),
  394. (* 211: 0, 1, 4, 6, 7, *) ( 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 ),
  395. (* 212: 2, 4, 6, 7, *) ( 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1 ),
  396. (* 213: 0, 2, 4, 6, 7, *) ( 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1 ),
  397. (* 214: 1, 2, 4, 6, 7, *) ( 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1 ),
  398. (* 215: 0, 1, 2, 4, 6, 7, *) ( 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  399. (* 216: 3, 4, 6, 7, *) ( 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1 ),
  400. (* 217: 0, 3, 4, 6, 7, *) ( 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 ),
  401. (* 218: 1, 3, 4, 6, 7, *) ( 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 ),
  402. (* 219: 0, 1, 3, 4, 6, 7, *) ( 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1 ),
  403. (* 220: 2, 3, 4, 6, 7, *) ( 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1 ),
  404. (* 221: 0, 2, 3, 4, 6, 7, *) ( 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  405. (* 222: 1, 2, 3, 4, 6, 7, *) ( 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1 ),
  406. (* 223: 0, 1, 2, 3, 4, 6, 7, *) ( 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  407. (* 224: 5, 6, 7, *) ( 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1 ),
  408. (* 225: 0, 5, 6, 7, *) ( 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1 ),
  409. (* 226: 1, 5, 6, 7, *) ( 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1 ),
  410. (* 227: 0, 1, 5, 6, 7, *) ( 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1 ),
  411. (* 228: 2, 5, 6, 7, *) ( 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 ),
  412. (* 229: 0, 2, 5, 6, 7, *) ( 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 ),
  413. (* 230: 1, 2, 5, 6, 7, *) ( 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 ),
  414. (* 231: 0, 1, 2, 5, 6, 7, *) ( 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 ),
  415. (* 232: 3, 5, 6, 7, *) ( 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1 ),
  416. (* 233: 0, 3, 5, 6, 7, *) ( 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1 ),
  417. (* 234: 1, 3, 5, 6, 7, *) ( 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1 ),
  418. (* 235: 0, 1, 3, 5, 6, 7, *) ( 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  419. (* 236: 2, 3, 5, 6, 7, *) ( 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1 ),
  420. (* 237: 0, 2, 3, 5, 6, 7, *) ( 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1 ),
  421. (* 238: 1, 2, 3, 5, 6, 7, *) ( 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  422. (* 239: 0, 1, 2, 3, 5, 6, 7, *) ( 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  423. (* 240: 4, 5, 6, 7, *) ( 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  424. (* 241: 0, 4, 5, 6, 7, *) ( 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 ),
  425. (* 242: 1, 4, 5, 6, 7, *) ( 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 ),
  426. (* 243: 0, 1, 4, 5, 6, 7, *) ( 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  427. (* 244: 2, 4, 5, 6, 7, *) ( 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 ),
  428. (* 245: 0, 2, 4, 5, 6, 7, *) ( 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 ),
  429. (* 246: 1, 2, 4, 5, 6, 7, *) ( 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  430. (* 247: 0, 1, 2, 4, 5, 6, 7, *) ( 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  431. (* 248: 3, 4, 5, 6, 7, *) ( 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 ),
  432. (* 249: 0, 3, 4, 5, 6, 7, *) ( 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  433. (* 250: 1, 3, 4, 5, 6, 7, *) ( 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 ),
  434. (* 251: 0, 1, 3, 4, 5, 6, 7, *) ( 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  435. (* 252: 2, 3, 4, 5, 6, 7, *) ( 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  436. (* 253: 0, 2, 3, 4, 5, 6, 7, *) ( 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  437. (* 254: 1, 2, 3, 4, 5, 6, 7, *) ( 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ),
  438. (* 255: 0, 1, 2, 3, 4, 5, 6, 7, *) ( -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 )
  439. );
  440. // Marching Cube EdgeTable
  441. const
  442. MC_EDGETABLE: array [0 .. 11, 0 .. 1] of Integer = ((0, 1), (1, 2), (2, 3),
  443. (3, 0), (4, 5), (5, 6), (6, 7), (7, 4), (0, 4), (1, 5), (2, 6), (3, 7));
  444. // Marching Tetrahedra TriTable
  445. (*
  446. + 0
  447. /|\
  448. / | \
  449. / | 0
  450. 3 | \
  451. / 2 \
  452. / | \
  453. +----4--------+ 1
  454. 3 \ | /
  455. \ | /
  456. 5 | 1
  457. \ | /
  458. \ | /
  459. \|/
  460. + 2
  461. *)
  462. MT_TRITABLE: array [0 .. 15, 0 .. 6] of Integer =
  463. ((-1, -1, -1, -1, -1, -1, -1), (2, 3, 0, -1, -1, -1, -1),
  464. (4, 1, 0, -1, -1, -1, -1), (2, 4, 1, 3, 4, 2, -1),
  465. (5, 2, 1, -1, -1, -1, -1), (5, 3, 0, 1, 5, 0, -1), (5, 2, 0, 4, 5, 0, -1),
  466. (3, 4, 5, -1, -1, -1, -1), (5, 4, 3, -1, -1, -1, -1),
  467. (0, 5, 4, 0, 2, 5, -1), (0, 5, 1, 0, 3, 5, -1), (1, 2, 5, -1, -1, -1, -1),
  468. (2, 4, 3, 1, 4, 2, -1), (0, 1, 4, -1, -1, -1, -1),
  469. (0, 3, 2, -1, -1, -1, -1), (-1, -1, -1, -1, -1, -1, -1));
  470. // Marching Tetrahedra EdgeTable
  471. MT_EDGETABLE: array [0 .. 5, 0 .. 1] of Integer = ((0, 1), (1, 2), (2, 0),
  472. (0, 3), (1, 3), (2, 3));
  473. // Marching Tetrahedra CubeSplit
  474. MT_CUBESPLIT: array [0 .. 5, 0 .. 3] of Integer = ((0, 5, 1, 6), (0, 1, 2, 6),
  475. (0, 2, 3, 6), (0, 3, 7, 6), (0, 7, 4, 6), (0, 4, 5, 6));
  476. // Test surface functions
  477. function SFSphere(X, Y, Z: Extended): TScalarValue;
  478. begin
  479. Result := sqr(X) + sqr(Y) + sqr(Z)
  480. end;
  481. function SFToroidal(X, Y, Z: Extended): TScalarValue;
  482. const
  483. FScale = 7;
  484. a = 2.5;
  485. begin
  486. X := FScale * X;
  487. Y := FScale * Y;
  488. Z := FScale * Z;
  489. Result := (sqr(sqrt(sqr(X) + sqr(Y)) - a) + sqr(Z)) *
  490. (sqr(sqrt(sqr(Y) + sqr(Z)) - a) + sqr(X)) *
  491. (sqr(sqrt(sqr(Z) + sqr(X)) - a) + sqr(Y));
  492. end;
  493. function SFDoubleTorus(X, Y, Z: Extended): TScalarValue;
  494. const
  495. FScale = 2.25;
  496. begin
  497. X := FScale * X;
  498. Y := FScale * Y;
  499. Z := FScale * Z;
  500. Result := PowerInteger(X, 8) + PowerInteger(X, 4) - 2 * PowerInteger(X, 6) - 2
  501. * sqr(X) * sqr(Y) + 2 * PowerInteger(X, 4) * sqr(Y) +
  502. PowerInteger(Y, 4) + sqr(Z)
  503. end;
  504. function SFChmutov1(X, Y, Z: Extended): TScalarValue;
  505. const
  506. FScale = 2.5;
  507. begin
  508. X := FScale * X;
  509. Y := FScale * Y;
  510. Z := FScale * Z;
  511. Result := 8 * (sqr(X) + sqr(Y) + sqr(Z)) - 8 *
  512. (PowerInteger(X, 4) + PowerInteger(Y, 4) + PowerInteger(Z, 4));
  513. end;
  514. function SFChmutov2(X, Y, Z: Extended): TScalarValue;
  515. const
  516. FScale = 2.5;
  517. begin
  518. X := FScale * X;
  519. Y := FScale * Y;
  520. Z := FScale * Z;
  521. Result := 2 * (sqr(X) * sqr(3 - 4 * sqr(X)) + sqr(Y) * sqr(3 - 4 * sqr(Y)) +
  522. sqr(Z) * sqr(3 - 4 * sqr(Z)));
  523. end;
  524. function SFKleinBottle(X, Y, Z: Extended): TScalarValue;
  525. const
  526. FScale = 7.5;
  527. begin
  528. X := FScale * X;
  529. Y := FScale * Y;
  530. Z := FScale * Z;
  531. Result := (sqr(X) + sqr(Y) + sqr(Z) + 2 * Y - 1) *
  532. (sqr(sqr(X) + sqr(Y) + sqr(Z) - 2 * Y - 1) - 8 * sqr(Z)) + 16 * X * Z *
  533. (sqr(X) + sqr(Y) + sqr(Z) - 2 * Y - 1);
  534. end;
  535. function SFMinkowski(X, Y, Z: Extended): TScalarValue;
  536. const
  537. FScale = 7;
  538. begin
  539. X := FScale * X;
  540. Y := FScale * Y;
  541. Z := FScale * Z;
  542. Result := (sqr(X) - sqr(Y) - sqr(Z) - 2) * (sqr(X) - sqr(Y) - sqr(Z) + 2) *
  543. (sqr(X) - sqr(Y) - sqr(Z) - 4) * (sqr(X) - sqr(Y) - sqr(Z) + 4) *
  544. (sqr(X) - sqr(Y) - sqr(Z));
  545. end;
  546. (* -------------------------------------------------------------------------
  547. Class IsoSurfaceExtractor
  548. Purpose: Extract an Isosurface from volume dataset for given Isovalue
  549. ------------------------------------------------------------------------- *)
  550. function TIsoSurfaceExtractor.BuildIndex(var ADatavals: array of Single;
  551. Isovalue: Single): word;
  552. var
  553. i: Integer;
  554. val: word;
  555. begin
  556. val := 1;
  557. Result := 0;
  558. for i := 1 to Length(ADatavals) do
  559. begin
  560. if ADatavals[i - 1] <= Isovalue then // Edge inside surface
  561. Result := Result + val;
  562. val := val * 2;
  563. end;
  564. end;
  565. // Compute intersection point of edge and surface by linear interpolation
  566. function InterpolateRugged(V0, V1: TAffineVector;
  567. var Val0, Val1, Isovalue: Single): TVertex;
  568. var
  569. Diff: Single;
  570. i: Integer;
  571. begin
  572. if Val0 <= Isovalue then
  573. begin
  574. Diff := Val0 / (Val0 + Val1);
  575. for i := 0 to 2 do
  576. Result.V[i] := V0.V[i] + Diff * (V1.V[i] - V0.V[i]);
  577. end
  578. else
  579. begin
  580. Diff := Val1 / (Val0 + Val1);
  581. for i := 0 to 2 do
  582. Result.V[i] := V1.V[i] + Diff * (V0.V[i] - V1.V[i]);
  583. end;
  584. end;
  585. function InterpolatePolished(V0, V1: TAffineVector;
  586. var Val0, Val1, Isovalue: Single): TVertex;
  587. var
  588. w0, w1: Single;
  589. begin
  590. if (Val0 = Val1) then
  591. w1 := 0.5
  592. else
  593. w1 := (Isovalue - Val0) / (Val1 - Val0);
  594. w0 := 1.0 - w1;
  595. Result.X := w0 * V0.X + w1 * V1.X;
  596. Result.Y := w0 * V0.Y + w1 * V1.Y;
  597. Result.Z := w0 * V0.Z + w1 * V1.Z;
  598. end;
  599. function TIsoSurfaceExtractor.Interpolate(const V0, V1: TAffineVector;
  600. var Val0, Val1, Isovalue: Single; isPolished: boolean): TVertex;
  601. begin
  602. if isPolished then
  603. Result := InterpolatePolished(V0, V1, Val0, Val1, Isovalue)
  604. else
  605. Result := InterpolateRugged(V0, V1, Val0, Val1, Isovalue)
  606. end;
  607. procedure TIsoSurfaceExtractor.MarchingTetrahedra(Isovalue: Single;
  608. out Vertices: TVertexArray; out Triangles: TIntegerArray; isPolished: boolean);
  609. var
  610. i, j, k: Integer;
  611. index: word;
  612. CubeVertices: array of TAffineVector;
  613. Tetrahedron: array [0 .. 3] of TAffineVector;
  614. DataTetra: array [0 .. 3] of Single;
  615. // Add Triangle to List
  616. procedure AppendTri();
  617. var
  618. edge: byte;
  619. Ver1, Ver2, Ver3: TVertex;
  620. VListlength: Integer;
  621. TListlength: Integer;
  622. begin
  623. edge := 0;
  624. while MT_TRITABLE[index, edge] <> -1 do
  625. begin
  626. Ver1 := Interpolate(Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge], 0]
  627. ], Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge], 1]],
  628. DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge], 0]],
  629. DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge], 1]], Isovalue, isPolished);
  630. Ver2 := Interpolate(Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge + 1],
  631. 0]], Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge + 1], 1]],
  632. DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge + 1], 0]],
  633. DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge + 1], 1]], Isovalue, isPolished);
  634. Ver3 := Interpolate(Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge + 2],
  635. 0]], Tetrahedron[MT_EDGETABLE[MT_TRITABLE[index, edge + 2], 1]],
  636. DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge + 2], 0]],
  637. DataTetra[MT_EDGETABLE[MT_TRITABLE[index, edge + 2], 1]], Isovalue, isPolished);
  638. VListlength := Length(Vertices) + 3;
  639. TListlength := Length(Triangles) + 3;
  640. SetLength(Vertices, VListlength);
  641. SetLength(Triangles, TListlength);
  642. Vertices[VListlength - 3] := Ver1;
  643. Vertices[VListlength - 2] := Ver2;
  644. Vertices[VListlength - 1] := Ver3;
  645. Triangles[TListlength - 3] := VListlength - 3;
  646. Triangles[TListlength - 2] := VListlength - 2;
  647. Triangles[TListlength - 1] := VListlength - 1;
  648. edge := edge + 3;
  649. end;
  650. end;
  651. // Split Cube in 6 Tetrahedrons and process each tetrahedron
  652. procedure SplitCube();
  653. var
  654. i, j: Integer;
  655. begin
  656. for i := 0 to 5 do
  657. begin
  658. for j := 0 to 3 do
  659. begin
  660. Tetrahedron[j] := CubeVertices[MT_CUBESPLIT[i, j]];
  661. DataTetra[j] := Data[Trunc(Tetrahedron[j].X),
  662. Trunc(Tetrahedron[j].Y), Trunc(Tetrahedron[j].Z)];
  663. end;
  664. index := BuildIndex(DataTetra, Isovalue);
  665. AppendTri();
  666. end;
  667. end;
  668. begin
  669. (*
  670. 1----2
  671. /| /|
  672. 0----3 |
  673. | 5--|-6
  674. |/ |/
  675. 4----7
  676. *)
  677. SetLength(CubeVertices, 8);
  678. for k := 0 to Dimensions['z'] - 2 do
  679. begin
  680. for j := 0 to Dimensions['y'] - 2 do
  681. begin
  682. for i := 0 to Dimensions['x'] - 2 do
  683. begin
  684. CubeVertices[0] := AffineVectorMake(i, j, k);
  685. CubeVertices[1] := AffineVectorMake(i, j, k + 1);
  686. CubeVertices[2] := AffineVectorMake(i + 1, j, k + 1);
  687. CubeVertices[3] := AffineVectorMake(i + 1, j, k);
  688. CubeVertices[4] := AffineVectorMake(i, j + 1, k);
  689. CubeVertices[5] := AffineVectorMake(i, j + 1, k + 1);
  690. CubeVertices[6] := AffineVectorMake(i + 1, j + 1, k + 1);
  691. CubeVertices[7] := AffineVectorMake(i + 1, j + 1, k);
  692. SplitCube();
  693. end; // for k
  694. end; // for j
  695. end; // for i
  696. end; // ccMT
  697. constructor TIsoSurfaceExtractor.Create;
  698. begin
  699. inherited;
  700. end;
  701. constructor TIsoSurfaceExtractor.Create(Xdim, Ydim, Zdim: Integer;
  702. var AData: TArray3DExt);
  703. begin
  704. Create();
  705. AssignData(Xdim, Ydim, Zdim, AData);
  706. end;
  707. destructor TIsoSurfaceExtractor.Destroy;
  708. begin
  709. inherited;
  710. end;
  711. procedure TIsoSurfaceExtractor.AssignData(Xdim, Ydim, Zdim: Integer;
  712. var AData: TArray3DExt);
  713. begin
  714. Dimensions['x'] := Xdim;
  715. Dimensions['y'] := Ydim;
  716. Dimensions['z'] := Zdim;
  717. Data := AData;
  718. end;
  719. //-----------------------------------------------------------------------
  720. procedure TIsoSurfaceExtractor.MarchingCubes(Isovalue: Single;
  721. out Vertices: TVertexArray; out Triangles: TIntegerArray; isPolished: boolean);
  722. var
  723. i, j, k: Integer;
  724. index: word;
  725. CubeVertices: array [0 .. 7] of TAffineVector;
  726. CubeData: array [0 .. 7] of Single;
  727. procedure AppendTri();
  728. var
  729. edge: byte;
  730. Ver1, Ver2, Ver3: TVertex;
  731. VListlength: Integer;
  732. TListlength: Integer;
  733. begin
  734. edge := 0;
  735. while MC_TRITABLE[index, edge] <> -1 do
  736. begin
  737. Ver1 := Interpolate(CubeVertices[MC_EDGETABLE[MC_TRITABLE[index, edge], 0]
  738. ], CubeVertices[MC_EDGETABLE[MC_TRITABLE[index, edge], 1]],
  739. CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge], 0]],
  740. CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge], 1]], Isovalue, isPolished);
  741. Ver2 := Interpolate(CubeVertices[MC_EDGETABLE[MC_TRITABLE[index,
  742. edge + 1], 0]], CubeVertices[MC_EDGETABLE[MC_TRITABLE[index, edge + 1],
  743. 1]], CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge + 1], 0]],
  744. CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge + 1], 1]], Isovalue, isPolished);
  745. Ver3 := Interpolate(CubeVertices[MC_EDGETABLE[MC_TRITABLE[index,
  746. edge + 2], 0]], CubeVertices[MC_EDGETABLE[MC_TRITABLE[index, edge + 2],
  747. 1]], CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge + 2], 0]],
  748. CubeData[MC_EDGETABLE[MC_TRITABLE[index, edge + 2], 1]], Isovalue, isPolished);
  749. VListlength := Length(Vertices) + 3;
  750. TListlength := Length(Triangles) + 3;
  751. SetLength(Vertices, VListlength);
  752. SetLength(Triangles, TListlength);
  753. Vertices[VListlength - 3] := Ver1;
  754. Vertices[VListlength - 2] := Ver2;
  755. Vertices[VListlength - 1] := Ver3;
  756. Triangles[TListlength - 3] := VListlength - 3;
  757. Triangles[TListlength - 2] := VListlength - 2;
  758. Triangles[TListlength - 1] := VListlength - 1;
  759. edge := edge + 3;
  760. end;
  761. end;
  762. begin
  763. (*
  764. 7----6
  765. /| /|
  766. 3----2 |
  767. | 4--|-5
  768. |/ |/
  769. 0----1
  770. *)
  771. for i := 0 to Dimensions['x'] - 2 do
  772. begin
  773. for j := 1 to Dimensions['y'] - 1 do
  774. begin
  775. for k := 0 to Dimensions['z'] - 2 do
  776. begin
  777. CubeVertices[0] := AffineVectorMake(i, j, k);
  778. CubeVertices[1] := AffineVectorMake(i + 1, j, k);
  779. CubeVertices[2] := AffineVectorMake(i + 1, j - 1, k);
  780. CubeVertices[3] := AffineVectorMake(i, j - 1, k);
  781. CubeVertices[4] := AffineVectorMake(i, j, k + 1);
  782. CubeVertices[5] := AffineVectorMake(i + 1, j, k + 1);
  783. CubeVertices[6] := AffineVectorMake(i + 1, j - 1, k + 1);
  784. CubeVertices[7] := AffineVectorMake(i, j - 1, k + 1);
  785. CubeData[0] := Data[i, j, k];
  786. CubeData[1] := Data[i + 1, j, k];
  787. CubeData[2] := Data[i + 1, j - 1, k];
  788. CubeData[3] := Data[i, j - 1, k];
  789. CubeData[4] := Data[i, j, k + 1];
  790. CubeData[5] := Data[i + 1, j, k + 1];
  791. CubeData[6] := Data[i + 1, j - 1, k + 1];
  792. CubeData[7] := Data[i, j - 1, k + 1];
  793. Index := BuildIndex(CubeData, Isovalue);
  794. AppendTri();
  795. end; // for k
  796. end; // for j
  797. end; // for i
  798. end;
  799. function TgxMarchingCube.add_c_vertex: Integer;
  800. var
  801. u: Single;
  802. vid: Integer;
  803. procedure VertexAdd(iv: Integer);
  804. begin
  805. with PVertices^[_Nverts] do
  806. begin
  807. u := u + 1;
  808. P := VectorAdd(P, PVertices[iv].P);
  809. N := VectorAdd(N, PVertices[iv].N);
  810. {$IFDEF UseDensity}
  811. Density := Density + PVertices[iv].Density;
  812. {$ENDIF}
  813. end
  814. end;
  815. begin
  816. test_vertex_addiction;
  817. u := 0;
  818. with PVertices^[_Nverts] do
  819. begin
  820. P := NullVector;
  821. N := NullVector;
  822. {$IFDEF UseDensity}
  823. Density := 0;
  824. {$ENDIF}
  825. end;
  826. Inc(_Nverts);
  827. // Computes the average of the intersection points of the cube
  828. vid := Get_x_vert(_i, _j, _k);
  829. if (vid <> -1) then
  830. VertexAdd(vid);
  831. vid := Get_y_vert(_i + 1, _j, _k);
  832. if (vid <> -1) then
  833. VertexAdd(vid);
  834. vid := Get_x_vert(_i, _j + 1, _k);
  835. if (vid <> -1) then
  836. VertexAdd(vid);
  837. vid := Get_y_vert(_i, _j, _k);
  838. if (vid <> -1) then
  839. VertexAdd(vid);
  840. vid := Get_x_vert(_i, _j, _k + 1);
  841. if (vid <> -1) then
  842. VertexAdd(vid);
  843. vid := Get_y_vert(_i + 1, _j, _k + 1);
  844. if (vid <> -1) then
  845. VertexAdd(vid);
  846. vid := Get_x_vert(_i, _j + 1, _k + 1);
  847. if (vid <> -1) then
  848. VertexAdd(vid);
  849. vid := Get_y_vert(_i, _j, _k + 1);
  850. if (vid <> -1) then
  851. VertexAdd(vid);
  852. vid := Get_z_vert(_i, _j, _k);
  853. if (vid <> -1) then
  854. VertexAdd(vid);
  855. vid := Get_z_vert(_i + 1, _j, _k);
  856. if (vid <> -1) then
  857. VertexAdd(vid);
  858. vid := Get_z_vert(_i + 1, _j + 1, _k);
  859. if (vid <> -1) then
  860. VertexAdd(vid);
  861. vid := Get_z_vert(_i, _j + 1, _k);
  862. if (vid <> -1) then
  863. VertexAdd(vid);
  864. ScaleVector(PVertices^[_Nverts].P, 1 / u);
  865. NormalizeVector(PVertices^[_Nverts].N);
  866. {$IFDEF UseDensity}
  867. PVertices^[_Nverts].Density := PVertices^[_Nverts].Density / u;
  868. {$ENDIF}
  869. Result := _Nverts - 1;
  870. end;
  871. procedure TgxMarchingCube.add_triangle(trig: array of Integer; N: Byte;
  872. v12: Integer = -1);
  873. var
  874. tv: array [0 .. 2] of Integer;
  875. t, tmod3: Integer;
  876. begin
  877. for t := 0 to 3 * N - 1 do
  878. begin
  879. tmod3 := t mod 3;
  880. case trig[t] of
  881. 0: tv[tmod3] := Get_x_vert(_i, _j, _k);
  882. 1: tv[tmod3] := Get_y_vert(_i + 1, _j, _k);
  883. 2: tv[tmod3] := Get_x_vert(_i, _j + 1, _k);
  884. 3: tv[tmod3] := Get_y_vert(_i, _j, _k);
  885. 4: tv[tmod3] := Get_x_vert(_i, _j, _k + 1);
  886. 5: tv[tmod3] := Get_y_vert(_i + 1, _j, _k + 1);
  887. 6: tv[tmod3] := Get_x_vert(_i, _j + 1, _k + 1);
  888. 7: tv[tmod3] := Get_y_vert(_i, _j, _k + 1);
  889. 8: tv[tmod3] := Get_z_vert(_i, _j, _k);
  890. 9: tv[tmod3] := Get_z_vert(_i + 1, _j, _k);
  891. 10: tv[tmod3] := Get_z_vert(_i + 1, _j + 1, _k);
  892. 11: tv[tmod3] := Get_z_vert(_i, _j + 1, _k);
  893. 12: tv[tmod3] := v12
  894. end;
  895. if (tv[tmod3] = -1) then
  896. Break;
  897. if (tmod3 = 2) then
  898. begin
  899. if (_Ntrigs >= _Strigs) then
  900. begin
  901. _Strigs := 2 * _Strigs;
  902. ReallocMem(PTriangles, _Strigs * SizeOf(TTriangleRec));
  903. end;
  904. with PTriangles^[_Ntrigs] do
  905. begin
  906. v1 := tv[0];
  907. v2 := tv[1];
  908. v3 := tv[2];
  909. end;
  910. Inc(_Ntrigs);
  911. end
  912. end
  913. end;
  914. function TgxMarchingCube.calc_u(v1, v2: Single): Extended;
  915. begin
  916. if (abs(FIsoValue - v1) >= 0.00001) then
  917. Result := 1
  918. else if (abs(FIsoValue - v2) >= 0.00001) then
  919. Result := 0
  920. else if (abs(v1 - v2) >= 0.00001) then
  921. Result := (FIsoValue - v1) / (v2 - v1)
  922. else
  923. Result := 0.5
  924. end;
  925. function TgxMarchingCube.add_x_vertex: Integer;
  926. var
  927. u: Single;
  928. begin
  929. test_vertex_addiction;
  930. u := calc_u(_Cube[0].Density, _Cube[1].Density);
  931. with PVertices^[_Nverts] do
  932. begin
  933. P.X := _Cube[0].P.X + u * FStepX;
  934. P.Y := _Cube[0].P.Y;
  935. P.Z := _Cube[0].P.Z;
  936. N.X := (1 - u) * Get_x_grad(_i, _j, _k) + u * Get_x_grad(_i + 1, _j, _k);
  937. N.Y := (1 - u) * Get_y_grad(_i, _j, _k) + u * Get_y_grad(_i + 1, _j, _k);
  938. N.Z := (1 - u) * Get_z_grad(_i, _j, _k) + u * Get_z_grad(_i + 1, _j, _k);
  939. NormalizeVector(N);
  940. {$IFDEF UseDensity}
  941. Density := _Cube[1].Density
  942. {$ENDIF}
  943. end;
  944. Inc(_Nverts);
  945. Result := _Nverts - 1;
  946. end;
  947. function TgxMarchingCube.add_y_vertex: Integer;
  948. var
  949. u: Single;
  950. begin
  951. test_vertex_addiction;
  952. u := calc_u(_Cube[0].Density, _Cube[3].Density);
  953. with PVertices^[_Nverts] do
  954. begin
  955. P.X := _Cube[0].P.X;
  956. P.Y := _Cube[0].P.Y + u * FStepY;
  957. P.Z := _Cube[0].P.Z;
  958. N.X := (1 - u) * Get_x_grad(_i, _j, _k) + u * Get_x_grad(_i, _j + 1, _k);
  959. N.Y := (1 - u) * Get_y_grad(_i, _j, _k) + u * Get_y_grad(_i, _j + 1, _k);
  960. N.Z := (1 - u) * Get_z_grad(_i, _j, _k) + u * Get_z_grad(_i, _j + 1, _k);
  961. NormalizeVector(N);
  962. {$IFDEF UseDensity}
  963. Density := _Cube[3].Density
  964. {$ENDIF}
  965. end;
  966. Inc(_Nverts);
  967. Result := _Nverts - 1;
  968. end;
  969. function TgxMarchingCube.add_z_vertex: Integer;
  970. var
  971. u: Single;
  972. begin
  973. test_vertex_addiction;
  974. u := calc_u(_Cube[0].Density, _Cube[4].Density);
  975. with PVertices^[_Nverts] do
  976. begin
  977. P.X := _Cube[0].P.X;
  978. P.Y := _Cube[0].P.Y;
  979. P.Z := _Cube[0].P.Z + u * FStepZ;;
  980. N.X := (1 - u) * Get_x_grad(_i, _j, _k) + u * Get_x_grad(_i, _j, _k + 1);
  981. N.Y := (1 - u) * Get_y_grad(_i, _j, _k) + u * Get_y_grad(_i, _j, _k + 1);
  982. N.Z := (1 - u) * Get_z_grad(_i, _j, _k) + u * Get_z_grad(_i, _j, _k + 1);
  983. NormalizeVector(N);
  984. {$IFDEF UseDensity}
  985. Density := _Cube[4].Density
  986. {$ENDIF}
  987. end;
  988. Inc(_Nverts);
  989. Result := _Nverts - 1;
  990. end;
  991. procedure TgxMarchingCube.clean_all(keepFacets: Boolean = False);
  992. begin
  993. clean_temps;
  994. clean_space;
  995. if (not keepFacets) then
  996. FreeMem(PVertices);
  997. FreeMem(PTriangles);
  998. PVertices := nil;
  999. PTriangles := nil;
  1000. _Nverts := 0;
  1001. _Ntrigs := 0;
  1002. _Sverts := 0;
  1003. _Strigs := 0;
  1004. end;
  1005. procedure TgxMarchingCube.clean_space;
  1006. begin
  1007. if (VoxelData <> nil) then
  1008. begin
  1009. FreeMem(VoxelData);
  1010. VoxelData := nil
  1011. end;
  1012. FSizeX := 0;
  1013. FSizeY := 0;
  1014. FSizeZ := 0
  1015. end;
  1016. procedure TgxMarchingCube.clean_temps;
  1017. begin
  1018. FreeMem(PVertsX);
  1019. PVertsX := nil;
  1020. FreeMem(PVertsY);
  1021. PVertsY := nil;
  1022. FreeMem(PVertsZ);
  1023. PVertsZ := nil;
  1024. end;
  1025. procedure TgxMarchingCube.compute_intersection_points;
  1026. var
  1027. k, j, i: Integer;
  1028. begin
  1029. _Cube[0] := getVoxelData(0, 0, 0);
  1030. _Cube[1] := getVoxelData(1, 0, 0);
  1031. _Cube[3] := getVoxelData(0, 1, 0);
  1032. _Cube[4] := getVoxelData(0, 0, 1);
  1033. { _step_x:= _Cube[1].P[0] - _Cube[0].P[0] ;
  1034. _step_y:= _Cube[3].P[1] - _Cube[0].P[1] ;
  1035. _step_z:= _Cube[4].P[2] - _Cube[0].P[2] ; }
  1036. for k := 0 to FSizeZ - 2 do
  1037. begin
  1038. _k := k;
  1039. for j := 0 to FSizeY - 2 do
  1040. begin
  1041. _j := j;
  1042. for i := 0 to FSizeX - 2 do
  1043. begin
  1044. _i := i;
  1045. _Cube[0] := getVoxelData(_i, _j, _k);
  1046. _Cube[1] := getVoxelData(_i + 1, _j, _k);
  1047. _Cube[3] := getVoxelData(_i, _j + 1, _k);
  1048. _Cube[4] := getVoxelData(_i, _j, _k + 1);
  1049. if (Internal(_Cube[0].Density)) then
  1050. begin
  1051. if (not Internal(_Cube[1].Density)) then
  1052. set_x_vert(add_x_vertex(), _i, _j, _k);
  1053. if (not Internal(_Cube[3].Density)) then
  1054. set_y_vert(add_y_vertex(), _i, _j, _k);
  1055. if (not Internal(_Cube[4].Density)) then
  1056. set_z_vert(add_z_vertex(), _i, _j, _k);
  1057. end
  1058. else
  1059. begin
  1060. if (Internal(_Cube[1].Density)) then
  1061. set_x_vert(add_x_vertex(), _i, _j, _k);
  1062. if (Internal(_Cube[3].Density)) then
  1063. set_y_vert(add_y_vertex(), _i, _j, _k);
  1064. if (Internal(_Cube[4].Density)) then
  1065. set_z_vert(add_z_vertex(), _i, _j, _k);
  1066. end
  1067. end
  1068. end
  1069. end
  1070. end;
  1071. procedure TgxMarchingCube.ReDim(ASizeX, ASizeY, ASizeZ: Integer;
  1072. xMin, xMax, yMin, yMax, zMin, zMax: Single);
  1073. begin
  1074. clean_all;
  1075. FSizeX := ASizeX;
  1076. FSizeY := ASizeY;
  1077. FSizeZ := ASizeZ;
  1078. FxMin := xMin;
  1079. FxMax := xMax;
  1080. FyMin := yMin;
  1081. FyMax := yMax;
  1082. FzMin := zMin;
  1083. FzMax := zMax;
  1084. FStepX := (FxMax - FxMin) / (FSizeX - 1);
  1085. FStepY := (FyMax - FyMin) / (FSizeY - 1);
  1086. FStepZ := (FzMax - FzMin) / (FSizeZ - 1);
  1087. VoxelData := nil;
  1088. PVertsX := nil;
  1089. PVertsY := nil;
  1090. PVertsZ := nil;
  1091. _Nverts := 0;
  1092. _Ntrigs := 0;
  1093. _Sverts := 0;
  1094. _Strigs := 0;
  1095. PVertices := nil;
  1096. PTriangles := nil;
  1097. Init_all;
  1098. // FillVoxelData;
  1099. end;
  1100. constructor TgxMarchingCube.Create;
  1101. begin
  1102. FOriginalMC := True; // now only original MC is implemented
  1103. FIsoValue := 0;
  1104. ScalarField := nil;
  1105. // SFSphere;//SFKleinBottle;//SFMinkowski;// SFChmutov2;// SFChmutov1;//SFDoubleTorus;// SFToroidal;
  1106. VoxelData := nil;
  1107. PVertsX := nil;
  1108. PVertsY := nil;
  1109. PVertsZ := nil;
  1110. _Nverts := 0;
  1111. _Ntrigs := 0;
  1112. _Sverts := 0;
  1113. _Strigs := 0;
  1114. PVertices := nil;
  1115. PTriangles := nil;
  1116. end;
  1117. constructor TgxMarchingCube.Create(SizeX, SizeY, SizeZ: Integer;
  1118. AIsoValue: TScalarValue = 0.0; xMin: Single = -0.5; xMax: Single = 0.5;
  1119. yMin: Single = -0.5; yMax: Single = 0.5; zMin: Single = -0.5;
  1120. zMax: Single = 0.5);
  1121. begin
  1122. FOriginalMC := True; // now only original MC is implemented
  1123. FIsoValue := AIsoValue;
  1124. ScalarField := SFSphere;
  1125. //SFKleinBottle;
  1126. //SFMinkowski;
  1127. //SFChmutov2;
  1128. //SFChmutov1;
  1129. //SFDoubleTorus;
  1130. //SFToroidal;
  1131. ReDim(SizeX, SizeY, SizeZ, xMin, xMax, yMin, yMax, zMin, zMax);
  1132. FillVoxelData;
  1133. end;
  1134. destructor TgxMarchingCube.Destroy;
  1135. begin
  1136. clean_all;
  1137. inherited;
  1138. end;
  1139. function TgxMarchingCube.getVoxelValue(i, j, k: Integer): TScalarValue;
  1140. begin
  1141. Result := VoxelData^[i + j * FSizeX + k * FSizeX * FSizeY].Density
  1142. end;
  1143. function TgxMarchingCube.getVoxelData(i, j, k: Integer): TVoxelRec;
  1144. begin
  1145. Result := VoxelData^[i + j * FSizeX + k * FSizeX * FSizeY]
  1146. end;
  1147. function TgxMarchingCube.Get_x_grad(i, j, k: Integer): Single;
  1148. begin
  1149. if (i > 0) then
  1150. if (i < FSizeX - 1) then
  1151. Result := (getVoxelValue(i + 1, j, k) - getVoxelValue(i - 1, j, k)) / 2
  1152. else
  1153. Result := getVoxelValue(i, j, k) - getVoxelValue(i - 1, j, k)
  1154. else
  1155. Result := getVoxelValue(i + 1, j, k) - getVoxelValue(i, j, k)
  1156. end;
  1157. function TgxMarchingCube.Get_x_vert(i, j, k: Integer): Integer;
  1158. begin
  1159. Result := PVertsX^[i + j * FSizeX + k * FSizeX * FSizeY]
  1160. end;
  1161. function TgxMarchingCube.Get_y_grad(i, j, k: Integer): Single;
  1162. begin
  1163. if (j > 0) then
  1164. if (j < FSizeY - 1) then
  1165. Result := (getVoxelValue(i, j + 1, k) - getVoxelValue(i, j - 1, k)) / 2
  1166. else
  1167. Result := getVoxelValue(i, j, k) - getVoxelValue(i, j - 1, k)
  1168. else
  1169. Result := getVoxelValue(i, j + 1, k) - getVoxelValue(i, j, k)
  1170. end;
  1171. function TgxMarchingCube.Get_y_vert(i, j, k: Integer): Integer;
  1172. begin
  1173. Result := PVertsY^[i + j * FSizeX + k * FSizeX * FSizeY]
  1174. end;
  1175. function TgxMarchingCube.Get_z_grad(i, j, k: Integer): Single;
  1176. begin
  1177. if (k > 0) then
  1178. if (k < FSizeZ - 1) then
  1179. Result := (getVoxelValue(i, j, k + 1) - getVoxelValue(i, j, k - 1)) / 2
  1180. else
  1181. Result := getVoxelValue(i, j, k) - getVoxelValue(i, j, k - 1)
  1182. else
  1183. Result := getVoxelValue(i, j, k + 1) - getVoxelValue(i, j, k)
  1184. end;
  1185. function TgxMarchingCube.Get_z_vert(i, j, k: Integer): Integer;
  1186. begin
  1187. Result := PVertsZ^[i + j * FSizeX + k * FSizeX * FSizeY]
  1188. end;
  1189. procedure TgxMarchingCube.Init_all;
  1190. begin
  1191. Init_temps;
  1192. Init_space;
  1193. if (PVertices <> nil) then
  1194. FreeMem(PVertices);
  1195. if (PTriangles <> nil) then
  1196. FreeMem(PTriangles);
  1197. _Nverts := 0;
  1198. _Ntrigs := 0;
  1199. _Sverts := ALLOC_SIZE;
  1200. _Strigs := ALLOC_SIZE;
  1201. GetMem(PVertices, _Sverts * SizeOf(TVertexRec));
  1202. GetMem(PTriangles, _Strigs * SizeOf(TTriangleRec));
  1203. end;
  1204. procedure TgxMarchingCube.Init_space;
  1205. begin
  1206. VoxelData := AllocMem(FSizeX * FSizeY * FSizeZ * SizeOf(TVoxelRec));
  1207. end;
  1208. procedure TgxMarchingCube.Init_temps;
  1209. var
  1210. spaceSize: Longword;
  1211. begin
  1212. spaceSize := FSizeX * FSizeY * FSizeZ;
  1213. GetMem(PVertsX, spaceSize * SizeOf(Integer));
  1214. GetMem(PVertsY, spaceSize * SizeOf(Integer));
  1215. GetMem(PVertsZ, spaceSize * SizeOf(Integer));
  1216. FillChar(PVertsX^, spaceSize * SizeOf(Integer), -1);
  1217. FillChar(PVertsY^, spaceSize * SizeOf(Integer), -1);
  1218. FillChar(PVertsZ^, spaceSize * SizeOf(Integer), -1);
  1219. end;
  1220. function TgxMarchingCube.Internal(AValue: TScalarValue): Boolean;
  1221. begin
  1222. Result := AValue <= FIsoValue
  1223. end;
  1224. procedure TgxMarchingCube.process_cube;
  1225. var
  1226. nt: Byte;
  1227. begin
  1228. if (FOriginalMC) then
  1229. begin
  1230. nt := 0;
  1231. while (MC_TRITABLE[_lut_entry][3 * nt] <> -1) do
  1232. Inc(nt);
  1233. add_triangle(MC_TRITABLE[_lut_entry], nt);
  1234. Exit;
  1235. end;
  1236. {
  1237. TODO complete algorithm with various tiling...
  1238. }
  1239. end;
  1240. procedure TgxMarchingCube.Run;
  1241. var
  1242. i, j, k, P: Integer;
  1243. begin
  1244. if (PVertsX = nil) then
  1245. begin
  1246. Init_temps;
  1247. _Nverts := 0;
  1248. _Ntrigs := 0;
  1249. end;
  1250. Compute_Intersection_Points;
  1251. for k := 0 to FSizeZ - 2 do
  1252. begin
  1253. _k := k;
  1254. for j := 0 to FSizeY - 2 do
  1255. begin
  1256. _j := j;
  1257. for i := 0 to FSizeX - 2 do
  1258. begin
  1259. _i := i;
  1260. _lut_entry := 0;
  1261. for P := 0 to 7 do
  1262. begin
  1263. _Cube[P] := getVoxelData(i + ((P xor (P shr 1)) and 1),
  1264. j + ((P shr 1) and 1), k + ((P shr 2) and 1));
  1265. // _Cube[p]:= getVoxelData( i+((p^(p>>1))&1), j+((p>>1)&1), k+((p>>2)&1) ) ;
  1266. if (Internal(_Cube[P].Density)) then
  1267. _lut_entry := _lut_entry or (1 shl P);
  1268. end;
  1269. process_cube;
  1270. end
  1271. end
  1272. end;
  1273. clean_temps;
  1274. end;
  1275. procedure TgxMarchingCube.Run(IsoValue: TScalarValue);
  1276. begin
  1277. FIsoValue := IsoValue;
  1278. Run
  1279. end;
  1280. procedure TgxMarchingCube.setVoxelValue(i, j, k: Integer; HfValue: TScalarValue);
  1281. begin
  1282. VoxelData^[i + j * FSizeX + k * FSizeX * FSizeY].Density := HfValue
  1283. end;
  1284. procedure TgxMarchingCube.set_x_vert(a_val, i, j, k: Integer);
  1285. begin
  1286. PVertsX^[i + j * FSizeX + k * FSizeX * FSizeY] := a_val
  1287. end;
  1288. procedure TgxMarchingCube.set_y_vert(a_val, i, j, k: Integer);
  1289. begin
  1290. PVertsY^[i + j * FSizeX + k * FSizeX * FSizeY] := a_val
  1291. end;
  1292. procedure TgxMarchingCube.set_z_vert(a_val, i, j, k: Integer);
  1293. begin
  1294. PVertsZ^[i + j * FSizeX + k * FSizeX * FSizeY] := a_val
  1295. end;
  1296. procedure TgxMarchingCube.test_vertex_addiction;
  1297. begin
  1298. if _Nverts >= _Sverts then
  1299. begin
  1300. _Sverts := 2 * _Sverts;
  1301. ReallocMem(PVertices, _Sverts * SizeOf(TVertexRec))
  1302. end;
  1303. end;
  1304. function TgxMarchingCube.voxel(i, j, k: Integer): PVoxelRec;
  1305. begin
  1306. if (k >= FSizeZ) or (j >= FSizeY) or (i >= FSizeX) then
  1307. Result := nil
  1308. else
  1309. Result := @VoxelData^[i + j * FSizeX + k * FSizeX * FSizeY]
  1310. end;
  1311. procedure TgxMarchingCube.FillVoxelData;
  1312. var
  1313. iX, iY, iZ: Integer;
  1314. X, Y, Z: Single;
  1315. begin
  1316. for iX := 0 to FSizeX - 1 do
  1317. begin
  1318. X := FxMin + iX * FStepX;
  1319. for iY := 0 to FSizeY - 1 do
  1320. begin
  1321. Y := FyMin + iY * FStepY;
  1322. for iZ := 0 to FSizeZ - 1 do
  1323. with VoxelData^[iX + iY * FSizeX + iZ * FSizeX * FSizeY] do
  1324. begin
  1325. Z := FzMin + iZ * FStepZ;
  1326. MakeVector(P, X, Y, Z);
  1327. Density := ScalarField(X, Y, Z);
  1328. if Internal(Density) then
  1329. Status := bpInternal
  1330. else
  1331. Status := bpExternal
  1332. end;
  1333. end;
  1334. end;
  1335. end;
  1336. procedure TgxMarchingCube.FillVoxelData(AIsoValue: TScalarValue; AScalarField: TScalarField = nil);
  1337. begin
  1338. FIsoValue := AIsoValue;
  1339. if Assigned(AScalarField) then
  1340. ScalarField := AScalarField;
  1341. FillVoxelData;
  1342. end;
  1343. procedure TgxMarchingCube.FillVoxelData(AIsoValue: TScalarValue; AScalarField: TScalarFieldInt);
  1344. var
  1345. iX, iY, iZ: Integer;
  1346. X, Y, Z: Single;
  1347. begin
  1348. FIsoValue := AIsoValue;
  1349. for iX := 0 to FSizeX - 1 do
  1350. begin
  1351. X := FxMin + iX * FStepX;
  1352. for iY := 0 to FSizeY - 1 do
  1353. begin
  1354. Y := FyMin + iY * FStepY;
  1355. for iZ := 0 to FSizeZ - 1 do
  1356. with VoxelData^[iX + iY * FSizeX + iZ * FSizeX * FSizeY] do
  1357. begin
  1358. Z := FzMin + iZ * FStepZ;
  1359. MakeVector(P, X, Y, Z);
  1360. Density := AScalarField(iX, iY, iZ);
  1361. if Internal(Density) then
  1362. Status := bpInternal
  1363. else
  1364. Status := bpExternal
  1365. end;
  1366. end;
  1367. end;
  1368. end;
  1369. procedure TgxMarchingCube.CalcVertices(Vertices: TgxVertexList;
  1370. Alpha: Single = 1);
  1371. var
  1372. i: Integer;
  1373. vx1, vx2, vx3: TgxVertexData;
  1374. function GetNrmColor(Nrm: TAffineVector): TVector4f;
  1375. begin
  1376. Result.V[0] := 0;
  1377. if Nrm.V[0] > 0.0 then
  1378. Result.V[0] := Result.V[0] + Nrm.V[0];
  1379. if Nrm.V[1] < 0.0 then
  1380. Result.V[0] := Result.V[0] - 0.5 * Nrm.V[1];
  1381. if Nrm.V[2] < 0.0 then
  1382. Result.V[0] := Result.V[0] - 0.5 * Nrm.V[2];
  1383. Result.V[1] := 1;
  1384. if Nrm.V[0] < 0.0 then
  1385. Result.V[1] := Result.V[1] - 0.5 * Nrm.V[0];
  1386. if Nrm.V[1] > 0.0 then
  1387. Result.V[1] := Result.V[1] + Nrm.V[1];
  1388. if Nrm.V[2] < 0.0 then
  1389. Result.V[1] := Result.V[1] - 0.5 * Nrm.V[2];
  1390. Result.V[2] := 0;
  1391. if Nrm.V[0] < 0.0 then
  1392. Result.V[2] := Result.V[2] - 0.5 * Nrm.V[0];
  1393. if Nrm.V[1] < 0.0 then
  1394. Result.V[2] := Result.V[2] - 0.5 * Nrm.V[1];
  1395. if Nrm.V[2] > 0.0 then
  1396. Result.V[2] := Result.V[2] + Nrm.V[2];
  1397. Result.V[3] := 0.3
  1398. end;
  1399. function GetColor(H: TScalarValue): TVector4f;
  1400. begin
  1401. Result := VectorMake(0.890, 0.855, 0.788, Alpha)
  1402. { if H <= 10 then Result:= VectorMake(0.922, 0.957, 0.980, 1.000) //<=10
  1403. else if H <= 50 then Result:= VectorMake(0.541, 0.027, 0.027, 1.000) // 10..50
  1404. else if H <= 300 then Result:= VectorMake(0.941, 0.910, 0.859, 1.000) //50..300
  1405. else if H <= 2000 then Result:= VectorMake(0.965, 0.969, 0.973, 1.000) //350.. 2000
  1406. else if H <= 4000 then Result:= VectorMake(0.890, 0.855, 0.788, 1.000) //2000..4000
  1407. else Result:= VectorMake(0.9, 0.9, 0.6, 1.0) }
  1408. end;
  1409. begin
  1410. Vertices.Clear;
  1411. Vertices.Capacity := 3 * _Ntrigs;
  1412. for i := 0 to _Ntrigs - 1 do
  1413. with PTriangles^[i] do
  1414. begin
  1415. vx1.coord := PVertices^[v1].P;
  1416. vx1.normal := PVertices^[v1].N;
  1417. vx2.coord := PVertices^[v2].P;
  1418. vx2.normal := PVertices^[v2].N;
  1419. vx3.coord := PVertices^[v3].P;
  1420. vx3.normal := PVertices^[v3].N;
  1421. {$IFDEF UseDensity}
  1422. vx1.Color := GetColor(PVertices^[v1].Density); // GetNrmColor(vx1.normal);
  1423. vx2.Color := GetColor(PVertices^[v2].Density); // GetNrmColor(vx2.normal);
  1424. vx3.Color := GetColor(PVertices^[v3].Density); // GetNrmColor(vx3.normal);
  1425. {$ELSE}
  1426. vx1.Color := VectorMake(0.890, 0.855, 0.788, Alpha);
  1427. vx2.Color := VectorMake(0.890, 0.855, 0.788, Alpha);
  1428. vx3.Color := VectorMake(0.890, 0.855, 0.788, Alpha);
  1429. {$ENDIF}
  1430. // Vertices.AddVertex3(vx1, vx2, vx3); seems to be correct the next line
  1431. Vertices.AddVertex3(vx3, vx2, vx1);
  1432. end;
  1433. end;
  1434. procedure TgxMarchingCube.CalcMeshObject(AMeshObject: TgxMeshObject; Alpha: Single);
  1435. var
  1436. i: Integer;
  1437. begin
  1438. AMeshObject.Clear;
  1439. AMeshObject.Vertices.Capacity := _Nverts;
  1440. AMeshObject.Normals.Capacity := _Nverts;
  1441. AMeshObject.Colors.Capacity := _Nverts;
  1442. with TgxFGVertexIndexList.CreateOwned(AMeshObject.FaceGroups) do
  1443. begin
  1444. Mode := fgmmTriangles;
  1445. for i := 0 to _Nverts - 1 do
  1446. begin
  1447. AMeshObject.Vertices.Add(PVertices^[i].P);
  1448. AMeshObject.Normals.Add(PVertices^[i].N);
  1449. // AMeshObject.Normals.Add(VectorScale(PVertices^[i].N, -1));
  1450. // AMeshObject.Colors.Add(VectorMake(0.890, 0.855, 0.788, Alpha));
  1451. end;
  1452. for i := 0 to _Ntrigs - 1 do
  1453. // with PTriangles^[i] do VertexIndices.Add(v1, v2, v3);
  1454. with PTriangles^[i] do
  1455. VertexIndices.Add(v3, v2, v1);
  1456. end;
  1457. end;
  1458. end.