First checkin for OpenMesh 2.0

git-svn-id: http://www.openmesh.org/svnrepo/OpenMesh/trunk@2 fdac6126-5c0c-442c-9429-916003d36597
This commit is contained in:
Jan Möbius
2009-02-06 13:37:46 +00:00
parent c3321ebdd9
commit 97f515985d
417 changed files with 76182 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
#== SYSTEM PART -- DON'T TOUCH ==============================================
include $(ACGMAKE)/Config
#==============================================================================
SUBDIRS = $(call find-subdirs)
PACKAGES := opensg boost
PROJ_LIBS := OpenMesh/Core
MODULES := cxxlib
#== SYSTEM PART -- DON'T TOUCH ==============================================
include $(ACGMAKE)/Rules
#==============================================================================

View File

@@ -0,0 +1,168 @@
//=============================================================================
//
// OpenMesh
// Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
// www.openmesh.org
//
//-----------------------------------------------------------------------------
//
// License
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, version 2.1.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//-----------------------------------------------------------------------------
//
// $Revision: 1802 $
// $Date: 2008-05-19 11:55:07 +0200 (Mo, 19. Mai 2008) $
//
//=============================================================================
/** \file CollapseInfoT.hh
Provides data class CollapseInfoT for storing all information
about a halfedge collapse.
*/
//=============================================================================
//
// STRUCT CollpaseInfoT
//
//=============================================================================
#ifndef OPENMESH_DECIMATER_COLLAPSEINFOT_HH
#define OPENMESH_DECIMATER_COLLAPSEINFOT_HH
//== INCLUDES =================================================================
//== NAMESPACE ================================================================
namespace OpenMesh {
namespace Decimater {
//== CLASS DEFINITION =========================================================
/** Stores information about a halfedge collapse.
The class stores information about a halfedge collapse. The most
important information is \c v0v1, \c v1v0, \c v0, \c v1, \c vl,
\c vr, which you can lookup in the following image:
\image html collapse_info.png
\see ModProgMeshT::Info
*/
template <class Mesh>
struct CollapseInfoT
{
public:
/** Initializing constructor.
*
* Given a mesh and a halfedge handle of the halfedge to be collapsed
* all important information of a halfedge collapse will be stored.
* \param _mesh Mesh source
* \param _heh Halfedge to collapse. The direction of the halfedge
* defines the direction of the collapse, i.e. the from-vertex
* will be removed and the to-vertex remains.
*/
CollapseInfoT(Mesh& _mesh, typename Mesh::HalfedgeHandle _heh);
Mesh& mesh;
typename Mesh::HalfedgeHandle v0v1; ///< Halfedge to be collapsed
typename Mesh::HalfedgeHandle v1v0; ///< Reverse halfedge
typename Mesh::VertexHandle v0; ///< Vertex to be removed
typename Mesh::VertexHandle v1; ///< Remaining vertex
typename Mesh::Point p0; ///< Position of removed vertex
typename Mesh::Point p1; ///< Positions of remaining vertex
typename Mesh::FaceHandle fl; ///< Left face
typename Mesh::FaceHandle fr; ///< Right face
typename Mesh::VertexHandle vl; ///< Left vertex
typename Mesh::VertexHandle vr; ///< Right vertex
//@{
/** Outer remaining halfedge of diamond spanned by \c v0, \c v1,
* \c vl, and \c vr
*/
typename Mesh::HalfedgeHandle vlv1, v0vl, vrv0, v1vr;
//@}
};
//-----------------------------------------------------------------------------
// CollapseInfoT::CollapseInfoT( _mesh, _heh )
//
// Local configuration of halfedge collapse to be stored in CollapseInfoT:
/*
vl
*
/ \
/ \
/ fl \
v0 *------>* v1
\ fr /
\ /
\ /
*
vr
*/
// Parameters:
// _mesh Reference to mesh
// _heh The halfedge (v0 -> v1) defining the collapse
//
template <class Mesh>
inline
CollapseInfoT<Mesh>::
CollapseInfoT(Mesh& _mesh, typename Mesh::HalfedgeHandle _heh) :
mesh(_mesh),
v0v1(_heh),
v1v0(_mesh.opposite_halfedge_handle(v0v1)),
v0(_mesh.to_vertex_handle(v1v0)),
v1(_mesh.to_vertex_handle(v0v1)),
p0(_mesh.point(v0)),
p1(_mesh.point(v1)),
fl(_mesh.face_handle(v0v1)),
fr(_mesh.face_handle(v1v0))
{
// get vl
if (fl.is_valid())
{
vlv1 = mesh.next_halfedge_handle(v0v1);
v0vl = mesh.next_halfedge_handle(vlv1);
vl = mesh.to_vertex_handle(vlv1);
vlv1 = mesh.opposite_halfedge_handle(vlv1);
v0vl = mesh.opposite_halfedge_handle(v0vl);
}
// get vr
if (fr.is_valid())
{
vrv0 = mesh.next_halfedge_handle(v1v0);
v1vr = mesh.next_halfedge_handle(vrv0);
vr = mesh.to_vertex_handle(vrv0);
vrv0 = mesh.opposite_halfedge_handle(vrv0);
v1vr = mesh.opposite_halfedge_handle(v1vr);
}
}
//=============================================================================
} // END_NS_DECIMATER
} // END_NS_OPENMESH
//=============================================================================
#endif // OPENMESH_DECIMATER_COLLAPSEINFOT_HH defined
//=============================================================================

View File

