/**************************************************************************** * VCGLib o o * * Visual and Computer Graphics Library o o * * _ O _ * * Copyright(C) 2004 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * ****************************************************************************/ #ifndef __VCGLIB_REFINE_LOOP #define __VCGLIB_REFINE_LOOP #include #include #include #include #include #include #include namespace vcg{ namespace tri{ /* Metodo di Loop dalla documentazione "Siggraph 2000 course on subdivision" d4------d3 d4------d3 / \ / \ / \ / \ u / \ / \ / e4--e3 \ / \ / \/ \ / / \/ \ \ / \ d5------d1------d2 -> d5--e5--d1--e2--d2 l--M--r \ /\ / \ \ /\ / / \ / \ / \ / \ e6--e7 / \ / \ / \ / \ / \ / d d6------d7 d6------d7 ******************************************************* */ // Nuovi punti (e.g. midpoint), ossia odd vertices // template struct OddPointLoop : public std::unary_function , typename MESH_TYPE::CoordType> { void operator()(typename MESH_TYPE::VertexType &nv, face::Pos ep) { face::Pos he(ep.f,ep.z,ep.f->V(ep.z)); typename MESH_TYPE::CoordType *l,*r,*u,*d; l = &he.v->P(); he.FlipV(); r = &he.v->P(); if( MESH_TYPE::HasPerVertexColor()) nv.C().lerp(ep.f->V(ep.z)->C(),ep.f->V1(ep.z)->C(),.5f); if (he.IsBorder()) { nv.P() = ((*l)*0.5 + (*r)*0.5); } else { he.FlipE(); he.FlipV(); u = &he.v->P(); he.FlipV(); he.FlipE(); assert(&he.v->P()== r); // back to r he.FlipF(); he.FlipE(); he.FlipV(); d = &he.v->P(); // abbiamo i punti l,r,u e d per ottenere M in maniera pesata nv.P()=((*l)*(3.0/8.0)+(*r)*(3.0/8.0)+(*d)*(1.0/8.0)+(*u)*(1.0/8.0)); } } Color4 WedgeInterp(Color4 &c0, Color4 &c1) { Color4 cc; return cc.lerp(c0,c1,0.5f); } template TexCoord2 WedgeInterp(TexCoord2 &t0, TexCoord2 &t1) { TexCoord2 tmp; tmp.n()=t0.n(); tmp.t()=(t0.t()+t1.t())/2.0; return tmp; } }; // vecchi punti, ossia even vertices template struct EvenPointLoop : public std::unary_function , typename MESH_TYPE::CoordType> { void operator()(typename MESH_TYPE::CoordType &nP, face::Pos ep) { face::Pos he(ep.f,ep.z,ep.f->V(ep.z)); typename MESH_TYPE::CoordType *r, *l, *curr; curr = &he.v->P(); if (he.IsBorder()) {//half edge di bordo he.FlipV(); r = &he.v->P(); he.FlipV(); assert(&he.v->P()== curr); // back to curr he.NextB(); if (&he.v->P() == curr) he.FlipV(); l = &he.v->P(); nP = ( *(curr) * (3.0)/(4.0) + (*l)*(1.0/8.0) + (*r)*(1.0/8.0)); } else { // compute valence of this vertex int k = 0; face::Pos heStart = he; std::vector otherVertVec; if(he.v->IsB())return ; do { he.FlipV(); otherVertVec.push_back(he.v->P()); he.FlipV(); he.FlipE(); he.FlipF(); k++; } while(he.f!=heStart.f || he.z!=heStart.z || he.v!=heStart.v); // while(he != heStart); float beta = 3.0 / 16.0; if(k > 3 ) beta = (1.0/(float)k) * (5.0/8.0 - pow((3.0/8.0 + 0.25 * cos(2*M_PI/k)),2)); *curr = *curr * (1 - k * beta) ; typename std::vector::iterator iter; for (iter = otherVertVec.begin(); iter != otherVertVec.end(); ++iter) { *curr = *curr + (*iter) * beta; } nP = *curr; } } // end of operator() Color4 WedgeInterp(Color4 &c0, Color4 &c1) { Color4 cc; return cc.lerp(c0,c1,0.5f); } Color4b WedgeInterp(Color4b &c0, Color4b &c1) { Color4b cc; cc.lerp(c0,c1,0.5f); return cc; } template TexCoord2 WedgeInterp(TexCoord2 &t0, TexCoord2 &t1) { TexCoord2 tmp; // assert(t0.n()== t1.n()); tmp.n()=t0.n(); tmp.t()=(t0.t()+t1.t())/2.0; return tmp; } }; template struct EvenParam { CoordType sum; bool border; int k; } ; template bool RefineOddEven(MESH_TYPE &m, ODD_VERT odd, EVEN_VERT even,float length, bool RefineSelected=false, CallBackPos *cbOdd = 0, CallBackPos *cbEven = 0) { EdgeLen ep(length); return RefineOddEvenE(m, odd, even, ep, RefineSelected, cbOdd, cbEven); } template bool RefineOddEvenE(MESH_TYPE &m, ODD_VERT odd, EVEN_VERT even, PREDICATE edgePred, bool RefineSelected=false, CallBackPos *cbOdd = 0, CallBackPos *cbEven = 0) { // n = numero di vertici iniziali int n = m.vn; // refine dei vertici odd, crea dei nuovi vertici in coda RefineE< MESH_TYPE,OddPointLoop > (m, odd, edgePred, RefineSelected, cbOdd); // momentaneamente le callback sono identiche, almeno cbOdd deve essere passata cbEven = cbOdd; vcg::tri::UpdateFlags::FaceBorderFromFF(m); // aggiorno i flag perche' IsB funzioni vcg::tri::UpdateFlags::VertexBorderFromFace (m); //vcg::tri::UpdateColor::VertexBorderFlag(m); // marco i vertici even [ i primi n ] come visitati int evenFlag = MESH_TYPE::VertexType::NewBitFlag(); for (int i = 0; i < n ; i++ ) { m.vert[i].SetUserBit(evenFlag); } int j = 0; // di texture per wedge (uno per ogni edge) typename MESH_TYPE::VertexIterator vi; typename MESH_TYPE::FaceIterator fi; for (fi = m.face.begin(); fi != m.face.end(); fi++) if(!(*fi).IsD()){ //itero facce for (int i = 0; i < 3; i++) { //itero vert if ( (*fi).V(i)->IsUserBit(evenFlag) && ! (*fi).V(i)->IsD() ) { if (RefineSelected && !(*fi).V(i)->IsS() ) break; face::Posaux (&(*fi),i); if( MESH_TYPE::HasPerVertexColor() ) { (*fi).V(i)->C().lerp((*fi).V0(i)->C() , (*fi).V1(i)->C(),0.5f); } if (cbEven) { (*cbEven)(int(100.0f * (float)j / (float)m.fn),"Refining"); j++; } even((*fi).V(i)->P(), aux); } } } return true; } } // namespace tri } // namespace vcg #endif