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