@@ -0,0 +1,489 @@
//=============================================================================
//
// OpenMesh
// Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
// www.openmesh.org
//
//-----------------------------------------------------------------------------
//
// License
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, version 2.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//-----------------------------------------------------------------------------
//
// $Revision: 2317 $
// $Date: 2008-07-24 15:32:54 +0200 (Do, 24. Jul 2008) $
//
//=============================================================================
/** \file DecimaterT.cc
*/
//=============================================================================
//
// CLASS DecimaterT - IMPLEMENTATION
//
//=============================================================================
#define OPENMESH_DECIMATER_DECIMATERT_CC
//== INCLUDES =================================================================
#include <OpenMesh/Tools/Decimater/DecimaterT.hh>
#include <vector>
#if defined(OM_CC_MIPS)
# include <float.h>
#else
# include <cfloat>
#endif
//== NAMESPACE ===============================================================
namespace OpenMesh {
namespace Decimater {
//== IMPLEMENTATION ==========================================================
template <class Mesh>
DecimaterT<Mesh>::
DecimaterT( Mesh& _mesh )
: mesh_(_mesh),
heap_(NULL),
cmodule_(NULL),
initialized_(false)
{
// default properties
mesh_.request_vertex_status();
mesh_.request_edge_status();
mesh_.request_face_status();
mesh_.request_face_normals();
// private vertex properties
mesh_.add_property( collapse_target_ );
mesh_.add_property( priority_ );
mesh_.add_property( heap_position_ );
}
//-----------------------------------------------------------------------------
template <class Mesh>
DecimaterT<Mesh>::
~DecimaterT()
{
// default properties
mesh_.release_vertex_status();
mesh_.release_edge_status();
mesh_.release_face_status();
mesh_.release_face_normals();
// private vertex properties
mesh_.remove_property(collapse_target_);
mesh_.remove_property(priority_);
mesh_.remove_property(heap_position_);
// dispose modules
{
typename ModuleList::iterator m_it, m_end = bmodules_.end();
for( m_it=bmodules_.begin(); m_it!=m_end; ++m_it)
delete *m_it;
bmodules_.clear();
if (cmodule_)
delete cmodule_;
}
}
//-----------------------------------------------------------------------------
template <class Mesh>
void
DecimaterT<Mesh>::
info( std::ostream& _os )
{
typename ModuleList::iterator m_it, m_end = bmodules_.end();
_os << "binary modules: " << bmodules_.size() << std::endl;
for( m_it=bmodules_.begin(); m_it!=m_end; ++m_it)
_os << " " << (*m_it)->name() << std::endl;
_os << "priority module: "
<< (cmodule_ ? cmodule_->name().c_str() : "<None>") << std::endl;
_os << "is initialized : " << (initialized_ ? "yes" : "no") << std::endl;
}
//-----------------------------------------------------------------------------
template <class Mesh>
bool
DecimaterT<Mesh>::
initialize()
{
typename ModuleList::iterator m_it, m_end = bmodules_.end();
Module *quadric=NULL;
Module* origC = NULL;
// If already initialized, remember original cModule (priority module)
// if no new cmodule is provided use old one
if (initialized_)
origC = cmodule_;
cmodule_ = NULL;
for (m_it=bmodules_.begin(); m_it != m_end; ++m_it)
{
if ( (*m_it)->name() == "Quadric")
quadric = *m_it;
if ( ! (*m_it)->is_binary() )
{
if ( !cmodule_ ) // only one non-binary module allowed!
cmodule_ = *m_it;
else
return false;
}
(*m_it)->initialize();
}
// If the decimater has already been initialized and we have no new cmodule,
// use the old cmodule
if ( initialized_ && !cmodule_ ) {
cmodule_ = origC;
cmodule_->initialize();
}
if (!cmodule_) // one non-binary module is mandatory!
{
if (!quadric)
return false;
else
{
cmodule_ = quadric; // let the quadric become the priority module
}
}
// If we do not reuse the original cmodule delete the new cmodule from the
// binary module list
if ( !initialized_ || (cmodule_ != origC) ) {
m_it = std::find(bmodules_.begin(), bmodules_.end(), cmodule_ );
bmodules_.erase( m_it );
}
return initialized_ = true;
}
//-----------------------------------------------------------------------------
template <class Mesh>
bool
DecimaterT<Mesh>::is_collapse_legal(const CollapseInfo& _ci)
{
// std::clog << "DecimaterT<>::is_collapse_legal()\n";
// locked ? deleted ?
if (mesh_.status(_ci.v0).locked() ||
mesh_.status(_ci.v0).deleted())
return false;
/*
if (!mesh_.is_collapse_ok(_ci.v0v1))
{
return false;
}
*/
if (_ci.vl.is_valid() && _ci.vr.is_valid() &&
mesh_.find_halfedge(_ci.vl, _ci.vr).is_valid() &&
mesh_.valence(_ci.vl) == 3 && mesh_.valence(_ci.vr) == 3)
{
return false;
}
//--- feature test ---
if (mesh_.status(_ci.v0).feature() &&
!mesh_.status(mesh_.edge_handle(_ci.v0v1)).feature())
return false;
//--- test one ring intersection ---
typename Mesh::VertexVertexIter vv_it;
for (vv_it = mesh_.vv_iter(_ci.v0); vv_it; ++vv_it)
mesh_.status(vv_it).set_tagged(false);
for (vv_it = mesh_.vv_iter(_ci.v1); vv_it; ++vv_it)
mesh_.status(vv_it).set_tagged(true);
for (vv_it = mesh_.vv_iter(_ci.v0); vv_it; ++vv_it)
if (mesh_.status(vv_it).tagged() &&
vv_it.handle() != _ci.vl &&
vv_it.handle() != _ci.vr)
return false;
// if both are invalid OR equal -> fail
if (_ci.vl == _ci.vr) return false;
//--- test boundary cases ---
if (mesh_.is_boundary(_ci.v0))
{
if (!mesh_.is_boundary(_ci.v1))
{// don't collapse a boundary vertex to an inner one
return false;
}
else
{// edge between two boundary vertices has to be a boundary edge
if (!(mesh_.is_boundary(_ci.v0v1) || mesh_.is_boundary(_ci.v1v0)))
return false;
}
// only one one ring intersection
if (_ci.vl.is_valid() && _ci.vr.is_valid())
return false;
}
// v0vl and v1vl must not both be boundary edges
if (_ci.vl.is_valid() &&
mesh_.is_boundary(_ci.vlv1) &&
mesh_.is_boundary(_ci.v0v1))
return false;
// v0vr and v1vr must not be both boundary edges
if (_ci.vr.is_valid() &&
mesh_.is_boundary(_ci.vrv0) &&
mesh_.is_boundary(_ci.v1vr))
return false;
// there have to be at least 2 incident faces at v0
if (mesh_.cw_rotated_halfedge_handle(
mesh_.cw_rotated_halfedge_handle(_ci.v0v1)) == _ci.v0v1)
return false;
// collapse passed all tests -> ok
return true;
}
//-----------------------------------------------------------------------------
template <class Mesh>
float
DecimaterT<Mesh>::collapse_priority(const CollapseInfo& _ci)
{
typename ModuleList::iterator m_it, m_end = bmodules_.end();
for (m_it = bmodules_.begin(); m_it != m_end; ++m_it)
{
if ( (*m_it)->collapse_priority(_ci) < 0.0)
return -1.0; // ILLEGAL_COLLAPSE
}
return cmodule_->collapse_priority(_ci);
}
//-----------------------------------------------------------------------------
template <class Mesh>
void
DecimaterT<Mesh>::heap_vertex(VertexHandle _vh)
{
// std::clog << "heap_vertex: " << _vh << std::endl;
float prio, best_prio(FLT_MAX);
typename Mesh::HalfedgeHandle heh, collapse_target;
// find best target in one ring
typename Mesh::VertexOHalfedgeIter voh_it(mesh_, _vh);
for (; voh_it; ++voh_it)
{
heh = voh_it.handle();
CollapseInfo ci(mesh_, heh);
if (is_collapse_legal(ci))
{
prio = collapse_priority(ci);
if (prio >= 0.0 && prio < best_prio)
{
best_prio = prio;
collapse_target = heh;
}
}
}
// target found -> put vertex on heap
if (collapse_target.is_valid())
{
// std::clog << " added|updated" << std::endl;
mesh_.property(collapse_target_, _vh) = collapse_target;
mesh_.property(priority_, _vh) = best_prio;
if (heap_->is_stored(_vh)) heap_->update(_vh);
else heap_->insert(_vh);
}
// not valid -> remove from heap
else
{
// std::clog << " n/a|removed" << std::endl;
if (heap_->is_stored(_vh)) heap_->remove(_vh);
mesh_.property(collapse_target_, _vh) = collapse_target;
mesh_.property(priority_, _vh) = -1;
}
}
//-----------------------------------------------------------------------------
template <class Mesh>
void
DecimaterT<Mesh>::
postprocess_collapse(CollapseInfo& _ci)
{
typename ModuleList::iterator m_it, m_end = bmodules_.end();
for (m_it = bmodules_.begin(); m_it != m_end; ++m_it)
(*m_it)->postprocess_collapse(_ci);
cmodule_->postprocess_collapse(_ci);
}
//-----------------------------------------------------------------------------
template <class Mesh>
size_t
DecimaterT<Mesh>::decimate( size_t _n_collapses )
{
if ( !is_initialized() )
return 0;
typename Mesh::VertexIter v_it, v_end(mesh_.vertices_end());
typename Mesh::VertexHandle vp;
typename Mesh::HalfedgeHandle v0v1;
typename Mesh::VertexVertexIter vv_it;
typename Mesh::VertexFaceIter vf_it;
unsigned int n_collapses(0);
typedef std::vector<typename Mesh::VertexHandle> Support;
typedef typename Support::iterator SupportIterator;
Support support(15);
SupportIterator s_it, s_end;
// check _n_collapses
if (!_n_collapses) _n_collapses = mesh_.n_vertices();
// initialize heap
HeapInterface HI(mesh_, priority_, heap_position_);
heap_ = std::auto_ptr<DeciHeap>(new DeciHeap(HI));
heap_->reserve(mesh_.n_vertices());
for (v_it = mesh_.vertices_begin(); v_it != v_end; ++v_it)
{
heap_->reset_heap_position( v_it.handle() );
if (!mesh_.status(v_it).deleted())
heap_vertex( v_it.handle() );
}
// process heap
while ((!heap_->empty()) && (n_collapses < _n_collapses))
{
// get 1st heap entry
vp = heap_->front();
v0v1 = mesh_.property(collapse_target_, vp);
heap_->pop_front();
// setup collapse info
CollapseInfo ci(mesh_, v0v1);
// check topological correctness AGAIN !
if (!is_collapse_legal(ci))
continue;
// store support (= one ring of *vp)
vv_it = mesh_.vv_iter(ci.v0);
support.clear();
for (; vv_it; ++vv_it)
support.push_back(vv_it.handle());
// perform collapse
mesh_.collapse(v0v1);
++n_collapses;
// update triangle normals
vf_it = mesh_.vf_iter(ci.v1);
for (; vf_it; ++vf_it)
if (!mesh_.status(vf_it).deleted())
mesh_.set_normal(vf_it, mesh_.calc_face_normal(vf_it.handle()));
// post-process collapse
postprocess_collapse(ci);
// update heap (former one ring of decimated vertex)
for (s_it = support.begin(), s_end = support.end();
s_it != s_end; ++s_it)
{
assert(!mesh_.status(*s_it).deleted());
heap_vertex(*s_it);
}
}
// delete heap
heap_.reset();
// DON'T do garbage collection here! It's up to the application.
return n_collapses;
}
//=============================================================================
} // END_NS_DECIMATER
} // END_NS_OPENMESH
//=============================================================================

