#include "MGCLStdAfx.h" #include "mg/Position.h" #include "Tl2/TL2LPline.h" #include "Tl2/TL2Triangles.h" #include "Tl2/TL2Fans.h" #if defined(_DEBUG) #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif //Constructor. mgTL2Triangles::mgTL2Triangles( MGCL::TL_DATA_KIND dkind, const MGSurface* surf ):m_kind(dkind),m_surface(surf),m_triangles(){ } ///Copy constructor. mgTL2Triangles::mgTL2Triangles( const mgTL2Triangles& tris ):m_kind(tris.m_kind),m_surface(tris.m_surface){ mgTL2Triangles& tris2=const_cast<mgTL2Triangles&>(tris); m_triangles.push_back(tris2.m_triangles); } //Return the i-th mgTL2Triangle. const mgTL2Triangle& mgTL2Triangles::operator[](int i)const{ return *(m_triangles[i]); } mgTL2Triangle& mgTL2Triangles::operator[](int i){ return *(m_triangles[i]); } static const std::string kind_string[3]={"(u,v)", "(x,y,z)", "(x,y,z) with normal"}; std::ostream& operator<< (std::ostream& out, const mgTL2Triangles& tris){ out<<"TLTriangles="<<(&tris)<<", surface="<<"tris.m_surface"<<",num of triangles=" <<tris.m_triangles.size()<<", kind="<<kind_string[tris.get_kind()]<<std::endl; mgTL2Triangles::const_iterator iter = tris.begin(); for(; iter != tris.end(); iter++) out<<**iter; out<<std::endl; return out; } ///Push back a triangel of type mgTESTRIANG_FAN. ///The veritces of the triangle is verticesIDs which are vertex id of fans. ///The vertex ids are converted to (x,y,x) or (u,v) according to triangles.is_uv(). void mgTL2Triangles::push_back( const mgTL2Fans& fans, int nvTri,//Number of vertices in verticesIDs. generally nvTri!=verticesIDs.size(). const std::vector<int>& verticesIDs ){ if(nvTri<=2) return; bool uv_is_required=is_uv(); bool normal_is_required=need_normal(); mgTL2Triangle* cfan=new mgTL2Triangle(nvTri,mgTESTRIANG_FAN); for(int i=0; i<nvTri; i++){ int id=verticesIDs[i]; if(uv_is_required) (*cfan)[i]=fans.uv(id); else (*cfan)[i]=fans.xyz(id,normal_is_required); } push_back(cfan); } ///Make strip data from pline0 and pline2. ///The number of vertices of pline0 is greater or equal to the one of pline2. ///And the differecne must be at most 1. void mgTL2Triangles::makeStrip( const mgTL2LPline& pline0, const mgTL2LPline& pline2 ){ bool normal_is_required=need_normal(); int n0=pline0.number_of_points(), n2=pline2.number_of_points(); assert(n0>=n2 && (n0-n2)<=1); int id2=0, n0m1=n0-1; if(n0==n2){ if(n0==2){ tessellate2by2(pline0,pline2); return; } MGVector dire1=pline0.eval(1.,1); MGPosition uvn0m1=pline0.uv(n0m1); MGPosition uv0=pline2.uv(0); MGVector dire2=uv0-uvn0m1; if(dire1.cangle(dire2)>RIGHT_ANGLE){ id2=1;n2--; mgTL2Triangle* stripP0=new mgTL2Triangle(3,mgTESTRIANG_STRIP); mgTL2Triangle& strip0=*stripP0; if(is_uv()){ strip0[0]=uvn0m1; strip0[1]=uv0; strip0[2]=pline2.uv(1); }else{ strip0[0]=pline0.xyz(n0m1,normal_is_required); strip0[1]=pline2.xyz(0,normal_is_required); strip0[2]=pline2.xyz(1,normal_is_required); } push_back(stripP0);//std::cout<<strip0<<std::endl; } } mgTL2Triangle* stripP=new mgTL2Triangle(n0+n2,mgTESTRIANG_STRIP); mgTL2Triangle& strip=*stripP; int j=0; if(is_uv()){ for(int i=0; i<n2; i++){ strip[j++]=pline0.uv(n0m1-i); strip[j++]=pline2.uv(id2+i); } if(n0>n2) strip[j]=pline0.uv(0); }else{ for(int i=0; i<n2; i++){ strip[j++]=pline0.xyz(n0m1-i,normal_is_required); strip[j++]=pline2.xyz(id2+i,normal_is_required); } if(n0>n2) strip[j]=pline0.xyz(0,normal_is_required); } push_back(stripP);//std::cout<<strip<<std::endl; } ///Make fan data from plinen and pline0. ///The number of vertices of plinen is 2 or greater than 2. ///The fan is made from the pline0's start point to n vertices of plinen. void mgTL2Triangles::makeFan( const mgTL2LPline& plinen, const mgTL2LPline& pline0 ){ int nlpn=plinen.number_of_points(); mgTL2Triangle* fanP=new mgTL2Triangle(nlpn+1,mgTESTRIANG_FAN); mgTL2Triangle& fan=*fanP; if(is_uv()){ fan[0]=pline0.uv(0); for(int i=0; i<nlpn; i++) fan[i+1]=plinen.uv(i); }else{ bool normal_is_required=need_normal(); fan[0]=pline0.xyz(0,normal_is_required); for(int i=0; i<nlpn; i++) fan[i+1]=plinen.xyz(i,normal_is_required); } push_back(fanP); } ///Tessellate a rectangle that has only 4 vertices, and puch back the tris to this. void mgTL2Triangles::tessellate2by2( const mgTL2LPline& pl, const mgTL2LPline& pl_opposite ){ MGVector dir1=pl_opposite.xyz(0)-pl.xyz(0); MGVector dir2=pl_opposite.xyz(1)-pl.xyz(1); int idmax; if(dir1%dir1<=dir2%dir2) idmax=0;//pl.xyz(0) is pivot of the fan. else idmax=1;//pl.xyz(1) is pivot of the fan. mgTL2Triangle* fanP=new mgTL2Triangle(4,mgTESTRIANG_FAN); mgTL2Triangle& fan=*fanP; if(is_uv()){ if(idmax){ fan[0]=pl.uv(1); fan[1]=pl_opposite.uv(0); fan[2]=pl_opposite.uv(1); fan[3]=pl.uv(0); }else{ fan[0]=pl.uv(0); fan[1]=pl.uv(1); fan[2]=pl_opposite.uv(0); fan[3]=pl_opposite.uv(1); } }else{ bool normal_is_required=need_normal(); if(idmax){ fan[0]=pl.xyz(1,normal_is_required); fan[1]=pl_opposite.xyz(0,normal_is_required); fan[2]=pl_opposite.xyz(1,normal_is_required); fan[3]=pl.xyz(0,normal_is_required); }else{ fan[0]=pl.xyz(0,normal_is_required); fan[1]=pl.xyz(1,normal_is_required); fan[2]=pl_opposite.xyz(0,normal_is_required); fan[3]=pl_opposite.xyz(1,normal_is_required); } } push_back(fanP); } ///Tessellate a rectangle that has only 4 edges, whose number of vertices are (2,2,2,n). ///Here n>=3. Tessellated tris are pushed back to this. void mgTL2Triangles::tessellate222n( const mgTL2LPline& pl3,//edge that has 3 or more than 3 vetices. const mgTL2LPline& pl2//opposite edge of pl3 whose vertices number is 2. ){ //std::cout<<pl3<<pl2<<std::endl; bool uv_is_required=is_uv(), normal_is_required=need_normal(); int n3=pl3.number_of_points(); std::unique_ptr<mgTL2Triangle> fan1P(new mgTL2Triangle(mgTESTRIANG_FAN)); mgTL2Triangle& fan1=*fan1P; std::unique_ptr<mgTL2Triangle> fan2P(new mgTL2Triangle(mgTESTRIANG_FAN)); mgTL2Triangle& fan2=*fan2P; MGPosition pivot1=pl2.xyz(1), pivot2=pl2.xyz(0); fan1.push_back(uv_is_required ? pl2.uv(1):pl2.xyz(1,normal_is_required));//Pivot1 fan1.push_back(uv_is_required ? pl3.uv(0):pl3.xyz(0,normal_is_required));//Edge Pivot1 to pl3 start. fan2.push_back(uv_is_required ? pl2.uv(0):pl2.xyz(0,normal_is_required));//Pivot2 fan2.push_back(fan1[0]);//Edge Pivot2 to Pivot1. int i=1; MGPosition xyzim1=pl3.xyz(0),xyzi=pl3.xyz(1); MGVector pv1Toxyzi=xyzi-pivot1, pv2Toxyzim1=xyzim1-pivot2; double l1i=pv1Toxyzi%pv1Toxyzi, l2im1=pv2Toxyzim1%pv2Toxyzim1; while(i<n3 && l1i<=l2im1){ fan1.push_back(uv_is_required ? pl3.uv(i):pl3.xyz(i,normal_is_required)); i++; if(i<n3){ xyzim1=xyzi; xyzi=pl3.xyz(i); pv1Toxyzi=xyzi-pivot1; pv2Toxyzim1=xyzim1-pivot2; l1i=pv1Toxyzi%pv1Toxyzi; l2im1=pv2Toxyzim1%pv2Toxyzim1; } } if(i==n3) fan1.push_back(fan2[0]); else fan2.push_back(uv_is_required ? pl3.uv(i-1):pl3.xyz(i-1,normal_is_required)); for(;i<n3; i++){ fan2.push_back(uv_is_required ? pl3.uv(i):pl3.xyz(i,normal_is_required)); } if(fan1.size()>=3){ //std::cout<<fan1<<std::endl; push_back(fan1P.release()); } if(fan2.size()>=3){ //std::cout<<fan2<<std::endl; push_back(fan2P.release()); } } ///Tessellate a rectangle that has 2 continuous edges of only 2 vertices. ///Tessellated triangles will be appended. void mgTL2Triangles::tessellate22nn( int id2, //id of edge that has 2 vertices. Next edge of id2 also have only 2 vertices. const mgTL2LPline pline[4] ){ int id2next=(id2+1)%4; int id2next2=(id2+2)%4; int id2pre=(id2+3)%4; const mgTL2LPline& lp0=pline[id2];//lp0.number_of_points()==2 const mgTL2LPline& lp1=pline[id2next];//lp1.number_of_points()==2 const mgTL2LPline& lp2=pline[id2next2]; const mgTL2LPline& lp3=pline[id2pre]; int n2=lp2.number_of_points(); int n3=lp3.number_of_points(); MGVector xyz2S=lp2.xyz(0)-lp2.xyz(1); MGVector xyz3E=lp3.xyz(n3-1)-lp3.xyz(n3-2); if(xyz3E%xyz3E > xyz2S%xyz2S){ std::unique_ptr<mgTL2Polyline> poly=lp1.polygonizeSL(lp3,0,n3-2); mgTL2LPline lpn(poly.get()); makeFan(lpn,lp0); mgTL2LPline lp3Sub(lp3,0,n3-1); lpn.reverse(); mgTL2LPline plines2[4]={lpn,lp1,lp2,lp3Sub}; tessellate4(plines2); }else{ std::unique_ptr<mgTL2Polyline> poly=lp2.polygonizeSL(lp1,1,0); mgTL2LPline lpn(poly.get()); makeFan(lpn,lp2); mgTL2LPline lp2Sub(lp2,1,n2-1); lpn.reverse(); mgTL2LPline plines2[4]={lpn,lp2Sub,lp3,lp0}; tessellate4(plines2); } }