Stage.Triangulation.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. //
  2. // The graphics engine GLScene
  3. //
  4. unit Stage.Triangulation;
  5. (*
  6. Classes and methods for triangulation of scatter points.
  7. *)
  8. interface
  9. uses
  10. System.Classes,
  11. System.Types,
  12. Stage.VectorGeometry;
  13. // Set these as applicable
  14. const
  15. MaxVertices = 500000;
  16. MaxTriangles = 1000000;
  17. ExPtTolerance = 0.000001;
  18. type
  19. TDProgressEvent = procedure(State: string; Pos, Max: Integer;
  20. AlwaysUpdate: Boolean = False) of object;
  21. // Points (Vertices)
  22. type
  23. DVertex = record
  24. X: Single;
  25. Y: Single;
  26. Z: Single; // Added to save height of terrain.
  27. U: Single;
  28. V: Single;
  29. MatIndex: Integer;
  30. end;
  31. // Created Triangles, vv# are the vertex pointers
  32. type
  33. DTriangle = record
  34. vv0: LongInt;
  35. vv1: LongInt;
  36. vv2: LongInt;
  37. PreCalc: Integer;
  38. Xc, Yc, R: Single;
  39. end;
  40. type
  41. TDVertex = array of DVertex;
  42. TDTriangle = array of DTriangle;
  43. TDComplete = array of Boolean;
  44. TDEdges = array of array of LongInt;
  45. type
  46. (*
  47. TGDelaunay2D is a class for Delaunay triangulation of arbitrary points
  48. Credit to Paul Bourke (http://paulbourke.net/) for the original Fortran 77 Program :))
  49. Conversion to Visual Basic by EluZioN ([email protected])
  50. Conversion from VB to Delphi6 by Dr Steve Evans ([email protected])
  51. June 2002 Update by Dr Steve Evans: Heap memory allocation
  52. added to prevent stack overflow when MaxVertices and MaxTriangles are very large.
  53. Additional Updates in June 2002: Bug in InCircle function fixed. Radius r := Sqrt(rsqr).
  54. Check for duplicate points added when inserting new point.
  55. For speed, all points pre-sorted in x direction using quicksort algorithm and
  56. triangles flagged when no longer needed. The circumcircle centre and radius of
  57. the triangles are now stored to improve calculation time.
  58. You can use this code however you like providing the above credits remain in tact
  59. *)
  60. TGDelaunay2D = class
  61. private
  62. function InCircle(Xp, Yp, X1, Y1, X2, Y2, X3, Y3: Single; out Xc,Yc, R:
  63. Single; j: Integer): Boolean;
  64. (* Takes as input NVERT vertices in arrays Vertex()
  65. Returned is a list of NTRI triangular faces in the array
  66. Triangle(). These triangles are arranged in clockwise order.*)
  67. function Triangulate(nvert: Integer): Integer;
  68. public
  69. Vertex: TDVertex;
  70. Triangle: TDTriangle;
  71. HowMany: Integer;
  72. TPoints: Integer; //< Total number of points (vertices)
  73. OnProgress: TDProgressEvent;
  74. constructor Create;
  75. destructor Destroy; override;
  76. procedure Mesh(sort: Boolean);
  77. procedure AddPoint(X, Y, Z, U, V: Single; MatIndex: Integer);
  78. procedure AddPointNoCheck(X, Y, Z, U, V: Single; MatIndex: Integer);
  79. procedure RemoveLastPoint;
  80. procedure QuickSort(var A: TDVertex; Low, High: Integer);
  81. end;
  82. implementation //--------------------------------------------------------------
  83. constructor TGDelaunay2D.Create;
  84. begin
  85. // Initiate total points to 1, using base 0 causes problems in the functions
  86. inherited;
  87. TPoints := 1;
  88. HowMany := 0;
  89. SetLength(Vertex, MaxVertices);
  90. SetLength(Triangle, MaxTriangles);
  91. OnProgress := nil;
  92. end;
  93. destructor TGDelaunay2D.Destroy;
  94. begin
  95. SetLength(Vertex, 0);
  96. SetLength(Triangle, 0);
  97. inherited;
  98. end;
  99. function TGDelaunay2D.InCircle(Xp, Yp, X1, Y1, X2, Y2, X3, Y3: Single;
  100. out Xc, Yc, R: Single; j: Integer): Boolean;
  101. // Return TRUE if the point (xp,yp) lies inside the circumcircle
  102. // made up by points (x1,y1) (x2,y2) (x3,y3)
  103. // The circumcircle centre is returned in (xc,yc) and the radius r
  104. // NOTE: A point on the edge is inside the circumcircle
  105. var
  106. eps: Single;
  107. m1: Single;
  108. m2: Single;
  109. mx1: Single;
  110. mx2: Single;
  111. my1: Single;
  112. my2: Single;
  113. dx: Single;
  114. dy: Single;
  115. rsqr: Single;
  116. drsqr: Single;
  117. begin
  118. eps := 0.000001;
  119. InCircle := False;
  120. // Check if xc,yc and r have already been calculated
  121. if Triangle[j].PreCalc = 1 then
  122. begin
  123. Xc := Triangle[j].Xc;
  124. Yc := Triangle[j].Yc;
  125. R := Triangle[j].R;
  126. rsqr := R * R;
  127. dx := Xp - Xc;
  128. dy := Yp - Yc;
  129. drsqr := dx * dx + dy * dy;
  130. end
  131. else
  132. begin
  133. if (Abs(Y1 - Y2) < eps) and (Abs(Y2 - Y3) < eps) then
  134. begin
  135. Write('INCIRCUM - F - Points are coincident !!');
  136. Exit;
  137. end;
  138. if Abs(Y2 - Y1) < eps then
  139. begin
  140. m2 := -(X3 - X2) / (Y3 - Y2);
  141. mx2 := (X2 + X3) / 2;
  142. my2 := (Y2 + Y3) / 2;
  143. Xc := (X2 + X1) / 2;
  144. Yc := m2 * (Xc - mx2) + my2;
  145. end
  146. else if Abs(Y3 - Y2) < eps then
  147. begin
  148. m1 := -(X2 - X1) / (Y2 - Y1);
  149. mx1 := (X1 + X2) / 2;
  150. my1 := (Y1 + Y2) / 2;
  151. Xc := (X3 + X2) / 2;
  152. Yc := m1 * (Xc - mx1) + my1;
  153. end
  154. else
  155. begin
  156. m1 := -(X2 - X1) / (Y2 - Y1);
  157. m2 := -(X3 - X2) / (Y3 - Y2);
  158. mx1 := (X1 + X2) / 2;
  159. mx2 := (X2 + X3) / 2;
  160. my1 := (Y1 + Y2) / 2;
  161. my2 := (Y2 + Y3) / 2;
  162. if (m1 - m2) <> 0 then // se
  163. begin
  164. Xc := (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
  165. Yc := m1 * (Xc - mx1) + my1;
  166. end
  167. else
  168. begin
  169. Xc := (X1 + X2 + X3) / 3;
  170. Yc := (Y1 + Y2 + Y3) / 3;
  171. end;
  172. end;
  173. dx := X2 - Xc;
  174. dy := Y2 - Yc;
  175. rsqr := dx * dx + dy * dy;
  176. R := Sqrt(rsqr);
  177. dx := Xp - Xc;
  178. dy := Yp - Yc;
  179. drsqr := dx * dx + dy * dy;
  180. // store the xc,yc and r for later use
  181. Triangle[j].PreCalc := 1;
  182. Triangle[j].Xc := Xc;
  183. Triangle[j].Yc := Yc;
  184. Triangle[j].R := R;
  185. end;
  186. if drsqr <= rsqr then
  187. InCircle := True;
  188. end;
  189. function TGDelaunay2D.Triangulate(nvert: Integer): Integer;
  190. var
  191. Complete: TDComplete;
  192. Edges: TDEdges;
  193. Nedge: LongInt;
  194. // For Super Triangle
  195. xmin: Single;
  196. xmax: Single;
  197. ymin: Single;
  198. ymax: Single;
  199. xmid: Single;
  200. ymid: Single;
  201. dx: Single;
  202. dy: Single;
  203. dmax: Single;
  204. // General Variables
  205. i: Integer;
  206. j: Integer;
  207. k: Integer;
  208. ntri: Integer;
  209. Xc: Single;
  210. Yc: Single;
  211. R: Single;
  212. inc: Boolean;
  213. begin
  214. // Allocate memory
  215. SetLength(Complete, MaxTriangles);
  216. SetLength(Edges, 2, MaxTriangles * 3);
  217. // Find the maximum and minimum vertex bounds.
  218. // This is to allow calculation of the bounding triangle
  219. xmin := Vertex[1].X;
  220. ymin := Vertex[1].Y;
  221. xmax := xmin;
  222. ymax := ymin;
  223. for i := 2 to nvert do
  224. begin
  225. if Vertex[i].X < xmin then
  226. xmin := Vertex[i].X;
  227. if Vertex[i].X > xmax then
  228. xmax := Vertex[i].X;
  229. if Vertex[i].Y < ymin then
  230. ymin := Vertex[i].Y;
  231. if Vertex[i].Y > ymax then
  232. ymax := Vertex[i].Y;
  233. end;
  234. dx := xmax - xmin;
  235. dy := ymax - ymin;
  236. if dx > dy then
  237. dmax := dx
  238. else
  239. dmax := dy;
  240. xmid := Trunc((xmax + xmin) / 2);
  241. ymid := Trunc((ymax + ymin) / 2);
  242. // Set up the supertriangle
  243. // This is a triangle which encompasses all the sample points.
  244. // The supertriangle coordinates are added to the end of the
  245. // vertex list. The supertriangle is the first triangle in
  246. // the triangle list.
  247. Vertex[nvert + 1].X := (xmid - 2 * dmax);
  248. Vertex[nvert + 1].Y := (ymid - dmax);
  249. Vertex[nvert + 2].X := xmid;
  250. Vertex[nvert + 2].Y := (ymid + 2 * dmax);
  251. Vertex[nvert + 3].X := (xmid + 2 * dmax);
  252. Vertex[nvert + 3].Y := (ymid - dmax);
  253. Triangle[1].vv0 := nvert + 1;
  254. Triangle[1].vv1 := nvert + 2;
  255. Triangle[1].vv2 := nvert + 3;
  256. Triangle[1].PreCalc := 0;
  257. Complete[1] := False;
  258. ntri := 1;
  259. // Include each point one at a time into the existing mesh
  260. for i := 1 to nvert do
  261. begin
  262. if Assigned(OnProgress) then
  263. OnProgress('Delaunay triangulation', i - 1, nvert);
  264. Nedge := 0;
  265. // Set up the edge buffer.
  266. // If the point (Vertex(i).x,Vertex(i).y) lies inside the circumcircle then the
  267. // three edges of that triangle are added to the edge buffer.
  268. j := 0;
  269. repeat
  270. j := j + 1;
  271. if Complete[j] <> True then
  272. begin
  273. inc := InCircle(Vertex[i].X, Vertex[i].Y, Vertex[Triangle[j].vv0].X,
  274. Vertex[Triangle[j].vv0].Y, Vertex[Triangle[j].vv1].X,
  275. Vertex[Triangle[j].vv1].Y, Vertex[Triangle[j].vv2].X,
  276. Vertex[Triangle[j].vv2].Y, Xc, Yc, R, j);
  277. // Include this if points are sorted by X
  278. if { usingsort and } ((Xc + R) < Vertex[i].X) then //
  279. Complete[j] := True //
  280. else //
  281. if inc then
  282. begin
  283. Edges[0, Nedge + 1] := Triangle[j].vv0;
  284. Edges[1, Nedge + 1] := Triangle[j].vv1;
  285. Edges[0, Nedge + 2] := Triangle[j].vv1;
  286. Edges[1, Nedge + 2] := Triangle[j].vv2;
  287. Edges[0, Nedge + 3] := Triangle[j].vv2;
  288. Edges[1, Nedge + 3] := Triangle[j].vv0;
  289. Nedge := Nedge + 3;
  290. Triangle[j].vv0 := Triangle[ntri].vv0;
  291. Triangle[j].vv1 := Triangle[ntri].vv1;
  292. Triangle[j].vv2 := Triangle[ntri].vv2;
  293. Triangle[j].PreCalc := Triangle[ntri].PreCalc;
  294. Triangle[j].Xc := Triangle[ntri].Xc;
  295. Triangle[j].Yc := Triangle[ntri].Yc;
  296. Triangle[j].R := Triangle[ntri].R;
  297. Triangle[ntri].PreCalc := 0;
  298. Complete[j] := Complete[ntri];
  299. j := j - 1;
  300. ntri := ntri - 1;
  301. end;
  302. end;
  303. until j >= ntri;
  304. // Tag multiple edges
  305. // Note: if all triangles are specified anticlockwise then all
  306. // interior edges are opposite pointing in direction.
  307. for j := 1 to Nedge - 1 do
  308. begin
  309. if not(Edges[0, j] = 0) and not(Edges[1, j] = 0) then
  310. begin
  311. for k := j + 1 to Nedge do
  312. begin
  313. if not(Edges[0, k] = 0) and not(Edges[1, k] = 0) then
  314. begin
  315. if Edges[0, j] = Edges[1, k] then
  316. begin
  317. if Edges[1, j] = Edges[0, k] then
  318. begin
  319. Edges[0, j] := 0;
  320. Edges[1, j] := 0;
  321. Edges[0, k] := 0;
  322. Edges[1, k] := 0;
  323. end;
  324. end;
  325. end;
  326. end;
  327. end;
  328. end;
  329. // Form new triangles for the current point
  330. // Skipping over any tagged edges.
  331. // All edges are arranged in clockwise order.
  332. for j := 1 to Nedge do
  333. begin
  334. if not(Edges[0, j] = 0) and not(Edges[1, j] = 0) then
  335. begin
  336. ntri := ntri + 1;
  337. Triangle[ntri].vv0 := Edges[0, j];
  338. Triangle[ntri].vv1 := Edges[1, j];
  339. Triangle[ntri].vv2 := i;
  340. Triangle[ntri].PreCalc := 0;
  341. Complete[ntri] := False;
  342. end;
  343. end;
  344. end;
  345. // Remove triangles with supertriangle vertices
  346. // These are triangles which have a vertex number greater than NVERT
  347. i := 0;
  348. repeat
  349. i := i + 1;
  350. if (Triangle[i].vv0 > nvert) or (Triangle[i].vv1 > nvert) or
  351. (Triangle[i].vv2 > nvert) then
  352. begin
  353. Triangle[i].vv0 := Triangle[ntri].vv0;
  354. Triangle[i].vv1 := Triangle[ntri].vv1;
  355. Triangle[i].vv2 := Triangle[ntri].vv2;
  356. i := i - 1;
  357. ntri := ntri - 1;
  358. end;
  359. until i >= ntri;
  360. Triangulate := ntri;
  361. // Free memory
  362. SetLength(Complete, 0);
  363. SetLength(Edges, 2, 0);
  364. end;
  365. procedure TGDelaunay2D.Mesh(sort: Boolean);
  366. begin
  367. if sort then
  368. QuickSort(Vertex, 1, tPoints - 1);
  369. (* usingsort:=sort; *)
  370. if tPoints > 3 then
  371. HowMany := Triangulate(tPoints - 1);
  372. // 'Returns number of triangles created.
  373. end;
  374. procedure TGDelaunay2D.AddPoint(X, Y, Z, U, V: Single; MatIndex: Integer);
  375. var
  376. i, AE: Integer;
  377. begin
  378. // Check for duplicate points
  379. AE := 0;
  380. i := 1;
  381. while i < tPoints do
  382. begin
  383. if (Abs(X - Vertex[i].X) < ExPtTolerance) and
  384. (Abs(Y - Vertex[i].Y) < ExPtTolerance) then
  385. AE := 1;
  386. inc(i);
  387. end;
  388. if AE = 0 then
  389. begin
  390. // Set Vertex coordinates where you clicked the pic box
  391. Vertex[tPoints].X := X;
  392. Vertex[tPoints].Y := Y;
  393. Vertex[tPoints].Z := Z;
  394. Vertex[tPoints].U := U;
  395. Vertex[tPoints].V := V;
  396. Vertex[tPoints].MatIndex := MatIndex;
  397. // Increment the total number of points
  398. tPoints := tPoints + 1;
  399. end;
  400. end;
  401. procedure TGDelaunay2D.AddPointNoCheck(X, Y, Z, U, V: Single; MatIndex: Integer);
  402. begin
  403. Vertex[tPoints].X := X;
  404. Vertex[tPoints].Y := Y;
  405. Vertex[tPoints].Z := Z;
  406. Vertex[tPoints].U := U;
  407. Vertex[tPoints].V := V;
  408. Vertex[tPoints].MatIndex := MatIndex;
  409. tPoints := tPoints + 1;
  410. end;
  411. procedure TGDelaunay2D.RemoveLastPoint;
  412. begin
  413. tPoints := tPoints - 1;
  414. end;
  415. procedure TGDelaunay2D.QuickSort(var A: TDVertex; Low, High: Integer);
  416. // Sort all points by x
  417. {sub}procedure DoQuickSort(var A: TDVertex; iLo, iHi: Integer);
  418. var
  419. Lo, Hi: Integer;
  420. Mid: Single;
  421. T: DVertex;
  422. begin
  423. Lo := iLo;
  424. Hi := iHi;
  425. Mid := A[(Lo + Hi) div 2].X;
  426. repeat
  427. while A[Lo].X < Mid do
  428. inc(Lo);
  429. while A[Hi].X > Mid do
  430. Dec(Hi);
  431. if Lo <= Hi then
  432. begin
  433. T := A[Lo];
  434. A[Lo] := A[Hi];
  435. A[Hi] := T;
  436. inc(Lo);
  437. Dec(Hi);
  438. end;
  439. until Lo > Hi;
  440. if Hi > iLo then
  441. DoQuickSort(A, iLo, Hi);
  442. if Lo < iHi then
  443. DoQuickSort(A, Lo, iHi);
  444. end;
  445. begin
  446. DoQuickSort(A, Low, High);
  447. end;
  448. //---------------------------------------------------------------------------
  449. end.