/**************************************************************************** * VCGLib o o * * Visual and Computer Graphics Library o o * * _ O _ * * Copyright(C) 2004-2016 \/)\/ * * 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_LOCALOPTIMIZATION #define __VCGLIB_LOCALOPTIMIZATION #include #include namespace vcg{ // Base class for Parameters // all parameters must be derived from this. class BaseParameterClass { }; template class LocalOptimization; enum ModifierType{ TetraEdgeCollapseOp, TriEdgeSwapOp, TriVertexSplitOp, TriEdgeCollapseOp,TetraEdgeSpliOpt,TetraEdgeSwapOp, TriEdgeFlipOp, QuadDiagCollapseOp, QuadEdgeCollapseOp}; /** \addtogroup tetramesh */ /*@{*/ /// This abstract class define which functions a local modification class must have to be used in the LocalOptimization framework. template class LocalModification { public: typedef typename LocalOptimization::HeapType HeapType; typedef typename MeshType::ScalarType ScalarType; inline LocalModification(){} virtual ~LocalModification(){} /// return the type of operation virtual ModifierType IsOfType() = 0 ; /// return true if the data have not changed since it was created virtual bool IsUpToDate() const = 0 ; /// return true if no constraint disallow this operation to be performed (ex: change of topology in edge collapses) virtual bool IsFeasible(BaseParameterClass *pp) = 0; /// Compute the priority to be used in the heap virtual ScalarType ComputePriority(BaseParameterClass *pp)=0; /// Return the priority to be used in the heap (implement static priority) virtual ScalarType Priority() const =0; /// Perform the operation virtual void Execute(MeshType &m, BaseParameterClass *pp)=0; /// perform initialization static void Init(MeshType &m, HeapType&, BaseParameterClass *pp); /// An approximation of the size of the heap with respect of the number of simplex /// of the mesh. When this number is exceeded a clear heap purging is performed. /// so it is should be reasonably larger than the minimum expected size to avoid too frequent clear heap /// For example for symmetric edge collapse a 5 is a good guess. /// while for non symmetric edge collapse a larger number like 9 is a better choice static float HeapSimplexRatio(BaseParameterClass *) {return 6.0f;} virtual const char *Info(MeshType &) {return 0;} /// Update the heap as a consequence of this operation virtual void UpdateHeap(HeapType&, BaseParameterClass *pp)=0; }; //end class local modification /// LocalOptimization: /// This class implements the algorihms running on 0-1-2-3-simplicial complex that are based on local modification /// The local modification can be and edge_collpase, or an edge_swap, a vertex plit...as far as they implement /// the interface defined in LocalModification. /// Implementation note: in order to keep the local modification itself indepented by its use in this class, they are not /// really derived by LocalModification. Instead, a wrapper is done to this purpose (see vcg/complex/tetramesh/decimation/collapse.h) template class LocalOptimization { public: LocalOptimization(MeshType &mm, BaseParameterClass *_pp): m(mm){ ClearTermination();HeapSimplexRatio=5; pp=_pp;} struct HeapElem; typedef typename MeshType::ScalarType ScalarType; typedef typename std::vector HeapType; typedef LocalModification LocModType; /// termination conditions enum LOTermination { LOnSimplices = 0x01, // test number of simplicies LOnVertices = 0x02, // test number of verticies LOnOps = 0x04, // test number of operations LOMetric = 0x08, // test Metric (error, quality...instance dependent) LOTime = 0x10 // test how much time is passed since the start } ; int tf; // Termination Flag int nPerformedOps, nTargetOps, nTargetSimplices, nTargetVertices; float timeBudget; clock_t start; ScalarType currMetric; ScalarType targetMetric; BaseParameterClass *pp; // The ratio between Heap size and the number of simplices in the current mesh // When this value is exceeded a ClearHeap Start; float HeapSimplexRatio; void SetTerminationFlag (int v){tf |= v;} void ClearTerminationFlag (int v){tf &= ~v;} bool IsTerminationFlag (int v){return ((tf & v)!=0);} void SetTargetSimplices (int ts ){nTargetSimplices = ts; SetTerminationFlag(LOnSimplices); } void SetTargetVertices (int tv ){nTargetVertices = tv; SetTerminationFlag(LOnVertices); } void SetTargetOperations(int to ){nTargetOps = to; SetTerminationFlag(LOnOps); } void SetTargetMetric (ScalarType tm ){targetMetric = tm; SetTerminationFlag(LOMetric); } void SetTimeBudget (float tb ){timeBudget = tb; SetTerminationFlag(LOTime); } void ClearTermination() { tf=0; nTargetSimplices=0; nTargetOps=0; targetMetric=0; timeBudget=0; nTargetVertices=0; } /// the mesh to optimize MeshType & m; ///the heap of operations HeapType h; ///the element of the heap // it is just a wrapper of the pointer to the localMod. // std heap does not work for // pointers and we want pointers to have heterogenous heaps. struct HeapElem { inline HeapElem(){locModPtr = NULL;} ~HeapElem(){} ///pointer to instance of local modifier LocModType *locModPtr; float pri; inline HeapElem( LocModType *_locModPtr) { locModPtr = _locModPtr; pri=float(locModPtr->Priority()); } /// STL heap has the largest element as the first one. /// usually we mean priority as an error so we should invert the comparison inline bool operator <(const HeapElem & h) const { return (pri > h.pri); //return (locModPtr->Priority() < h.locModPtr->Priority()); } bool IsUpToDate() const { return locModPtr->IsUpToDate(); } }; /// Default distructor ~LocalOptimization(){ typename HeapType::iterator i; for(i = h.begin(); i != h.end(); i++) delete (*i).locModPtr; } /// main cycle of optimization bool DoOptimization() { assert ( ( ( tf & LOnSimplices )==0) || ( nTargetSimplices!= -1)); assert ( ( ( tf & LOnVertices )==0) || ( nTargetVertices != -1)); assert ( ( ( tf & LOnOps )==0) || ( nTargetOps != -1)); assert ( ( ( tf & LOMetric )==0) || ( targetMetric != -1)); assert ( ( ( tf & LOTime )==0) || ( timeBudget != -1)); start=clock(); nPerformedOps =0; while( !GoalReached() && !h.empty()) { if(h.size()> m.SimplexNumber()*HeapSimplexRatio ) ClearHeap(); std::pop_heap(h.begin(),h.end()); LocModType *locMod = h.back().locModPtr; currMetric=h.back().pri; h.pop_back(); if( locMod->IsUpToDate() ) { //printf("popped out: %s\n",locMod->Info(m)); if (locMod->IsFeasible(this->pp)) { nPerformedOps++; locMod->Execute(m,this->pp); locMod->UpdateHeap(h,this->pp); } } delete locMod; } return !(h.empty()); } // It removes from the heap all the operations that are no more 'uptodate' // (e.g. collapses that have some recently modified vertices) // This function is called from time to time by the doOptimization (e.g. when the heap is larger than fn*3) void ClearHeap() { // int sz=h.size(); int t0=clock(); for(auto hi=h.begin();hi!=h.end();) { if(!(*hi).locModPtr->IsUpToDate()) { delete (*hi).locModPtr; *hi=h.back(); if(&*hi==&h.back()) { hi=h.end(); h.pop_back(); break; } h.pop_back(); continue; } ++hi; } // printf("\nReduced heap from %7i to %7i (fn %7i) in %7.2f \n",sz,h.size(),m.fn,float(clock()-t0)/CLOCKS_PER_SEC); make_heap(h.begin(),h.end()); } ///initialize for all vertex the temporary mark must call only at the start of decimation ///by default it takes the first element in the heap and calls Init (static funcion) of that type ///of local modification. template void Init() { vcg::tri::InitVertexIMark(m); // The expected size of heap depends on the type of the local modification we are using.. HeapSimplexRatio = LocalModificationType::HeapSimplexRatio(pp); LocalModificationType::Init(m,h,pp); std::make_heap(h.begin(),h.end()); if(!h.empty()) currMetric=h.front().pri; } template void Finalize() { LocalModificationType::Finalize(m,h,pp); } /// say if the process is to end or not: the process ends when any of the termination conditions is verified /// override this function to implemetn other tests bool GoalReached(){ if ( IsTerminationFlag(LOnSimplices) && ( m.SimplexNumber()<= nTargetSimplices)) return true; if ( IsTerminationFlag(LOnVertices) && ( m.VertexNumber() <= nTargetVertices)) return true; if ( IsTerminationFlag(LOnOps) && (nPerformedOps == nTargetOps)) return true; if ( IsTerminationFlag(LOMetric) && ( currMetric > targetMetric)) return true; if ( IsTerminationFlag(LOTime) ) { clock_t cur = clock(); if(cur timeBudget) return true; } return false; } };//end class decimation }//end namespace #endif