PageRenderTime 24ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/Triangulate.hx

https://bitbucket.org/deltaluca/stressing
Haxe | 254 lines | 209 code | 31 blank | 14 comment | 49 complexity | a4e9972eda5ad3ee4ce23f3351e94494 MD5 | raw file
  1. package;
  2. import ogl.GLM;
  3. typedef P2 = {x:Float,y:Float};
  4. typedef PV = {x:Float,y:Float,u:Float,cnt:Int};
  5. typedef TValues = {e0:Float,e1:Float,e2:Float};
  6. ///
  7. /// Triangulate.triangulate(fs:Array<P2>):ts:Array<Int>
  8. /// ts[i,i+1,i+2] (i%3) triangle indices
  9. ///
  10. /// Triangulate.divide(fs:Array<P2>,ts:Array<Int>,vs:Array<TValues>):{fs:Array<PV>,ts:Array<Int>}
  11. /// each triangle turned into 7, with 6 extra vertices.
  12. ///
  13. class Triangulate {
  14. static inline var epsilon = 1e-12;
  15. static inline function h(a:Float,b:Float) return 0.5*(a+b);
  16. public static function divide(fs:Array<P2>,ts:Array<Int>,vs:Array<TValues>,skipTs=false):{fs:Array<PV>,ts:Null<Array<Int>>} {
  17. var nf = fs.length;
  18. var nt = Std.int(ts.length/3);
  19. // fs[i] -> ofs[i]
  20. // ed[i] -> ofs[#fs + i] for 1 vertex
  21. var ofs:Array<PV> = [];
  22. for (f in fs) ofs.push({x:f.x,y:f.y,u:0.0,cnt:0});
  23. function gen(a:P2,b:P2) return
  24. { x:h(a.x,b.x),
  25. y:h(a.y,b.y),
  26. u:0.0,
  27. cnt:0
  28. };
  29. // Generate edge vertices
  30. // (i,j) -> (i*#fs + j)
  31. var ed = new Map<Int,Int>();
  32. for (i in 0...nt) {
  33. var t = i*3;
  34. var t0 = ts[t+0];
  35. var t1 = ts[t+1];
  36. var t2 = ts[t+2];
  37. function insert(a, b) {
  38. var ind = a*nf + b;
  39. if (!ed.exists(ind)) {
  40. var jnd = ed[ind] = ofs.length;
  41. ofs.push(gen(fs[a],fs[b]));
  42. }
  43. }
  44. insert(t1,t2);
  45. insert(t2,t0);
  46. insert(t0,t1);
  47. }
  48. // And non-normalised colours
  49. // And new triangles.
  50. var ots:Array<Int> = if (skipTs) null else [];
  51. for (i in 0...Std.int(ts.length/3)) {
  52. var val = vs[i];
  53. var t = i*3;
  54. var t0 = ts[t+0];
  55. var t1 = ts[t+1];
  56. var t2 = ts[t+2];
  57. var u0 = ed[t1*nf+t2];
  58. var u1 = ed[t2*nf+t0];
  59. var u2 = ed[t0*nf+t1];
  60. var ind = ofs.length;
  61. var f0 = ofs[t0]; f0.cnt++; f0.u += val.e1+val.e2-val.e0;
  62. var f1 = ofs[t1]; f1.cnt++; f1.u += val.e2+val.e0-val.e1;
  63. var f2 = ofs[t2]; f2.cnt++; f2.u += val.e0+val.e1-val.e2;
  64. var e0 = ofs[ed[t1*nf+t2]]; e0.cnt++; e0.u += val.e0;
  65. var e1 = ofs[ed[t2*nf+t0]]; e1.cnt++; e1.u += val.e1;
  66. var e2 = ofs[ed[t0*nf+t1]]; e2.cnt++; e2.u += val.e2;
  67. if (!skipTs)
  68. ots = ots.concat([
  69. t0,u2,u1, t1,u0,u2, t2,u1,u0,
  70. u0,u1,u2
  71. ]);
  72. }
  73. return {
  74. fs: ofs,
  75. ts: ots
  76. };
  77. }
  78. // compute circumcircle of (c1,c2,c3) and whether point is contained within it.
  79. public static inline function circumscribed(point:P2, c1:P2, c2:P2, c3:P2, circle:Vec3) {
  80. var ax = c1.x;
  81. var ay = c1.y;
  82. var bx = c2.x - ax;
  83. var by = c2.y - ay;
  84. var cx = c3.x - ax;
  85. var cy = c3.y - ay;
  86. var px = point.x - ax;
  87. var py = point.y - ay;
  88. var d = bx*cy - by*cx;
  89. if (d*d < epsilon) return false;
  90. else {
  91. var id = 1/(2*d);
  92. var bl = bx*bx + by*by;
  93. var cl = cx*cx + cy*cy;
  94. var x = (cy*bl - by*cl)*id;
  95. var y = (bx*cl - cx*bl)*id;
  96. var cl = x*x + y*y;
  97. circle.x = ax + x;
  98. circle.y = ay + y;
  99. circle.z = Math.sqrt(cl);
  100. px -= x;
  101. py -= y;
  102. return (px*px + py*py) < cl;
  103. }
  104. }
  105. public static inline function lex(a:P2, b:P2) {
  106. return (a.x < b.x) || (a.x == b.x && a.y < b.y);
  107. }
  108. public static inline function sort<T>(xs:Array<T>, n:Int, lt:T->T->Bool) {
  109. for (i in 1...n) {
  110. var v = xs[i];
  111. var pos = i;
  112. while (pos > 0 && lt(v, xs[pos-1])) {
  113. xs[pos] = xs[pos-1];
  114. pos--;
  115. }
  116. xs[pos] = v;
  117. }
  118. }
  119. public static function triangulate(points:Array<P2>, ?count:Null<Int>):Array<Int> {
  120. var n = if (count == null) points.length else count;
  121. if (n < 3) return [];
  122. var triangles = [];
  123. var complete = [];
  124. var edges = [];
  125. sort(points, n, lex);
  126. var minx = points[0].x;
  127. var miny = points[0].y;
  128. var maxx = minx;
  129. var maxy = miny;
  130. for (i in 1...n) {
  131. var p = points[i];
  132. if (p.x < minx) minx = p.x;
  133. if (p.y < miny) miny = p.y;
  134. if (p.x > maxx) maxx = p.x;
  135. if (p.y > maxy) maxy = p.y;
  136. }
  137. var dx = maxx - minx;
  138. var dy = maxy - miny;
  139. var dmax = if (dx > dy) dx else dy;
  140. var midx = (maxx + minx)*0.5;
  141. var midy = (maxy + miny)*0.5;
  142. var ntri = 1;
  143. triangles[0] = points.length;
  144. triangles[1] = points.length+1;
  145. triangles[2] = points.length+2;
  146. complete[0] = false;
  147. points.push({x:midx-2*dmax, y:midy-dmax });
  148. points.push({x:midx, y:midy+2*dmax});
  149. points.push({x:midx+2*dmax, y:midy-dmax });
  150. var circle:Vec3 = [0,0,0];
  151. for (i in 0...n) {
  152. var p = points[i];
  153. var nedge = 0;
  154. var j = 0;
  155. while (j < ntri) {
  156. if (complete[j]) {
  157. j++;
  158. continue;
  159. }
  160. var tri = j*3;
  161. var inside = circumscribed(
  162. p, points[triangles[tri+0]], points[triangles[tri+1]], points[triangles[tri+2]], circle
  163. );
  164. if (circle.x + circle.z < p.x) complete[j] = true;
  165. if (inside) {
  166. edges[(nedge<<1)+0] = triangles[tri+0];
  167. edges[(nedge<<1)+1] = triangles[tri+1];
  168. edges[(nedge<<1)+2] = triangles[tri+1];
  169. edges[(nedge<<1)+3] = triangles[tri+2];
  170. edges[(nedge<<1)+4] = triangles[tri+2];
  171. edges[(nedge<<1)+5] = triangles[tri+0];
  172. nedge += 3;
  173. var ktri = (ntri-1)*3;
  174. triangles[tri+0] = triangles[ktri+0];
  175. triangles[tri+1] = triangles[ktri+1];
  176. triangles[tri+2] = triangles[ktri+2];
  177. complete[j] = complete[ntri-1];
  178. ntri--;
  179. }
  180. else j++;
  181. }
  182. for (j in 0...nedge-1) {
  183. var je = j<<1;
  184. for (k in j+1...nedge) {
  185. var ke = k<<1;
  186. if (edges[je] == edges[ke+1] && edges[je+1] == edges[ke]) {
  187. edges[je] = edges[je+1] = -1;
  188. edges[ke] = edges[ke+1] = -1;
  189. }
  190. }
  191. }
  192. for (j in 0...nedge) {
  193. var je = j<<1;
  194. if (edges[je] == -1 || edges[je+1] == -1) continue;
  195. var tri = ntri*3;
  196. triangles[tri+0] = edges[je];
  197. triangles[tri+1] = edges[je+1];
  198. triangles[tri+2] = i;
  199. complete[ntri] = false;
  200. ntri++;
  201. }
  202. }
  203. var i = 0;
  204. while (i < ntri) {
  205. var tri = i*3;
  206. if (triangles[tri+0] >= n
  207. || triangles[tri+1] >= n
  208. || triangles[tri+2] >= n) {
  209. var ktri = (ntri-1)*3;
  210. triangles[tri+0] = triangles[ktri+0];
  211. triangles[tri+1] = triangles[ktri+1];
  212. triangles[tri+2] = triangles[ktri+2];
  213. ntri--;
  214. }
  215. else i++;
  216. }
  217. while (triangles.length > ntri*3) triangles.pop();
  218. points.pop();
  219. points.pop();
  220. points.pop();
  221. return triangles;
  222. }
  223. }