Mshb Add Remove.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. MeshBase& MeshBase::addVtx(C Vec &pos)
  6. {
  7. exclude(VTX_DUP);
  8. Realloc1 (vtx._pos , vtxs());
  9. if(vtx._nrm )ReallocZero1(vtx._nrm , vtxs());
  10. if(vtx._tan )ReallocZero1(vtx._tan , vtxs());
  11. if(vtx._bin )ReallocZero1(vtx._bin , vtxs());
  12. if(vtx._hlp )ReallocZero1(vtx._hlp , vtxs());
  13. if(vtx._tex0 )ReallocZero1(vtx._tex0 , vtxs());
  14. if(vtx._tex1 )ReallocZero1(vtx._tex1 , vtxs());
  15. if(vtx._tex2 )ReallocZero1(vtx._tex2 , vtxs());
  16. if(vtx._matrix )ReallocZero1(vtx._matrix , vtxs());
  17. if(vtx._blend )ReallocZero1(vtx._blend , vtxs());
  18. if(vtx._size )ReallocZero1(vtx._size , vtxs());
  19. if(vtx._material)ReallocZero1(vtx._material, vtxs());
  20. if(vtx._color )ReallocZero1(vtx._color , vtxs());
  21. if(vtx._flag )ReallocZero1(vtx._flag , vtxs());
  22. Int t=vtxs(); vtx._elms++; vtx.pos(t)=pos;
  23. return T;
  24. }
  25. MeshBase& MeshBase::addEdge(C VecI2 &ind)
  26. {
  27. exclude(ADJ_ALL);
  28. Realloc1 (edge._ind , edges());
  29. if(edge._nrm )ReallocZero1(edge._nrm , edges());
  30. if(edge._flag)ReallocZero1(edge._flag, edges());
  31. if(edge._id )ReallocZero1(edge._id , edges());
  32. Int t=edges(); edge._elms++;
  33. edge.ind (t)=ind;
  34. if(edge.flag())edge.flag(t)=ETQ_R;
  35. return T;
  36. }
  37. MeshBase& MeshBase::addTri(C VecI &ind)
  38. {
  39. exclude(ADJ_ALL);
  40. Realloc1 (tri._ind , tris());
  41. if(tri._nrm )ReallocZero1(tri._nrm , tris());
  42. if(tri._flag)ReallocZero1(tri._flag, tris());
  43. if(tri._id )ReallocZero1(tri._id , tris());
  44. Int t=tris(); tri._elms++; tri.ind(t)=ind;
  45. return T;
  46. }
  47. MeshBase& MeshBase::addQuad(C VecI4 &ind)
  48. {
  49. exclude(ADJ_ALL);
  50. Realloc1 (quad._ind , quads());
  51. if(quad._nrm )ReallocZero1(quad._nrm , quads());
  52. if(quad._flag)ReallocZero1(quad._flag, quads());
  53. if(quad._id )ReallocZero1(quad._id , quads());
  54. Int t=quads(); quad._elms++; quad.ind(t)=ind;
  55. return T;
  56. }
  57. MeshBase& MeshBase::add(C MeshBase &src, UInt flag_and)
  58. {
  59. if(!src.is())return T;
  60. C MeshBase *meshes[]={this, &src};
  61. return create(meshes, Elms(meshes), flag_and);
  62. }
  63. MeshBase& MeshBase::add(C MeshRender &src, UInt flag_and) {MeshBase mb(src, flag_and); return add(mb);}
  64. MeshBase& MeshBase::add(C MeshPart &src, UInt flag_and) {MeshBase mb(src, flag_and); return add(mb);}
  65. /******************************************************************************
  66. MeshBase& addEdge(C Vec2 &pos, Int edge ); // add edge by splitting 'edge' edge into two edges at 'pos' position
  67. MeshBase& MeshBase::addEdge(C Vec2 &pos, Int e)
  68. {
  69. exclude((VTX_ALL|ADJ_ALL|EDGE_ALL)^(VTX_POS|EDGE_IND|EDGE_ID|EDGE_FLAG));
  70. Clamp(e, -1, edges()-1);
  71. ReallocZero1(vtx ._pos , vtxs ());
  72. ReallocZero1(edge._ind , edges());
  73. ReallocZero1(edge._flag, edges());
  74. if(edge._id)ReallocZero1(edge._id , edges());
  75. Int vtx_last=vtxs (); vtx ._elms++;
  76. Int edge_last=edges(); edge._elms++;
  77. vtx.pos(vtx_last).set(pos, 0);
  78. if(e==-1)
  79. {
  80. edge.flag(edge_last)=ETQ_R;
  81. edge.ind (edge_last).set(vtx_last);
  82. }else
  83. {
  84. Bool sd= ((edge.flag(e)&ETQ_LR)!=ETQ_L);
  85. VecI2 &ind= edge.ind (e);
  86. vtx .pos ( vtx_last).z=Avg(vtx.pos(ind.x).z, vtx.pos(ind.y).z);
  87. edge.ind (edge_last).set(vtx_last, ind.c[sd]); ind.c[sd]=vtx_last;
  88. edge.flag(edge_last)=edge.flag(e); if(!sd)edge.flag(edge_last)=EtqFlagSwap(edge.flag(edge_last));
  89. if(edge.id()){edge.id (edge_last)=edge.id (e); if(!sd)edge.id (edge_last).reverse();}
  90. }
  91. return T;
  92. }
  93. MeshBase& subVtx (Int vtx ); // subtract vertex and try to re-connect 2D edges
  94. MeshBase& MeshBase::subVtx(Int v)
  95. {
  96. if(InRange(v, vtx))
  97. {
  98. Int edge_ind[2], edge_num=0;
  99. REPA(edge)
  100. {
  101. if(edge.ind(i).c[0]==v
  102. || edge.ind(i).c[1]==v)if(edge_num<2)edge_ind[edge_num++]=i;
  103. }
  104. if(edge_num==2)
  105. {
  106. VecI2 id0, id1;
  107. Vec nrm;
  108. UInt flag;
  109. Int i0, i1, e;
  110. Int *p;
  111. e=edge_ind[0]; p=edge.ind(e).c;
  112. if(p[1]==v){i0=p[0]; if(edge.nrm())nrm = edge.nrm(e); if(edge.flag())flag = edge.flag(e) ; if(edge.id()) id0=edge.id(e);}
  113. if(p[0]==v){i0=p[1]; if(edge.nrm())nrm =-edge.nrm(e); if(edge.flag())flag =EtqFlagSwap(edge.flag(e)); if(edge.id()){id0=edge.id(e); id0.reverse();}}
  114. e=edge_ind[1]; p=edge.ind(e).c;
  115. if(p[0]==v){i1=p[1]; if(edge.nrm())nrm+= edge.nrm(e); if(edge.flag())flag|= edge.flag(e) ; if(edge.id()) id1=edge.id(e);}
  116. if(p[1]==v){i1=p[0]; if(edge.nrm())nrm-= edge.nrm(e); if(edge.flag())flag|=EtqFlagSwap(edge.flag(e)); if(edge.id()){id1=edge.id(e); id1.reverse();}}
  117. REPA(edge)
  118. {
  119. if((edge.ind(i).x==i0 && edge.ind(i).y==i1)
  120. || (edge.ind(i).x==i1 && edge.ind(i).y==i0))goto is;
  121. }
  122. addEdge(VecI2(i0,i1));
  123. if(edge.nrm ())edge.nrm (edges()-1)=!nrm;
  124. if(edge.flag())edge.flag(edges()-1)=flag;
  125. if(edge.id ())edge.id (edges()-1)=Max(id0, id1);
  126. is:;
  127. }
  128. removeVtx(v);
  129. }
  130. return T;
  131. }
  132. /******************************************************************************/
  133. MeshBase& MeshBase::removeVtx (Int v) {if(InRange(v, vtx )){Memt<Bool> is; is.setNum(vtxs ()); FREPA(vtx )is[i]=(i!=v); keepVtxs (is);} return T;}
  134. MeshBase& MeshBase::removeEdge(Int e) {if(InRange(e, edge)){Memt<Bool> is; is.setNum(edges()); FREPA(edge)is[i]=(i!=e); keepEdges(is);} return T;}
  135. MeshBase& MeshBase::removeTri (Int t) {if(InRange(t, tri )){Memt<Bool> is; is.setNum(tris ()); FREPA(tri )is[i]=(i!=t); keepTris (is);} return T;}
  136. MeshBase& MeshBase::removeQuad(Int q) {if(InRange(q, quad)){Memt<Bool> is; is.setNum(quads()); FREPA(quad)is[i]=(i!=q); keepQuads(is);} return T;}
  137. MeshBase& MeshBase::removeFace(Int f)
  138. {
  139. if(f&SIGN_BIT)removeQuad(f^SIGN_BIT);
  140. else removeTri (f );
  141. return T;
  142. }
  143. /******************************************************************************/
  144. MeshBase& MeshBase::keepVtxs(C MemPtr<Bool> &is)
  145. {
  146. exclude(VTX_DUP|ADJ_ALL);
  147. Int *p;
  148. Memt<Bool> face_is;
  149. Memt<Int > vtx_remap; SetRemap(vtx_remap, is, vtxs());
  150. // vtx
  151. MeshBase temp(CountIs(is), 0, 0, 0, flag());
  152. temp.copyVtxs(T, is);
  153. // edge
  154. face_is.setNum(edges()); FREPA(edge){p=edge.ind(i).c; face_is[i]=(ElmIs(is, p[0]) && ElmIs(is, p[1]));}
  155. temp.edge._elms=CountIs(face_is); temp.include(flag()&EDGE_ALL);
  156. temp.copyEdges(T, face_is);
  157. IndRemap(vtx_remap, temp.edge.ind(), temp.edges());
  158. // tri
  159. face_is.setNum(tris()); FREPA(tri){p=tri.ind(i).c; face_is[i]=(ElmIs(is, p[0]) && ElmIs(is, p[1]) && ElmIs(is, p[2]));}
  160. temp.tri._elms=CountIs(face_is); temp.include(flag()&TRI_ALL);
  161. temp.copyTris(T, face_is);
  162. IndRemap(vtx_remap, temp.tri.ind(), temp.tris());
  163. // quad
  164. face_is.setNum(quads()); FREPA(quad){p=quad.ind(i).c; face_is[i]=(ElmIs(is, p[0]) && ElmIs(is, p[1]) && ElmIs(is, p[2]) && ElmIs(is, p[3]));}
  165. temp.quad._elms=CountIs(face_is); temp.include(flag()&QUAD_ALL);
  166. temp.copyQuads(T, face_is);
  167. IndRemap(vtx_remap, temp.quad.ind(), temp.quads());
  168. // end
  169. Swap(T, temp); return T;
  170. }
  171. MeshBase& MeshBase::keepEdges(C MemPtr<Bool> &is)
  172. {
  173. Int edges =CountIs(is);
  174. if( edges!=T.edges())
  175. {
  176. exclude(ADJ_ALL); MeshBase temp(0, edges, 0, 0, flag()); temp.copyEdges(T, is);
  177. Swap(edge, temp.edge);
  178. }
  179. return T;
  180. }
  181. MeshBase& MeshBase::keepTris(C MemPtr<Bool> &is)
  182. {
  183. Int tris =CountIs(is);
  184. if( tris!=T.tris())
  185. {
  186. exclude(ADJ_ALL); MeshBase temp(0, 0, tris, 0, flag()); temp.copyTris(T, is);
  187. Swap(tri, temp.tri);
  188. }
  189. return T;
  190. }
  191. MeshBase& MeshBase::keepQuads(C MemPtr<Bool> &is)
  192. {
  193. Int quads =CountIs(is);
  194. if( quads!=T.quads())
  195. {
  196. exclude(ADJ_ALL); MeshBase temp(0, 0, 0, quads, flag()); temp.copyQuads(T, is);
  197. Swap(quad, temp.quad);
  198. }
  199. return T;
  200. }
  201. MeshBase& MeshBase::removeVtxs(C MemPtr<Int> &vtxs)
  202. {
  203. if(vtxs.elms()){Memt<Bool> nis; CreateIsNot(nis, vtxs, T.vtxs()); keepVtxs(nis);}
  204. return T;
  205. }
  206. MeshBase& MeshBase::removeEdges(C MemPtr<Int> &edges, Bool remove_unused_vtxs)
  207. {
  208. if(edges.elms()){Memt<Bool> nis; CreateIsNot(nis, edges, T.edges()); keepEdges(nis); if(remove_unused_vtxs)removeUnusedVtxs();}
  209. return T;
  210. }
  211. MeshBase& MeshBase::removeTris(C MemPtr<Int> &tris, Bool remove_unused_vtxs)
  212. {
  213. if(tris.elms()){Memt<Bool> nis; CreateIsNot(nis, tris, T.tris()); keepTris(nis); if(remove_unused_vtxs)removeUnusedVtxs();}
  214. return T;
  215. }
  216. MeshBase& MeshBase::removeQuads(C MemPtr<Int> &quads, Bool remove_unused_vtxs)
  217. {
  218. if(quads.elms()){Memt<Bool> nis; CreateIsNot(nis, quads, T.quads()); keepQuads(nis); if(remove_unused_vtxs)removeUnusedVtxs();}
  219. return T;
  220. }
  221. MeshBase& MeshBase::removeFaces(C MemPtr<Int> &faces, Bool remove_unused_vtxs)
  222. {
  223. if(faces.elms())
  224. {
  225. Memt<Bool> tri_is, quad_is; CreateFaceIsNot(tri_is, quad_is, faces, tris(), quads());
  226. keepTris ( tri_is);
  227. keepQuads(quad_is);
  228. if(remove_unused_vtxs)removeUnusedVtxs();
  229. }
  230. return T;
  231. }
  232. /******************************************************************************/
  233. static Int SameVtxs(C Int *a, Int a_elms, C Int *b, Int b_elms)
  234. {
  235. Int same=0; REP(a_elms)
  236. {
  237. Int x=a[i];
  238. REP(b_elms)if(b[i]==x){same++; break;}
  239. }
  240. return same;
  241. }
  242. static Bool Continuous(C Int *a, Int a_elms, C Int *b, Int b_elms)
  243. {
  244. REP(a_elms)
  245. {
  246. Int x=a[i], y=a[(i+1)%a_elms];
  247. REP(b_elms)
  248. {
  249. if(y==b[i] && x==b[(i+1)%b_elms])return true; // we need to check reversed order, because they are continuous if one face has the same vtxs but in reversed order
  250. }
  251. }
  252. return false;
  253. }
  254. enum RDSF
  255. {
  256. RDSF_REMOVE =1<<0, // this face is marked to be removed
  257. RDSF_LIST =1<<1, // this face is already listed in the queue
  258. RDSF_CHECKED=1<<2, // this face is already processed
  259. };
  260. MeshBase& MeshBase::removeDoubleSideFaces(Bool remove_unused_vtxs)
  261. {
  262. Memt<Byte> face_flag; face_flag.setNumZero(faces());
  263. {
  264. Index face_face; linkFaceFace(face_face);
  265. Memt<Int> face_list;
  266. REP(faces()) // iterate all faces
  267. {
  268. Int f=i;
  269. check:
  270. Byte &ff=face_flag[f];
  271. if( !(ff&(RDSF_REMOVE|RDSF_CHECKED))) // if this face was not yet removed or checked
  272. {
  273. ff|=RDSF_CHECKED; // mark as checked
  274. VecI4 face_vtx; Int face_vtxs;
  275. if(InRange(f, tri))
  276. {
  277. VecI &tri_vtx=face_vtx.xyz; tri_vtx=tri.ind(f); tri_vtx.remap(vtx.dup()); face_vtxs=3;
  278. }else
  279. {
  280. Int quad_index=f-tris(); face_vtx=quad.ind(quad_index); face_vtx.remap(vtx.dup()); face_vtxs=4;
  281. }
  282. C IndexGroup &ig=face_face.group[f]; REPA(ig) // iterate all faces connected to this face
  283. {
  284. VecI4 test_face_vtx; Int test_face_vtxs;
  285. UInt test_face=ig[i], test_face2;
  286. if( test_face&SIGN_BIT) // quad
  287. {
  288. test_face^=SIGN_BIT; test_face2=tris()+test_face; test_face_vtx=quad.ind(test_face); test_face_vtx.remap(vtx.dup()); test_face_vtxs=4;
  289. }else
  290. {
  291. test_face2=test_face; VecI &tri_vtx=test_face_vtx.xyz; tri_vtx=tri.ind(test_face); tri_vtx.remap(vtx.dup()); test_face_vtxs=3;
  292. }
  293. Byte &test_ff=face_flag[test_face2];
  294. if( !(test_ff&(RDSF_REMOVE|RDSF_CHECKED))) // if this face was not yet removed or checked
  295. {
  296. if(SameVtxs(face_vtx.c, face_vtxs, test_face_vtx.c, test_face_vtxs)>=3) // if this is an overlapping face
  297. {
  298. test_ff|=RDSF_REMOVE; // remove overlapping face
  299. }else
  300. if(!(test_ff&RDSF_LIST) // not yet listed
  301. && Continuous(face_vtx.c, face_vtxs, test_face_vtx.c, test_face_vtxs))
  302. {
  303. face_list.add(test_face2); test_ff|=RDSF_LIST; // mark as already listed
  304. }
  305. }
  306. }
  307. if(face_list.elms()){f=face_list.pop(); goto check;} // process listed elements first
  308. }
  309. }
  310. }
  311. {
  312. Memt<Bool> is; is.reserve(Max(tris(), quads()));
  313. Byte *quad_flag=face_flag.data()+tris(); is.setNum(quads()); REPAO(is)=!(quad_flag[i]&RDSF_REMOVE); keepQuads(is); // !! delete quads first, because removing tris below changes the number of tris, which is needed to get 'quad_flag' !!
  314. Byte * tri_flag=face_flag.data() ; is.setNum( tris()); REPAO(is)=!( tri_flag[i]&RDSF_REMOVE); keepTris (is); // !! delete tris next !!
  315. }
  316. if(remove_unused_vtxs)removeUnusedVtxs();
  317. return T;
  318. }
  319. /******************************************************************************/
  320. MeshBase& MeshBase::mergeFaces(Int a, Int b)
  321. {
  322. if(a!=b)
  323. {
  324. Bool a_quad=FlagTest(a, SIGN_BIT), a_in_range; Int ai=a; if(a_quad){ai^=SIGN_BIT; a_in_range=InRange(ai, quad);}else a_in_range=InRange(ai, tri);
  325. if(a_in_range)
  326. {
  327. Bool b_quad=FlagTest(b, SIGN_BIT), b_in_range; Int bi=b; if(b_quad){bi^=SIGN_BIT; b_in_range=InRange(bi, quad);}else b_in_range=InRange(bi, tri);
  328. if(b_in_range)
  329. {
  330. VecI4 a_ind , b_ind;
  331. Int a_inds, b_inds;
  332. if(a_quad){a_ind=quad.ind(ai); a_inds=4;}else{a_ind.xyz=tri.ind(ai); a_inds=3;}
  333. if(b_quad){b_ind=quad.ind(bi); b_inds=4;}else{b_ind.xyz=tri.ind(bi); b_inds=3;}
  334. REPD(a_ofs, a_inds)
  335. {
  336. Int ai=a_ind.c[a_ofs];
  337. REPD(b_ofs, b_inds)if(b_ind.c[b_ofs]==ai)
  338. {
  339. Int a_next=a_ind.c[(a_ofs+1 )%a_inds];
  340. Int b_prev=b_ind.c[(b_ofs-1+b_inds)%b_inds];
  341. if(a_next==b_prev)
  342. {
  343. // first remove faces
  344. Int faces[]={a, b}; removeFaces(faces, false);
  345. // add new faces
  346. if(!a_quad && !b_quad) // 2 triangles
  347. {
  348. VecI4 q(a_ind.c[(a_ofs+2)%a_inds], ai, b_ind.c[(b_ofs+1)%b_inds], a_next);
  349. if(vtx.pos())REP(4) // check if any of the points is inline
  350. {
  351. C Vec &p0=vtx.pos(q.c[i]), &p1=vtx.pos(q.c[(i+1)%4]), &p2=vtx.pos(q.c[(i+2)%4]);
  352. if(DistPointStr(p1, p0, !(p2-p0))<=EPS)
  353. {
  354. addTri(VecI(q.c[i], q.c[(i+2)%4], q.c[(i+3)%4]));
  355. goto added;
  356. }
  357. }
  358. addQuad(q);
  359. added:;
  360. }else
  361. if(a_quad && b_quad)addQuad(VecI4(a_ind.c[(a_ofs+2)%a_inds], a_ind.c[(a_ofs+3)%a_inds], b_ind.c[(b_ofs+1)%b_inds], b_ind.c[(b_ofs+2)%b_inds]));else // 2 quads
  362. { // one triangle and one quad
  363. if(b_quad) // put quad to 'a'
  364. {
  365. Swap(a_ofs , b_ofs );
  366. Swap(a_ind , b_ind );
  367. Swap(a_inds, b_inds);
  368. a_ofs=(a_ofs-1+a_inds)%a_inds;
  369. b_ofs=(b_ofs+1 )%b_inds;
  370. }
  371. Int b=b_ind.c[(b_ofs+1)%b_inds]; // set 'b' triangle outer vtx
  372. VecI4 face(a_ind.c[(a_ofs+2)%a_inds], a_ind.c[(a_ofs+3)%a_inds], // 'a' quad outer vtxs
  373. a_ind.c[ a_ofs ], a_ind.c[(a_ofs+1)%a_inds]); // 'a' quad inner vtxs
  374. if(vtx.pos()) // there are 3 possible quads (original, or with one corner replaced with point from the triangle), pick one with the biggest area
  375. {
  376. VecI4 f1=face; f1.w=b;
  377. VecI4 f2=face; f2.z=b;
  378. Flt area=(GetNormalU(vtx.pos(face.x), vtx.pos(face.y), vtx.pos(face.w))+GetNormalU(vtx.pos(face.z), vtx.pos(face.w), vtx.pos(face.y))).length2(),
  379. a1 =(GetNormalU(vtx.pos(f1 .x), vtx.pos(f1 .y), vtx.pos(f1 .w))+GetNormalU(vtx.pos(f1 .z), vtx.pos(f1 .w), vtx.pos(f1 .y))).length2(),
  380. a2 =(GetNormalU(vtx.pos(f2 .x), vtx.pos(f2 .y), vtx.pos(f2 .w))+GetNormalU(vtx.pos(f2 .z), vtx.pos(f2 .w), vtx.pos(f2 .y))).length2();
  381. if(a1>area){face=f1; area=a1;}
  382. if(a2>area){face=f2; area=a2;}
  383. }
  384. addQuad(face);
  385. }
  386. // remove unused vtxs
  387. removeUnusedVtxs();
  388. return T;
  389. }
  390. }
  391. }
  392. }
  393. }
  394. }
  395. return T;
  396. }
  397. /******************************************************************************/
  398. // OPTIMIZE
  399. /******************************************************************************/
  400. Bool MeshBase::removeUnusedVtxs(Bool include_edge_references)
  401. {
  402. C Int *p;
  403. Memt<Bool> is; is.setNumZero(vtxs());
  404. if(include_edge_references)REPA(edge){p=edge.ind(i).c; REPD(j, 2)is[p[j]]=true;}
  405. REPA(tri ){p=tri .ind(i).c; REPD(j, 3)is[p[j]]=true;}
  406. REPA(quad){p=quad.ind(i).c; REPD(j, 4)is[p[j]]=true;}
  407. Int vtxs =CountIs(is);
  408. if( vtxs!=T.vtxs())
  409. {
  410. if(!include_edge_references)exclude(EDGE_ALL);
  411. MeshBase temp(vtxs, 0, 0, 0, flag()&(~VTX_DUP)); temp.copyVtxs(T, is);
  412. Memt<Int> remap;
  413. SetRemap(remap, is , T.vtxs ());
  414. IndRemap(remap, edge.ind(), T.edges());
  415. IndRemap(remap, tri .ind(), T.tris ());
  416. IndRemap(remap, quad.ind(), T.quads());
  417. Swap(vtx, temp.vtx);
  418. return true;
  419. }
  420. return false;
  421. }
  422. /******************************************************************************/
  423. MeshBase& MeshBase::removeDoubleEdges()
  424. {
  425. if(edge.flag())
  426. {
  427. Memt<Bool> is; is.setNum(edges()); REPAO(is)=((edge.flag(i)&ETQ_LR)!=ETQ_LR);
  428. keepEdges (is );
  429. removeUnusedVtxs(true);
  430. }
  431. return T;
  432. }
  433. /******************************************************************************/
  434. struct TriFromQuad
  435. {
  436. Int quad_index;
  437. VecI vtx_index;
  438. void from(Int quad_index, Int p0, Int p1, Int p2)
  439. {
  440. T.quad_index=quad_index;
  441. vtx_index.set(p0, p1, p2);
  442. }
  443. };
  444. MeshBase& MeshBase::removeDegenerateFaces(Flt eps)
  445. {
  446. Memt<Bool> tri_is, quad_is;
  447. tri_is.setNum(tris ());
  448. quad_is.setNum(quads());
  449. // triangles
  450. REPA(tri)if(tri_is[i]=tri.ind(i).allDifferent())
  451. {
  452. C Int *p=tri.ind(i).c;
  453. if(!Tri(vtx.pos(p[0]), vtx.pos(p[1]), vtx.pos(p[2])).valid(eps))tri_is[i]=false;
  454. }
  455. // quads
  456. Memc<TriFromQuad> tri_from_quad;
  457. REPA(quad)
  458. {
  459. C Int *p=quad.ind(i).c;
  460. if(Quad(vtx.pos(p[0]), vtx.pos(p[1]), vtx.pos(p[2]), vtx.pos(p[3])).valid(eps))
  461. {
  462. quad_is[i]=true;
  463. }else
  464. {
  465. quad_is[i]=false;
  466. Int p0=p[0], p1=p[1], p2=p[2], p3=p[3];
  467. C Vec &vp0=vtx.pos(p0), &vp1=vtx.pos(p1), &vp2=vtx.pos(p2), &vp3=vtx.pos(p3);
  468. if(Tri(vp0, vp1, vp3).valid(eps)){tri_from_quad.New().from(i, p0, p1, p3); if(Tri(vp1, vp2, vp3).valid(eps))tri_from_quad.New().from(i, p1, p2, p3);}else // second tri can also be valid, this can happen for <--| case when 2 tris are valid but quad is not
  469. if(Tri(vp0, vp1, vp2).valid(eps)){tri_from_quad.New().from(i, p0, p1, p2); if(Tri(vp2, vp3, vp0).valid(eps))tri_from_quad.New().from(i, p2, p3, p0);}else // \ |
  470. if(Tri(vp1, vp2, vp3).valid(eps)) tri_from_quad.New().from(i, p1, p2, p3);else // no need to check for 013 because it was checked at start \|
  471. if(Tri(vp2, vp3, vp0).valid(eps)) tri_from_quad.New().from(i, p2, p3, p0); // no need to check for 012 because it was checked at start
  472. }
  473. }
  474. Int src_tris =CountIs( tri_is),
  475. src_quads=CountIs(quad_is);
  476. if( src_tris!=tris() || src_quads!=quads())
  477. {
  478. exclude(ADJ_ALL);
  479. // set flag
  480. UInt flag=T.flag();
  481. if(tri_from_quad.elms())
  482. {
  483. if(quad.flag())flag|=TRI_FLAG;
  484. if(quad.id ())flag|=TRI_ID ;
  485. if(quad.nrm ())flag|=TRI_NRM ;
  486. }
  487. // create temp mesh
  488. MeshBase temp(0, 0, src_tris+tri_from_quad.elms(), src_quads, flag);
  489. // copy original data
  490. temp.copyTris (T, tri_is);
  491. temp.copyQuads(T, quad_is);
  492. // set missing data
  493. if(temp.tri.flag() && !tri.flag())ZeroN(temp.tri.flag(), src_tris);
  494. if(temp.tri.id () && !tri.id ())ZeroN(temp.tri.id (), src_tris);
  495. if(temp.tri.nrm () && !tri.nrm ())REP(src_tris)
  496. {
  497. C VecI &ind=temp.tri.ind(i);
  498. temp.tri.nrm(i)=GetNormal(vtx.pos(ind.x), vtx.pos(ind.y), vtx.pos(ind.z));
  499. }
  500. // copy additional triangles from quads
  501. REPA(tri_from_quad)
  502. {
  503. C TriFromQuad &tfq=tri_from_quad[i];
  504. temp.tri.ind (src_tris+i)=tfq.vtx_index;
  505. if(temp.tri.flag())temp.tri.flag(src_tris+i)=(quad.flag() ? quad.flag(tfq.quad_index) : 0);
  506. if(temp.tri.id ())temp.tri.id (src_tris+i)=(quad.id () ? quad.id (tfq.quad_index) : 0);
  507. if(temp.tri.nrm ())temp.tri.nrm (src_tris+i)=(quad.nrm () ? quad.nrm (tfq.quad_index) : GetNormal(vtx.pos(tfq.vtx_index.x), vtx.pos(tfq.vtx_index.y), vtx.pos(tfq.vtx_index.z)));
  508. }
  509. // swap new data with old one
  510. Swap(temp.tri , tri );
  511. Swap(temp.quad, quad);
  512. }
  513. return T;
  514. }
  515. /******************************************************************************/
  516. MeshBase& MeshBase::removeSingleFaces(Flt fraction)
  517. {
  518. setAdjacencies(true, false);
  519. Flt f=0.25f;
  520. Memt<Bool> tri_is; tri_is.setNum( tris()); REPA(tri ){C VecI &a=tri .adjFace(i); if(a.x!=-1 || a.y!=-1 || a.z!=-1 ) tri_is[i]=true;else{f+=fraction; if( tri_is[i]=(f>=1))f--;}} // compare to -1 and not >=0 because it can have SIGN_BIT
  521. Memt<Bool> quad_is; quad_is.setNum(quads()); REPA(quad){C VecI4 &a=quad.adjFace(i); if(a.x!=-1 || a.y!=-1 || a.z!=-1 || a.w!=-1)quad_is[i]=true;else{f+=fraction; if(quad_is[i]=(f>=1))f--;}} // compare to -1 and not >=0 because it can have SIGN_BIT
  522. keepTris ( tri_is);
  523. keepQuads(quad_is);
  524. return T;
  525. }
  526. /******************************************************************************/
  527. struct VtxEdgeLink
  528. {
  529. Int edges;
  530. Int vtx[2], edge[2];
  531. };
  532. MeshBase& MeshBase::weldInlineEdges(Flt cos_edge, Flt cos_vtx, Bool z_test)
  533. {
  534. CHS(cos_edge);
  535. Int *p;
  536. Memt<Bool> edge_is; edge_is.setNum (edges());
  537. Memt<VtxEdgeLink> vi; vi .setNumZero(vtxs ());
  538. // link vtx->vtx, edge
  539. FREPA(edge)
  540. {
  541. edge_is[i]=true;
  542. p=edge.ind(i).c;
  543. FREPD(j, 2)
  544. {
  545. VtxEdgeLink &v=vi[p[j]];
  546. if(v.edges<2)
  547. {
  548. v.vtx [v.edges]=p[!j];
  549. v.edge[v.edges]=i;
  550. }
  551. v.edges++;
  552. }
  553. }
  554. // edge is
  555. FREPA(vtx)if(vi[i].edges==2)
  556. if(CosBetween(vtx.pos(vi[i].vtx[0]).xy, vtx.pos(i).xy,
  557. vtx.pos(vi[i].vtx[1]).xy)<=cos_edge)
  558. {
  559. if(cos_vtx>-1 && vtx.nrm() && Dot(vtx.nrm(vi[i].vtx[0]).xy, vtx.nrm(vi[i].vtx[1]).xy)<cos_vtx)continue;
  560. if(z_test)
  561. {
  562. Flt s= LerpR(vtx.pos(vi[i].vtx[0]).xy, vtx.pos(vi[i].vtx[1]).xy, vtx.pos(i).xy);
  563. if(!Equal(Lerp (vtx.pos(vi[i].vtx[0]).z , vtx.pos(vi[i].vtx[1]).z, s), vtx.pos(i).z))continue;
  564. }
  565. VtxEdgeLink &v=vi[i];
  566. Int l_vtx =v.vtx [0],
  567. r_vtx =v.vtx [1],
  568. l_edge=v.edge[0],
  569. r_edge=v.edge[1];
  570. edge_is[r_edge]=false;
  571. p=edge.ind(l_edge).c ; p[(p[0]!=i )]=r_vtx;
  572. p= vi[l_vtx ].vtx ; p[(p[0]!=i )]=r_vtx;
  573. p= vi[r_vtx ].vtx ; p[(p[0]!=i )]=l_vtx;
  574. p= vi[r_vtx ].edge; p[(p[0]!=r_edge)]=l_edge;
  575. }
  576. // create mesh
  577. Int edges=CountIs(edge_is); if(edges!=T.edges())
  578. {
  579. exclude(VTX_DUP|FACE_ALL|ADJ_ALL);
  580. MeshBase temp(0, edges, 0, 0, flag()); temp.copyEdges(T, edge_is);
  581. Swap(edge, temp.edge);
  582. removeUnusedVtxs();
  583. }
  584. return T;
  585. }
  586. /******************************************************************************/
  587. static Bool VertexValueTest(MeshBase &mshb, Int mid, Int pa, Int pb) // return true if shouldn't be welded
  588. {
  589. Flt length=Dist(mshb.vtx.pos(pa), mshb.vtx.pos(pb));
  590. if( length>EPS)
  591. {
  592. Flt step=Dist(mshb.vtx.pos(mid), mshb.vtx.pos(pa))/length;
  593. if( mshb.vtx.material())
  594. {
  595. VecB4 m =Lerp(mshb.vtx.material(pa ), mshb.vtx.material(pb), step),
  596. mm= mshb.vtx.material(mid);
  597. const Int mtrl_eps=5;
  598. if(Abs(m.x-mm.x)>mtrl_eps
  599. || Abs(m.y-mm.y)>mtrl_eps
  600. || Abs(m.z-mm.z)>mtrl_eps
  601. || Abs(m.w-mm.w)>mtrl_eps)return true;
  602. }
  603. if(mshb.vtx.color())
  604. {
  605. Color c =Lerp(mshb.vtx.color(pa ), mshb.vtx.color(pb), step),
  606. cm= mshb.vtx.color(mid);
  607. const Int col_eps=3;
  608. if(Abs(c.a-cm.a)>col_eps
  609. || Abs(c.r-cm.r)>col_eps
  610. || Abs(c.g-cm.g)>col_eps
  611. || Abs(c.b-cm.b)>col_eps)return true;
  612. }
  613. const Flt tex_eps2=Sqr(0.01f);
  614. if(mshb.vtx.tex0() && Dist2(Lerp(mshb.vtx.tex0(pa), mshb.vtx.tex0(pb), step), mshb.vtx.tex0(mid))>tex_eps2)return true;
  615. if(mshb.vtx.tex1() && Dist2(Lerp(mshb.vtx.tex1(pa), mshb.vtx.tex1(pb), step), mshb.vtx.tex1(mid))>tex_eps2)return true;
  616. if(mshb.vtx.tex2() && Dist2(Lerp(mshb.vtx.tex2(pa), mshb.vtx.tex2(pb), step), mshb.vtx.tex2(mid))>tex_eps2)return true;
  617. }
  618. return false;
  619. }
  620. MeshBase& MeshBase::weldCoplanarFaces(Flt cos_face, Flt cos_vtx, Bool safe, Flt max_face_length)
  621. {
  622. setAdjacencies(true, false);
  623. setFaceNormals();
  624. exclude (EDGE_ADJ_FACE|FACE_ADJ_EDGE);
  625. Bool vtx_value_test=(vtx.tex0() || vtx.tex1() || vtx.tex2() || vtx.material() || vtx.color()),
  626. face_length_test=(max_face_length>=0); max_face_length*=max_face_length; // it's now squared
  627. C Vec *pos=vtx.pos();
  628. Memt<Bool> tri_is; tri_is.setNum(tris ()); SetMemN( tri_is.data(), 1, tri_is.elms());
  629. Memt<Bool> quad_is; quad_is.setNum(quads()); SetMemN(quad_is.data(), 1, quad_is.elms());
  630. // Find these triangles : "/|\"
  631. for(Int i=0; i<tris(); )if(!tri_is[i])i++;else // for each tri
  632. {
  633. Bool found=false;
  634. C Vec &nrm =tri.nrm (i);
  635. Int *af =tri.adjFace(i).c;
  636. REPD(vi, 3) // for each tris adjacent tri
  637. {
  638. Int face =af[vi];
  639. if( face!=-1 && !(face&SIGN_BIT)) // compare to -1 and not >=0 because it can have SIGN_BIT
  640. {
  641. // co-planar test
  642. if(Dot(tri.nrm(face), nrm)<cos_face)continue;
  643. // same vertex test
  644. Int *af2=tri.adjFace(face).c,
  645. *p =tri.ind (i ).c,
  646. *p2 =tri.ind (face).c;
  647. Int vi2; for(vi2=3; --vi2>=0; )if(af2[vi2]==i)break; if(vi2<0)continue;
  648. if(p[vi]!=p2[(vi2+1)%3] || p[(vi+1)%3]!=p2[vi2])continue;
  649. // vertex normal test
  650. if(cos_vtx>-1 && vtx.nrm() && Dot(vtx.nrm(p[(vi+2)%3]), vtx.nrm(p2[(vi2+2)%3]))<cos_vtx)continue;
  651. // safety test (faces without other neighbors)
  652. if(safe)if(af[(vi+1)%3]!=-1 || af2[(vi2+2)%3]!=-1)continue; // compare to -1 and not >=0 because it can have SIGN_BIT
  653. // edges inline test
  654. if(DistPointEdge(pos[p[(vi+1)%3]], pos[p[(vi+2)%3]], pos[p2[(vi2+2)%3]])>EPS)continue;
  655. // face length test
  656. if(face_length_test)
  657. if(Dist2(pos[p[ vi ]], pos[p2[(vi2+2)%3]])>max_face_length
  658. || Dist2(pos[p[(vi+2)%3]], pos[p2[(vi2+2)%3]])>max_face_length)continue;
  659. // vertex values test
  660. if(vtx_value_test)if(VertexValueTest(T, p[(vi+1)%3], p[(vi+2)%3], p2[(vi2+2)%3]))continue;
  661. // remap points & adj
  662. p[(vi+1)%3]= p2[(vi2+2)%3];
  663. af[ vi ]=af2[(vi2+1)%3];
  664. // fix adjacency
  665. REPD(a, 3)if(af2[a]!=-1) // compare to -1 and not >=0 because it can have SIGN_BIT
  666. {
  667. Int face3=af2[a];
  668. if( face3&SIGN_BIT){REPD(j, 4)if(quad.adjFace(face3^SIGN_BIT).c[j]==face)quad.adjFace(face3^SIGN_BIT).c[j]=i;}
  669. else {REPD(j, 3)if(tri .adjFace(face3 ).c[j]==face)tri .adjFace(face3 ).c[j]=i;}
  670. }
  671. // remove face
  672. tri_is[face]=0;
  673. found=true;
  674. break;
  675. }
  676. }
  677. if(!found)i++;
  678. }
  679. // quads
  680. for(Int i=0; i<quads(); )if(!quad_is[i])i++;else // for each quad
  681. {
  682. C Vec &nrm =quad.nrm(i);
  683. Bool found=false;
  684. Int *af =quad.adjFace(i).c;
  685. REPD(vi, 4) // for each quads adjacent face
  686. {
  687. Int face =af[vi];
  688. if( face!=-1) // compare to -1 and not >=0 because it can have SIGN_BIT
  689. {
  690. // co-planar test
  691. Int vtxs;
  692. if(face&SIGN_BIT){if(Dot(quad.nrm(face^SIGN_BIT), nrm)<cos_face)continue; vtxs=4;}
  693. else {if(Dot(tri .nrm(face ), nrm)<cos_face)continue; vtxs=3;}
  694. // same vertex test
  695. Int *af2, *p2, *p =quad.ind(i ).c;
  696. if(face&SIGN_BIT){p2=quad.ind(face^SIGN_BIT).c; af2=quad.adjFace(face^SIGN_BIT).c;}
  697. else {p2=tri .ind(face ).c; af2=tri .adjFace(face ).c;}
  698. Int vi2; for(vi2=vtxs; --vi2>=0; )if(af2[vi2]==(i^SIGN_BIT))break; if(vi2<0)continue;
  699. if(p[vi]!=p2[(vi2+1)%vtxs] || p[(vi+1)%4]!=p2[vi2])continue;
  700. // vertex normal test
  701. if(cos_vtx>-1 && vtx.nrm())
  702. {
  703. C Vec &n_2 =vtx.nrm(p [(vi +2)% 4]),
  704. &n_3 =vtx.nrm(p [(vi +3)% 4]),
  705. &n2_2=vtx.nrm(p2[(vi2+2)%vtxs]);
  706. if(Dot(n_2, n2_2)<cos_vtx
  707. || Dot(n_3, n2_2)<cos_vtx)continue;
  708. if(face&SIGN_BIT)
  709. {
  710. C Vec &n2_3=vtx.nrm(p2[(vi2+3)%4]);
  711. if(Dot(n_2, n2_3)<cos_vtx
  712. || Dot(n_3, n2_3)<cos_vtx)continue;
  713. }
  714. }
  715. // safety test (faces without other neighbors)
  716. if(safe)
  717. {
  718. if(af [(vi +1)%4]!=-1 || af [(vi +3)%4]!=-1)continue; // compare to -1 and not >=0 because it can have SIGN_BIT
  719. if(face&SIGN_BIT)if(af2[(vi2+1)%4]!=-1 || af2[(vi2+3)%4]!=-1)continue; // compare to -1 and not >=0 because it can have SIGN_BIT
  720. }
  721. // face length test
  722. if(face_length_test)
  723. {
  724. if(Dist2(pos[p[(vi+2)%4]], pos[p2[(vi2+2)%vtxs]])>max_face_length
  725. || Dist2(pos[p[(vi+3)%4]], pos[p2[(vi2+2)%vtxs]])>max_face_length)continue;
  726. if(face&SIGN_BIT)
  727. if(Dist2(pos[p[(vi+2)%4]], pos[p2[(vi2+3)%4]])>max_face_length
  728. || Dist2(pos[p[(vi+3)%4]], pos[p2[(vi2+3)%4]])>max_face_length)continue;
  729. }
  730. // edges inline test
  731. if(face&SIGN_BIT)
  732. {
  733. if(DistPointEdge(pos[p [vi ]], pos[p[(vi+3)%4]], pos[p2[(vi2+2)%4]])>EPS)continue;
  734. if(DistPointEdge(pos[p2[vi2]], pos[p[(vi+2)%4]], pos[p2[(vi2+3)%4]])>EPS)continue;
  735. // vertex values test
  736. if(vtx_value_test)
  737. {
  738. if(VertexValueTest(T, p [vi ], p[(vi+3)%4], p2[(vi2+2)%4])
  739. || VertexValueTest(T, p2[vi2], p[(vi+2)%4], p2[(vi2+3)%4]))continue;
  740. }
  741. // remap points & adj
  742. p[ vi ]= p2[(vi2+2)%4];
  743. p[(vi+1)%4]= p2[(vi2+3)%4];
  744. af[ vi ]=af2[(vi2+2)%4];
  745. }else
  746. {
  747. if(DistPointEdge (pos[p[vi]], pos[p[(vi+3)%4]], pos[p2[(vi2+2)%3]])<=EPS
  748. && DistPointPlane(pos[p2[(vi2+2)%3]], pos[p2[vi2]], CrossN(nrm, pos[p2[vi2]]-pos[p[(vi+2)%4]]))<=EPS)
  749. {
  750. if(safe)if(af2[(vi2+1)%3]!=-1)continue; // compare to -1 and not >=0 because it can have SIGN_BIT
  751. // remap points & adj
  752. p[vi]= p2[(vi2+2)%3];
  753. af[vi]=af2[(vi2+2)%3];
  754. }else
  755. if(DistPointEdge (pos[p2[vi2]], pos[p[(vi+2)%4]], pos[p2[(vi2+2)%3]])<=EPS
  756. && DistPointPlane(pos[p2[(vi2+2)%3]], pos[p[vi]], CrossN(nrm, pos[p[(vi+3)%4]]-pos[p[vi]]))<=EPS)
  757. {
  758. if(safe)if(af2[(vi2+2)%3]!=-1)continue; // compare to -1 and not >=0 because it can have SIGN_BIT
  759. // remap points & adj
  760. p[(vi+1)%4]= p2[(vi2+2)%3];
  761. af[ vi ]=af2[(vi2+1)%3];
  762. }else continue;
  763. }
  764. // fix adjacency
  765. REPD(a, vtxs)
  766. {
  767. Int face3 =af2[a];
  768. if( face3!=-1) // compare to -1 and not >=0 because it can have SIGN_BIT
  769. {
  770. if( face3&SIGN_BIT){REPD(j, 4)if(quad.adjFace(face3^SIGN_BIT).c[j]==face)quad.adjFace(face3^SIGN_BIT).c[j]=(i^SIGN_BIT);}
  771. else {REPD(j, 3)if(tri .adjFace(face3 ).c[j]==face)tri .adjFace(face3 ).c[j]=(i^SIGN_BIT);}
  772. }
  773. }
  774. // remove face
  775. if(face&SIGN_BIT)quad_is[face^SIGN_BIT]=0;
  776. else tri_is[face ]=0;
  777. found=true;
  778. break;
  779. }
  780. }
  781. if(!found)i++;
  782. }
  783. exclude (EDGE_ALL|ADJ_ALL);
  784. keepTris ( tri_is);
  785. keepQuads (quad_is);
  786. removeUnusedVtxs( );
  787. return T;
  788. }
  789. /******************************************************************************/
  790. }
  791. /******************************************************************************/