View File

@@ -0,0 +1,282 @@
//=============================================================================
//
// OpenMesh
// Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
// www.openmesh.org
//
//-----------------------------------------------------------------------------
//
// License
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, version 2.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//-----------------------------------------------------------------------------
//
// $Revision: 1802 $
// $Date: 2008-05-19 11:55:07 +0200 (Mo, 19. Mai 2008) $
//
//=============================================================================
/** \file DecimaterT.hh
*/
//=============================================================================
//
// CLASS DecimaterT
//
//=============================================================================
#ifndef OPENMESH_DECIMATER_DECIMATERT_HH
#define OPENMESH_DECIMATER_DECIMATERT_HH
//== INCLUDES =================================================================
#include <memory>
#include <OpenMesh/Core/Utils/Property.hh>
#include <OpenMesh/Tools/Utils/HeapT.hh>
#include <OpenMesh/Tools/Decimater/ModBaseT.hh>
//== NAMESPACE ================================================================
namespace OpenMesh {
namespace Decimater {
//== CLASS DEFINITION =========================================================
/** Decimater framework.
\see BaseModT, \ref decimater_docu
*/
template < typename MeshT >
class DecimaterT
{
public: //-------------------------------------------------------- public types
typedef DecimaterT< MeshT > Self;
typedef MeshT Mesh;
typedef CollapseInfoT<MeshT> CollapseInfo;
typedef ModBaseT<Self> Module;
typedef std::vector< Module* > ModuleList;
public: //------------------------------------------------------ public methods
/// Constructor
DecimaterT( Mesh& _mesh );
/// Destructor
~DecimaterT();
/** Initialize decimater and decimating modules.
Return values:
true ok
false No ore more than one non-binary module exist. In that case
the decimater is uninitialized!
*/
bool initialize();
/// Returns whether decimater has been successfully initialized.
bool is_initialized() const { return initialized_; }
/// Print information about modules to _os
void info( std::ostream& _os );
public: //--------------------------------------------------- module management
/// access mesh. used in modules.
Mesh& mesh() { return mesh_; }
/// add module to decimater
template < typename _Module >
bool add( ModHandleT<_Module>& _mh )
{
if (_mh.is_valid())
return false;
_mh.init( new _Module(*this) );
bmodules_.push_back( _mh.module() );
initialized_ = false;
return true;
}
/// remove module
template < typename _Module >
bool remove( ModHandleT<_Module>& _mh )
{
if (!_mh.is_valid())
return false;
typename ModuleList::iterator it = std::find(bmodules_.begin(),
bmodules_.end(),
_mh.module() );
if ( it == bmodules_.end() ) // module not found
return false;
delete *it;
bmodules_.erase( it ); // finally remove from list
_mh.clear();
initialized_ = false; // reset initialized state
return true;
}
/// get module referenced by handle _mh
template < typename Module >
Module& module( ModHandleT<Module>& _mh )
{
assert( _mh.is_valid() );
return *_mh.module();
}
public:
/** Decimate (perform _n_collapses collapses). Return number of
performed collapses. If _n_collapses is not given reduce as
much as possible */
size_t decimate( size_t _n_collapses = 0 );
/// Decimate to target complexity, returns number of collapses
size_t decimate_to( size_t _n_vertices )
{
return ( (_n_vertices < mesh().n_vertices()) ?
decimate( mesh().n_vertices() - _n_vertices ) : 0 );
}
private:
void update_modules(CollapseInfo& _ci)
{
typename ModuleList::iterator m_it, m_end = bmodules_.end();
for (m_it = bmodules_.begin(); m_it != m_end; ++m_it)
(*m_it)->postprocess_collapse(_ci);
cmodule_->postprocess_collapse(_ci);
}
public:
typedef typename Mesh::VertexHandle VertexHandle;
typedef typename Mesh::HalfedgeHandle HalfedgeHandle;
/// Heap interface
class HeapInterface
{
public:
HeapInterface(Mesh& _mesh,
VPropHandleT<float> _prio,
VPropHandleT<int> _pos)
: mesh_(_mesh), prio_(_prio), pos_(_pos)
{ }
inline bool
less( VertexHandle _vh0, VertexHandle _vh1 )
{ return mesh_.property(prio_, _vh0) < mesh_.property(prio_, _vh1); }
inline bool
greater( VertexHandle _vh0, VertexHandle _vh1 )
{ return mesh_.property(prio_, _vh0) > mesh_.property(prio_, _vh1); }
inline int
get_heap_position(VertexHandle _vh)
{ return mesh_.property(pos_, _vh); }
inline void
set_heap_position(VertexHandle _vh, int _pos)
{ mesh_.property(pos_, _vh) = _pos; }
private:
Mesh& mesh_;
VPropHandleT<float> prio_;
VPropHandleT<int> pos_;
};
typedef Utils::HeapT<VertexHandle, HeapInterface> DeciHeap;
private: //---------------------------------------------------- private methods
/// Insert vertex in heap
void heap_vertex(VertexHandle _vh);
/// Is an edge collapse legal? Performs topological test only.
/// The method evaluates the status bit Locked, Deleted, and Feature.
/// \attention The method temporarily sets the bit Tagged. After usage
/// the bit will be disabled!
bool is_collapse_legal(const CollapseInfo& _ci);
/// Calculate priority of an halfedge collapse (using the modules)
float collapse_priority(const CollapseInfo& _ci);
/// Post-process a collapse
void postprocess_collapse(CollapseInfo& _ci);
private: //------------------------------------------------------- private data
// reference to mesh
Mesh& mesh_;
// heap
std::auto_ptr<DeciHeap> heap_;
// list of modules
ModuleList bmodules_;
Module* cmodule_;
bool initialized_;
// vertex properties
VPropHandleT<HalfedgeHandle> collapse_target_;
VPropHandleT<float> priority_;
VPropHandleT<int> heap_position_;
private: // Noncopyable
DecimaterT(const Self&);
Self& operator = (const Self&);
};
//=============================================================================
} // END_NS_DECIMATER
} // END_NS_OPENMESH
//=============================================================================
#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_DECIMATER_DECIMATERT_CC)
#define OPENMESH_DECIMATER_TEMPLATES
#include "DecimaterT.cc"
#endif
//=============================================================================
#endif // OPENMESH_DECIMATER_DECIMATERT_HH defined
//=============================================================================

