Polygon.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. // POLY
  6. /******************************************************************************/
  7. Poly::Poly()
  8. {
  9. _infinite=angle=id=0;
  10. pos=null;
  11. }
  12. Poly& Poly::del()
  13. {
  14. _infinite=angle=id=0;
  15. pos =null;
  16. vtx.del();
  17. return T;
  18. }
  19. Poly& Poly::create(Vec *pos, Int id)
  20. {
  21. del();
  22. T.pos=pos;
  23. T.id =id;
  24. return T;
  25. }
  26. /******************************************************************************/
  27. Bool Poly::infinite()
  28. {
  29. if(!_infinite)
  30. {
  31. if(!vtx.elms())return false;
  32. if(!angle )setAngle();
  33. Flt angle=0;
  34. Int num =0; MFREP(vtx)
  35. {
  36. Flt a=vtx[i].angle;
  37. if( a>EPS && a<PI2-EPS) // vertexes with angle ~0 should be ignored because it's unknown whether they should be set to 0 or PI2
  38. {
  39. angle+=a;
  40. num++;
  41. }
  42. }
  43. _infinite=1+(angle>num*PI);
  44. }
  45. return _infinite==2;
  46. }
  47. /******************************************************************************/
  48. Flt Poly::length2D()C
  49. {
  50. if(vtx.elms()>=2)
  51. {
  52. Vec2 *prev =&pos[vtx[vtx.last()].index].xy;
  53. Flt length=0; MFREP(vtx)
  54. {
  55. Vec2 *next=&pos[vtx[i].index].xy;
  56. length+=Dist(*prev, *next); prev=next;
  57. }
  58. return length;
  59. }
  60. return 0;
  61. }
  62. Flt Poly::length3D()C
  63. {
  64. if(vtx.elms()>=2)
  65. {
  66. Vec *prev =&pos[vtx[vtx.last()].index];
  67. Flt length=0; MFREP(vtx)
  68. {
  69. Vec *next=&pos[vtx[i].index];
  70. length+=Dist(*prev, *next); prev=next;
  71. }
  72. return length;
  73. }
  74. return 0;
  75. }
  76. /******************************************************************************/
  77. void Poly::setAngle()
  78. {
  79. if(vtx.elms())
  80. {
  81. MemlNode *prev =vtx.first(),
  82. *cur =vtx.loopNext(prev);
  83. Vec2 *prevv=&pos[vtx[prev].index].xy,
  84. *curv =&pos[vtx[cur ].index].xy;
  85. REPA(vtx)
  86. {
  87. MemlNode *next =vtx.loopNext(cur);
  88. Vec2 *nextv=&pos[vtx[next].index].xy;
  89. vtx[cur] . angle=AngleFull(AngleBetween(*prevv, *curv, *nextv));
  90. prev=cur ; prevv=curv ;
  91. cur =next; curv =nextv;
  92. }
  93. angle=true;
  94. }
  95. }
  96. /******************************************************************************/
  97. void Poly::removeVtx(MemlNode *v)
  98. {
  99. MemlNode *prev=vtx.loopPrev(v),
  100. *next=vtx.loopNext(v);
  101. vtx.remove(v);
  102. if(!vtx.elms())
  103. {
  104. _infinite=0;
  105. angle =0;
  106. }else
  107. if(angle)
  108. {
  109. Vtx &P = vtx[ prev ],
  110. &N = vtx[ next ];
  111. Vec2 &pp=pos[vtx[vtx.loopPrev(prev)].index].xy,
  112. &nn=pos[vtx[vtx.loopNext(next)].index].xy,
  113. &p =pos[ P.index].xy,
  114. &n =pos[ N.index].xy;
  115. P.angle=AngleFull(AngleBetween(pp, p, n));
  116. N.angle=AngleFull(AngleBetween(p, n, nn));
  117. }
  118. }
  119. /******************************************************************************/
  120. void Poly::link(Poly &poly, MemlNode *i, MemlNode *pi)
  121. {
  122. // T0..i, pi..p1, p0..pi, i..T1
  123. Poly temp; temp.create(pos, id);
  124. MemlNode *c;
  125. for(c= T.vtx.first(); c; c=c->next()){temp.addVtx( T.vtx[c].index); if(c== i)break;}
  126. for(c=pi ; c; c=c->next()){temp.addVtx(poly.vtx[c].index); }
  127. for(c=poly.vtx.first(); c; c=c->next()){temp.addVtx(poly.vtx[c].index); if(c==pi)break;}
  128. for(c= i ; c; c=c->next()){temp.addVtx( T.vtx[c].index); }
  129. if(angle || poly.angle)temp.setAngle();
  130. Swap(T, temp);
  131. }
  132. /******************************************************************************/
  133. void Poly::draw2D(C Color &color)
  134. {
  135. MemlNode *cur=vtx.first();
  136. REPA(vtx)
  137. {
  138. MemlNode *next=vtx.loopNext(cur);
  139. D.line(color, pos[vtx[cur].index].xy, pos[vtx[next].index].xy);
  140. D.dot (color, pos[vtx[cur].index].xy);
  141. cur=next;
  142. }
  143. }
  144. void Poly::draw3D(C Color &color)
  145. {
  146. MemlNode *cur=vtx.first();
  147. REPA(vtx)
  148. {
  149. MemlNode *next=vtx.loopNext(cur);
  150. D.line(color, pos[vtx[cur].index], pos[vtx[next].index]);
  151. D.dot (color, pos[vtx[cur].index]);
  152. cur=next;
  153. }
  154. }
  155. /******************************************************************************/
  156. // MAIN
  157. /******************************************************************************/
  158. static Int CompareAngle(C Vec4 &a, C Vec4 &b)
  159. {
  160. if(Int c=Compare(b.z, a.z))return c; // compare 'b' against 'a' so generated poly will be in clockwise order
  161. return Compare(a.w, b.w);
  162. }
  163. static Int CompareAngle(C VecD4 &a, C VecD4 &b)
  164. {
  165. if(Int c=Compare(b.z, a.z))return c; // compare 'b' against 'a' so generated poly will be in clockwise order
  166. return Compare(a.w, b.w);
  167. }
  168. static Flt Dist(C Vec2 &p1, C Vec2 &p2, C Vec2 &p3)
  169. {
  170. return (p2.x-p1.x)*(p3.y-p1.y) - (p2.y-p1.y)*(p3.x-p1.x); // return DistPointPlane(p2, p1, Perp(p3-p1));
  171. }
  172. static Dbl Dist(C VecD2 &p1, C VecD2 &p2, C VecD2 &p3)
  173. {
  174. return (p2.x-p1.x)*(p3.y-p1.y) - (p2.y-p1.y)*(p3.x-p1.x); // return DistPointPlane(p2, p1, Perp(p3-p1));
  175. }
  176. /******************************************************************************/
  177. void CreateConvex2D(MemPtr<Vec2> poly, C Vec2 *point, Int points)
  178. {
  179. poly.clear();
  180. if(points>=1)
  181. {
  182. if(points==1)poly.add(point[0]);else
  183. {
  184. // find the most to the left bottom
  185. Int min_index=points-1;
  186. Vec2 min_value=point[min_index];
  187. REP(points-1){C Vec2 &p=point[i]; if(p.x<min_value.x || p.x==min_value.x && p.y<min_value.y){min_value=p; min_index=i;}} // if same X then compare Y to avoid having last point on the same line as #0 #1 that is useless
  188. // sort by angle
  189. Memt<Vec4> temp; temp.setNum(points);
  190. C Vec2 &start=point[min_index];
  191. REPA(temp)
  192. {
  193. // encode angle in 'z'
  194. C Vec2 &p=point[i];
  195. Vec2 d=p-start;
  196. temp[i].set(p, d.any() ? d.y/d.x : 1/d.x, Abs(d.y)+Abs(d.x)); // Warning: here we assume that +-Inf is obtained when dividing by d.x==0, first sort by 'z' (angle), then sort by 'w' (distance), if "!d.any()" which means both XY are zero and this is the starting point, then use 1/x to get INF instead of NAN which would break or even crash (stack overflow when sorting), use 'any' instead of comparing 'min_index' because there could be other points with the same coordinates
  197. }
  198. temp.sort(CompareAngle);
  199. // create poly
  200. poly.add(temp[0].xy);
  201. poly.add(temp[1].xy);
  202. for(Int i=2; i<temp.elms(); i++)
  203. {
  204. C Vec2 &p=temp[i].xy;
  205. for(; poly.elms()>=2 && Dist(p, poly.last(), poly[poly.elms()-2])<=0; )poly.removeLast();
  206. poly.add(p);
  207. }
  208. }
  209. }
  210. }
  211. void CreateConvex2D(MemPtr<VecD2> poly, C VecD2 *point, Int points)
  212. {
  213. poly.clear();
  214. if(points>=1)
  215. {
  216. if(points==1)poly.add(point[0]);else
  217. {
  218. // find the most to the left bottom
  219. Int min_index=points-1;
  220. VecD2 min_value=point[min_index];
  221. REP(points-1){C VecD2 &p=point[i]; if(p.x<min_value.x || p.x==min_value.x && p.y<min_value.y){min_value=p; min_index=i;}} // if same X then compare Y to avoid having last point on the same line as #0 #1 that is useless
  222. // sort by angle
  223. Memt<VecD4> temp; temp.setNum(points);
  224. C VecD2 &start=point[min_index];
  225. REPA(temp)
  226. {
  227. // encode angle in 'z'
  228. C VecD2 &p=point[i];
  229. VecD2 d=p-start;
  230. temp[i].set(p, d.any() ? d.y/d.x : 1/d.x, Abs(d.y)+Abs(d.x)); // Warning: here we assume that +-Inf is obtained when dividing by d.x==0, first sort by 'z' (angle), then sort by 'w' (distance), if "!d.any()" which means both XY are zero and this is the starting point, then use 1/x to get INF instead of NAN which would break or even crash (stack overflow when sorting), use 'any' instead of comparing 'min_index' because there could be other points with the same coordinates
  231. }
  232. temp.sort(CompareAngle);
  233. // create poly
  234. poly.add(temp[0].xy);
  235. poly.add(temp[1].xy);
  236. for(Int i=2; i<temp.elms(); i++)
  237. {
  238. C VecD2 &p=temp[i].xy;
  239. for(; poly.elms()>=2 && Dist(p, poly.last(), poly[poly.elms()-2])<=0; )poly.removeLast();
  240. poly.add(p);
  241. }
  242. }
  243. }
  244. }
  245. /******************************************************************************/
  246. void CreateConvex2Dxz(MemPtr<Vec2> poly, C Vec *point, Int points)
  247. {
  248. poly.clear();
  249. if(points>=1)
  250. {
  251. if(points==1)poly.add(point[0].xz());else
  252. {
  253. // find the most to the left bottom
  254. Int min_index=points-1;
  255. Vec2 min_value=point[min_index].xz();
  256. REP(points-1){C Vec &p=point[i]; if(p.x<min_value.x || p.x==min_value.x && p.z<min_value.y){min_value=p.xz(); min_index=i;}} // if same X then compare Y to avoid having last point on the same line as #0 #1 that is useless
  257. // sort by angle
  258. Memt<Vec4> temp; temp.setNum(points);
  259. Vec2 start=point[min_index].xz();
  260. REPA(temp)
  261. {
  262. // encode angle in 'z'
  263. Vec2 p=point[i].xz(), d=p-start;
  264. temp[i].set(p, d.any() ? d.y/d.x : 1/d.x, Abs(d.y)+Abs(d.x)); // Warning: here we assume that +-Inf is obtained when dividing by d.x==0, first sort by 'z' (angle), then sort by 'w' (distance), if "!d.any()" which means both XY are zero and this is the starting point, then use 1/x to get INF instead of NAN which would break or even crash (stack overflow when sorting), use 'any' instead of comparing 'min_index' because there could be other points with the same coordinates
  265. }
  266. temp.sort(CompareAngle);
  267. // create poly
  268. poly.add(temp[0].xy);
  269. poly.add(temp[1].xy);
  270. for(Int i=2; i<temp.elms(); i++)
  271. {
  272. C Vec2 &p=temp[i].xy;
  273. for(; poly.elms()>=2 && Dist(p, poly.last(), poly[poly.elms()-2])<=0; )poly.removeLast();
  274. poly.add(p);
  275. }
  276. }
  277. }
  278. }
  279. void CreateConvex2Dxz(MemPtr<VecD2> poly, C VecD *point, Int points)
  280. {
  281. poly.clear();
  282. if(points>=1)
  283. {
  284. if(points==1)poly.add(point[0].xz());else
  285. {
  286. // find the most to the left bottom
  287. Int min_index=points-1;
  288. VecD2 min_value=point[min_index].xz();
  289. REP(points-1){C VecD &p=point[i]; if(p.x<min_value.x || p.x==min_value.x && p.z<min_value.y){min_value=p.xz(); min_index=i;}} // if same X then compare Y to avoid having last point on the same line as #0 #1 that is useless
  290. // sort by angle
  291. Memt<VecD4> temp; temp.setNum(points);
  292. VecD2 start=point[min_index].xz();
  293. REPA(temp)
  294. {
  295. // encode angle in 'z'
  296. VecD2 p=point[i].xz(), d=p-start;
  297. temp[i].set(p, d.any() ? d.y/d.x : 1/d.x, Abs(d.y)+Abs(d.x)); // Warning: here we assume that +-Inf is obtained when dividing by d.x==0, first sort by 'z' (angle), then sort by 'w' (distance), if "!d.any()" which means both XY are zero and this is the starting point, then use 1/x to get INF instead of NAN which would break or even crash (stack overflow when sorting), use 'any' instead of comparing 'min_index' because there could be other points with the same coordinates
  298. }
  299. temp.sort(CompareAngle);
  300. // create poly
  301. poly.add(temp[0].xy);
  302. poly.add(temp[1].xy);
  303. for(Int i=2; i<temp.elms(); i++)
  304. {
  305. C VecD2 &p=temp[i].xy;
  306. for(; poly.elms()>=2 && Dist(p, poly.last(), poly[poly.elms()-2])<=0; )poly.removeLast();
  307. poly.add(p);
  308. }
  309. }
  310. }
  311. }
  312. /******************************************************************************/
  313. void Triangulate(C MemPtr<Vec> &poly, MeshBase &mesh, Bool convex)
  314. {
  315. if(poly.elms()>=3)
  316. {
  317. mesh.create(poly.elms(), 0, poly.elms()-2, 0);
  318. Vec *pos=mesh.vtx.pos();
  319. if(poly.elms()==3)
  320. {
  321. pos[0]=poly[0];
  322. pos[1]=poly[1];
  323. pos[2]=poly[2];
  324. mesh.tri.ind(0).set(0, 1, 2);
  325. }else
  326. {
  327. // triangulate
  328. Memt<Int> temp; temp.setNum(poly.elms());
  329. REPA(poly)
  330. {
  331. temp[i]=i;
  332. pos [i]=poly[i];
  333. }
  334. if(convex)
  335. {
  336. REP(temp.elms()-2)
  337. {
  338. mesh.tri.ind(i).set(temp[i], temp[i+1], temp[i+2]);
  339. temp.remove(i+1, true);
  340. }
  341. }else
  342. {
  343. // validate polygon normal
  344. Vec nrm, *normal=null;
  345. if(!normal)
  346. {
  347. nrm.zero(); REPA(poly)nrm+=GetNormalEdge(poly[i], poly[(i+1)%poly.elms()]); // get average face normal
  348. normal=&nrm;
  349. }
  350. for(mesh.tri._elms=0; temp.elms()>=3; )
  351. {
  352. Bool added=false;
  353. REP(temp.elms()-2)
  354. {
  355. Tri tri(pos[temp[i]], pos[temp[i+1]], pos[temp[i+2]]);
  356. if(Dot(*normal, tri.n)>0)
  357. {
  358. Vec cross[3]={Cross(tri.n, tri.p[0]-tri.p[1]), Cross(tri.n, tri.p[1]-tri.p[2]), Cross(tri.n, tri.p[2]-tri.p[0])};
  359. REPAD(t, temp)if(t<i || t>i+2)if(Cuts(pos[temp[t]], tri, cross))goto cuts;
  360. {
  361. Int t=mesh.tri.elms(); mesh.tri._elms++; mesh.tri.ind(t).set(temp[i], temp[i+1], temp[i+2]);
  362. temp.remove(i+1, true);
  363. added=true;
  364. }
  365. cuts:;
  366. }
  367. }
  368. if(!added)break;
  369. }
  370. }
  371. }
  372. }else
  373. {
  374. mesh.del();
  375. }
  376. }
  377. void Triangulate(C MemPtr<VtxFull> &poly, MeshBase &mesh, UInt flag_and, Bool convex)
  378. {
  379. if(poly.elms()>=3)
  380. {
  381. mesh.create(poly.elms(), 0, poly.elms()-2, 0, flag_and&~(VTX_FLAG|VTX_DUP));
  382. Vec *pos=mesh.vtx.pos();
  383. if(poly.elms()==3)
  384. {
  385. poly[0].to(mesh, 0);
  386. poly[1].to(mesh, 1);
  387. poly[2].to(mesh, 2);
  388. mesh.tri.ind(0).set(0, 1, 2);
  389. }else
  390. {
  391. // triangulate
  392. Memt<Int> temp; temp.setNum(poly.elms());
  393. REPA(poly)
  394. {
  395. temp[i]=i;
  396. poly[i].to(mesh, i);
  397. }
  398. if(convex)
  399. {
  400. REP(temp.elms()-2)
  401. {
  402. mesh.tri.ind(i).set(temp[i], temp[i+1], temp[i+2]);
  403. temp.remove(i+1, true);
  404. }
  405. }else
  406. {
  407. // validate polygon normal
  408. Vec nrm, *normal=null;
  409. if(!normal)
  410. {
  411. nrm.zero(); REPA(poly)nrm+=GetNormalEdge(poly[i].pos, poly[(i+1)%poly.elms()].pos); // get average face normal
  412. normal=&nrm;
  413. }
  414. for(mesh.tri._elms=0; temp.elms()>=3; )
  415. {
  416. Bool added=false;
  417. REP(temp.elms()-2)
  418. {
  419. Tri tri(pos[temp[i]], pos[temp[i+1]], pos[temp[i+2]]);
  420. if(Dot(*normal, tri.n)>0)
  421. {
  422. Vec cross[3]={Cross(tri.n, tri.p[0]-tri.p[1]), Cross(tri.n, tri.p[1]-tri.p[2]), Cross(tri.n, tri.p[2]-tri.p[0])};
  423. REPAD(t, temp)if(t<i || t>i+2)if(Cuts(pos[temp[t]], tri, cross))goto cuts;
  424. {
  425. Int t=mesh.tri.elms(); mesh.tri._elms++; mesh.tri.ind(t).set(temp[i], temp[i+1], temp[i+2]);
  426. temp.remove(i+1, true);
  427. added=true;
  428. }
  429. cuts:;
  430. }
  431. }
  432. if(!added)break;
  433. }
  434. }
  435. }
  436. }else mesh.del();
  437. }
  438. void Triangulate(C MemPtr< Memc<Vec> > &polys, MeshBase &mesh, Flt weld_pos_eps, Bool convex, C Byte *poly_flags)
  439. {
  440. // count number of vertexes and triangles
  441. Int vtxs=0, max_vtxs=0,
  442. tris=0;
  443. REPA(polys)
  444. {
  445. C Memc<Vec> &poly=polys[i];
  446. if(poly.elms()>=3)
  447. {
  448. MAX(max_vtxs, poly.elms());
  449. vtxs+=poly.elms();
  450. tris+=poly.elms()-2;
  451. }
  452. }
  453. // build mesh
  454. Memt<Int> temp;
  455. mesh.create(vtxs, 0, tris, 0, poly_flags ? FACE_FLAG : 0); mesh.tri._elms=0; Vec *pos=mesh.vtx.pos();
  456. vtxs=0;
  457. FREPA(polys)
  458. {
  459. C Memc<Vec> &poly=polys[i];
  460. if(poly.elms()>=3)
  461. {
  462. Byte flag=(poly_flags ? poly_flags[i] : 0);
  463. if(poly.elms()==3)
  464. {
  465. pos[vtxs+0]=poly[0];
  466. pos[vtxs+1]=poly[1];
  467. pos[vtxs+2]=poly[2];
  468. Int t=mesh.tri.elms(); mesh.tri._elms++; mesh.tri.ind(t).set(vtxs, vtxs+1, vtxs+2); if(mesh.tri.flag())mesh.tri.flag(t)=flag;
  469. vtxs+=3;
  470. }else
  471. if(convex)
  472. {
  473. FREP(poly.elms() )pos[temp.New()=vtxs+i]=poly[i]; // order is important
  474. REP(temp.elms()-2)
  475. {
  476. Int t=mesh.tri.elms(); mesh.tri._elms++; mesh.tri.ind(t).set(temp[i], temp[i+1], temp[i+2]); if(mesh.tri.flag())mesh.tri.flag(t)=flag;
  477. temp.remove(i+1, true);
  478. }
  479. temp.clear();
  480. vtxs+=poly.elms();
  481. }else
  482. {
  483. Vec nrm(0);
  484. FREPA(poly) // order is important
  485. {
  486. nrm+=GetNormalEdge(poly[i], poly[(i+1)%poly.elms()]); // get average face normal
  487. pos[temp.New()=vtxs+i]=poly[i];
  488. }
  489. for(; temp.elms()>=3; )
  490. {
  491. Bool added=false;
  492. REP(temp.elms()-2)
  493. {
  494. Tri tri(pos[temp[i]], pos[temp[i+1]], pos[temp[i+2]]);
  495. if(Dot(nrm, tri.n)>0)
  496. {
  497. Vec cross[3]={Cross(tri.n, tri.p[0]-tri.p[1]), Cross(tri.n, tri.p[1]-tri.p[2]), Cross(tri.n, tri.p[2]-tri.p[0])};
  498. REPAD(t, temp)if(t<i || t>i+2)if(Cuts(pos[temp[t]], tri, cross))goto cuts;
  499. {
  500. Int t=mesh.tri.elms(); mesh.tri._elms++; mesh.tri.ind(t).set(temp[i], temp[i+1], temp[i+2]); if(mesh.tri.flag())mesh.tri.flag(t)=flag;
  501. temp.remove(i+1, true);
  502. added=true;
  503. }
  504. cuts:;
  505. }
  506. }
  507. if(!added)break;
  508. }
  509. temp.clear();
  510. vtxs+=poly.elms();
  511. }
  512. }
  513. }
  514. mesh.weldVtx(VTX_ALL, weld_pos_eps);
  515. }
  516. void Triangulate(C MemPtr< Memc<VtxFull> > &polys, MeshBase &mesh, UInt flag_and, Flt weld_pos_eps, Bool convex, C Byte *poly_flags)
  517. {
  518. // count number of vertexes and triangles
  519. Int vtxs=0, max_vtxs=0,
  520. tris=0;
  521. REPA(polys)
  522. {
  523. C Memc<VtxFull> &poly=polys[i];
  524. if(poly.elms()>=3)
  525. {
  526. MAX(max_vtxs, poly.elms());
  527. vtxs+=poly.elms();
  528. tris+=poly.elms()-2;
  529. }
  530. }
  531. // build mesh
  532. Memt<Int> temp;
  533. mesh.create(vtxs, 0, tris, 0, flag_and & ((VTX_ALL&~(VTX_FLAG|VTX_DUP)) | (poly_flags ? FACE_FLAG : 0))); mesh.tri._elms=0; Vec *pos=mesh.vtx.pos();
  534. vtxs=0;
  535. FREPA(polys)
  536. {
  537. C Memc<VtxFull> &poly=polys[i];
  538. if(poly.elms()>=3)
  539. {
  540. Byte flag=(poly_flags ? poly_flags[i] : 0);
  541. if(poly.elms()==3)
  542. {
  543. poly[0].to(mesh, vtxs+0);
  544. poly[1].to(mesh, vtxs+1);
  545. poly[2].to(mesh, vtxs+2);
  546. Int t=mesh.tri.elms(); mesh.tri._elms++; mesh.tri.ind(t).set(vtxs, vtxs+1, vtxs+2); if(mesh.tri.flag())mesh.tri.flag(t)=flag;
  547. vtxs+=3;
  548. }else
  549. if(convex)
  550. {
  551. FREP(poly.elms() )poly[i].to(mesh, temp.New()=vtxs+i); // order is important
  552. REP(temp.elms()-2)
  553. {
  554. Int t=mesh.tri.elms(); mesh.tri._elms++; mesh.tri.ind(t).set(temp[i], temp[i+1], temp[i+2]); if(mesh.tri.flag())mesh.tri.flag(t)=flag;
  555. temp.remove(i+1, true);
  556. }
  557. temp.clear();
  558. vtxs+=poly.elms();
  559. }else
  560. {
  561. Vec nrm(0);
  562. FREPA(poly) // order is important
  563. {
  564. nrm+=GetNormalEdge(poly[i].pos, poly[(i+1)%poly.elms()].pos); // get average face normal
  565. poly[i].to(mesh, temp.New()=vtxs+i);
  566. }
  567. for(; temp.elms()>=3; )
  568. {
  569. Bool added=false;
  570. REP(temp.elms()-2)
  571. {
  572. Tri tri(pos[temp[i]], pos[temp[i+1]], pos[temp[i+2]]);
  573. if(Dot(nrm, tri.n)>0)
  574. {
  575. Vec cross[3]={Cross(tri.n, tri.p[0]-tri.p[1]), Cross(tri.n, tri.p[1]-tri.p[2]), Cross(tri.n, tri.p[2]-tri.p[0])};
  576. REPAD(t, temp)if(t<i || t>i+2)if(Cuts(pos[temp[t]], tri, cross))goto cuts;
  577. {
  578. Int t=mesh.tri.elms(); mesh.tri._elms++; mesh.tri.ind(t).set(temp[i], temp[i+1], temp[i+2]); if(mesh.tri.flag())mesh.tri.flag(t)=flag;
  579. temp.remove(i+1, true);
  580. added=true;
  581. }
  582. cuts:;
  583. }
  584. }
  585. if(!added)break;
  586. }
  587. temp.clear();
  588. vtxs+=poly.elms();
  589. }
  590. }
  591. }
  592. mesh.weldVtx(VTX_ALL, weld_pos_eps);
  593. }
  594. /******************************************************************************/
  595. void ClipPoly(C MemPtr<Vec> &poly, C Plane &plane, MemPtr<Vec> output)
  596. {
  597. output.clear();
  598. switch(poly.elms())
  599. {
  600. case 0: break;
  601. case 1:
  602. if(Dist(poly[0], plane)<0)output.add(poly[0]);
  603. break;
  604. default: // >=2
  605. {
  606. Vec prev =poly.last();
  607. Flt prev_dist=Dist(prev, plane);
  608. FREPA(poly) // preserve order
  609. {
  610. C Vec &next =poly[i];
  611. Flt next_dist=Dist(next, plane);
  612. if( prev_dist<0)
  613. {
  614. output.add(prev);
  615. if(next_dist>=0) // change of side
  616. {
  617. output.add(Lerp(prev, next, prev_dist/(prev_dist-next_dist))); // -prev_dist/(next_dist-prev_dist)
  618. }
  619. }
  620. else // prev_dist>=0
  621. {
  622. if(next_dist<0) // change of side
  623. {
  624. output.add(Lerp(prev, next, prev_dist/(prev_dist-next_dist)));
  625. }
  626. }
  627. prev =next;
  628. prev_dist=next_dist;
  629. }
  630. }break;
  631. }
  632. }
  633. void ClipPoly(C MemPtr<VtxFull> &poly, C Plane &plane, MemPtr<VtxFull> output)
  634. {
  635. output.clear();
  636. switch(poly.elms())
  637. {
  638. case 0: break;
  639. case 1:
  640. if(Dist(poly[0].pos, plane)<0)output.add(poly[0]);
  641. break;
  642. default: // >=2
  643. {
  644. C VtxFull *prev =&poly.last();
  645. Flt prev_dist=Dist(prev->pos, plane);
  646. FREPA(poly) // preserve order
  647. {
  648. C VtxFull &next =poly[i];
  649. Flt next_dist=Dist(next.pos, plane);
  650. if( prev_dist<0)
  651. {
  652. output.add(*prev);
  653. if(next_dist>=0) // change of side
  654. {
  655. output.New().lerp(*prev, next, prev_dist/(prev_dist-next_dist)); // -prev_dist/(next_dist-prev_dist)
  656. }
  657. }
  658. else // prev_dist>=0
  659. {
  660. if(next_dist<0) // change of side
  661. {
  662. output.New().lerp(*prev, next, prev_dist/(prev_dist-next_dist));
  663. }
  664. }
  665. prev =&next;
  666. prev_dist= next_dist;
  667. }
  668. }break;
  669. }
  670. }
  671. /******************************************************************************/
  672. void SplitPoly(C MemPtr<Vec> &poly, C Plane &plane, MemPtr<Vec> output_positive, MemPtr<Vec> output_negative)
  673. {
  674. output_positive.clear();
  675. output_negative.clear();
  676. switch(poly.elms())
  677. {
  678. case 0: break;
  679. case 1:
  680. if(Dist(poly[0], plane)<0)output_negative.add(poly[0]);
  681. else output_positive.add(poly[0]);
  682. break;
  683. default: // >=2
  684. {
  685. Vec prev =poly.last();
  686. Flt prev_dist=Dist(prev, plane);
  687. FREPA(poly) // preserve order
  688. {
  689. Bool have_mid =false;
  690. C Vec &next =poly[i]; Vec mid;
  691. Flt next_dist=Dist(next, plane);
  692. // negative
  693. if(prev_dist<0)
  694. {
  695. output_negative.add(prev);
  696. if(next_dist>=0) // change of side
  697. {
  698. if(!have_mid){have_mid=true; mid=Lerp(prev, next, prev_dist/(prev_dist-next_dist));} // -prev_dist/(next_dist-prev_dist)
  699. output_negative.add(mid);
  700. }
  701. }
  702. else // prev_dist>=0
  703. {
  704. if(next_dist<0) // change of side
  705. {
  706. if(!have_mid){have_mid=true; mid=Lerp(prev, next, prev_dist/(prev_dist-next_dist));}
  707. output_negative.add(mid);
  708. }
  709. }
  710. // positive
  711. if(prev_dist>0)
  712. {
  713. output_positive.add(prev);
  714. if(next_dist<=0) // change of side
  715. {
  716. if(!have_mid){have_mid=true; mid=Lerp(prev, next, prev_dist/(prev_dist-next_dist));} // -prev_dist/(next_dist-prev_dist)
  717. output_positive.add(mid);
  718. }
  719. }
  720. else // prev_dist<=0
  721. {
  722. if(next_dist>0) // change of side
  723. {
  724. if(!have_mid){have_mid=true; mid=Lerp(prev, next, prev_dist/(prev_dist-next_dist));}
  725. output_positive.add(mid);
  726. }
  727. }
  728. prev =next;
  729. prev_dist=next_dist;
  730. }
  731. }break;
  732. }
  733. }
  734. void SplitPoly(C MemPtr<VtxFull> &poly, C Plane &plane, MemPtr<VtxFull> output_positive, MemPtr<VtxFull> output_negative)
  735. {
  736. output_positive.clear();
  737. output_negative.clear();
  738. switch(poly.elms())
  739. {
  740. case 0: break;
  741. case 1:
  742. if(Dist(poly[0].pos, plane)<0)output_negative.add(poly[0]);
  743. else output_positive.add(poly[0]);
  744. break;
  745. default: // >=2
  746. {
  747. C VtxFull *prev =&poly.last();
  748. Flt prev_dist=Dist(prev->pos, plane);
  749. FREPA(poly) // preserve order
  750. {
  751. Bool have_mid =false;
  752. C VtxFull &next =poly[i]; VtxFull mid;
  753. Flt next_dist=Dist(next.pos, plane);
  754. // negative
  755. if(prev_dist<0)
  756. {
  757. output_negative.add(*prev);
  758. if(next_dist>=0) // change of side
  759. {
  760. if(!have_mid){have_mid=true; mid.lerp(*prev, next, prev_dist/(prev_dist-next_dist));} // -prev_dist/(next_dist-prev_dist)
  761. output_negative.add(mid);
  762. }
  763. }
  764. else // prev_dist>=0
  765. {
  766. if(next_dist<0) // change of side
  767. {
  768. if(!have_mid){have_mid=true; mid.lerp(*prev, next, prev_dist/(prev_dist-next_dist));}
  769. output_negative.add(mid);
  770. }
  771. }
  772. // positive
  773. if(prev_dist>0)
  774. {
  775. output_positive.add(*prev);
  776. if(next_dist<=0) // change of side
  777. {
  778. if(!have_mid){have_mid=true; mid.lerp(*prev, next, prev_dist/(prev_dist-next_dist));} // -prev_dist/(next_dist-prev_dist)
  779. output_positive.add(mid);
  780. }
  781. }
  782. else // prev_dist<=0
  783. {
  784. if(next_dist>0) // change of side
  785. {
  786. if(!have_mid){have_mid=true; mid.lerp(*prev, next, prev_dist/(prev_dist-next_dist));}
  787. output_positive.add(mid);
  788. }
  789. }
  790. prev =&next;
  791. prev_dist= next_dist;
  792. }
  793. }break;
  794. }
  795. }
  796. /******************************************************************************/
  797. void DrawPoly2D(C MemPtr<Vec> &poly, C Color &edge_color, C Color &vtx_color)
  798. {
  799. if(poly.elms())
  800. {
  801. if(edge_color.a)
  802. {
  803. VI.color(edge_color);
  804. Vec2 prev=poly.first().xy;
  805. REPA(poly)
  806. {
  807. C Vec2 &next=poly[i].xy; VI.line(prev, next);
  808. prev=next;
  809. }
  810. VI.end();
  811. }
  812. if(vtx_color.a)
  813. {
  814. VI.color(vtx_color);
  815. REPA(poly)VI.dot (poly[i].xy);
  816. VI.end ();
  817. }
  818. }
  819. }
  820. void DrawPoly(C MemPtr<Vec> &poly, C Color &edge_color, C Color &vtx_color)
  821. {
  822. if(poly.elms())
  823. {
  824. if(edge_color.a)
  825. {
  826. VI.color(edge_color);
  827. Vec prev=poly.first();
  828. REPA(poly)
  829. {
  830. C Vec &next=poly[i]; VI.line(prev, next);
  831. prev=next;
  832. }
  833. VI.end();
  834. }
  835. if(vtx_color.a)
  836. {
  837. VI.color(vtx_color);
  838. REPA(poly)VI.dot (poly[i]);
  839. VI.end ();
  840. }
  841. }
  842. }
  843. /******************************************************************************/
  844. }
  845. /******************************************************************************/