1 #ifndef _DIAMONDPARA
2 #define _DIAMONDPARA
3 
4 #include <algorithm>
5 #include <ctime>
6 #include <vcg/complex/algorithms/refine.h>
7 #include <vcg/complex/complex.h>
8 #include <vcg/space/color4.h>
9 #include <vcg/space/intersection2.h>
10 
11 class DiamondParametrizator
12 {
13     typedef IsoParametrization::CoordType CoordType;
14     typedef IsoParametrization::PScalarType PScalarType;
15 
16     IsoParametrization *isoParam;
17 
18     ///data used for splitting
19     typedef std::pair<int,int> EdgeKey;
20 
21     ///interpolation data
22     struct InterpData
23     {
24         float alpha;
25         int I;
26         vcg::Point2<float> UV;
27     };
28 
29     std::map<EdgeKey,InterpData> alphaMap;
30 
31     ///data used to store an retrieve edges
32     //typedef std::pair<AbstractFace*,int> TriEdge;
33     //std::vector<DiamondPatch> DDAdiacency;
34     //std::map<TriEdge,int> edgeMap;
35     //int sampleSize;
36 
37     template <class FaceType>
AssignDiamond(FaceType * face)38     int AssignDiamond(FaceType *face)
39     {
40         PScalarType val=(PScalarType)1.0/(PScalarType)3.0;
41         CoordType bary3d(val,val,val);
42         int I_interp;
43         vcg::Point2<PScalarType> UV_interp;
44         isoParam->Phi(face,bary3d,I_interp,UV_interp);
45         int D_interp=isoParam->getHDiamIndex(I_interp,UV_interp);
46         face->WT(0).N()=D_interp;
47         face->WT(1).N()=D_interp;
48         face->WT(2).N()=D_interp;
49         return D_interp;
50     }
51 
52     ///associate the diamond in which a face belongs to
AssociateDiamond()53     void AssociateDiamond()
54     {
55         ParamMesh *to_param=isoParam->ParaMesh();
56         typedef ParamMesh::FaceType FaceType;
57 
58         ///first step first associating initial faces to diamond
59         for (unsigned int i=0;i<to_param->face.size();i++)
60         {
61             #ifndef _MESHLAB
62             if ((i%1000)==0)
63             printf("associating diamond %d - %d \n",i,i+1000);
64             #endif
65             FaceType *curr=&to_param->face[i];
66             AssignDiamond(curr);
67             curr->C()=colorDiam[curr->WT(0).N()];
68         }
69     }
70 
InterpEdge(const ParamFace * f,const int & index_edge,const float & alpha,int & I,vcg::Point2<PScalarType> & UV)71     void InterpEdge(const ParamFace *f,const int &index_edge,
72                     const float &alpha,int &I,vcg::Point2<PScalarType> &UV)
73     {
74         #ifndef NDEBUG
75         float eps=0.00001f;
76         #endif
77         int index0=index_edge;
78         int index1=(index_edge+1)%3;
79         CoordType bary=CoordType(0,0,0);
80         assert((alpha>=0)&&(alpha<=1));
81         bary.V(index0)=alpha;
82         bary.V(index1)=((PScalarType)1.0-alpha);
83         isoParam->Phi(f,bary,I,UV);
84         assert((UV.X()>=0)&&(UV.Y()>=0)&&(UV.X()<=1)&&(UV.Y()<=1)&&(UV.X()+UV.Y()<=1+eps));
85     }
86 
87 template <class FaceType>
QuadCoord(FaceType * curr,const int & vert_num,vcg::Point2f & UVQuad,int & indexQuad)88 void QuadCoord(FaceType * curr,const int &vert_num,vcg::Point2f &UVQuad,int &indexQuad)
89 {
90     typedef typename FaceType::VertexType VertexType;
91 //    typedef typename FaceType::PScalarType PScalarType;
92 
93     VertexType* v=curr->V(vert_num);
94 
95     int DiamIndex=curr->WT(0).N(); ///get index of diamond associated to the face
96     assert((curr->WT(0).N()==curr->WT(1).N())&&(curr->WT(1).N()==curr->WT(2).N()));
97 
98     ///transform to quad coordinates
99     int I=v->T().N();
100     vcg::Point2f UV=v->T().P();
101 
102     ///transform in diamond coordinates
103     vcg::Point2f UVDiam/*,UVQuad*/;
104     isoParam->GE1(I,UV,DiamIndex,UVDiam);
105 
106     ///transform in quad coordinates
107     isoParam->GE1Quad(DiamIndex,UVDiam,UVQuad);
108 
109     indexQuad=DiamIndex;
110     /*return (UVQuad);*/
111 }
112 
113 template <class FaceType>
To_Split(FaceType * curr,const float & border,bool to_split[3],InterpData Idata[3])114     bool To_Split(FaceType * curr,const float	&border,
115                   bool to_split[3],InterpData Idata[3])
116     {
117         to_split[0]=false;
118         to_split[1]=false;
119         to_split[2]=false;
120 
121 //        typedef typename FaceType::ScalarType FScalarType;
122 
123         /*ParamMesh *to_param=isoParam->ParaMesh();*/
124 
125         /*int DiamIndex=curr->WT(0).N(); *////get index of diamond associated to the face
126         assert((curr->WT(0).N()==curr->WT(1).N())&&(curr->WT(1).N()==curr->WT(2).N()));
127 
128         vcg::Point2<PScalarType> UVQuad[3];
129         int index[3];
130 
131         QuadCoord(curr,0,UVQuad[0],index[0]);
132         QuadCoord(curr,1,UVQuad[1],index[1]);
133         QuadCoord(curr,2,UVQuad[2],index[2]);
134 
135         ///outern border
136         vcg::Box2<PScalarType> bbox,bbox0;
137         bbox.Add(vcg::Point2<PScalarType>(-border,-border));
138         bbox.Add(vcg::Point2<PScalarType>(1+border,1+border));
139         bbox0.Add(vcg::Point2<PScalarType>(0,0));
140         bbox0.Add(vcg::Point2<PScalarType>(1,1));
141 
142         if (bbox.IsIn(UVQuad[0])&&bbox.IsIn(UVQuad[1])&&bbox.IsIn(UVQuad[2]))
143             return false; ///no intersection is possible
144 
145         ///else test which edges must be split
146         //vcg::Segment2<float> border_seg[4];
147         vcg::Line2<float> border_seg[4];
148         border_seg[0].Set(vcg::Point2f(0,0),vcg::Point2f(1,0));
149         border_seg[1].Set(vcg::Point2f(1,0),vcg::Point2f(0,1));
150         border_seg[2].Set(vcg::Point2f(0,1),vcg::Point2f(1,0));
151         border_seg[3].Set(vcg::Point2f(0,0),vcg::Point2f(0,1));
152         bool intersected=false;
153         for (int edge=0;edge<3;edge++)
154         {
155             vcg::Segment2<float> curr_edge=vcg::Segment2<float>(UVQuad[edge],UVQuad[(edge+1)%3]);
156             float dist_medium=1.0;
157             for (int j=0;j<4;j++)
158             {
159                 vcg::Point2f p_inters;
160                 vcg::Line2<float> curr_border=border_seg[j];
161                 bool intersect=LineSegmentIntersection(curr_border,curr_edge,p_inters);
162 
163                 float l_test0=(curr_edge.P0()-p_inters).Norm();
164                 float l_test1=(curr_edge.P1()-p_inters).Norm();
165                 float l_test=std::min(l_test0,l_test1);
166 
167                 const PScalarType _EPS=(PScalarType)0.0001;
168                 if ((intersect)&&(l_test>=_EPS))
169                 {
170                     float length=curr_edge.Length();
171                     float dist=((curr_edge.P0()-p_inters).Norm());
172                     float Ndist=dist/length;
173                     float alpha=1.0-Ndist;
174                     float dist_medium1=fabs(alpha-0.5);
175 
176                     if (dist_medium1<dist_medium)
177                     {
178                         dist_medium=dist_medium1;
179                         int I;
180                         vcg::Point2f UV;
181                         InterpEdge(curr,edge,alpha,I,UV);
182                         Idata[edge].alpha=alpha;
183                         Idata[edge].I=I;
184                         Idata[edge].UV=UV;
185                         to_split[edge]=true;
186                         intersected=true;
187                     }
188                 }
189             }
190         }
191         if(!intersected)
192             assert(0);
193         return(intersected);
194     }
195 
196     // Basic subdivision class
197     // This class must provide methods for finding the position of the newly created vertices
198     // In this implementation we simply put the new vertex in the MidPoint position.
199     // Color and TexCoords are interpolated accordingly.
200     template<class MESH_TYPE>
201     struct SplitMidPoint : public   std::unary_function<vcg::face::Pos<typename MESH_TYPE::FaceType> ,  typename MESH_TYPE::CoordType >
202     {
203         typedef typename MESH_TYPE::VertexType VertexType;
204         typedef typename MESH_TYPE::FaceType FaceType;
205         typedef typename MESH_TYPE::CoordType CoordType;
206         MESH_TYPE &m;
207         std::map<EdgeKey,InterpData> *alphaMap;
208         IsoParametrization *isoParam;
209 
SplitMidPointSplitMidPoint210         SplitMidPoint (MESH_TYPE &_m):m(_m){}
211 
operatorSplitMidPoint212         void operator()(typename MESH_TYPE::VertexType &nv, vcg::face::Pos<typename MESH_TYPE::FaceType>  ep)
213         {
214             //printf("DONE\n");
215 
216             ParamMesh *to_param=isoParam->ParaMesh();
217 
218             ///get eth value on which the edge must be split
219             VertexType* v0=ep.f->V(ep.z);
220             VertexType* v1=ep.f->V1(ep.z);
221 
222             int i0=IndexFromPointer(v0,to_param);
223             int i1=IndexFromPointer(v1,to_param);
224 
225             assert(v0!=v1);
226             EdgeKey k;
227             int index0=ep.z;
228             int index1=(ep.z+1)%3;
229 
230             if (i0>i1)
231             {
232                 std::swap(v0,v1);
233                 std::swap(i0,i1);
234                 std::swap(index0,index1);
235             }
236 
237             k=EdgeKey(i0,i1);
238             std::map<EdgeKey,InterpData>::iterator ItE=alphaMap->find(k);
239             assert(ItE!=alphaMap->end());
240             InterpData interp=(*ItE).second;
241             float alpha=interp.alpha;
242             assert((alpha>=0)&&(alpha<=1));
243             nv.P()= v0->P()*alpha+v1->P()*(1.0-alpha);
244             nv.RPos= v0->RPos*alpha+v1->RPos*(1.0-alpha);
245 
246             if( vcg::tri::HasPerVertexNormal(m))
247                 nv.N()=v0->N()*alpha+v1->N()*((PScalarType)1.0-alpha);
248             if( vcg::tri::HasPerVertexColor(m))
249             {
250                 CoordType color=CoordType(v0->C().X(),v0->C().Y(),v0->C().Z());
251                 color=color*alpha+color*((PScalarType)1.0-alpha);
252                 nv.C()=vcg::Color4b((unsigned char)color.X(),(unsigned char)color.Y(),(unsigned char)color.Z(),(unsigned char)255);
253             }
254 
255             nv.T().N()=interp.I;
256             nv.T().P()=interp.UV;
257         }
258 
WedgeInterpSplitMidPoint259         vcg::TexCoord2<float> WedgeInterp(vcg::TexCoord2<float> &t0, vcg::TexCoord2<float> &t1)
260         {
261             vcg::TexCoord2<float> tmp;
262             assert(t0.n()== t1.n());
263             tmp.n()=t0.n();
264             tmp.t()=(t0.t()+t1.t())/2.0;
265             return tmp;
266         }
267     };
268 
269 
270 
271     template <class MESH_TYPE>//, class FLT>
272     class EdgePredicate
273     {
274         typedef typename MESH_TYPE::VertexType VertexType;
275         typedef typename MESH_TYPE::FaceType FaceType;
276     public:
277         std::map<EdgeKey,InterpData> *alphaMap;
278         IsoParametrization *isoParam;
279 
operator()280         bool operator()(vcg::face::Pos<typename MESH_TYPE::FaceType> ep) const
281         {
282             ParamMesh *to_param=isoParam->ParaMesh();
283 
284             VertexType* v0=ep.f->V(ep.z);
285             VertexType* v1=ep.f->V1(ep.z);
286 
287             int i0=IndexFromPointer(v0,to_param);
288             int i1=IndexFromPointer(v1,to_param);
289 
290             assert(v0!=v1);
291             EdgeKey k;
292 
293             if (i0>i1)
294             {
295                 std::swap(v0,v1);
296                 std::swap(i0,i1);
297             }
298 
299             k=EdgeKey(i0,i1);
300             std::map<EdgeKey,InterpData>::iterator ItE=alphaMap->find(k);
301             bool to_split=(ItE!=alphaMap->end());
302             return (to_split);
303         }
304     };
305 
IndexFromPointer(ParamVertex * v,ParamMesh * mesh)306     static int IndexFromPointer(ParamVertex * v,ParamMesh *mesh)
307     {
308         int index=v-&(*mesh->vert.begin());
309         return (index);
310     }
311 
InsertInterpData(ParamFace * curr,const int & edge,ParamMesh * to_param,InterpData & Idata)312     void InsertInterpData(ParamFace *curr,const int &edge,
313                           ParamMesh *to_param,InterpData &Idata)
314     {
315         ParamVertex *v0=curr->V(edge);
316         ParamVertex *v1=curr->V1(edge);
317         int i0=IndexFromPointer(v0,to_param);
318         int i1=IndexFromPointer(v1,to_param);
319         if (i0>i1)
320         {
321             std::swap(v0,v1);
322             std::swap(i0,i1);
323             Idata.alpha=(PScalarType)1.0-Idata.alpha;
324             assert((Idata.alpha>=0)&&(Idata.alpha<=1));
325         }
326         EdgeKey k=EdgeKey(i0,i1);
327         std::map<EdgeKey,InterpData>::iterator ItE=alphaMap.find(k);
328         if(ItE!=alphaMap.end())
329         {
330             if (fabs((*ItE).second.alpha-0.5)>fabs(Idata.alpha-0.5))
331             {
332                 (*ItE).second.alpha=Idata.alpha;
333                 (*ItE).second.I=Idata.I;
334                 (*ItE).second.UV=Idata.UV;
335             }
336         }
337         else
338             alphaMap.insert(std::pair<EdgeKey,InterpData>(k,Idata));
339     }
340 
Split(const PScalarType & border)341     bool Split(const PScalarType &border)
342     {
343         alphaMap.clear();
344 
345         ParamMesh *to_param=isoParam->ParaMesh();
346 
347         ///copy paramesh
348 
349         typedef ParamMesh::FaceType FaceType;
350         SplitMidPoint<ParamMesh> splMd(*to_param);
351         EdgePredicate<ParamMesh> eP;
352 
353         ///second step.. test the split if needed
354         for (unsigned int i=0;i<to_param->face.size();i++)
355         {
356             ///get the current face and test the edges
357             FaceType * curr=&to_param->face[i];
358             InterpData Idata[3];
359             bool to_split[3];
360 #ifndef _MESHLAB
361             if ((i%1000)==0)
362             printf("testing face %d - %d \n",i,i+1000);
363 #endif
364             bool is_out=To_Split<FaceType>(curr,border,to_split,Idata);
365             if (is_out){
366                 for (int edge=0;edge<3;edge++)
367                     if (to_split[edge])
368                         InsertInterpData(curr,edge,to_param,Idata[edge]);
369             }
370 
371         }
372         splMd.isoParam=isoParam;
373         splMd.alphaMap=&alphaMap;
374         eP.isoParam=isoParam;
375         eP.alphaMap=&alphaMap;
376 
377         #ifndef _MESHLAB
378         int f0=to_param->fn;
379         #endif
380         bool done=vcg::tri::RefineE<ParamMesh,SplitMidPoint<ParamMesh>,EdgePredicate<ParamMesh> >(*to_param,splMd,eP);
381         #ifndef _MESHLAB
382         printf("FACE ADDED  %d \n",to_param->fn-f0);
383         #endif
384         return done;
385 
386     }
387 
SetWedgeCoords(const PScalarType & border)388     void SetWedgeCoords(const PScalarType &border)
389     {
390         typedef ParamMesh::FaceType FaceType;
391 
392         ParamMesh *to_param=isoParam->ParaMesh();
393         int edge_size=(int)ceil(sqrt((PScalarType)num_diamonds));
394         PScalarType edgedim=1.0/(PScalarType)edge_size;
395         for (unsigned int i=0;i<to_param->face.size();i++)
396         {
397             #ifndef _MESHLAB
398             if ((i%1000)==0)
399             printf("setting Wedge coords %d - %d \n",i,i+1000);
400             #endif
401             ///get the current face and test the edges
402             FaceType * curr=&to_param->face[i];
403             for (int j=0;j<3;j++)
404             {
405                 vcg::Point2f QCoord;
406                 vcg::Point2i IntCoord;
407                 int index;
408                 QuadCoord(curr,j,QCoord,index);
409                 IntCoord.X()=index/edge_size;
410                 IntCoord.Y()=index%edge_size;
411                 ///transform from [ -border,1 + border] to [0,1]
412                 QCoord+=vcg::Point2f(border,border);
413                 QCoord/=(PScalarType)1.0+(PScalarType)2.0*border;
414                 assert((QCoord.X()>=0)&&(QCoord.X()<=1)&&(QCoord.Y()>=0)&&(QCoord.Y()<=1));
415 
416                 QCoord*=edgedim;
417                 QCoord.X()+=edgedim*(PScalarType)IntCoord.X();
418                 QCoord.Y()+=edgedim*(PScalarType)IntCoord.Y();
419                 assert(QCoord.X()<=1);
420                 assert(QCoord.Y()<=1);
421                 curr->WT(j).P()=QCoord;
422                 ///and finally set for global texture coords
423             }
424         }
425     }
426 
427     int num_diamonds;
428 
429 public:
430 
431     std::vector<vcg::Color4b > colorDiam;
432 
433     ///initialize the parameterization
Init(IsoParametrization * _isoParam)434     void Init(IsoParametrization *_isoParam)
435     {
436 
437         isoParam=_isoParam;
438 
439         ///COUNT THE NUMBER OF EDGES
440         num_diamonds=0;
441         for (unsigned int i=0;i<isoParam->AbsMesh()->face.size();i++)
442         {
443             AbstractFace *f=&isoParam->AbsMesh()->face[i];
444             for (int j=0;j<3;j++)
445                 if (f->FFp(j)<f)
446                     num_diamonds++;
447         }
448 
449         colorDiam.resize(num_diamonds);
450         srand(clock());
451         for (unsigned int i=0;i<colorDiam.size();i++)
452             colorDiam[i]=vcg::Color4b(rand()%255,rand()%255,rand()%255,255);
453 
454     }
455 
456     //void Draw()
457     //{
458     //	ParamMesh *to_param=isoParam->ParaMesh();
459     //	//vcg::tri::UpdateNormal<ParamMesh>::PerFaceNormalized(*to_param);
460     //	glDepthRange(0.01,1.0);
461     //	glEnable(GL_LIGHTING);
462     //	glEnable(GL_LIGHT0);
463     //	glEnable(GL_NORMALIZE);
464     //	glBegin(GL_TRIANGLES);
465     //	for (int i=0;i<to_param->face.size();i++)
466     //	{
467 
468     //		/*vcg::glColor(to_param->face[i].C());*/
469 
470     //		CoordType p0=to_param->face[i].V(0)->P();
471     //		CoordType p1=to_param->face[i].V(1)->P();
472     //		CoordType p2=to_param->face[i].V(2)->P();
473     //		CoordType norm=(p1-p0)^(p2-p0);
474     //		norm.Normalize();
475     //		vcg::glNormal(norm);
476     //		vcg::Point2f t0=to_param->face[i].WT(0).P();
477     //		vcg::Point2f t1=to_param->face[i].WT(1).P();
478     //		vcg::Point2f t2=to_param->face[i].WT(2).P();
479     //		vcg::Color4b c0,c1,c2;
480     //		if ((t0.X()< 0)||(t0.Y()< 0)||(t0.X()>1.0)||(t0.Y()>1.0))
481     //		c0=vcg::Color4b(0,0,255,255);
482     //		else
483     //		c0=vcg::Color4b(t0.X()*255.0,t0.Y()*255.0,0,255);
484     //		if ((t1.X()< 0)||(t1.Y()< 0)||(t1.X()>1.0)||(t1.Y()>1.0))
485     //		c1=vcg::Color4b(0,0,255,255);
486     //		else
487     //		c1=vcg::Color4b(t1.X()*255.0,t1.Y()*255.0,0,255);
488     //		if ((t2.X()< 0)||(t2.Y()< 0)||(t2.X()>1.0)||(t2.Y()>1.0))
489     //		c2=vcg::Color4b(0,0,255,255);
490     //		else
491     //		c2=vcg::Color4b(t2.X()*255.0,t2.Y()*255.0,0,255);
492     //		vcg::glColor(c0);
493     //		vcg::glVertex(to_param->face[i].V(0)->P());
494     //		vcg::glColor(c1);
495     //		vcg::glVertex(to_param->face[i].V(1)->P());
496     //		vcg::glColor(c2);
497     //		vcg::glVertex(to_param->face[i].V(2)->P());
498     //	}
499     //	glEnd();
500 
501     //	/*glDepthRange(0,0.99999);
502     //	glDisable(GL_LIGHTING);
503     //	glDisable(GL_LIGHT0);
504     //	glDisable(GL_NORMALIZE);
505     //	glLineWidth(1);
506     //	glColor3d(0,0,0);
507     //	for (int i=0;i<to_param->face.size();i++)
508     //	{
509     //		glBegin(GL_LINE_LOOP);
510     //		CoordType p0=to_param->face[i].V(0)->P();
511     //		CoordType p1=to_param->face[i].V(1)->P();
512     //		CoordType p2=to_param->face[i].V(2)->P();
513     //		vcg::glVertex(to_param->face[i].V(0)->P());
514     //		vcg::glVertex(to_param->face[i].V(1)->P());
515     //		vcg::glVertex(to_param->face[i].V(2)->P());
516     //		glEnd();
517     //	}*/
518     //
519     //	glDepthRange(0.0,1.0);
520     //}
521 
522 
523 
524     ///set the vertex coordinates
525     template <class MeshType>
526     void SetCoordinates(MeshType &mesh,const PScalarType &border=0.01)
527     {
528         std::vector<vcg::Color4b > colorDiam;
529 
530         //ParamMesh *to_param=isoParam->ParaMesh();
531 
532         bool done=true;
533         /*int n0=to_param->fn;*/
534         int step=0;
535         while (done)
536         {
537             #ifndef _MESHLAB
538                 printf("step %d \n",step);
539             #endif
540             AssociateDiamond();
541             done=Split(border);
542             isoParam->Update();
543             step++;
544         }
545 
546         AssociateDiamond();
547         SetWedgeCoords(border);
548 
549         ///copy parametrization to the new mesh
550         mesh.Clear();
551         vcg::tri::Append<MeshType,ParamMesh>::Mesh(mesh,*isoParam->ParaMesh());
552 
553     }
554 
555 };
556 #endif
557