266
Tools/Decimater/ModBaseT.hh Normal file
View File

@@ -0,0 +1,266 @@
//=============================================================================
//
// OpenMesh
// Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
// www.openmesh.org
//
//-----------------------------------------------------------------------------
//
// License
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, version 2.1.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//-----------------------------------------------------------------------------
//
// $Revision: 1802 $
// $Date: 2008-05-19 11:55:07 +0200 (Mo, 19. Mai 2008) $
//
//=============================================================================
/** \file ModBaseT.hh
Base class for all decimation modules.
*/
//=============================================================================
//
// CLASS ModBaseT
//
//=============================================================================
#ifndef OPENMESH_DECIMATER_MODBASET_HH
#define OPENMESH_DECIMATER_MODBASET_HH
//== INCLUDES =================================================================
#include <OpenMesh/Core/Utils/Noncopyable.hh>
#include <OpenMesh/Tools/Decimater/CollapseInfoT.hh>
#include <string>
//== NAMESPACE ================================================================
namespace OpenMesh {
namespace Decimater {
//== FORWARD DECLARATIONS =====================================================
template <typename Mesh> class DecimaterT;
//== CLASS DEFINITION =========================================================
/** Handle for mesh decimation modules
\internal
*/
template <typename Module>
class ModHandleT : private Utils::Noncopyable
{
public:
typedef ModHandleT<Module> Self;
typedef Module module_type;
public:
/// Default constructor
ModHandleT() : mod_(NULL) {}
/// Destructor
~ModHandleT() { /* don't delete mod_, since handle is not owner! */ }
/// Check handle status
/// \return \c true, if handle is valid, else \c false.
bool is_valid() const { return mod_ != NULL; }
private:
#if defined(OM_CC_MSVC)
friend class DecimaterT;
#else
template <typename Mesh> friend class DecimaterT;
#endif
void clear() { mod_ = NULL; }
void init(Module* _m) { mod_ = _m; }
Module* module() { return mod_; }
private:
Module* mod_;
};
//== CLASS DEFINITION =========================================================
/// Macro that sets up the name() function
/// \internal
#define DECIMATER_MODNAME(_mod_name) \
virtual const std::string& name() const { \
static std::string _s_modname_(#_mod_name); return _s_modname_; \
}
/** Convenience macro, to be used in derived modules
* The macro defines the types
* - \c Handle, type of the module's handle.
* - \c Base, type of ModBaseT<>.
* - \c Mesh, type of the associated mesh passed by the decimater type.
* - \c CollapseInfo, to your convenience
* and uses DECIMATER_MODNAME() to define the name of the module.
*
* \param Classname The name of the derived class.
* \param DecimaterT Pass here the decimater type, which is the
* template parameter passed to ModBaseT.
* \param Name Give the module a name.
*/
#define DECIMATING_MODULE(Classname, DecimaterT, Name) \
typedef Classname < DecimaterT > Self; \
typedef OpenMesh::Decimater::ModHandleT< Self > Handle; \
typedef OpenMesh::Decimater::ModBaseT< DecimaterT > Base; \
typedef typename Base::Mesh Mesh; \
typedef typename Base::CollapseInfo CollapseInfo; \
DECIMATER_MODNAME( Name )
//== CLASS DEFINITION =========================================================
/** Base class for all decimation modules.
Each module has to implement this interface.
To build your own module you have to
-# derive from this class.
-# create the basic settings with DECIMATING_MODULE().
-# override collapse_priority(), if necessary.
-# override initialize(), if necessary.
-# override postprocess_collapse(), if necessary.
A module has two major working modes:
-# binary mode
-# non-binary mode
In the binary mode collapse_priority() checks a constraint and
returns LEGAL_COLLAPSE or ILLEGAL_COLLAPSE.
In the non-binary mode the module computes a float error value in
the range [0, inf) and returns it. In the case a constraint has
been set, e.g. the error must be lower than a upper bound, and the
constraint is violated, collapse_priority() must return
ILLEGAL_COLLAPSE.
\see collapse_priority()
\todo "Tutorial on building a custom decimation module."
*/
template <typename DecimaterType>
class ModBaseT
{
public:
typedef typename DecimaterType::Mesh Mesh;
typedef CollapseInfoT<Mesh> CollapseInfo;
enum {
ILLEGAL_COLLAPSE = -1, ///< indicates an illegal collapse
LEGAL_COLLAPSE = 0 ///< indicates a legal collapse
};
protected:
/// Default constructor
/// \see \ref decimater_docu
ModBaseT(DecimaterType& _dec, bool _is_binary)
: dec_(_dec), is_binary_(_is_binary) {}
public:
/// Virtual desctructor
virtual ~ModBaseT() { }
/// Set module's name (using DECIMATER_MODNAME macro)
DECIMATER_MODNAME(ModBase);
/// Returns true if criteria returns a binary value.
bool is_binary(void) const { return is_binary_; }
/// Set whether module is binary or not.
void set_binary(bool _b) { is_binary_ = _b; }
public: // common interface
/// Initialize module-internal stuff
virtual void initialize() { }
/** Return collapse priority.
*
* In the binary mode collapse_priority() checks a constraint and
* returns LEGAL_COLLAPSE or ILLEGAL_COLLAPSE.
*
* In the non-binary mode the module computes a float error value in
* the range [0, inf) and returns it. In the case a constraint has
* been set, e.g. the error must be lower than a upper bound, and the
* constraint is violated, collapse_priority() must return
* ILLEGAL_COLLAPSE.
*
* \return Collapse priority in the range [0,inf),
* \c LEGAL_COLLAPSE or \c ILLEGAL_COLLAPSE.
*/
virtual float collapse_priority(const CollapseInfoT<Mesh>& /* _ci */)
{ return LEGAL_COLLAPSE; }
/** After _from_vh has been collapsed into _to_vh, this method
will be called.
*/
virtual void postprocess_collapse(const CollapseInfoT<Mesh>& /* _ci */)
{}
protected:
/// Access the mesh associated with the decimater.
Mesh& mesh() { return dec_.mesh(); }
private:
// hide copy constructor & assignemnt
ModBaseT(const ModBaseT& _cpy);
ModBaseT& operator=(const ModBaseT& );
// reference to decimater
DecimaterType &dec_;
bool is_binary_;
};
//=============================================================================
} // namespace Decimater
} // namespace OpenMesh
//=============================================================================
#endif // OPENMESH_DECIMATER_MODBASE_HH defined
//=============================================================================

View File

@@ -0,0 +1,97 @@
//=============================================================================
//
// OpenMesh
// Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
// www.openmesh.org
//
//-----------------------------------------------------------------------------
//
// License
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, version 2.1.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//-----------------------------------------------------------------------------
//
// $Revision: 1802 $
// $Date: 2008-05-19 11:55:07 +0200 (Mo, 19. Mai 2008) $
//
//=============================================================================
/** \file ModQuadricT.hh
*/
//=============================================================================
//
// CLASS ModQuadricT
//
//=============================================================================
#ifndef OPENMESH_TOOLS_MODINDEPENDENTSETST_HH
#define OPENMESH_TOOLS_MODINDEPENDENTSETST_HH
//== INCLUDES =================================================================
#include <OpenMesh/Tools/Decimater/ModBaseT.hh>
//== NAMESPACE ================================================================
namespace OpenMesh { // BEGIN_NS_OPENMESH
namespace Decimater { // BEGIN_NS_DECIMATER
//== CLASS DEFINITION =========================================================
/** Lock one-ring around remaining vertex after a collapse to prevent
* further collapses of halfedges incident to the one-ring vertices.
*/
template <class DecimaterType>
class ModIndependentSetsT : public ModBaseT<DecimaterType>
{
public:
DECIMATING_MODULE( ModIndependentSetsT, DecimaterType, IndependentSets );
/// Constructor
ModIndependentSetsT( DecimaterType &_dec ) : Base(_dec, true) {}
/// override
void postprocess_collapse(const CollapseInfo& _ci)
{
typename Mesh::VertexVertexIter vv_it;
Base::mesh().status(_ci.v1).set_locked(true);
vv_it = Base::mesh().vv_iter(_ci.v1);
for (; vv_it; ++vv_it)
Base::mesh().status(vv_it).set_locked(true);
}
private:
/// hide this method
void set_binary(bool _b) {}
};
//=============================================================================
} // END_NS_DECIMATER
} // END_NS_OPENMESH
//=============================================================================
#endif // OPENMESH_TOOLS_MODINDEPENDENTSETST_HH defined
//=============================================================================

View File

@@ -0,0 +1,175 @@
//=============================================================================
//
// OpenMesh
// Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
// www.openmesh.org
//
//-----------------------------------------------------------------------------
//
// License
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, version 2.1.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//-----------------------------------------------------------------------------
//
// $Revision: 1802 $
// $Date: 2008-05-19 11:55:07 +0200 (Mo, 19. Mai 2008) $
//
//=============================================================================
/** \file ModNormalFlippingT.hh
*/
//=============================================================================
//
// CLASS ModNormalFlipping
//
//=============================================================================
#ifndef OPENMESH_DECIMATER_MODNORMALFLIPPING_HH
#define OPENMESH_DECIMATER_MODNORMALFLIPPING_HH
//== INCLUDES =================================================================
#include <OpenMesh/Tools/Decimater/ModBaseT.hh>
//== NAMESPACES ===============================================================
namespace OpenMesh { // BEGIN_NS_OPENMESH
namespace Decimater { // BEGIN_NS_DECIMATER
//== CLASS DEFINITION =========================================================
/** Decimating module to avoid flipping of faces.
*
* This module can be used only as a binary module. The criterion
* of allowing/disallowing the collapse is the angular deviation between
* the face normal of the orignal faces and normals of the faces after the
* collapse. The collapse will pass the test, if the deviation is below
* a given threshold.
*/
template <typename DecimaterT>
class ModNormalFlippingT : public ModBaseT< DecimaterT >
{
public:
DECIMATING_MODULE( ModNormalFlippingT, DecimaterT, NormalFlipping );
public:
/// Constructor
ModNormalFlippingT( DecimaterT &_dec) : Base(_dec, true)
{
set_max_normal_deviation( 90.0f );
}
~ModNormalFlippingT()
{ }
public:
/** Compute collapse priority due to angular deviation of face normals
* before and after a collapse.
*
* -# Compute for each adjacent face of \c _ci.v0 the face
* normal if the collpase would be executed.
*
* -# Prevent the collapse, if the angle between the original and the
* new normal is below a given threshold.
*
* \param _ci The collapse description
* \return LEGAL_COLLAPSE or ILLEGAL_COLLAPSE
*
* \see set_max_normal_deviation()
*/
float collapse_priority(const CollapseInfo& _ci)
{
// simulate collapse
Base::mesh().set_point(_ci.v0, _ci.p1);
// check for flipping normals
typename Mesh::ConstVertexFaceIter vf_it(Base::mesh(), _ci.v0);
typename Mesh::FaceHandle fh;
typename Mesh::Scalar c(1.0);
for (; vf_it; ++vf_it)
{
fh = vf_it.handle();
if (fh != _ci.fl && fh != _ci.fr)
{
typename Mesh::Normal n1 = Base::mesh().normal(fh);
typename Mesh::Normal n2 = Base::mesh().calc_face_normal(fh);
c = dot(n1, n2);
if (c < min_cos_)
break;
}
}
// undo simulation changes
Base::mesh().set_point(_ci.v0, _ci.p0);
return float( (c < min_cos_) ? Base::ILLEGAL_COLLAPSE : Base::LEGAL_COLLAPSE );
}
public:
/// get normal deviation
float max_normal_deviation() const { return max_deviation_ / M_PI * 180.0; }
/// \deprecated
float normal_deviation() const { return max_normal_deviation(); }
/** Set normal deviation
*
* Set the maximum angular deviation of the orignal normal and the new
* normal in degrees.
*/
void set_max_normal_deviation(float _f) {
max_deviation_ = _f / 180.0 * M_PI;
min_cos_ = cos(max_deviation_);
}
/// \deprecated
void set_normal_deviation(float _f)
{ set_max_normal_deviation(_f); }
private:
// hide this method
void set_binary(bool _b) {}
private:
// maximum normal deviation
double max_deviation_, min_cos_;
};
//=============================================================================
} // END_NS_DECIMATER
} // END_NS_OPENMESH
//=============================================================================
#endif // OPENACG_MODNORMALFLIPPING_HH defined
//=============================================================================

View File

@@ -0,0 +1,173 @@
//=============================================================================
//
// OpenMesh
// Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
// www.openmesh.org
//
//-----------------------------------------------------------------------------
//
// License
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, version 2.1.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//-----------------------------------------------------------------------------
//
// $Revision: 1802 $
// $Date: 2008-05-19 11:55:07 +0200 (Mo, 19. Mai 2008) $
//
//=============================================================================
/** \file ModProgMeshT.cc
*/
//=============================================================================
//
// CLASS ModProgMeshT - IMPLEMENTATION
//
//=============================================================================
#define OPENMESH_DECIMATER_MODPROGMESH_CC
//== INCLUDES =================================================================
#include <vector>
#include <fstream>
// --------------------
#include <OpenMesh/Core/Utils/vector_cast.hh>
#include <OpenMesh/Core/IO/BinaryHelper.hh>
#include <OpenMesh/Core/Utils/Endian.hh>
// --------------------
#include <OpenMesh/Tools/Decimater/ModProgMeshT.hh>
//== NAMESPACE ===============================================================
namespace OpenMesh {
namespace Decimater {
//== IMPLEMENTATION ==========================================================
template <class DecimaterType>
bool
ModProgMeshT<DecimaterType>::
write( const std::string& _ofname )
{
// sort vertices
size_t i=0, N=Base::mesh().n_vertices(), n_base_vertices(0), n_base_faces(0);
std::vector<typename Mesh::VertexHandle> vhandles(N);
// base vertices
typename Mesh::VertexIter
v_it=Base::mesh().vertices_begin(),
v_end=Base::mesh().vertices_end();
for (; v_it != v_end; ++v_it)
if (!Base::mesh().status(v_it).deleted())
{
vhandles[i] = v_it.handle();
Base::mesh().property( idx_, v_it ) = i;
++i;
}
n_base_vertices = i;
// deleted vertices
typename InfoList::reverse_iterator
r_it=pmi_.rbegin(), r_end=pmi_.rend();
for (; r_it!=r_end; ++r_it)
{
vhandles[i] = r_it->v0;
Base::mesh().property( idx_, r_it->v0) = i;
++i;
}
// base faces
typename Mesh::ConstFaceIter f_it = Base::mesh().faces_begin(),
f_end = Base::mesh().faces_end();
for (; f_it != f_end; ++f_it)
if (!Base::mesh().status(f_it).deleted())
++n_base_faces;
// ---------------------------------------- write progressive mesh
std::ofstream out( _ofname.c_str(), std::ios::binary );
if (!out)
return false;
// always use little endian byte ordering
bool swap = Endian::local() != Endian::LSB;
// write header
out << "ProgMesh";
IO::store( out, n_base_vertices, swap );
IO::store( out, n_base_faces , swap );
IO::store( out, pmi_.size() , swap );
Vec3f p;
// write base vertices
for (i=0; i<n_base_vertices; ++i)
{
assert (!Base::mesh().status(vhandles[i]).deleted());
p = vector_cast< Vec3f >( Base::mesh().point(vhandles[i]) );
IO::store( out, p, swap );
}
// write base faces
for (f_it=Base::mesh().faces_begin(); f_it != f_end; ++f_it)
{
if (!Base::mesh().status(f_it).deleted())
{
typename Mesh::ConstFaceVertexIter fv_it(Base::mesh(), f_it.handle());
IO::store( out, Base::mesh().property( idx_, fv_it ) );
IO::store( out, Base::mesh().property( idx_, ++fv_it ) );
IO::store( out, Base::mesh().property( idx_, ++fv_it ) );
}
}
// write detail info
for (r_it=pmi_.rbegin(); r_it!=r_end; ++r_it)
{
// store v0.pos, v1.idx, vl.idx, vr.idx
IO::store( out, vector_cast<Vec3f>(Base::mesh().point(r_it->v0)));
IO::store( out, Base::mesh().property( idx_, r_it->v1 ) );
IO::store( out,
r_it->vl.is_valid() ? Base::mesh().property(idx_, r_it->vl) : -1 );
IO::store( out,
r_it->vr.is_valid() ? Base::mesh().property(idx_, r_it->vr) : -1 );
}
return true;
}
//=============================================================================
} // END_NS_DECIMATER
} // END_NS_OPENMESH
//=============================================================================

View File

@@ -0,0 +1,180 @@
//=============================================================================
//
// OpenMesh
// Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
// www.openmesh.org
//
//-----------------------------------------------------------------------------
//
// License
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, version 2.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//-----------------------------------------------------------------------------
//
// $Revision: 1802 $
// $Date: 2008-05-19 11:55:07 +0200 (Mo, 19. Mai 2008) $
//
//=============================================================================
/** \file ModProgMeshT.hh
*/
//=============================================================================
//
// CLASS ModProgMeshT
//
//=============================================================================
#ifndef OPENMESH_TOOLS_MODPROGMESHT_HH
#define OPENMESH_TOOLS_MODPROGMESHT_HH
//== INCLUDES =================================================================
#include <OpenMesh/Tools/Decimater/ModBaseT.hh>
#include <OpenMesh/Core/Utils/Property.hh>
//== NAMESPACE ================================================================
namespace OpenMesh {
namespace Decimater {
//== CLASS DEFINITION =========================================================
/** Collect progressive mesh information while decimating.
*
* The progressive mesh data is stored in an internal structure, which
* can be evaluated after the decimation process and (!) before calling
* the garbage collection of the decimated mesh.
*/
template <class DecimaterType>
class ModProgMeshT : public ModBaseT<DecimaterType>
{
public:
DECIMATING_MODULE( ModProgMeshT, DecimaterType, ProgMesh );
/** Struct storing progressive mesh information
* \see CollapseInfoT, ModProgMeshT
*/
struct Info
{
/// Initializing constructor copies appropriate handles from
/// collapse information \c _ci.
Info( const CollapseInfo& _ci )
: v0(_ci.v0), v1(_ci.v1), vl(_ci.vl),vr(_ci.vr)
{}
typename Mesh::VertexHandle v0; ///< See CollapseInfoT::v0
typename Mesh::VertexHandle v1; ///< See CollapseInfoT::v1
typename Mesh::VertexHandle vl; ///< See CollapseInfoT::vl
typename Mesh::VertexHandle vr; ///< See CollapseInfoT::vr
};
/// Type of the list storing the progressive mesh info Info.
typedef std::vector<Info> InfoList;
public:
/// Constructor
ModProgMeshT( DecimaterType &_dec ) : Base(_dec, true)
{
Base::mesh().add_property( idx_ );
}
/// Destructor
~ModProgMeshT()
{
Base::mesh().remove_property( idx_ );
}
const InfoList& pmi() const
{
return pmi_;
}
public: // inherited
/// Stores collapse information in a queue.
/// \see infolist()
void postprocess_collapse(const CollapseInfo& _ci)
{
pmi_.push_back( Info( _ci ) );
}
bool is_binary(void) const { return true; }
public: // specific methods
/** Write progressive mesh data to a file in proprietary binary format .pm.
*
* The methods uses the collected data to write a progressive mesh
* file. It's a binary format with little endian byte ordering:
*
* - The first 8 bytes contain the word "ProgMesh".
* - 32-bit int for the number of vertices \c NV in the base mesh.
* - 32-bit int for the number of faces in the base mesh.
* - 32-bit int for the number of halfedge collapses (now vertex splits)
* - Positions of vertices of the base mesh (32-bit float triplets).<br>
* \c [x,y,z][x,y,z]...
* - Triplets of indices (32-bit int) for each triangle (index in the
* list of vertices of the base mesh defined by the positions.<br>
* \c [v0,v1,v2][v0,v1,v2]...
* - For each collapse/split a detail information package made of
* 3 32-bit floats for the positions of vertex \c v0, and 3 32-bit
* int indices for \c v1, \c vl, and \c vr.
* The index for \c vl or \c vr might be -1, if the face on this side
* of the edge does not exists.
*
* \remark Write file before calling the garbage collection of the mesh.
* \param _ofname Name of the file, where to write the progressive mesh
* \return \c true on success of the operation, else \c false.
*/
bool write( const std::string& _ofname );
/// Reference to collected information
const InfoList& infolist() const { return pmi_; }
private:
// hide this method form user
void set_binary(bool _b) {}
InfoList pmi_;
VPropHandleT<int> idx_;
};
//=============================================================================
} // END_NS_DECIMATER
} // END_NS_OPENMESH
//=============================================================================
#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_DECIMATER_MODPROGMESH_CC)
#define OSG_MODPROGMESH_TEMPLATES
#include "ModProgMeshT.cc"
#endif
//=============================================================================
#endif // OPENMESH_TOOLS_PROGMESHT_HH defined
//=============================================================================

View File

@@ -0,0 +1,125 @@
//=============================================================================
//
// OpenMesh
// Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
// www.openmesh.org
//
//-----------------------------------------------------------------------------
//
// License
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, version 2.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//-----------------------------------------------------------------------------
//
// $Revision: 1802 $
// $Date: 2008-05-19 11:55:07 +0200 (Mo, 19. Mai 2008) $
//
//=============================================================================
/** \file ModQuadricT.cc
Bodies of template member function.
*/
//=============================================================================
//
// CLASS ModQuadric - IMPLEMENTATION
//
//=============================================================================
#define OPENMESH_DECIMATER_MODQUADRIC_CC
//== INCLUDES =================================================================
#include <OpenMesh/Tools/Decimater/ModQuadricT.hh>
//== NAMESPACE ===============================================================
namespace OpenMesh { // BEGIN_NS_OPENMESH
namespace Decimater { // BEGIN_NS_DECIMATER
//== IMPLEMENTATION ==========================================================
template<class DecimaterType>
void
ModQuadricT<DecimaterType>::
initialize()
{
using Geometry::Quadricd;
// alloc quadrics
if (!quadrics_.is_valid())
Base::mesh().add_property( quadrics_ );
// clear quadrics
typename Mesh::VertexIter v_it = Base::mesh().vertices_begin(),
v_end = Base::mesh().vertices_end();
for (; v_it != v_end; ++v_it)
Base::mesh().property(quadrics_, v_it).clear();
// calc (normal weighted) quadric
typename Mesh::FaceIter f_it = Base::mesh().faces_begin(),
f_end = Base::mesh().faces_end();
typename Mesh::FaceVertexIter fv_it;
typename Mesh::VertexHandle vh0, vh1, vh2;
typedef Vec3d Vec3;
double a,b,c,d, area;
for (; f_it != f_end; ++f_it)
{
fv_it = Base::mesh().fv_iter(f_it.handle());
vh0 = fv_it.handle(); ++fv_it;
vh1 = fv_it.handle(); ++fv_it;
vh2 = fv_it.handle();
Vec3 v0, v1, v2;
{
using namespace OpenMesh;
v0 = vector_cast<Vec3>(Base::mesh().point(vh0));
v1 = vector_cast<Vec3>(Base::mesh().point(vh1));
v2 = vector_cast<Vec3>(Base::mesh().point(vh2));
}
Vec3 n = (v1-v0) % (v2-v0);
area = n.norm();
if (area > FLT_MIN)
{
n /= area;
area *= 0.5;
}
a = n[0];
b = n[1];
c = n[2];
d = -(vector_cast<Vec3>(Base::mesh().point(vh0))|n);
Quadricd q(a, b, c, d);
q *= area;
Base::mesh().property(quadrics_, vh0) += q;
Base::mesh().property(quadrics_, vh1) += q;
Base::mesh().property(quadrics_, vh2) += q;
}
}
//=============================================================================
} // END_NS_DECIMATER
} // END_NS_OPENMESH
//=============================================================================

View File

@@ -0,0 +1,178 @@
//=============================================================================
//
// OpenMesh
// Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
// www.openmesh.org
//
//-----------------------------------------------------------------------------
//
// License
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, version 2.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//-----------------------------------------------------------------------------
//
// $Revision: 1802 $
// $Date: 2008-05-19 11:55:07 +0200 (Mo, 19. Mai 2008) $
//
//=============================================================================
//=============================================================================
//
// CLASS ModQuadricT
//
//=============================================================================
#ifndef OSG_MODQUADRIC_HH
#define OSG_MODQUADRIC_HH
//== INCLUDES =================================================================
#include <float.h>
#include <OpenMesh/Tools/Decimater/ModBaseT.hh>
#include <OpenMesh/Core/Utils/Property.hh>
#include <OpenMesh/Core/Utils/vector_cast.hh>
#include <OpenMesh/Core/Geometry/QuadricT.hh>
//== NAMESPACE ================================================================
namespace OpenMesh {
namespace Decimater {
//== CLASS DEFINITION =========================================================
/** Mesh decimation module computing collapse priority based on error quadrics.
*
* This module can be used as a binary and non-binary module.
*/
template <class DecimaterType>
class ModQuadricT : public ModBaseT<DecimaterType>
{
public:
// Defines the types Self, Handle, Base, Mesh, and CollapseInfo
// and the memberfunction name()
DECIMATING_MODULE( ModQuadricT, DecimaterType, Quadric );
public:
/** Constructor
* \internal
*/
ModQuadricT( DecimaterType &_dec )
: Base(_dec, false)
{
unset_max_err();
Base::mesh().add_property( quadrics_ );
}
/// Destructor
virtual ~ModQuadricT()
{
Base::mesh().remove_property(quadrics_);
}
public: // inherited
/// Initalize the module and prepare the mesh for decimation.
virtual void initialize(void);
/** Compute collapse priority based on error quadrics.
*
* \see ModBaseT::collapse_priority() for return values
* \see set_max_err()
*/
virtual float collapse_priority(const CollapseInfo& _ci)
{
using namespace OpenMesh;
typedef Geometry::QuadricT<double> Q;
Q q = Base::mesh().property(quadrics_, _ci.v0);
q += Base::mesh().property(quadrics_, _ci.v1);
double err = q(_ci.p1);
//min_ = std::min(err, min_);
//max_ = std::max(err, max_);
//double err = q( p );
return float( (err < max_err_) ? err : float( Base::ILLEGAL_COLLAPSE ) );
}
/// Post-process halfedge collapse (accumulate quadrics)
virtual void postprocess_collapse(const CollapseInfo& _ci)
{
Base::mesh().property(quadrics_, _ci.v1) +=
Base::mesh().property(quadrics_, _ci.v0);
}
public: // specific methods
/** Set maximum quadric error constraint and enable binary mode.
* \param _err Maximum error allowed
* \param _binary Let the module work in non-binary mode in spite of the
* enabled constraint.
* \see unset_max_err()
*/
void set_max_err(double _err, bool _binary=true)
{
max_err_ = _err;
Base::set_binary(_binary);
}
/// Unset maximum quadric error constraint and restore non-binary mode.
/// \see set_max_err()
void unset_max_err(void)
{
max_err_ = DBL_MAX;
Base::set_binary(false);
}
/// Return value of max. allowed error.
double max_err() const { return max_err_; }
private:
// maximum quadric error
double max_err_;
// this vertex property stores a quadric for each vertex
VPropHandleT< Geometry::QuadricT<double> > quadrics_;
};
//=============================================================================
} // END_NS_DECIMATER
} // END_NS_OPENMESH
//=============================================================================
#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_DECIMATER_MODQUADRIC_CC)
#define OSG_MODQUADRIC_TEMPLATES
#include "ModQuadricT.cc"
#endif
//=============================================================================
#endif // OSG_MODQUADRIC_HH defined
//=============================================================================

View File

@@ -0,0 +1,291 @@
//=============================================================================
//
// OpenMesh
// Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
// www.openmesh.org
//
//-----------------------------------------------------------------------------
//
// License
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, version 2.1.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//-----------------------------------------------------------------------------
//
// $Revision: 1802 $
// $Date: 2008-05-19 11:55:07 +0200 (Mo, 19. Mai 2008) $
//
//=============================================================================
/** \file ModRoundnessT.hh
*/
//=============================================================================
//
// CLASS ModRoundnessT
//
//=============================================================================
#ifndef OPENMESH_TOOLS_MODROUNDNESST_HH
#define OPENMESH_TOOLS_MODROUNDNESST_HH
//== INCLUDES =================================================================
#include <OpenMesh/Tools/Decimater/ModBaseT.hh>
#include <math.h>
#if defined(OM_CC_MSVC)
# define OM_ENABLE_WARNINGS 4244
# pragma warning(disable : OM_ENABLE_WARNINGS )
#endif
//== NAMESPACE ================================================================
namespace OpenMesh { // BEGIN_NS_OPENMESH
namespace Decimater { // BEGIN_NS_DECIMATER
//== CLASS DEFINITION =========================================================
/** Compute error value based on roundness criteria.
*/
template <class DecimaterType>
class ModRoundnessT : public ModBaseT<DecimaterType>
{
public:
DECIMATING_MODULE( ModRoundnessT, DecimaterType, Roundness );
public:
// typedefs
typedef typename Mesh::Point Point;
typedef typename vector_traits<Point>::value_type value_type;
public:
/// Constructor
ModRoundnessT( DecimaterType &_dec ) :
Base(_dec, false),
min_r_(-1.0)
{ }
/// Destructor
~ModRoundnessT() { }
public: // inherited
/** Compute collapse priority due to roundness of triangle.
*
* The roundness is computed by dividing the radius of the
* circumference by the length of the shortest edge. The result is
* normalized.
*
* \return [0:1] or ILLEGAL_COLLAPSE in non-binary mode
* \return LEGAL_COLLAPSE or ILLEGAL_COLLAPSE in binary mode
* \see set_min_roundness()
*/
float collapse_priority(const CollapseInfo& _ci)
{
// using namespace OpenMesh;
typename Mesh::ConstVertexOHalfedgeIter voh_it(Base::mesh(), _ci.v0);
double r;
double priority = 0.0; //==LEGAL_COLLAPSE
typename Mesh::FaceHandle fhC, fhB;
Vec3f B,C;
if ( min_r_ < 0.0 ) // continues mode
{
C = vector_cast<Vec3f>(Base::mesh().point( Base::mesh().to_vertex_handle(voh_it)));
fhC = Base::mesh().face_handle( voh_it.handle() );
for (++voh_it; voh_it; ++voh_it)
{
B = C;
fhB = fhC;
C = vector_cast<Vec3f>(Base::mesh().point(Base::mesh().to_vertex_handle(voh_it)));
fhC = Base::mesh().face_handle( voh_it.handle() );
if ( fhB == _ci.fl || fhB == _ci.fr )
continue;
// simulate collapse using position of v1
r = roundness( vector_cast<Vec3f>(_ci.p1), B, C );
// return the maximum non-roundness
priority = std::max( priority, (1.0-r) );
}
}
else // binary mode
{
C = vector_cast<Vec3f>(Base::mesh().point( Base::mesh().to_vertex_handle(voh_it)));
fhC = Base::mesh().face_handle( voh_it.handle() );
for (++voh_it; voh_it && (priority==Base::LEGAL_COLLAPSE); ++voh_it)
{
B = C;
fhB = fhC;
C = vector_cast<Vec3f>(Base::mesh().point(Base::mesh().to_vertex_handle(voh_it)));
fhC = Base::mesh().face_handle( voh_it.handle() );
if ( fhB == _ci.fl || fhB == _ci.fr )
continue;
priority = ( (r=roundness( vector_cast<Vec3f>(_ci.p1), B, C )) < min_r_)
? Base::ILLEGAL_COLLAPSE
: Base::LEGAL_COLLAPSE;
}
}
return (float) priority;
}
public: // specific methods
void set_min_angle( float _angle, bool /* _binary=true */ )
{
assert( _angle > 0 && _angle < 60 );
_angle = float(M_PI * _angle /180.0);
Vec3f A,B,C;
A = Vec3f( 0, 0, 0);
B = Vec3f( 2*cos(_angle), 0, 0);
C = Vec3f( cos(_angle), sin(_angle), 0);
double r1 = roundness(A,B,C);
_angle = float(0.5 * ( M_PI - _angle ));
A = Vec3f( 0, 0, 0);
B = Vec3f( 2*cos(_angle), 0, 0);
C = Vec3f( cos(_angle), sin(_angle), 0);
double r2 = roundness(A,B,C);
set_min_roundness( value_type(std::min(r1,r2)), true );
}
/** Set a minimum roundness value.
* \param _min_roundness in range (0,1)
* \param _binary Set true, if the binary mode should be enabled,
* else false. In latter case the collapse_priority()
* returns a float value if the constrain does not apply
* and ILLEGAL_COLLAPSE else.
*/
void set_min_roundness( value_type _min_roundness, bool _binary=true )
{
assert( 0.0 <= _min_roundness && _min_roundness <= 1.0 );
min_r_ = _min_roundness;
Base::set_binary(_binary);
}
/// Unset minimum value constraint and enable non-binary mode.
void unset_min_roundness()
{
min_r_ = -1.0;
Base::set_binary(false);
}
// Compute a normalized roundness of a triangle ABC
//
// Having
// A,B,C corner points of triangle
// a,b,c the vectors BC,CA,AB
// Area area of triangle
//
// then define
//
// radius of circumference
// R := -----------------------
// length of shortest edge
//
// ||a|| * ||b|| * ||c||
// ---------------------
// 4 * Area ||a|| * ||b|| * ||c||
// = ----------------------- = -----------------------------------
// min( ||a||,||b||,||c||) 4 * Area * min( ||a||,||b||,||c|| )
//
// ||a|| * ||b|| * ||c||
// = -------------------------------------------------------
// 4 * 1/2 * ||cross(B-A,C-A)|| * min( ||a||,||b||,||c|| )
//
// a'a * b'b * c'c
// R<> = ----------------------------------------------------------
// 4 * cross(B-A,C-A)'cross(B-A,C-A) * min( a'a, b'b, c'c )
//
// a'a * b'b * c'c
// R = 1/2 * sqrt(---------------------------)
// AA * min( a'a, b'b, c'c )
//
// At angle 60<36> R has it's minimum for all edge lengths = sqrt(1/3)
//
// Define normalized roundness
//
// nR := sqrt(1/3) / R
//
// AA * min( a'a, b'b, c'c )
// = sqrt(4/3) * sqrt(---------------------------)
// a'a * b'b * c'c
//
double roundness( const Vec3f& A, const Vec3f& B, const Vec3f &C )
{
const value_type epsilon = value_type(1e-15);
static const value_type sqrt43 = value_type(sqrt(4.0/3.0)); // 60<36>,a=b=c, **)
Vec3f vecAC = C-A;
Vec3f vecAB = B-A;
// compute squared values to avoid sqrt-computations
value_type aa = (B-C).sqrnorm();
value_type bb = vecAC.sqrnorm();
value_type cc = vecAB.sqrnorm();
value_type AA = cross(vecAC,vecAB).sqrnorm(); // without factor 1/4 **)
if ( AA < epsilon )
return 0.0;
double nom = AA * std::min( std::min(aa,bb),cc );
double denom = aa * bb * cc;
double nR = sqrt43 * sqrt(nom/denom);
return nR;
}
private:
value_type min_r_;
};
//=============================================================================
} // END_NS_DECIMATER
} // END_NS_OPENMESH
//=============================================================================
#if defined(OM_CC_MSVC) && defined(OM_ENABLE_WARNINGS)
# pragma warning(default : OM_ENABLE_WARNINGS)
# undef OM_ENABLE_WARNINGS
#endif
//=============================================================================
#endif // OPENMESH_TOOLS_PROGMESHT_HH defined
//=============================================================================

View File

@@ -0,0 +1,21 @@
# angle in degrees [0,60]
#
# compute roundness of first case
A = [ 0.0335717 0.0576863 -0.0503314 ]';
B = [ 0.0325544 0.057614 -0.0504989 ]';
C = [ 0.0323531 0.057051 -0.0504476 ]';
#
vecAC=C-A;
vecAB=B-A;
aa = norm(B-C)^2;
bb = norm(vecAC)^2;
cc = norm(vecAB)^2;
AA = norm(cross(vecAC,vecAB))^2
nom = AA * min( aa, min(bb,cc) );
denom = aa * bb * cc;
nR1 = sqrt(4.0/3.0) * sqrt(nom/denom)

View File

@@ -0,0 +1,46 @@
# angle in degrees [0,60]
# [replace :angle: with a value between 0 and 60]
alpha_d = :angle:;
# compute roundness of first case
alpha = pi * alpha_d/180;
A = [ 0 0 0 ]';
B = [ 2*cos(alpha) 0 0 ]';
C = [ cos(alpha) sin(alpha) 0 ]';
#
vecAC=C-A;
vecAB=B-A;
aa = norm(B-C)^2;
bb = norm(vecAC)^2;
cc = norm(vecAB)^2;
AA = norm(cross(vecAC,vecAB))^2;
nom = AA * min( aa, min(bb,cc) );
denom = aa * bb * cc;
nR1 = sqrt(4.0/3.0) * sqrt(nom/denom)
# compute roundness of 2nd case
alpha = pi * ((180-alpha_d)/2)/180;
A = [ 0 0 0 ]';
B = [ 2*cos(alpha) 0 0 ]';
C = [ cos(alpha) sin(alpha) 0 ]';
#
vecAC=C-A;
vecAB=B-A;
aa = norm(B-C)^2;
bb = norm(vecAC)^2;
cc = norm(vecAB)^2;
AA = norm(cross(vecAC,vecAB))^2;
nom = AA * min( aa, min(bb,cc) );
denom = aa * bb * cc;
nR2 = sqrt(4.0/3.0) * sqrt(nom/denom)

View File

@@ -0,0 +1,8 @@
#!/bin/sh
i=0
while ((i <= 60)); do
cat roundness.m | perl -pe "s/:angle:/$i/" > tmp.m
echo $i `octave -q tmp.m 2> /dev/null | grep -v "nR2" | perl -pe 's/^nR1 = (.*)$/\1/'`
i=$((++i))
done