diff --git a/Apps/Decimating/CmdOption.hh b/Apps/Decimating/CmdOption.hh new file mode 100644 index 00000000..aa09937f --- /dev/null +++ b/Apps/Decimating/CmdOption.hh @@ -0,0 +1,56 @@ +#ifndef CMDOPTION +#define CMDOPTION + +template +class CmdOption +{ +public: + + typedef T value_type; + + CmdOption(const T& _val) : val_(_val), valid_(true) { } + CmdOption() : valid_(false), enabled_(false) { } + + // has been set and has a value + bool is_valid(void) const { return valid_; } + bool has_value(void) const { return is_valid(); } + + // has been set and may have an value (check with is_valid()) + bool is_enabled() const { return enabled_; } + + void enable() { enabled_ = true; } + + CmdOption& operator = ( const T& _val ) + { + val_ = _val; + valid_=true; + enable(); + return *this; + } + + operator T () { return val_; } + // operator const T& () const { return val_; } + + operator T* () { return is_valid() ? &val_ : NULL; } + +private: + + T val_; + bool valid_; + bool enabled_; + +private: // non-copyable + + CmdOption(const CmdOption&); + CmdOption& operator = ( const CmdOption& ); + +}; + +template < typename T > +std::ostream& operator << ( std::ostream& _os, CmdOption& _opt ) +{ + _os << (T&)_opt; + return _os; +} + +#endif diff --git a/Apps/Decimating/DecimaterViewerWidget.cc b/Apps/Decimating/DecimaterViewerWidget.cc new file mode 100644 index 00000000..f1cb3651 --- /dev/null +++ b/Apps/Decimating/DecimaterViewerWidget.cc @@ -0,0 +1,111 @@ +//============================================================================= +// +// 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: 1.2 $ +// $Date: 2007-05-18 15:17:21 $ +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#ifdef _MSC_VER +# pragma warning(disable: 4267 4311) +#endif + +#include +#include + +#include +#include + +#include +#include + +#include + + +//== IMPLEMENTATION ========================================================== + + +//----------------------------------------------------------------------------- + +void DecimaterViewerWidget::keyPressEvent(QKeyEvent* _event) +{ + switch (_event->key()) + { + case Key_D: + { + int rc; + if ( (rc=decimater_->decimate(steps_)) ) + { + decimater_->mesh().garbage_collection(); + std::cout << rc << " vertices removed!\n"; + updateGL(); + } + else + std::cout << "Decimation failed\n"; + break; + } + + case Key_Plus: + steps_ = std::min( ++steps_, (size_t)(mesh_.n_vertices() * 0.1) ); + updateGL(); + std::cout << "# decimating steps increased to " << steps_ << std::endl; + break; + + case Key_Minus: + steps_ = std::max( --steps_, size_t(1) ); + updateGL(); + std::cout << "# decimating steps increased to " << steps_ << std::endl; + break; + + case Key_S: + { + OpenMesh::IO::Options opt; + + opt += OpenMesh::IO::Options::Binary; + + if (OpenMesh::IO::write_mesh( mesh(), "result.off", opt )) + std::cout << "mesh saved in 'result.off'\n"; + } + break; + + case Key_Q: + case Key_Escape: + qApp->quit(); + + default: + this->inherited_t::keyPressEvent(_event); + } +} + +void DecimaterViewerWidget::animate( void ) +{ +// updateGL(); +// timer_->start(300, true); +} + +//============================================================================= diff --git a/Apps/Decimating/DecimaterViewerWidget.hh b/Apps/Decimating/DecimaterViewerWidget.hh new file mode 100644 index 00000000..f18c5a0c --- /dev/null +++ b/Apps/Decimating/DecimaterViewerWidget.hh @@ -0,0 +1,172 @@ +//============================================================================= +// +// 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: 1.3 $ +// $Date: 2008-03-11 09:18:01 $ +// +//============================================================================= + + +#ifndef OPENMESHAPPS_DECIMATERVIEWERWIDGET_HH +#define OPENMESHAPPS_DECIMATERVIEWERWIDGET_HH + + +//== INCLUDES ================================================================= + +#if !defined(OM_USE_OSG) +# define OM_USE_OSG 0 +#endif + + +#include +#include +#include + +//-------------------- +#include +//-------------------- +#if OM_USE_OSG +# include +# define DEFAULT_TRAITS Kernel_OSG::Traits +# define TRIMESH_KERNEL Kernel_OSG::TriMesh_OSGArrayKernelT +#else +//-------------------- +# include +# include +# define DEFAULT_TRAITS DefaultTraits +# define TRIMESH_KERNEL TriMesh_ArrayKernelT +#endif + +#include + +#include +#include +#include + + +//== CLASS DEFINITION ========================================================= + + +using namespace OpenMesh; + +struct MyTraits : public DEFAULT_TRAITS +{ + VertexAttributes ( Attributes::Normal ); + FaceAttributes ( Attributes::Normal ); +}; + +typedef TRIMESH_KERNEL mesh_t; +typedef MeshViewerWidgetT MeshViewerWidget; + +//== CLASS DEFINITION ========================================================= + + +class DecimaterViewerWidget : public MeshViewerWidget +{ + Q_OBJECT + +public: + + typedef MeshViewerWidget inherited_t; + + typedef Decimater::DecimaterT decimater_t; + typedef Decimater::ModQuadricT< decimater_t > mod_quadric_t; + typedef Decimater::ModNormalFlippingT< decimater_t > mod_nf_t; + + // object types + typedef std::auto_ptr< decimater_t > decimater_o; + typedef std::auto_ptr< mod_quadric_t > mod_quadric_o; + typedef std::auto_ptr< mod_nf_t > mod_nf_o; + + /// default constructor + DecimaterViewerWidget(QWidget* _parent=0, const char* _name=0) + : MeshViewerWidget(_parent), steps_(1) + { + timer_ = new QTimer(this); + + connect( timer_, SIGNAL(timeout()), SLOT(animate()) ); + } + + /// destructor + ~DecimaterViewerWidget() + { + delete timer_; + } + +public: // inherited + + bool open_mesh(const char* _filename, OpenMesh::IO::Options _opt) + { + bool rc; + + if ( (rc = inherited_t::open_mesh( _filename, _opt )) ) + { + std::cout << "prepare decimater" << std::endl; + + // to be compatible with gcc 2.95.3 + { + decimater_o tmp( new decimater_t ( mesh() ) ); + decimater_ = tmp; + } + { + mod_quadric_o tmp( new mod_quadric_t( *decimater_ ) ); + mod_quadric_ = tmp; + } + { + mod_nf_o tmp( new mod_nf_t ( *decimater_ ) ); + mod_nf_ = tmp; + } + + decimater_->initialize(); + } + return rc; + } + +protected slots: + + void animate( void ); + +protected: + + virtual void keyPressEvent(QKeyEvent* _event); + + +private: + + bool animate_; + QTimer *timer_; + + decimater_o decimater_; + mod_quadric_o mod_quadric_; + mod_nf_o mod_nf_; + + size_t steps_; +}; + + +//============================================================================= +#endif // OPENMESHAPPS_DECIMATERVIEWERWIDGET_HH defined +//============================================================================= + diff --git a/Apps/Decimating/Decimating.pro b/Apps/Decimating/Decimating.pro new file mode 100644 index 00000000..50cc991a --- /dev/null +++ b/Apps/Decimating/Decimating.pro @@ -0,0 +1,25 @@ +################################################################################ +# +################################################################################ + +contains( OPENFLIPPER , OpenFlipper ){ + include( $$TOPDIR/qmake/all.include ) +} else { + include( $$TOPDIR/OpenMesh/qmake/all.include ) +} + +INCLUDEPATH += ../../.. + +Application() +glew() +glut() +openmesh() + +DIRECTORIES = . ../QtViewer + +# Input +HEADERS += $$getFilesFromDir($$DIRECTORIES,*.hh) +SOURCES += $$getFilesFromDir($$DIRECTORIES,*.cc) +FORMS += $$getFilesFromDir($$DIRECTORIES,*.ui) + +################################################################################ diff --git a/Apps/Decimating/OpenMesh_Apps_Decimating.vcproj b/Apps/Decimating/OpenMesh_Apps_Decimating.vcproj new file mode 100644 index 00000000..3dcc7e2b --- /dev/null +++ b/Apps/Decimating/OpenMesh_Apps_Decimating.vcproj @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Apps/Decimating/decimater.cc b/Apps/Decimating/decimater.cc new file mode 100644 index 00000000..34074d6e --- /dev/null +++ b/Apps/Decimating/decimater.cc @@ -0,0 +1,499 @@ +//============================================================================= +// +// 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: 1.2 $ +// $Date: 2007-05-18 15:17:22 $ +// +//============================================================================= + +#if !defined(OM_USE_OSG) +# define OM_USE_OSG 0 +#endif + +// ---------------------------------------------------------------------------- + +#include +#include +#include +#include +#include +#include +//-------------------- +#include +//-------------------- +#if OM_USE_OSG +# include +#else +# include +#endif +#include +//-------------------- +#include +#include +#include +#include +#include +#include +#include +#include + +//----------------------------------------------------------------- traits ---- + +#if OM_USE_OSG +typedef OpenMesh::Kernel_OSG::Traits MyTraits; +#else +typedef OpenMesh::DefaultTraits MyTraits; +#endif + +//------------------------------------------------------------------- mesh ---- + +#if OM_USE_OSG +typedef OpenMesh::Kernel_OSG::TriMesh_OSGArrayKernelT ArrayTriMesh; +#else +typedef OpenMesh::TriMesh_ArrayKernelT ArrayTriMesh; +#endif + + +//-------------------------------------------------------------- decimator ---- + +typedef OpenMesh::Decimater::DecimaterT Decimater; + + +//---------------------------------------------------------------- globals ---- + +int gverbose = 0; +int gdebug = 0; + + +//--------------------------------------------------------------- forwards ---- + +void usage_and_exit(int xcode); + + +//--------------------------------------------------- decimater arguments ---- + +#include "CmdOption.hh" + + +struct DecOptions +{ + DecOptions() + : n_collapses(0) + { } + + CmdOption decorate_name; + CmdOption n_collapses; + CmdOption Q; // Quadrics + CmdOption NF; // Normal Flipping + CmdOption IS; // Independent Sets + CmdOption PM; // Progressive Mesh + CmdOption R; // Roundness + + + template + bool init( CmdOption& _o, const std::string& _val ) + { + if ( _val.empty() ) + _o.enable(); + else + { + std::istringstream istr( _val ); + + T v; + + if ( (istr >> v).fail() ) + return false; + + _o = v; + } + return true; + } + + + bool parse_argument( const std::string& arg ) + { + std::string::size_type pos = arg.find(':'); + + std::string name; + std::string value; + + if (pos == std::string::npos) + name = arg; + else + { + name = arg.substr(0, pos); + value = arg.substr(pos+1, arg.size()); + } + strip(name); + strip(value); + + if (name == "Q") return init(Q, value); + if (name == "NF") return init(NF, value); + if (name == "PM") return init(PM, value); + if (name == "IS") return init(IS, value); + if (name == "R") return init(R, value); + return false; + } + + + std::string& strip(std::string & line) + { + std::string::size_type pos = 0; + + pos = line.find_last_not_of(" \t"); + + if ( pos!=0 && pos!=std::string::npos ) + { + ++pos; + line.erase( pos, line.length()-pos ); + } + + pos = line.find_first_not_of(" \t"); + if ( pos!=0 && pos!=std::string::npos ) + { + line.erase(0,pos); + } + + return line; + } + +}; + +//----------------------------------------------------- decimater wrapper ---- +// +template +bool +decimate(const std::string &_ifname, + const std::string &_ofname, + DecOptions &_opt) +{ + using namespace std; + + Mesh mesh; + OpenMesh::IO::Options opt; + OpenMesh::Utils::Timer timer; + + // ---------------------------------------- read source mesh + { + if (gverbose) + clog << "source mesh: "; + bool rc; + + if (gverbose) + clog << _ifname << endl; + if ( !(rc = OpenMesh::IO::read_mesh(mesh, _ifname, opt)) ) + { + cerr << " ERROR: read failed!" << endl; + return rc; + } + } + + // ---------------------------------------- do some decimation + { + // ---- 0 - For module NormalFlipping one needs face normals + + if ( !opt.check( OpenMesh::IO::Options::FaceNormal ) ) + { + if ( !mesh.has_face_normals() ) + mesh.request_face_normals(); + + if (gverbose) + clog << " updating face normals" << endl; + mesh.update_face_normals(); + } + + // ---- 1 - create decimater instance + Decimater decimater( mesh ); + + // ---- 2 - registrate modules + if (gverbose) + clog << " registrate modules" << endl; + + + typename OpenMesh::Decimater::ModQuadricT::Handle modQ; + + if (_opt.Q.is_enabled()) + { + decimater.add(modQ); + if (_opt.Q.has_value()) + decimater.module( modQ ).set_max_err( _opt.Q ); + } + + typename OpenMesh::Decimater::ModNormalFlippingT::Handle modNF; + + if (_opt.NF.is_enabled()) + { + decimater.add(modNF); + if (_opt.NF.has_value()) + decimater.module( modNF ).set_normal_deviation( _opt.NF ); + } + + typename OpenMesh::Decimater::ModProgMeshT::Handle modPM; + + if ( _opt.PM.is_enabled() ) + decimater.add(modPM); + + + typename OpenMesh::Decimater::ModIndependentSetsT::Handle modIS; + + if ( _opt.IS.is_enabled() ) + decimater.add(modIS); + + + typename OpenMesh::Decimater::ModRoundnessT::Handle modR; + + if ( _opt.R.is_enabled() ) + { + decimater.add( modR ); + if ( _opt.R.has_value() ) + decimater.module( modR ).set_min_angle( _opt.R, + !modQ.is_valid() || + !decimater.module(modQ).is_binary()); + } + + // ---- 3 - initialize decimater + + if (gverbose) + clog << "initializing mesh" << endl; + + { + bool rc; + timer.start(); + rc = decimater.initialize(); + timer.stop(); + if (!rc) + { + std::cerr << " initializing failed!" << std::endl; + return false; + } + } + if (gverbose) + std::clog << " Elapsed time: " << timer.as_string() << std::endl; + + if (gverbose) + decimater.info( clog ); + + // ---- 4 - do it + + if (gverbose) + { + std::clog << "decimating" << std::endl; + std::clog << " # vertices: " << mesh.n_vertices() << std::endl; + } + + float nv_before = float(mesh.n_vertices()); + + timer.start(); + int rc = 0; + if (_opt.n_collapses < 0.0) + rc = decimater.decimate_to( size_t(-_opt.n_collapses) ); + else if (_opt.n_collapses >= 1.0 || _opt.n_collapses == 0.0) + rc = decimater.decimate( size_t(_opt.n_collapses) ); + else if (_opt.n_collapses > 0.0f) + rc = decimater.decimate_to(size_t(mesh.n_vertices()*_opt.n_collapses)); + timer.stop(); + + // ---- 5 - write progmesh file for progviewer (before garbage collection!) + + if ( _opt.PM.has_value() ) + decimater.module(modPM).write( _opt.PM ); + + // ---- 6 - throw away all tagged edges + + mesh.garbage_collection(); + + if (gverbose) + { + std::clog << " # executed collapses: " << rc << std::endl; + std::clog << " # vertices: " << mesh.n_vertices() << ", " + << ( 100.0*mesh.n_vertices()/nv_before ) << "%\n"; + std::clog << " Elapsed time: " << timer.as_string() << std::endl; + std::clog << " collapses/s : " << rc/timer.seconds() << std::endl; + } + + } + + // write resulting mesh + if ( ! _ofname.empty() ) + { + std::string ofname(_ofname); + + std::string::size_type pos = ofname.rfind('.'); + if (pos == std::string::npos) + { + ofname += ".off"; + pos = ofname.rfind('.'); + } + + if ( _opt.decorate_name.is_enabled() ) + { + std::stringstream s; s << mesh.n_vertices(); + std::string n; s >> n; + ofname.insert( pos, "-"); + ofname.insert(++pos, n ); + } + + OpenMesh::IO::Options opt; + + //opt += OpenMesh::IO::Options::Binary; + + if ( !OpenMesh::IO::write_mesh(mesh, ofname, opt ) ) + { + std::cerr << " Cannot write decimated mesh to file '" + << ofname << "'\n"; + return false; + } + std::clog << " Exported decimated mesh to file '" << ofname << "'\n"; + } + + return true; +} + +//------------------------------------------------------------------ main ----- + +int main(int argc, char* argv[]) +{ + std::string ifname, ofname; + + DecOptions opt; + + // +#if OM_USE_OSG + osg::osgInit( argc, argv ); +#endif + + //---------------------------------------- parse command line + { + int c; + + while ( (c=getopt( argc, argv, "dDhi:M:n:o:v")) != -1 ) + { + switch (c) + { + case 'D': opt.decorate_name = true; break; + case 'd': gdebug = true; break; + case 'h': usage_and_exit(0); + case 'i': ifname = optarg; break; + case 'M': opt.parse_argument( optarg ); break; + case 'n': opt.n_collapses = float(atof(optarg)); break; + case 'o': ofname = optarg; break; + case 'v': gverbose = true; break; + case '?': + default: + std::cerr << "FATAL: cannot process command line option!" + << std::endl; + exit(-1); + } + } + } + + //---------------------------------------- + + if ( (-1.0f < opt.n_collapses) && (opt.n_collapses < 0.0f) ) + { + std::cerr << "Error: Option -n: invalid value argument!" << std::endl; + usage_and_exit(2); + } + + //---------------------------------------- + + if (gverbose) + { + std::clog << " Input file: " << ifname << std::endl; + std::clog << " Output file: " << ofname << std::endl; + std::clog << " #collapses: " << opt.n_collapses << std::endl; + } + + + //---------------------------------------- + + + + if (gverbose) + { + std::clog << "Begin decimation" << std::endl; + } + + bool rc = decimate( ifname, ofname, opt ); + + if (gverbose) + { + if (!rc) + std::clog << "Decimation failed!" << std::endl; + else + std::clog << "Decimation done." << std::endl; + } + + //---------------------------------------- + return 0; +} + + +//----------------------------------------------------------------------------- + +void usage_and_exit(int xcode) +{ + std::string errmsg; + + switch(xcode) + { + case 1: errmsg = "Option not supported!"; break; + case 2: errmsg = "Invalid output file format!"; break; + } + + std::cerr << std::endl; + if (xcode) + { + std::cerr << "Error " << xcode << ": " << errmsg << std::endl << std::endl; + } + std::cerr << "Usage: decimator [Options] -i input-file -o output-file\n" + << " Decimating a mesh using quadrics and normal flipping.\n" + << std::endl; + std::cerr << "Options\n" + << std::endl; + std::cerr << " -M \"{Module-Name}[:Value]}\"\n" + << " Use named module with eventually given parameterization\n" + << std::endl; + std::cerr << " -n \n" + << " N >= 1: do N halfedge collapses.\n" + << " N <=-1: decimate down to |N| vertices.\n" + << " 0 < N < 1: decimate down to N%.\n" + << std::endl; + std::cerr << std::endl; + std::cerr << "Modules:\n\n"; + std::cerr << " IS - ModIndependentSets\n"; + std::cerr << " NF[:angle] - ModNormalFlipping\n"; + std::cerr << " PM[:file name] - ModProgMesh\n"; + std::cerr << " Q[:error] - ModQuadric\n"; + std::cerr << " R[:angle] - ModRoundness\n"; + std::cerr << " 0 < angle < 60\n"; + + exit( xcode ); +} + + + +// end of file +//============================================================================= diff --git a/Apps/Decimating/decimaterviewer.cc b/Apps/Decimating/decimaterviewer.cc new file mode 100644 index 00000000..a23072a6 --- /dev/null +++ b/Apps/Decimating/decimaterviewer.cc @@ -0,0 +1,126 @@ +//============================================================================= +// +// 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: 1.3 $ +// $Date: 2008-03-11 09:18:01 $ +// +//============================================================================= +#ifdef _MSC_VER +# pragma warning(disable: 4267 4311) +#endif + +#include +#include +#include +#include +#include + +#include "DecimaterViewerWidget.hh" + +#include + + +void usage_and_exit(int xcode); + + +int main(int argc, char **argv) +{ +#if defined(OM_USE_OSG) && OM_USE_OSG + osg::osgInit(argc, argv); +#endif + + // OpenGL check + QApplication::setColorSpec( QApplication::CustomColor ); + QApplication app(argc,argv); + + glutInit(&argc,argv); + + if ( !QGLFormat::hasOpenGL() ) { + QString msg = "System has no OpenGL support!"; + QMessageBox::critical( NULL, "OpenGL", msg + argv[1] ); + return -1; + } + + + int c; + OpenMesh::IO::Options opt; + + while ( (c=getopt(argc,argv,"s"))!=-1 ) + { + switch(c) + { + case 's': opt += OpenMesh::IO::Options::Swap; break; + case 'h': + usage_and_exit(0); + default: + usage_and_exit(1); + } + } + // create widget + DecimaterViewerWidget w(0, "Viewer"); +// app.setMainWidget(&w); + + w.resize(400, 400); + w.show(); + + // load scene + if ( optind < argc ) + { + if ( ! w.open_mesh(argv[optind], opt) ) + { + QString msg = "Cannot read mesh from file:\n '"; + msg += argv[optind]; + msg += "'"; + QMessageBox::critical( NULL, w.windowTitle(), msg ); + return 1; + } + } + + if ( ++optind < argc ) + { + if ( ! w.open_texture( argv[optind] ) ) + { + QString msg = "Cannot load texture image from file:\n '"; + msg += argv[optind]; + msg += "'\n\nPossible reasons:\n"; + msg += "- Mesh file didn't provide texture coordinates\n"; + msg += "- Texture file does not exist\n"; + msg += "- Texture file is not accessible.\n"; + QMessageBox::warning( NULL, w.windowTitle(), msg ); + } + } + + return app.exec(); +} + +void usage_and_exit(int xcode) +{ + std::cout << "Usage: decimaterviewer [-s] [mesh] [texture]\n" << std::endl; + std::cout << "Options:\n" + << " -s\n" + << " Reverse byte order, when reading binary files.\n" + << std::endl; + exit(xcode); +} diff --git a/Apps/Deprecated/IvViewer/ACGMakefile b/Apps/Deprecated/IvViewer/ACGMakefile new file mode 100644 index 00000000..0b7543d8 --- /dev/null +++ b/Apps/Deprecated/IvViewer/ACGMakefile @@ -0,0 +1,37 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS := $(call find-subdirs) + +USE_COIN := no +USE_SOQT := no + +ifeq ($(USE_COIN),yes) + USE_SOQT := yes +endif + +ifeq ($(USE_SOQT),yes) + + CXX_DEFS += -DUSE_SOQT=1 + +ifeq ($(USE_COIN),yes) + PACKAGES := coin soqt_coin glut opengl qt +else + PACKAGES := Inventor soqt_inventor glut opengl qt +endif + +else + PACKAGES := inventor opengl x11 +endif + + +PROJ_LIBS = OpenMesh/Core + +MODULES := cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Apps/Deprecated/IvViewer/SoOpenMeshNodeT.cc b/Apps/Deprecated/IvViewer/SoOpenMeshNodeT.cc new file mode 100644 index 00000000..00986e53 --- /dev/null +++ b/Apps/Deprecated/IvViewer/SoOpenMeshNodeT.cc @@ -0,0 +1,370 @@ +//============================================================================= +// +// 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: 1800 $ +// $Date: 2008-05-19 11:51:23 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + +//============================================================================= +// +// Class SoOpenMeshNodeT - implementation +// +//============================================================================= + + +#define OPENMESH_SOOPENMESHNODE_CC + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include +#include +#include + +#include "SoOpenMeshNodeT.hh" +// Attention must be included after SoOpenMeshNodeT.hh +// as it redefines several macros! +#include "SoOpenMeshSupport.hh" + +#include + + +//== NAMESPACES ============================================================== + + +namespace OpenMesh { + + +//== IMPLEMENTATION ========================================================== + + +// Helper functions: draw vertices +inline void glVertex(const OpenMesh::Vec3f& _v) { glVertex3fv(_v); } +inline void glVertex(const OpenMesh::Vec3d& _v) { glVertex3dv(_v); } + +// Helper functions: draw normal +inline void glNormal(const OpenMesh::Vec3f& _n) { glNormal3fv(_n); } +inline void glNormal(const OpenMesh::Vec3d& _n) { glNormal3dv(_n); } + +// Helper function: convert Vec to SbVec3f +template inline SbVec3f sbvec3f(const Vec& _v) { + return SbVec3f(_v[0], _v[1], _v[2]); +} + + +//----------------------------------------------------------------------------- + + +template +void +SoOpenMeshNodeT::initClass() +{ + SO_NODE_INIT_CLASS(SoOpenMeshNodeT, SoShape, "Shape"); +} + + +//----------------------------------------------------------------------------- + + +template +SoOpenMeshNodeT::SoOpenMeshNodeT(const Mesh* _mesh) : + mesh_(_mesh) +{ + SO_NODE_CONSTRUCTOR(SoOpenMeshNodeT); +} + + +//----------------------------------------------------------------------------- + + +template +void +SoOpenMeshNodeT::GLRender(SoGLRenderAction *action) +{ + if (mesh_ && shouldGLRender(action)) + { + SoState* state = action->getState(); + SbBool send_normals = (SoLightModelElement::get(state) != + SoLightModelElement::BASE_COLOR); + + SoMaterialBundle mb(action); + mb.sendFirst(); + + drawFaces(send_normals); + } +} + + +//---------------------------------------------------------------------------- + + +template +void +SoOpenMeshNodeT:: +drawFaces(bool _send_normals, OpenMesh::GenProg::Bool2Type) +{ + typename Mesh::ConstFaceIter f_it(mesh_->faces_begin()), + f_end(mesh_->faces_end()); + + typename Mesh::ConstFaceVertexIter fv_it; + + + if (_send_normals) + { + glBegin(GL_TRIANGLES); + for (; f_it!=f_end; ++f_it) + { + glNormal(mesh_->normal(f_it)); + fv_it = mesh_->cfv_iter(f_it.handle()); + glVertex(mesh_->point(fv_it)); + ++fv_it; + glVertex(mesh_->point(fv_it)); + ++fv_it; + glVertex(mesh_->point(fv_it)); + } + glEnd(); + } + else + { + glBegin(GL_TRIANGLES); + for (; f_it!=f_end; ++f_it) + { + fv_it = mesh_->cfv_iter(f_it.handle()); + glVertex(mesh_->point(fv_it)); + ++fv_it; + glVertex(mesh_->point(fv_it)); + ++fv_it; + glVertex(mesh_->point(fv_it)); + } + glEnd(); + } +} + + +//---------------------------------------------------------------------------- + + +template +void +SoOpenMeshNodeT:: +drawFaces(bool _send_normals, OpenMesh::GenProg::Bool2Type) +{ + typename Mesh::ConstFaceIter f_it(mesh_->faces_begin()), + f_end(mesh_->faces_end()); + + typename Mesh::ConstFaceVertexIter fv_it; + + + if (_send_normals) + { + for (; f_it!=f_end; ++f_it) + { + glBegin(GL_POLYGON); + glNormal(mesh_->normal(f_it)); + for (fv_it=mesh_->cfv_iter(f_it.handle()); fv_it; ++fv_it) + glVertex(mesh_->point(fv_it)); + glEnd(); + } + } + else + { + for (; f_it!=f_end; ++f_it) + { + glBegin(GL_POLYGON); + for (fv_it=mesh_->cfv_iter(f_it.handle()); fv_it; ++fv_it) + glVertex(mesh_->point(fv_it)); + glEnd(); + } + } +} + + +//----------------------------------------------------------------------------- + + +template +void +SoOpenMeshNodeT::generatePrimitives(SoAction* _action) +{ + if (mesh_) + genPrimitives(_action); +} + + +//---------------------------------------------------------------------------- + + +template +void +SoOpenMeshNodeT:: +genPrimitives(SoAction* _action, OpenMesh::GenProg::Bool2Type) +{ + typename Mesh::ConstFaceIter f_it(mesh_->faces_begin()), + f_end(mesh_->faces_end()); + + typename Mesh::ConstFaceVertexIter fv_it; + + + SoPrimitiveVertex pv; + + beginShape(_action, TRIANGLES); + + for (; f_it!=f_end; ++f_it) + { + pv.setNormal(sbvec3f(mesh_->normal(f_it))); + + fv_it = mesh_->cfv_iter(f_it.handle()); + + pv.setPoint(sbvec3f(mesh_->point(fv_it))); + shapeVertex(&pv); + ++fv_it; + + pv.setPoint(sbvec3f(mesh_->point(fv_it))); + shapeVertex(&pv); + ++fv_it; + + pv.setPoint(sbvec3f(mesh_->point(fv_it))); + shapeVertex(&pv); + } + + endShape(); +} + + +//---------------------------------------------------------------------------- + + +template +void +SoOpenMeshNodeT:: +genPrimitives(SoAction* _action, OpenMesh::GenProg::Bool2Type) +{ + typename Mesh::ConstFaceIter f_it(mesh_->faces_begin()), + f_end(mesh_->faces_end()); + + typename Mesh::ConstFaceVertexIter fv_it; + + SoPrimitiveVertex pv; + + + for (; f_it!=f_end; ++f_it) + { + beginShape(_action, POLYGON); + + pv.setNormal(sbvec3f(mesh_->normal(f_it))); + + for (fv_it=mesh_->cfv_iter(f_it.handle()); fv_it; ++fv_it) + { + pv.setPoint(sbvec3f(mesh_->point(fv_it))); + shapeVertex(&pv); + } + + endShape(); + } +} + + +//----------------------------------------------------------------------------- + + +template +void +SoOpenMeshNodeT::computeBBox(SoAction *action, + SbBox3f &box, + SbVec3f ¢er) +{ + if (mesh_ && mesh_->n_vertices()) + { + typename Mesh::ConstVertexIter vIt(mesh_->vertices_begin()); + typename Mesh::ConstVertexIter vEnd(mesh_->vertices_end()); + + typename Mesh::Point min(mesh_->point(vIt)); + typename Mesh::Point max(mesh_->point(vIt)); + + + for (++vIt; vIt != vEnd; ++vIt) + { + max.maximize(mesh_->point(vIt)); + min.minimize(mesh_->point(vIt)); + } + + box.setBounds(SbVec3f(min[0],min[1],min[2]), + SbVec3f(max[0],max[1],max[2])); + } + + else box.setBounds(SbVec3f(0,0,0), SbVec3f(0,0,0)); +} + + +//----------------------------------------------------------------------------- + +#if 0 +/* As we are using templates, we cannot use the predefined macro + SO_NODE_SOURCE to automatically generate the following piece of + code. Ugly, but necessary. +*/ + +template +SoType SoOpenMeshNodeT::classTypeId; + +template +SoFieldData *SoOpenMeshNodeT::fieldData; + +template +const SoFieldData **SoOpenMeshNodeT::parentFieldData; + +template +SbBool SoOpenMeshNodeT::firstInstance = TRUE; + +template +SoType SoOpenMeshNodeT::getTypeId() const { + return classTypeId; +} + +template +const SoFieldData* +SoOpenMeshNodeT::getFieldData() const { + SO__NODE_CHECK_CONSTRUCT("SoOpenMeshNodeT"); + return fieldData; +} + +template +void* SoOpenMeshNodeT::createInstance() { + return (void *)(new SoOpenMeshNodeT); +} + +#else + +SO_NODE_SOURCE(SoOpenMeshNodeT); + +#endif + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Apps/Deprecated/IvViewer/SoOpenMeshNodeT.hh b/Apps/Deprecated/IvViewer/SoOpenMeshNodeT.hh new file mode 100644 index 00000000..53940b27 --- /dev/null +++ b/Apps/Deprecated/IvViewer/SoOpenMeshNodeT.hh @@ -0,0 +1,117 @@ +//============================================================================= +// +// 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: 1800 $ +// $Date: 2008-05-19 11:51:23 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + +//============================================================================= +// +// Class SoOpenMeshNode +// +// This class defines an basic inventor node to display an OpenMesh +// +//============================================================================= + + +#ifndef OPENMESH_SOOPENMESHNODE_HH +#define OPENMESH_SOOPENMESHNODE_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +template +class SoOpenMeshNodeT : public SoShape +{ + + SO_NODE_HEADER(SoOpenMeshNodeT); + + +public: + + static void initClass(); + SoOpenMeshNodeT(const Mesh* _mesh=0); + void setMesh(const Mesh* mesh) { d_mesh = mesh; } + + +protected: + + virtual void GLRender(SoGLRenderAction *action); + virtual void computeBBox(SoAction *action, SbBox3f &box, SbVec3f ¢er); + virtual void generatePrimitives(SoAction *action); + + +private: + + virtual ~SoOpenMeshNodeT() {}; + + + // Draw faces as triangles / polygons + void drawFaces(bool _send_normals) { + typedef typename Mesh::Face Face; + drawFaces(_send_normals, typename Face::IsTriangle()); + } + void drawFaces(bool _send_normals, OpenMesh::GenProg::Bool2Type); + void drawFaces(bool _send_normals, OpenMesh::GenProg::Bool2Type); + + + // Generate primitives + void genPrimitives(SoAction* _action) { + typedef typename Mesh::Face Face; + genPrimitives(_action, typename Face::IsTriangle()); + } + void genPrimitives(SoAction* _action, OpenMesh::GenProg::Bool2Type); + void genPrimitives(SoAction* _action, OpenMesh::GenProg::Bool2Type); + + + const Mesh* mesh_; +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(INCLUDE_TEMPLATES) && !defined(OPENMESH_SOOPENMESHNODE_CC) +# define OPENMESH_SOOPENMESHMODE_TEMPLATES +# include "SoOpenMeshNodeT.cc" +#endif +//============================================================================= +#endif // OPENMESH_SOOPENMESHNODE_HH +//============================================================================= diff --git a/Apps/Deprecated/IvViewer/SoOpenMeshSupport.hh b/Apps/Deprecated/IvViewer/SoOpenMeshSupport.hh new file mode 100644 index 00000000..3f51d1ec --- /dev/null +++ b/Apps/Deprecated/IvViewer/SoOpenMeshSupport.hh @@ -0,0 +1,111 @@ +#ifndef SOOPENMESHSUPPORT_H +#define SOOPENMESHSUPPORT_H + +//== REDEFINE DEFINES SO THEY WORK WITH TEMPLATES ============================ + +#define SO_NODE_SOURCE_TEMPLATE template + +// ----------------------------------------------------------------- COIN ---- +// +// define __COIN__ is set by coin headers +#ifdef __COIN__ + +#ifdef PRIVATE_NODE_TYPESYSTEM_SOURCE +# undef PRIVATE_NODE_TYPESYSTEM_SOURCE +#endif + +#define PRIVATE_NODE_TYPESYSTEM_SOURCE(_class_) \ +SO_NODE_SOURCE_TEMPLATE \ +SoType _class_::getClassTypeId(void) { return _class_::classTypeId; } \ +SO_NODE_SOURCE_TEMPLATE \ +SoType _class_::getTypeId(void) const { return _class_::classTypeId; } \ +/* Don't set value explicitly to SoType::badType(), to avoid a bug in */ \ +/* Sun CC v4.0. (Bitpattern 0x0000 equals SoType::badType()). */ \ +SO_NODE_SOURCE_TEMPLATE \ +SoType _class_::classTypeId + +// FIXME: document. 20000103 mortene. +#ifdef SO_NODE_ABSTRACT_SOURCE +# undef SO_NODE_ABSTRACT_SOURCE +#endif + +#define SO_NODE_ABSTRACT_SOURCE(_class_) \ +PRIVATE_NODE_TYPESYSTEM_SOURCE(_class_); \ + \ +SO_NODE_SOURCE_TEMPLATE \ +unsigned int _class_::classinstances = 0; \ +SO_NODE_SOURCE_TEMPLATE \ +const SoFieldData ** _class_::parentFieldData = NULL; \ +SO_NODE_SOURCE_TEMPLATE \ +SoFieldData * _class_::fieldData = NULL; \ + \ +SO_NODE_SOURCE_TEMPLATE \ +const SoFieldData ** \ +_class_::getFieldDataPtr(void) \ +{ \ + return (const SoFieldData **)(&_class_::fieldData); \ +} \ + \ +SO_NODE_SOURCE_TEMPLATE \ +const SoFieldData * \ +_class_::getFieldData(void) const \ +{ \ + return _class_::fieldData; \ +} + + + +// FIXME: document. 20000103 mortene. +#ifdef SO_NODE_SOURCE +# undef SO_NODE_SOURCE +#endif +#define SO_NODE_SOURCE(_class_) \ +SO_NODE_ABSTRACT_SOURCE(_class_); \ + \ +SO_NODE_SOURCE_TEMPLATE \ +void * \ +_class_::createInstance(void) \ +{ \ + return new _class_; \ +} + +// ------------------------------------------------------------------ SGI ---- +#else + +#ifdef SO_NODE_SOURCE +# undef SO_NODE_SOURCE +#endif + +#define SO_NODE_SOURCE(_class_) \ + SO_NODE_SOURCE_TEMPLATE \ + SoType _class_::classTypeId; \ + \ + SO_NODE_SOURCE_TEMPLATE \ + SoFieldData *_class_::fieldData; \ + \ + SO_NODE_SOURCE_TEMPLATE \ + const SoFieldData **_class_::parentFieldData; \ + \ + SO_NODE_SOURCE_TEMPLATE \ + SbBool _class_::firstInstance = TRUE; \ + \ + SO_NODE_SOURCE_TEMPLATE \ + SoType _class_::getTypeId() const { \ + return classTypeId; \ + } \ + \ + SO_NODE_SOURCE_TEMPLATE \ + const SoFieldData* \ + _class_::getFieldData() const { \ + SO__NODE_CHECK_CONSTRUCT("SoOpenMeshNodeT"); \ + return fieldData; \ + } \ + \ + SO_NODE_SOURCE_TEMPLATE \ + void* _class_::createInstance() { \ + return (void *)(new _class_); \ + } \ + +#endif + +#endif diff --git a/Apps/Deprecated/IvViewer/ivviewer.cc b/Apps/Deprecated/IvViewer/ivviewer.cc new file mode 100644 index 00000000..d08640c5 --- /dev/null +++ b/Apps/Deprecated/IvViewer/ivviewer.cc @@ -0,0 +1,140 @@ +//============================================================================= +// +// 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: 4483 $ +// $Date: 2009-01-28 11:41:31 +0100 (Mi, 28. Jan 2009) $ +// +//============================================================================= + +// + +#if !defined(USE_SOQT) +# define USE_SOQT 0 +#endif + +//== INCLUDES ================================================================= + + +#include +// +// Attention! must include this before including inventor files! +// There some dependencies not solved yet! +#include +#include +// +#include +#if USE_SOQT +# include +# include +# include +#else +# include +# include +#endif +#include +// +#include + + +//== CLASS DEFINITION ========================================================= + + +struct MyTraits : public OpenMesh::DefaultTraits +{ + VertexAttributes(OpenMesh::Attributes::Normal); + HalfedgeAttributes(OpenMesh::Attributes::PrevHalfedge); + FaceAttributes(OpenMesh::Attributes::Normal); +}; + + +typedef OpenMesh::TriMesh_ArrayKernelT MyMesh; +typedef OpenMesh::SoOpenMeshNodeT MyNode; + + + +//== IMPLEMENTATION =========================================================== + + + +int main(int argc, char **argv) +{ + OpenMesh::IO::Options opt; + +#if USE_SOQT + QApplication app(argc,argv); + + SoQt::init( argv[0] ); + + MyNode::initClass(); + SoQtExaminerViewer *myViewer = new SoQtExaminerViewer(); + + + // Read a mesh + MyMesh mesh; + if (argc > 1 && OpenMesh::IO::read_mesh(mesh, argv[1], opt)) + { + if (!opt.check( OpenMesh::IO::Options::FaceNormal)) + mesh.update_face_normals(); + + SoSeparator* root = new SoSeparator(); + root->addChild(new MyNode(&mesh)); + + myViewer->setSceneGraph(root); + } + + QObject::connect(qApp, SIGNAL(lastWindowClosed()), qApp, SLOT(quit())); + + myViewer->show(); + SoQt::mainLoop(); +#else + // Inventor stuff + Widget myWindow = SoXt::init(argv[0]); + MyNode::initClass(); + SoXtExaminerViewer *myViewer = + new SoXtExaminerViewer(myWindow); + + + + // Read a mesh + MyMesh mesh; + if (argc > 1 && OpenMesh::IO::read_mesh(mesh, argv[1], opt)) + { + if (!opt.check( OpenMesh::IO::Options::FaceNormal)) + mesh.update_face_normals(); + + SoSeparator* root = new SoSeparator(); + root->addChild(new MyNode(&mesh)); + + myViewer->setSceneGraph(root); + } + + myViewer->show(); + SoXt::show(myWindow); + SoXt::mainLoop(); +#endif +} + + +//============================================================================= diff --git a/Apps/Deprecated/OsgViewer/ACGMakefile b/Apps/Deprecated/OsgViewer/ACGMakefile new file mode 100644 index 00000000..8c47783a --- /dev/null +++ b/Apps/Deprecated/OsgViewer/ACGMakefile @@ -0,0 +1,21 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + +#CXX_SRC_EXT := .cc +#CXX_HDR_EXT := .h + +CXX_CFLAGS += -DOM_USE_OSG=1 + +SUBDIRS = + +PACKAGES := osg qt glut opengl x11 math + +PROJ_LIBS = OpenMesh/Apps/QtViewer OpenMesh/Tools OpenMesh/Core + +MODULES := moc cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Apps/Deprecated/OsgViewer/README b/Apps/Deprecated/OsgViewer/README new file mode 100644 index 00000000..34dfe021 --- /dev/null +++ b/Apps/Deprecated/OsgViewer/README @@ -0,0 +1,11 @@ +Usage: + + 1. osgviewer + + Load a model via I/O routines of OpenMesh and save as a OpenSG + binary file in file opensg.bin. + + 2. osgviewer + + Load model previously stored in opensg.bin via OpenSG BINLoader. + diff --git a/Apps/Deprecated/OsgViewer/meshviewer.cc b/Apps/Deprecated/OsgViewer/meshviewer.cc new file mode 100644 index 00000000..0f60038f --- /dev/null +++ b/Apps/Deprecated/OsgViewer/meshviewer.cc @@ -0,0 +1,134 @@ +//============================================================================= +// +// 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: 1800 $ +// $Date: 2008-05-19 11:51:23 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= +#ifdef _MSC_VER +# pragma warning(disable: 4267 4311) +#endif + +#include +#include +#include +#include +#include +#include +#include + + +struct MyTraits : public OpenMesh::Kernel_OSG::Traits +{ + VertexAttributes(OpenMesh::Attributes::Normal | + OpenMesh::Attributes::TexCoord ); + HalfedgeAttributes(OpenMesh::Attributes::PrevHalfedge); + FaceAttributes(OpenMesh::Attributes::Normal); +}; + + +typedef OpenMesh::Kernel_OSG::TriMesh_OSGArrayKernelT MyMesh; +typedef MeshViewerWidgetT MeshViewerWidget; + +void usage_and_exit(int xcode); + +int main(int argc, char **argv) +{ + osg::osgInit(argc, argv); + + // OpenGL check + QApplication::setColorSpec( QApplication::CustomColor ); + QApplication app(argc,argv); + + if ( !QGLFormat::hasOpenGL() ) { + QString msg = "System has no OpenGL support!"; + QMessageBox::critical( NULL, "OpenGL", msg + argv[1], 0 ); + return -1; + } + + + int c; + OpenMesh::IO::Options opt; + + while ( (c=getopt(argc,argv,"s"))!=-1 ) + { + switch(c) + { + case 's': opt += OpenMesh::IO::Options::Swap; break; + case 'h': + usage_and_exit(0); + default: + usage_and_exit(1); + } + } + // create widget + MeshViewerWidget* w = new MeshViewerWidget(0, "Viewer"); + app.setMainWidget(w); + + // static mesh, hence use strips + w->enable_strips(); + + w->resize(400, 400); + w->show(); + + // load scene + if ( optind < argc ) + { + if ( ! w->open_mesh(argv[optind], opt) ) + { + QString msg = "Cannot read mesh from file:\n '"; + msg += argv[optind]; + msg += "'"; + QMessageBox::critical( NULL, w->caption(), msg, 0 ); + return 1; + } + } + + if ( ++optind < argc ) + { + if ( ! w->open_texture( argv[optind] ) ) + { + QString msg = "Cannot load texture image from file:\n '"; + msg += argv[optind]; + msg += "'\n\nPossible reasons:\n"; + msg += "- Mesh file didn't provide texture coordinates\n"; + msg += "- Texture file does not exist\n"; + msg += "- Texture file is not accessible.\n"; + QMessageBox::warning( NULL, w->caption(), msg, 0 ); + } + } + + return app.exec(); +} + +void usage_and_exit(int xcode) +{ + std::cout << "Usage: meshviewer [-s] [mesh] [texture]\n" << std::endl; + std::cout << "Options:\n" + << " -s\n" + << " Reverse byte order, when reading binary files.\n" + << std::endl; + exit(xcode); +} diff --git a/Apps/Deprecated/OsgViewer/osgviewer.cc b/Apps/Deprecated/OsgViewer/osgviewer.cc new file mode 100644 index 00000000..d4dfafcb --- /dev/null +++ b/Apps/Deprecated/OsgViewer/osgviewer.cc @@ -0,0 +1,481 @@ +// -------------------- STL +#include +#include +#include +#include +// -------------------- OpenSG +#include +#include +#include +#include +#include +#include +#include +// -------------------- OpenMesh +#include // always before kernel type + +#include +#include + +#include +#include + +// -------------------- +#include + + +// ----------------------------------------------------------- namespace ----- + +OSG_USING_NAMESPACE + + +// ------------------------------------------------------------- OpenMesh ---- + +struct MeshTraits : public OpenMesh::Kernel_OSG::Traits +{ + HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge); + VertexAttributes ( OpenMesh::Attributes::Normal | + OpenMesh::Attributes::Color ); + FaceAttributes ( OpenMesh::Attributes::Normal ); +}; + +typedef OpenMesh::Kernel_OSG::TriMesh_OSGArrayKernelT mesh_t; +typedef OpenMesh::Subdivider::Uniform::LoopT< mesh_t > loop_t; +typedef OpenMesh::Smoother::JacobiLaplaceSmootherT< mesh_t > smoother_t; + +// --------------------------------------------------------------- globals ---- + +class MeshContainer +{ +public: + + typedef std::vector meshbag_t; + + const size_t InvalidIndex; + +public: + + MeshContainer() : InvalidIndex(size_t(-1)) + { } + + ~MeshContainer() + { + meshbag_t::iterator it = meshes_.begin(); + for(;it != meshes_.end(); ++it) + delete *it; + } + + size_t size() const { return meshes_.size(); } + + mesh_t& operator [] ( size_t idx ) + { + if (idx < meshes_.size()) + return *(meshes_[idx]); + throw std::range_error("Invalid index"); + } + + const mesh_t& operator [] ( size_t idx ) const + { + if (idx < meshes_.size()) + return *(meshes_[idx]); + throw std::range_error("Invalid index"); + } + + bool bind( osg::GeometryPtr geo ) + { + std::auto_ptr obj(new mesh_t); + + return (OpenMesh::Kernel_OSG::bind< mesh_t >( *obj, geo)) + ? (meshes_.push_back(obj.release()), true) + : false; + } + + + +private: + + meshbag_t meshes_; + +private: // non-copyable + + MeshContainer( const MeshContainer& ); + MeshContainer& operator = ( const MeshContainer& ); +}; + + +struct Globals +{ + // OpenSG specific entities + SimpleSceneManager* mgr; + GLUTWindowPtr gwin; + NodePtr root; + std::vector geos; + size_t sel; + bool statistics; + + // OpenMesh specific entities + MeshContainer meshes; + +} g; + + +// -------------------------------------------------------------- forwards ---- + +void display(void); +void reshape(int width, int height); +void mouse(int button, int state, int x, int y); +void keyboard(unsigned char key, int x, int y); +void motion(int x, int y); + + +// ---------------------------------------------------------------- helper ---- + +// setup the GLUT library which handles the windows for us +int setupGLUT(int *argc, char *argv[]) +{ + glutInit(argc, argv); + glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); + + int winid = glutCreateWindow("OpenMesh within OpenSG"); + + glutReshapeFunc(reshape); + glutDisplayFunc(display); + glutMouseFunc(mouse); + glutMotionFunc(motion); + glutKeyboardFunc(keyboard); + + return winid; +} + + +// -------------------------------------------------- locate geometry node ---- +/* + This function uses the fact that ::dcast() acts like dynamic_cast. It tries + to dcast the core to a GeometryPtr, and tests the result to see if it + actually was derived from Geometry. +*/ + +Action::ResultE bindGeo(NodePtr& node) +{ + GeometryPtr geo = GeometryPtr::dcast(node->getCore()); + + if (geo!=NullFC) + { + if ( g.meshes.bind( geo ) ) + { + std::cout << " Geometry connected to OpenMesh object\n"; + g.geos.push_back(geo); + g.sel = g.meshes.size()-1; + assert( g.geos.size() == g.meshes.size() ); + } + else + std::cerr << " Warning! Could not bind the OpenMesh" + << " object to the geometry!\n"; + } + return Action::Continue; +} + +// ------------------------------------------------------------------ main ---- + + +int main(int argc, char **argv) +{ + // OSG init + osgInit(argc,argv); + + int winid = setupGLUT(&argc, argv); + + // the connection between GLUT and OpenSG + g.gwin = GLUTWindow::create(); + g.gwin->setId(winid); + g.gwin->init(); + + // -------------------- create root node with core + std::cout << "Create root node with core\n"; + + g.root = Node::create(); + NodeCorePtr core = Group::create(); + + osg::beginEditCP(g.root); + { + g.root->setCore(core); + } + osg::endEditCP(g.root); + + // -------------------- load the scene + std::cout << "Load a scene from '" << argv[1] << "'\n"; + + NodePtr node = SceneFileHandler::the().read( argv[1] ); + + if ( node != NullFC ) + { + osg::beginEditCP(g.root); + { + g.root->addChild(node); + } + osg::endEditCP(g.root); + } + else + return 1; + + // -------------------- bind all geometry nodes to an OpenMesh + std::cout << "Bind all geometry nodes\n"; + + traverse(g.root, + osgTypedFunctionFunctor1CPtrRef(bindGeo)); + + if (!g.meshes.size()) + { + std::cerr << " No geometry found. Nothing to do!\n"; + return 1; + } + else + std::cout << " Number of bound geometry: " << g.meshes.size() << std::endl; + + // -------------------- create the SimpleSceneManager helper + std::cout << "Create simple scene manager\n"; + + g.mgr = new SimpleSceneManager; + + // tell the manager what to manage + g.mgr->setWindow(g.gwin); + g.mgr->setRoot (g.root); + + // + g.mgr->useOpenSGLogo(); + g.mgr->setStatistics(false); + + // -------------------- show the whole scene + std::cout << "Display everything\n"; + + g.mgr->showAll(); + + glutMainLoop(); + return 0; +} + +// --------------------------------------------------------------- display ---- + +void display(void) +{ + g.mgr->redraw(); +} + +// --------------------------------------------------------------- reshape ---- + +void reshape(int w, int h) +{ + g.mgr->resize(w, h); + glutPostRedisplay(); +} + +// ----------------------------------------------------------------- mouse ---- + +void mouse(int button, int state, int x, int y) +{ + if (state) + { + g.mgr->mouseButtonRelease(button, x, y); +// if ( g.mode & FLYMODE ) +// glutIdleFunc(NULL); + } + else + { + g.mgr->mouseButtonPress(button, x, y); +// if ( g.mode & FLYMODE ) +// glutIdleFunc(idle); + } + glutPostRedisplay(); +} + +// -------------------------------------------------------------- keyboard ---- + +void keyboard(unsigned char key, int x, int y) +{ +#define MESH g.meshes[g.sel] +#define GEO g.geos[g.sel] +#define YN(b) (b?"yes":"no") + OpenMesh::Utils::Timer t; + + using namespace std; + + switch(key) + { + case 27: // escape + exit(0); + break; + + case 'i': + { + cout << "OpenMesh information for obj #" << g.sel << ":\n"; + cout << " #Vertices: " << MESH.n_vertices() << endl; + cout << " #Faces: " << MESH.n_faces() << endl; + cout << " #Edges: " << MESH.n_edges() << endl; + cout << " v. normal: " << YN(MESH.has_vertex_normals()) << endl; + cout << " v. color: " << YN(MESH.has_vertex_colors()) << endl; + cout << "v. texcoord: " << YN(MESH.has_vertex_texcoords()) << endl; + cout << " f. normal: " << YN(MESH.has_face_normals()) << endl; + cout << " f. color: " << YN(MESH.has_face_colors()) << endl; + break; + } + case 'I': + cout << "Geometry information for obj #" << g.sel << ":\n"; + cout << " #Types: " << GEO->getTypes()->size() << endl; + cout << " #Lengths: " << GEO->getLengths()->size() << endl; + cout << " #Indices: " << GEO->getIndices()->size() << endl; + cout << "#Positions: " << GEO->getPositions()->size() << endl; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if ((size_t(key)-size_t('0')) < g.meshes.size()) + { + g.sel = (size_t(key)-size_t('0')); + cout << "Selected geometry #" << g.sel << endl; + } + break; + + case '+': + g.sel = ++g.sel % g.meshes.size(); + cout << "Selected geometry #" << g.sel << endl; + break; + + case '-': + g.sel = (g.sel + g.meshes.size()-1) % g.meshes.size(); + cout << "Selected geometry #" << g.sel << endl; + break; + + case 'S': + g.mgr->setStatistics( g.statistics=!g.statistics ); + g.statistics + ? cout << "Statistics enabled.\n" + : cout << "Statistics disabled.\n"; + glutPostRedisplay(); + break; + + case 'w': + { + OpenMesh::IO::Options opt; + + if (MESH.has_vertex_colors()) + opt += OpenMesh::IO::Options::VertexColor; + if (MESH.has_face_colors()) + opt += OpenMesh::IO::Options::FaceColor; + if (MESH.has_vertex_normals()) + opt += OpenMesh::IO::Options::VertexNormal; + + std::string ofname; + { + std::stringstream ostr; + ostr << "object-" << g.sel << ".om"; + ofname = ostr.str(); + } + + cout << "Writing OpenMesh of geometry #" << g.sel + << " to " << ofname << std::endl; + t.start(); + bool rc = OpenMesh::IO::write_mesh( MESH, ofname, opt); + t.stop(); + rc + ? cout << " Done (" << t.as_string() << ")\n" + : cout << " Failed to store OpenMesh\n"; + + break; + } + + case 's': + { + cout << "Appyling two smoothing steps on selected geometry.."; + t.start(); + smoother_t smoother( g.meshes[g.sel] ); + smoother.initialize( smoother_t::Tangential, smoother_t::C1 ); + beginEditCP(g.geos[g.sel]); + smoother.smooth(2); + endEditCP(g.geos[g.sel]); + t.stop(); + cout << "done. " << t.as_string() << endl; + glutPostRedisplay(); + break; + } + + case 't': + { + cout << "Applying two smoothing steps on all bound geometry.."; + t.start(); + for(size_t i = 0; i < g.meshes.size(); ++i) + { + smoother_t smoother( g.meshes[i] ); + smoother.initialize( smoother_t::Tangential, smoother_t::C1 ); + beginEditCP(g.geos[i]); + smoother.smooth(2); + endEditCP(g.geos[i]); + } + t.stop(); + cout << "done. " << t.as_string() << endl; + glutPostRedisplay(); + break; + } + + case 'c': + { + OpenMesh::IO::Options opt; + + if (MESH.has_vertex_colors()) + opt += OpenMesh::IO::Options::VertexColor; + if (MESH.has_face_colors()) + opt += OpenMesh::IO::Options::FaceColor; + if (MESH.has_vertex_normals()) + opt += OpenMesh::IO::Options::VertexNormal; + + mesh_t m(MESH); + + std::string ofname; + { + std::stringstream ostr; + ostr << "copy-" << g.sel << ".om"; + ofname = ostr.str(); + } + + cout << "Writing copy of geometry #" << g.sel + << " to " << ofname << std::endl; + t.start(); + bool rc = OpenMesh::IO::write_mesh( MESH, ofname, opt); + t.stop(); + rc + ? cout << " Done (" << t.as_string() << ")\n" + : cout << " Failed to store OpenMesh\n"; + + OpenMesh::IO::write_mesh( m, ofname ); + + break; + } + + case 'u': + { + cout << "Applying one step of loop subdivision.."; + t.start(); + loop_t loop; + beginEditCP( GEO ); + loop( MESH, 1 ); + MESH.update_normals(); + endEditCP( GEO ); + t.stop(); + cout << "done. " << t.as_string() << endl; + glutPostRedisplay(); + break; + } + + default: + cout << "key [0x" << setw(4) << hex << key << dec << "]\n"; + } +#undef YN +#undef MESH +} + +//----------------------------------------------------------------- motion ---- + +void motion(int x, int y) +{ + g.mgr->mouseMove(x, y); + glutPostRedisplay(); +} diff --git a/Apps/Deprecated/ProgViewer/ACGMakefile b/Apps/Deprecated/ProgViewer/ACGMakefile new file mode 100644 index 00000000..dd5b34d0 --- /dev/null +++ b/Apps/Deprecated/ProgViewer/ACGMakefile @@ -0,0 +1,18 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + +CXX_CFLAGS += -DQT_THREAD_SUPPORT + +SUBDIRS = $(call find-subdirs) + +PACKAGES := qt4 glut opengl x11 math + +PROJ_LIBS = OpenMesh/Apps/QtViewer OpenMesh/Tools OpenMesh/Core + +MODULES := moc4 cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Apps/Deprecated/ProgViewer/OpenMesh_Apps_ProgViewer.vcproj b/Apps/Deprecated/ProgViewer/OpenMesh_Apps_ProgViewer.vcproj new file mode 100644 index 00000000..0ae89add --- /dev/null +++ b/Apps/Deprecated/ProgViewer/OpenMesh_Apps_ProgViewer.vcproj @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Apps/Deprecated/ProgViewer/ProgViewerWidget.cc b/Apps/Deprecated/ProgViewer/ProgViewerWidget.cc new file mode 100644 index 00000000..f4b8b6cf --- /dev/null +++ b/Apps/Deprecated/ProgViewer/ProgViewerWidget.cc @@ -0,0 +1,321 @@ +//============================================================================= +// +// 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: 1800 $ +// $Date: 2008-05-19 11:51:23 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#ifdef _MSC_VER +# pragma warning(disable: 4267 4311) +#endif + +#include +#include +// -------------------- +#include +#include +#include +// -------------------- +#include +#include +#include +#include +#include +// -------------------- +#ifdef ARCH_DARWIN +# include +#else +# include +#endif + +using namespace Qt; +//== IMPLEMENTATION ========================================================== + + +void +ProgViewerWidget::open_prog_mesh(const char* _filename) +{ + MyMesh::Point p; + unsigned int i, i0, i1, i2; + unsigned int v1, vl, vr; + char c[10]; + + std::ifstream ifs(_filename, std::ios::binary); + if (!ifs) + { + std::cerr << "read error\n"; + exit(1); + } + + // + bool swap = OpenMesh::Endian::local() != OpenMesh::Endian::LSB; + + // read header + ifs.read(c, 8); c[8] = '\0'; + if (std::string(c) != std::string("ProgMesh")) + { + std::cerr << "Wrong file format.\n"; + exit(1); + } + OpenMesh::IO::binary::restore( ifs, n_base_vertices_, swap ); + OpenMesh::IO::binary::restore( ifs, n_base_faces_, swap ); + OpenMesh::IO::binary::restore( ifs, n_detail_vertices_, swap ); + + n_max_vertices_ = n_base_vertices_ + n_detail_vertices_; + + // load base mesh + mesh_.clear(); + + for (i=0; i::restore( ifs, p, swap ); + mesh_.add_vertex(p); + } + + for (i=0; i::restore( ifs, i0, swap); + OpenMesh::IO::binary::restore( ifs, i1, swap); + OpenMesh::IO::binary::restore( ifs, i2, swap); + mesh_.add_face(mesh_.vertex_handle(i0), + mesh_.vertex_handle(i1), + mesh_.vertex_handle(i2)); + } + + + // load progressive detail + for (i=0; i::restore( ifs, p, swap ); + OpenMesh::IO::binary::restore( ifs, v1, swap ); + OpenMesh::IO::binary::restore( ifs, vl, swap ); + OpenMesh::IO::binary::restore( ifs, vr, swap ); + + PMInfo pminfo; + pminfo.p0 = p; + pminfo.v1 = MyMesh::VertexHandle(v1); + pminfo.vl = MyMesh::VertexHandle(vl); + pminfo.vr = MyMesh::VertexHandle(vr); + pminfos_.push_back(pminfo); + } + pmiter_ = pminfos_.begin(); + + + // update face and vertex normals + mesh_.update_face_normals(); + mesh_.update_vertex_normals(); + + // bounding box + MyMesh::ConstVertexIter + vIt(mesh_.vertices_begin()), + vEnd(mesh_.vertices_end()); + + MyMesh::Point bbMin, bbMax; + + bbMin = bbMax = mesh_.point(vIt); + for (; vIt!=vEnd; ++vIt) + { + bbMin.minimize(mesh_.point(vIt)); + bbMax.maximize(mesh_.point(vIt)); + } + + // set center and radius + set_scene_pos(0.5f*(bbMin + bbMax), 0.5*(bbMin - bbMax).norm()); + + // info + std::cerr << mesh_.n_vertices() << " vertices, " + << mesh_.n_edges() << " edge, " + << mesh_.n_faces() << " faces, " + << n_detail_vertices_ << " detail vertices\n"; + + setWindowTitle( QFileInfo(_filename).fileName() ); +} + + +//----------------------------------------------------------------------------- + + +void ProgViewerWidget::refine(unsigned int _n) +{ + size_t n_vertices = mesh_.n_vertices(); + + while (n_vertices < _n && pmiter_ != pminfos_.end()) + { + pmiter_->v0 = mesh_.add_vertex(pmiter_->p0); + mesh_.vertex_split(pmiter_->v0, + pmiter_->v1, + pmiter_->vl, + pmiter_->vr); + ++pmiter_; + ++n_vertices; + } + + mesh_.update_face_normals(); + mesh_.update_vertex_normals(); + + std::cerr << n_vertices << " vertices\n"; +} + + +//----------------------------------------------------------------------------- + + +void ProgViewerWidget::coarsen(unsigned int _n) +{ + size_t n_vertices = mesh_.n_vertices(); + + while (n_vertices > _n && pmiter_ != pminfos_.begin()) + { + --pmiter_; + + MyMesh::HalfedgeHandle hh = + mesh_.find_halfedge(pmiter_->v0, pmiter_->v1); + + mesh_.collapse(hh); + + --n_vertices; + } + + mesh_.garbage_collection(); + mesh_.update_face_normals(); + mesh_.update_vertex_normals(); + + std::cerr << n_vertices << " vertices\n"; +} + + +//----------------------------------------------------------------------------- + +void ProgViewerWidget::keyPressEvent(QKeyEvent* _event) +{ + switch (_event->key()) + { + case Key_Minus: + if ( _event->modifiers() & ShiftModifier) + coarsen(mesh_.n_vertices()-1); + else + coarsen((unsigned int)(0.9*mesh_.n_vertices())); + updateGL(); + break; + + case Key_Plus: + if (_event->modifiers() & ShiftModifier) + refine(mesh_.n_vertices()+1); + else + refine((unsigned int)(std::max( 1.1*mesh_.n_vertices(), + mesh_.n_vertices()+1.0) )); + updateGL(); + break; + + case Key_Home: + coarsen(n_base_vertices_); + updateGL(); + break; + + case Key_A: + if (timer_->isActive()) + { + timer_->stop(); + std::cout << "animation stopped!" << std::endl; + } + else + { + timer_->setSingleShot(true); + timer_->start(0); + std::cout << "animation started!" << std::endl; + } + break; + + case Key_End: + refine(n_base_vertices_ + n_detail_vertices_); + updateGL(); + break; + + case Key_P: + { + const size_t refine_max = 100000; + const size_t n_loop = 5; + + OpenMesh::Utils::Timer t; + size_t count; + + coarsen(0); count = mesh_.n_vertices(); + refine(refine_max); count = mesh_.n_vertices() - count; + + t.start(); + for (size_t i=0; iBase::keyPressEvent(_event); + } +} + +void ProgViewerWidget::animate( void ) +{ + if (animateRefinement_) + { + refine((unsigned int)( 1.1*(mesh_.n_vertices()+1) )); + if ( mesh_.n_vertices() > n_base_vertices_+(0.5*n_detail_vertices_)) + animateRefinement_ = false; + } + else + { + coarsen((unsigned int)(0.9*(mesh_.n_vertices()-1))); + if ( mesh_.n_vertices() == n_base_vertices_ ) + animateRefinement_ = true; + } + updateGL(); + timer_->setSingleShot(true); + timer_->start(300); +} + +//============================================================================= diff --git a/Apps/Deprecated/ProgViewer/ProgViewerWidget.hh b/Apps/Deprecated/ProgViewer/ProgViewerWidget.hh new file mode 100644 index 00000000..8f451d4f --- /dev/null +++ b/Apps/Deprecated/ProgViewer/ProgViewerWidget.hh @@ -0,0 +1,137 @@ +//============================================================================= +// +// 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: 1800 $ +// $Date: 2008-05-19 11:51:23 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +#ifndef OPENMESHAPPS_PROGVIEWERWIDGET_HH +#define OPENMESHAPPS_PROGVIEWERWIDGET_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + + + +//== CLASS DEFINITION ========================================================= + + +using namespace OpenMesh; +using namespace OpenMesh::Attributes; + + +struct MyTraits : public OpenMesh::DefaultTraits +{ + VertexAttributes ( OpenMesh::Attributes::Normal | + OpenMesh::Attributes::Status ); + EdgeAttributes ( OpenMesh::Attributes::Status ); + HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge ); + FaceAttributes ( OpenMesh::Attributes::Normal | + OpenMesh::Attributes::Status ); +}; + + +typedef OpenMesh::TriMesh_ArrayKernelT MyMesh; +typedef MeshViewerWidgetT MeshViewerWidget; + + +//== CLASS DEFINITION ========================================================= + + + +class ProgViewerWidget : public MeshViewerWidget +{ + Q_OBJECT + +public: + + typedef MeshViewerWidget Base; + typedef ProgViewerWidget This; + + +public: + /// default constructor + ProgViewerWidget(QWidget* _parent=0) + : MeshViewerWidget(_parent) + { + timer_ = new QTimer(this); + + connect( timer_, SIGNAL(timeout()), SLOT(animate()) ); + } + + /// destructor + ~ProgViewerWidget() + { + delete timer_; + } + + /// open progressive mesh + void open_prog_mesh(const char* _filename); + +protected slots: + +void animate( void ); + +private: + + QTimer *timer_; + + struct PMInfo + { + MyMesh::Point p0; + MyMesh::VertexHandle v0, v1, vl, vr; + }; + typedef std::vector PMInfoContainer; + typedef PMInfoContainer::iterator PMInfoIter; + + /// refine mesh up to _n vertices + void refine(unsigned int _n); + + /// coarsen mesh down to _n vertices + void coarsen(unsigned int _n); + + virtual void keyPressEvent(QKeyEvent* _event); + + // mesh data + bool animateRefinement_; + PMInfoContainer pminfos_; + PMInfoIter pmiter_; + size_t n_base_vertices_, n_base_faces_, n_detail_vertices_; + size_t n_max_vertices_; +}; + + +//============================================================================= +#endif // OPENMESHAPPS_PROGVIEWERWIDGET_HH defined +//============================================================================= + diff --git a/Apps/Deprecated/ProgViewer/progviewer.cc b/Apps/Deprecated/ProgViewer/progviewer.cc new file mode 100644 index 00000000..d19f61e1 --- /dev/null +++ b/Apps/Deprecated/ProgViewer/progviewer.cc @@ -0,0 +1,78 @@ +//============================================================================= +// +// 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: 2096 $ +// $Date: 2008-06-26 13:16:48 +0200 (Do, 26. Jun 2008) $ +// +//============================================================================= + +#ifdef _MSC_VER +# pragma warning(disable: 4267 4311) +#endif + +#include +#include + +#include +#include +#include +#include + +#include + +int main(int argc, char **argv) +{ + // OpenGL check + QApplication::setColorSpec( QApplication::CustomColor ); + QApplication app(argc,argv); + + glutInit(&argc,argv); + + if ( !QGLFormat::hasOpenGL() ) { + std::cerr << "This system has no OpenGL support.\n"; + return -1; + } + + + // create widget + ProgViewerWidget w(0); + w.resize(400, 400); + w.show(); + + // load scene + if (argc > 1) w.open_prog_mesh(argv[1]); + + + // print usage info + std::cout << "\n\n" + << "Press Minus : Coarsen mesh\n" + << " Plus : Refine mesh\n" + << " Home : Coarsen down to base mesh\n" + << " End : Refine up to finest mesh\n" + << "\n"; + + + return app.exec(); +} diff --git a/Apps/Deprecated/Streaming-qt4/ACGMakefile b/Apps/Deprecated/Streaming-qt4/ACGMakefile new file mode 100644 index 00000000..3e506776 --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/ACGMakefile @@ -0,0 +1,16 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = $(call find-subdirs) + +PACKAGES := + +PROJ_LIBS := + +MODULES := + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Apps/Deprecated/Streaming-qt4/Client/ACGMakefile b/Apps/Deprecated/Streaming-qt4/Client/ACGMakefile new file mode 100644 index 00000000..7be85569 --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Client/ACGMakefile @@ -0,0 +1,19 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + +CXX_CFLAGS += -DQT_THREAD_SUPPORT + +SUBDIRS = $(call find-subdirs) + +PACKAGES := qt4 glut opengl + +PROJ_LIBS := OpenMesh/Apps/QtViewer \ + OpenMesh/Core OpenMesh/Tools + +MODULES := moc4 cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Apps/Deprecated/Streaming-qt4/Client/MeshViewerWidgetT.cc b/Apps/Deprecated/Streaming-qt4/Client/MeshViewerWidgetT.cc new file mode 100644 index 00000000..b25f11da --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Client/MeshViewerWidgetT.cc @@ -0,0 +1,603 @@ +//============================================================================= +// +// 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: 1800 $ +// $Date: 2008-05-19 11:51:23 +0200 (Mon, 19 May 2008) $ +// +//============================================================================= +#define OPENMESHAPPS_MESHVIEWERWIDGET_CC + +//== INCLUDES ================================================================= + +#ifdef _MSC_VER +//# pragma warning(disable: 4267 4311) +#endif + +// +#include +#include +#include +#include +#include +#include +#include + +using namespace OpenMesh; + + +//== IMPLEMENTATION ========================================================== + + +template +bool +MeshViewerWidgetT::open_mesh(const char* _filename, + IO::Options _opt) +{ + // load mesh + // calculate normals + // set scene center and radius + + mesh_.request_face_normals(); + mesh_.request_face_colors(); + mesh_.request_vertex_normals(); + mesh_.request_vertex_texcoords2D(); + + if ( IO::read_mesh(mesh_, _filename, _opt )) + { + opt_ = _opt; + + // update face and vertex normals + if ( ! opt_.check( IO::Options::FaceNormal ) ) + mesh_.update_face_normals(); + + if ( ! opt_.check( IO::Options::VertexNormal ) ) + mesh_.update_vertex_normals(); + + if ( mesh_.has_vertex_colors() ) + add_draw_mode("Colored"); + + if ( _opt.check( IO::Options::FaceColor ) ) + add_draw_mode("Colored Faces"); + else + mesh_.release_face_colors(); + + // bounding box + typename Mesh::ConstVertexIter vIt(mesh_.vertices_begin()); + typename Mesh::ConstVertexIter vEnd(mesh_.vertices_end()); + + typedef typename Mesh::Point Point; + using OpenMesh::Vec3f; + + Vec3f bbMin, bbMax; + + bbMin = bbMax = OpenMesh::vector_cast(mesh_.point(vIt)); + + for (size_t count=0; vIt!=vEnd; ++vIt, ++count) + { + bbMin.minimize( OpenMesh::vector_cast(mesh_.point(vIt))); + bbMax.maximize( OpenMesh::vector_cast(mesh_.point(vIt))); + + if ( ! opt_.check( IO::Options::VertexColor ) && + mesh_.has_vertex_colors() ) + { + typename Mesh::Color + c( 54, + (unsigned char)(54.5+200.0*count/mesh_.n_vertices()), + 54 ); + mesh_.set_color( vIt, c ); + } + } + + + // set center and radius + set_scene_pos( (bbMin+bbMax)*0.5, (bbMin-bbMax).norm()*0.5 ); + + // info + std::clog << mesh_.n_vertices() << " vertices, " + << mesh_.n_edges() << " edge, " + << mesh_.n_faces() << " faces\n"; + + // + { + std::clog << "Computing strips.." << std::flush; + OpenMesh::Utils::Timer t; + t.start(); + compute_strips(); + t.stop(); + std::clog << "done [" << strips_.n_strips() + << " strips created in " << t.as_string() << "]\n"; + } + +#if defined(OM_CC_MSVC) + updateGL(); +#endif + + return true; + } + return false; +} + + +//----------------------------------------------------------------------------- + +template +bool MeshViewerWidgetT::open_texture( const char *_filename ) +{ + QImage texsrc; + QString fname = _filename; + + if (texsrc.load( fname )) + { + return set_texture( texsrc ); + } + return false; +} + + +//----------------------------------------------------------------------------- + +template +bool MeshViewerWidgetT::set_texture( QImage& _texsrc ) +{ + std::clog << "set_texture\n"; + + if ( !opt_.vertex_has_texcoord() ) + return false; + + { + // adjust texture size: 2^k * 2^l + int tex_w, w( _texsrc.width() ); + int tex_h, h( _texsrc.height() ); + + for (tex_w=1; tex_w <= w; tex_w <<= 1) ; + for (tex_h=1; tex_h <= h; tex_h <<= 1) ; + tex_w >>= 1; + tex_h >>= 1; + _texsrc = _texsrc.scaled( tex_w, tex_h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); + } + + QImage texture( QGLWidget::convertToGLFormat ( _texsrc ) ); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ROW_LENGTH, 0); + glPixelStorei(GL_PACK_SKIP_ROWS, 0); + glPixelStorei(GL_PACK_SKIP_PIXELS, 0); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + if ( tex_id_ > 0 ) + { + glDeleteTextures(1, &tex_id_); + } + glGenTextures(1, &tex_id_); + glBindTexture(GL_TEXTURE_2D, tex_id_); + + // glTexGenfv( GL_S, GL_SPHERE_MAP, 0 ); + // glTexGenfv( GL_T, GL_SPHERE_MAP, 0 ); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glTexImage2D(GL_TEXTURE_2D, // target + 0, // level + GL_RGBA, // internal format + texture.width(), // width (2^n) + texture.height(), // height (2^m) + 0, // border + GL_RGBA, // format + GL_UNSIGNED_BYTE, // type + texture.bits() ); // pointer to pixels + + return true; +} + + +//----------------------------------------------------------------------------- + +template +void +MeshViewerWidgetT::draw_openmesh(const std::string& _draw_mode) +{ + typename Mesh::ConstFaceIter fIt(mesh_.faces_begin()), + fEnd(mesh_.faces_end()); + + typename Mesh::ConstFaceVertexIter fvIt; + +#if defined(OM_USE_OSG) && OM_USE_OSG + if (_draw_mode == "OpenSG Indices") // -------------------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); + + if ( tex_id_ && mesh_.has_vertex_texcoords2D() ) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 0, mesh_.texcoords2D()); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tex_id_); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, tex_mode_); + } + + glDrawElements(GL_TRIANGLES, + mesh_.osg_indices()->size(), + GL_UNSIGNED_INT, + &mesh_.osg_indices()->getField()[0] ); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + else +#endif + + if (_draw_mode == "Wireframe") // -------------------------------------------- + { + glBegin(GL_TRIANGLES); + for (; fIt!=fEnd; ++fIt) + { + fvIt = mesh_.cfv_iter(fIt.handle()); + glVertex3fv( &mesh_.point(fvIt)[0] ); + ++fvIt; + glVertex3fv( &mesh_.point(fvIt)[0] ); + ++fvIt; + glVertex3fv( &mesh_.point(fvIt)[0] ); + } + glEnd(); + } + + else if (_draw_mode == "Solid Flat") // ------------------------------------- + { + glBegin(GL_TRIANGLES); + for (; fIt!=fEnd; ++fIt) + { + glNormal3fv( &mesh_.normal(fIt)[0] ); + + fvIt = mesh_.cfv_iter(fIt.handle()); + glVertex3fv( &mesh_.point(fvIt)[0] ); + ++fvIt; + glVertex3fv( &mesh_.point(fvIt)[0] ); + ++fvIt; + glVertex3fv( &mesh_.point(fvIt)[0] ); + } + glEnd(); + + + } + + + else if (_draw_mode == "Solid Smooth") // ----------------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); + + if ( tex_id_ && mesh_.has_vertex_texcoords2D() ) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 0, mesh_.texcoords2D()); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tex_id_); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, tex_mode_); + } + + glBegin(GL_TRIANGLES); + for (; fIt!=fEnd; ++fIt) + { + fvIt = mesh_.cfv_iter(fIt.handle()); + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + } + glEnd(); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + if ( tex_id_ && mesh_.has_vertex_texcoords2D() ) + { + glDisable(GL_TEXTURE_2D); + } + } + + else if (_draw_mode == "Colored") // ---------------------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); + + if ( mesh_.has_vertex_colors() ) + { + glEnableClientState( GL_COLOR_ARRAY ); + glColorPointer(3, GL_UNSIGNED_BYTE, 0,mesh_.vertex_colors()); + } + + glBegin(GL_TRIANGLES); + for (; fIt!=fEnd; ++fIt) + { + fvIt = mesh_.cfv_iter(fIt.handle()); + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + } + glEnd(); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + } + + + else if (_draw_mode == "Colored Faces") // ---------------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); + + glBegin(GL_TRIANGLES); + for (; fIt!=fEnd; ++fIt) + { + glColor( fIt.handle() ); + + fvIt = mesh_.cfv_iter(fIt.handle()); + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + } + glEnd(); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + } + + + else if ( _draw_mode == "Strips'n VertexArrays" ) // ------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); + + if ( tex_id_ && mesh_.has_vertex_texcoords2D() ) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 0, mesh_.texcoords2D()); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tex_id_); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, tex_mode_); + } + + typename MyStripifier::StripsIterator strip_it = strips_.begin(); + typename MyStripifier::StripsIterator strip_last = strips_.end(); + + // Draw all strips + for (; strip_it!=strip_last; ++strip_it) + { + glDrawElements(GL_TRIANGLE_STRIP, + strip_it->size(), GL_UNSIGNED_INT, &(*strip_it)[0] ); + } + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + + + else if (_draw_mode == "Show Strips" && strips_.is_valid() ) // ------------- + { + typename MyStripifier::StripsIterator strip_it = strips_.begin(); + typename MyStripifier::StripsIterator strip_last = strips_.end(); + + float cmax = 256.0f; + int range = 220; + int base = (int)cmax-range; + int drcol = 13; + int dgcol = 31; + int dbcol = 17; + + int rcol=0, gcol=dgcol, bcol=dbcol+dbcol; + + // Draw all strips + for (; strip_it!=strip_last; ++strip_it) + { + typename MyStripifier::IndexIterator idx_it = strip_it->begin(); + typename MyStripifier::IndexIterator idx_last = strip_it->end(); + + rcol = (rcol+drcol) % range; + gcol = (gcol+dgcol) % range; + bcol = (bcol+dbcol) % range; + + glBegin(GL_TRIANGLE_STRIP); + glColor3f((rcol+base)/cmax, (gcol+base)/cmax, (bcol+base)/cmax); + for ( ;idx_it != idx_last; ++idx_it ) + glVertex3fv( &mesh_.point( OM_TYPENAME Mesh::VertexHandle(*idx_it))[0] ); + glEnd(); + } + glColor3f(1.0, 1.0, 1.0); + } + + + else if( _draw_mode == "Points" ) // ----------------------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + glDrawArrays( GL_POINTS, 0, mesh_.n_vertices() ); + glDisableClientState(GL_VERTEX_ARRAY); + } + + +} + + +//----------------------------------------------------------------------------- + + +template +void +MeshViewerWidgetT::draw_scene(const std::string& _draw_mode) +{ + + if ( ! mesh_.n_vertices() ) + return; + +#if defined(OM_USE_OSG) && OM_USE_OSG + else if ( _draw_mode == "OpenSG Indices") + { + glEnable(GL_LIGHTING); + glShadeModel(GL_SMOOTH); + draw_openmesh( _draw_mode ); + } + else +#endif + if ( _draw_mode == "Points" ) + { + glDisable(GL_LIGHTING); + draw_openmesh(_draw_mode); + } + else if (_draw_mode == "Wireframe") + { + glDisable(GL_LIGHTING); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + draw_openmesh(_draw_mode); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + + else if ( _draw_mode == "Hidden-Line" ) + { + glEnable(GL_LIGHTING); + glShadeModel(GL_SMOOTH); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDepthRange(0.01, 1.0); + draw_openmesh("Solid Smooth"); + + glDisable(GL_LIGHTING); + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE); + glColor4f( 0.4f, 0.4f, 0.4f, 1.0f ); + glDepthRange( 0.0, 1.0 ); + draw_openmesh( "Wireframe" ); + + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL); + } + + else if (_draw_mode == "Solid Flat") + { + glEnable(GL_LIGHTING); + glShadeModel(GL_FLAT); + draw_openmesh(_draw_mode); + } + + else if (_draw_mode == "Solid Smooth" || + _draw_mode == "Strips'n VertexArrays" ) + { + glEnable(GL_LIGHTING); + glShadeModel(GL_SMOOTH); + draw_openmesh(_draw_mode); + } + + else if (_draw_mode == "Show Strips") + { + glDisable(GL_LIGHTING); + draw_openmesh(_draw_mode); + } + + else if (_draw_mode == "Colored" ) + { + glDisable(GL_LIGHTING); + draw_openmesh(_draw_mode); + } + + else if (_draw_mode == "Colored Faces" ) + { + glDisable(GL_LIGHTING); + draw_openmesh(_draw_mode); + } +} + + +//----------------------------------------------------------------------------- + +#define TEXMODE( Mode ) \ + tex_mode_ = Mode; std::cout << "Texture mode set to " << #Mode << std::endl + +template +void +MeshViewerWidgetT::keyPressEvent( QKeyEvent* _event) +{ + switch( _event->key() ) + { + case Qt::Key_I: + std::cout << "\n# Vertices : " << mesh_.n_vertices() << std::endl; + std::cout << "# Edges : " << mesh_.n_edges() << std::endl; + std::cout << "# Faces : " << mesh_.n_faces() << std::endl; + std::cout << "binary input : " << opt_.check(opt_.Binary) << std::endl; + std::cout << "swapped input : " << opt_.check(opt_.Swap) << std::endl; + std::cout << "vertex normal : " + << opt_.check(opt_.VertexNormal) << std::endl; + std::cout << "vertex texcoord: " + << opt_.check(opt_.VertexTexCoord) << std::endl; + std::cout << "vertex color : " + << opt_.check(opt_.VertexColor) << std::endl; + this->QGLViewerWidget::keyPressEvent( _event ); + break; + + case Qt::Key_T: + switch( tex_mode_ ) + { + case GL_MODULATE: TEXMODE(GL_DECAL); break; + case GL_DECAL: TEXMODE(GL_BLEND); break; + case GL_BLEND: TEXMODE(GL_REPLACE); break; + case GL_REPLACE: TEXMODE(GL_MODULATE); break; + } + updateGL(); + break; + + default: + this->QGLViewerWidget::keyPressEvent( _event ); + } +} + +#undef TEXMODE + +//============================================================================= diff --git a/Apps/Deprecated/Streaming-qt4/Client/MeshViewerWidgetT.hh b/Apps/Deprecated/Streaming-qt4/Client/MeshViewerWidgetT.hh new file mode 100644 index 00000000..6ee85808 --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Client/MeshViewerWidgetT.hh @@ -0,0 +1,163 @@ +//============================================================================= +// +// 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: 1800 $ +// $Date: 2008-05-19 11:51:23 +0200 (Mon, 19 May 2008) $ +// +//============================================================================= + + +#ifndef OPENMESHAPPS_MESHVIEWERWIDGETT_HH +#define OPENMESHAPPS_MESHVIEWERWIDGETT_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include +#include +#include +#include + + +//== FORWARDS ================================================================= + +class QImage; + + +//== CLASS DEFINITION ========================================================= + + +template +class MeshViewerWidgetT : public QGLViewerWidget +{ +public: + typedef M Mesh; + typedef OpenMesh::StripifierT MyStripifier; + + + /// default constructor + MeshViewerWidgetT(QWidget* _parent=0, const char* _name=0) + : QGLViewerWidget(_parent, _name), + f_strips_(false), + tex_id_(0), + tex_mode_(GL_MODULATE), + strips_(mesh_) + { + add_draw_mode("Points"); + add_draw_mode("Hidden-Line"); +#if defined(OM_USE_OSG) && OM_USE_OSG + add_draw_mode("OpenSG Indices"); +#endif + } + + void enable_strips() { + f_strips_ = true; + add_draw_mode("Strips'n VertexArrays"); + add_draw_mode("Show Strips"); + } + void disable_strips() { f_strips_ = false; } + + /// destructor + ~MeshViewerWidgetT() {} + + /// open mesh + virtual bool open_mesh(const char* _filename, OpenMesh::IO::Options _opt); + + /// load texture + virtual bool open_texture( const char *_filename ); + bool set_texture( QImage& _texsrc ); + + + Mesh& mesh() { return mesh_; } + const Mesh& mesh() const { return mesh_; } + + +protected: + + /// inherited drawing method + virtual void draw_scene(const std::string& _draw_mode); + +protected: + + /// draw the mesh + virtual void draw_openmesh(const std::string& _drawmode); + + void glVertex( const typename Mesh::VertexHandle vh ) + { glVertex3fv( &mesh_.point( vh )[0] ); } + + void glNormal( const typename Mesh::VertexHandle vh ) + { glNormal3fv( &mesh_.normal( vh )[0] ); } + + void glTexCoord( const typename Mesh::VertexHandle vh ) + { glTexCoord2fv( &mesh_.texcoord(vh)[0] ); } + + void glColor( const typename Mesh::VertexHandle vh ) + { glColor3ubv( &mesh_.color(vh)[0] ); } + + void glColor( const typename Mesh::FaceHandle fh ) + { glColor3ubv( &mesh_.color(fh)[0] ); } + + + +protected: // Strip support + + void compute_strips(void) + { + if (f_strips_) + { + strips_.clear(); + strips_.stripify(); + } + } + +protected: // inherited + + virtual void keyPressEvent( QKeyEvent* _event); + +protected: + + bool f_strips_; // enable/disable strip usage + GLuint tex_id_; + GLint tex_mode_; + OpenMesh::IO::Options opt_; // mesh file contained texcoords? + + Mesh mesh_; + MyStripifier strips_; +}; + + +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESHAPPS_MESHVIEWERWIDGET_CC) +# define OPENMESH_MESHVIEWERWIDGET_TEMPLATES +# include "MeshViewerWidgetT.cc" +#endif +//============================================================================= +#endif // OPENMESHAPPS_MESHVIEWERWIDGETT_HH defined +//============================================================================= + diff --git a/Apps/Deprecated/Streaming-qt4/Client/MyMesh.hh b/Apps/Deprecated/Streaming-qt4/Client/MyMesh.hh new file mode 100644 index 00000000..b6dfdb2e --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Client/MyMesh.hh @@ -0,0 +1,23 @@ +#ifndef OPENMESH_APPS_VDPMSTREAMING_CLIENT_MYMESH_HH +#define OPENMESH_APPS_VDPMSTREAMING_CLIENT_MYMESH_HH + +#include +#include +#include +#include + + +using OpenMesh::VDPM::MeshTraits; + + +//== CLASS DEFINITION ========================================================= + + +typedef OpenMesh::TriMesh_ArrayKernelT MyMesh; + +static QMutex mutex_; + + +//== CLASS DEFINITION ========================================================= + +#endif //OPENMESH_APPS_VDPMSTREAMING_CLIENT_MYMESH_HH defined diff --git a/Apps/Deprecated/Streaming-qt4/Client/QGLViewerWidget.cc b/Apps/Deprecated/Streaming-qt4/Client/QGLViewerWidget.cc new file mode 100644 index 00000000..d729c478 --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Client/QGLViewerWidget.cc @@ -0,0 +1,621 @@ +//============================================================================= +// +// 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: 1800 $ +// $Date: 2008-05-19 11:51:23 +0200 (Mon, 19 May 2008) $ +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#ifdef _MSC_VER +# pragma warning(disable: 4267 4311 4305) +#endif + +#include + +#include +// #include +#include +#include +#include +#include + +#include +#include + +#if !defined(M_PI) +# define M_PI 3.1415926535897931 +#endif + +using namespace OpenMesh; + + +//== IMPLEMENTATION ========================================================== + + +QGLViewerWidget::QGLViewerWidget( QWidget* _parent, const char* _name ) + : QGLWidget( _parent ) +{ + // qt stuff + setWindowTitle(_name); +// setBackgroundMode( NoBackground ); + setFocusPolicy(Qt::StrongFocus); + setAcceptDrops( true ); + setCursor(Qt::PointingHandCursor); + + + // popup menu + popup_menu_ = new QMenu("Draw Mode Menu", this); + + connect( popup_menu_, SIGNAL(activated(int)), + this, SLOT(slotPopupMenu(int))); + + + // init draw modes + n_draw_modes_ = 0; + add_draw_mode("Wireframe"); + add_draw_mode("Solid Flat"); + add_draw_mode("Solid Smooth"); + + // for example + add_draw_mode("Colored"); + + slotPopupMenu(2); +} + + +//---------------------------------------------------------------------------- + + +QGLViewerWidget::~QGLViewerWidget() +{ +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::initializeGL() +{ + // OpenGL state + glClearColor(1.0, 1.0, 1.0, 0.0); + glDisable( GL_DITHER ); + glEnable( GL_DEPTH_TEST ); + glEnable( GL_CULL_FACE ); + + + // material + GLfloat mat_a[] = {0.7, 0.6, 0.5, 1.0}; + GLfloat mat_d[] = {0.8, 0.7, 0.6, 1.0}; + GLfloat mat_s[] = {1.0, 1.0, 1.0, 1.0}; + GLfloat shine[] = {120.0}; + +// GLfloat mat_a[] = {0.2, 0.2, 0.2, 1.0}; +// GLfloat mat_d[] = {0.4, 0.4, 0.4, 1.0}; +// GLfloat mat_s[] = {0.8, 0.8, 0.8, 1.0}; +// GLfloat shine[] = {128.0}; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_a); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_d); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_s); + glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shine); + + + // lighting + glLoadIdentity(); + + GLfloat pos1[] = { 0.1, 0.1, -0.02, 0.0}; + GLfloat pos2[] = {-0.1, 0.1, -0.02, 0.0}; + GLfloat pos3[] = { 0.0, 0.0, 0.1, 0.0}; + GLfloat col1[] = {.05, .05, .4, 1.0}; + GLfloat col2[] = {.4, .05, .05, 1.0}; + GLfloat col3[] = {1.0, 1.0, 1.0, 1.0}; + + glEnable(GL_LIGHT0); + glLightfv(GL_LIGHT0,GL_POSITION, pos1); + glLightfv(GL_LIGHT0,GL_DIFFUSE, col1); + glLightfv(GL_LIGHT0,GL_SPECULAR, col1); + + glEnable(GL_LIGHT1); + glLightfv(GL_LIGHT1,GL_POSITION, pos2); + glLightfv(GL_LIGHT1,GL_DIFFUSE, col2); + glLightfv(GL_LIGHT1,GL_SPECULAR, col2); + + glEnable(GL_LIGHT2); + glLightfv(GL_LIGHT2,GL_POSITION, pos3); + glLightfv(GL_LIGHT2,GL_DIFFUSE, col3); + glLightfv(GL_LIGHT2,GL_SPECULAR, col3); + + + // Fog + GLfloat fogColor[4] = { 0.4, 0.4, 0.5, 1.0 }; + glFogi(GL_FOG_MODE, GL_LINEAR); + glFogfv(GL_FOG_COLOR, fogColor); + glFogf(GL_FOG_DENSITY, 0.35); + glHint(GL_FOG_HINT, GL_DONT_CARE); + glFogf(GL_FOG_START, 5.0f); + glFogf(GL_FOG_END, 25.0f); + + // scene pos and size + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix_); + set_scene_pos(Vec3f(0.0, 0.0, 0.0), 1.0); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::resizeGL( int _w, int _h ) +{ + update_projection_matrix(); + glViewport(0, 0, _w, _h); + updateGL(); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::paintGL() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glMatrixMode( GL_PROJECTION ); + glLoadMatrixd( projection_matrix_ ); + glMatrixMode( GL_MODELVIEW ); + glLoadMatrixd( modelview_matrix_ ); + + if (draw_mode_) + { + assert(draw_mode_ <= n_draw_modes_); + draw_scene(draw_mode_names_[draw_mode_-1]); + } +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::draw_scene(const std::string& _draw_mode) +{ + if (_draw_mode == "Wireframe") + { + glDisable(GL_LIGHTING); + glutWireTeapot(0.5); + } + + else if (_draw_mode == "Solid Flat") + { + glEnable(GL_LIGHTING); + glShadeModel(GL_FLAT); + glutSolidTeapot(0.5); + } + + else if (_draw_mode == "Solid Smooth") + { + glEnable(GL_LIGHTING); + glShadeModel(GL_SMOOTH); + glutSolidTeapot(0.5); + } + +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::mousePressEvent( QMouseEvent* _event ) +{ + // popup menu + if (_event->button() == Qt::RightButton) + { + popup_menu_->exec(QCursor::pos()); + } + + else + { + last_point_ok_ = map_to_sphere( last_point_2D_=_event->pos(), + last_point_3D_ ); + } +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::mouseMoveEvent( QMouseEvent* _event ) +{ + QPoint newPoint2D = _event->pos(); + + if ( (newPoint2D.x()<0) || (newPoint2D.x()>width()) || + (newPoint2D.y()<0) || (newPoint2D.y()>height()) ) return; + + + // Left button: rotate around center_ + // Middle button: translate object + // Left & middle button: zoom in/out + + + float value_y; + Vec3f newPoint3D; + bool newPoint_hitSphere = map_to_sphere( newPoint2D, newPoint3D ); + + float dx = newPoint2D.x() - last_point_2D_.x(); + float dy = newPoint2D.y() - last_point_2D_.y(); + + float w = width(); + float h = height(); + + + + // enable GL context + makeCurrent(); + + + // move in z direction + if ( (_event->button() == Qt::LeftButton) && (_event->button() == Qt::MidButton)) + { + value_y = radius_ * dy * 3.0 / h; + translate(Vec3f(0.0, 0.0, value_y)); + } + + + // move in x,y direction + else if (_event->button() == Qt::MidButton) + { + float z = - (modelview_matrix_[ 2]*center_[0] + + modelview_matrix_[ 6]*center_[1] + + modelview_matrix_[10]*center_[2] + + modelview_matrix_[14]) / + (modelview_matrix_[ 3]*center_[0] + + modelview_matrix_[ 7]*center_[1] + + modelview_matrix_[11]*center_[2] + + modelview_matrix_[15]); + + float aspect = w / h; + float near_plane = 0.01 * radius_; + float top = tan(fovy()/2.0f*M_PI/180.0f) * near_plane; + float right = aspect*top; + + translate(Vec3f( 2.0*dx/w*right/near_plane*z, + -2.0*dy/h*top/near_plane*z, + 0.0f)); + } + + + + // rotate + else if (_event->button() == Qt::LeftButton) + { + if (last_point_ok_) + { + if ( (newPoint_hitSphere = map_to_sphere(newPoint2D, newPoint3D)) ) + { + Vec3f axis = last_point_3D_ % newPoint3D; + float cos_angle = (last_point_3D_ | newPoint3D); + if ( fabs(cos_angle) < 1.0 ) + { + float angle = 2.0 * acos( cos_angle ) * 180.0 / M_PI; + rotate( axis, angle ); + } + } + } + } + + + // remember this point + last_point_2D_ = newPoint2D; + last_point_3D_ = newPoint3D; + last_point_ok_ = newPoint_hitSphere; + + // trigger redraw + updateGL(); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::mouseReleaseEvent( QMouseEvent* /* _event */ ) +{ + last_point_ok_ = false; +} + + +//----------------------------------------------------------------------------- + + +void QGLViewerWidget::wheelEvent(QWheelEvent* _event) +{ + // Use the mouse wheel to zoom in/out + + float d = -(float)_event->delta() / 120.0 * 0.2 * radius_; + translate(Vec3f(0.0, 0.0, d)); + updateGL(); + _event->accept(); +} + + +//---------------------------------------------------------------------------- + + +void QGLViewerWidget::keyPressEvent( QKeyEvent* _event) +{ + switch( _event->key() ) + { + case Qt::Key_C: + if ( glIsEnabled( GL_CULL_FACE ) ) + { + glDisable( GL_CULL_FACE ); + std::cout << "Back face culling: disabled\n"; + } + else + { + glEnable( GL_CULL_FACE ); + std::cout << "Back face culling: enabled\n"; + } + updateGL(); + break; + + case Qt::Key_I: + std::cout << "Radius: " << radius_ << std::endl; + std::cout << "Center: " << center_ << std::endl; + break; + + case Qt::Key_Space: + case Qt::Key_M: + { + double fps = performance(); + std::cout << "fps: " +#if defined(OM_CC_GCC) && (OM_CC_VERSION < 30000) + << std::setiosflags (std::ios::fixed) +#else + << std::setiosflags (std::ios_base::fixed) +#endif + << fps << std::endl; + } + break; + + case Qt::Key_Q: + case Qt::Key_Escape: + qApp->quit(); + } + _event->ignore(); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::translate( const Vec3f& _trans ) +{ + // Translate the object by _trans + // Update modelview_matrix_ + makeCurrent(); + glLoadIdentity(); + glTranslated( _trans[0], _trans[1], _trans[2] ); + glMultMatrixd( modelview_matrix_ ); + glGetDoublev( GL_MODELVIEW_MATRIX, modelview_matrix_); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::rotate( const Vec3f& _axis, float _angle ) +{ + // Rotate around center center_, axis _axis, by angle _angle + // Update modelview_matrix_ + + Vec3f t( modelview_matrix_[0]*center_[0] + + modelview_matrix_[4]*center_[1] + + modelview_matrix_[8]*center_[2] + + modelview_matrix_[12], + modelview_matrix_[1]*center_[0] + + modelview_matrix_[5]*center_[1] + + modelview_matrix_[9]*center_[2] + + modelview_matrix_[13], + modelview_matrix_[2]*center_[0] + + modelview_matrix_[6]*center_[1] + + modelview_matrix_[10]*center_[2] + + modelview_matrix_[14] ); + + makeCurrent(); + glLoadIdentity(); + glTranslatef(t[0], t[1], t[2]); + glRotated( _angle, _axis[0], _axis[1], _axis[2]); + glTranslatef(-t[0], -t[1], -t[2]); + glMultMatrixd(modelview_matrix_); + glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix_); +} + + +//---------------------------------------------------------------------------- + + +bool +QGLViewerWidget::map_to_sphere( const QPoint& _v2D, Vec3f& _v3D ) +{ + if ( (_v2D.x() >= 0) && (_v2D.x() <= width()) && + (_v2D.y() >= 0) && (_v2D.y() <= height()) ) + { + double x = (double)(_v2D.x() - 0.5*width()) / (double)width(); + double y = (double)(0.5*height() - _v2D.y()) / (double)height(); + double sinx = sin(M_PI * x * 0.5); + double siny = sin(M_PI * y * 0.5); + double sinx2siny2 = sinx * sinx + siny * siny; + + _v3D[0] = sinx; + _v3D[1] = siny; + _v3D[2] = sinx2siny2 < 1.0 ? sqrt(1.0 - sinx2siny2) : 0.0; + + return true; + } + else return false; +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::update_projection_matrix() +{ + makeCurrent(); + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective(45.0, (GLfloat) width() / (GLfloat) height(), + 0.01*radius_, 100.0*radius_); + glGetDoublev( GL_PROJECTION_MATRIX, projection_matrix_); + glMatrixMode( GL_MODELVIEW ); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::view_all() +{ + translate( Vec3f( -(modelview_matrix_[0]*center_[0] + + modelview_matrix_[4]*center_[1] + + modelview_matrix_[8]*center_[2] + + modelview_matrix_[12]), + -(modelview_matrix_[1]*center_[0] + + modelview_matrix_[5]*center_[1] + + modelview_matrix_[9]*center_[2] + + modelview_matrix_[13]), + -(modelview_matrix_[2]*center_[0] + + modelview_matrix_[6]*center_[1] + + modelview_matrix_[10]*center_[2] + + modelview_matrix_[14] + + 3.0*radius_) ) ); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::set_scene_pos( const Vec3f& _cog, float _radius ) +{ + center_ = _cog; + radius_ = _radius; + glFogf( GL_FOG_START, _radius ); + glFogf( GL_FOG_END, 4.0*_radius ); + + update_projection_matrix(); + view_all(); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::add_draw_mode(std::string _s) +{ + ++n_draw_modes_; + + // insert in popup menu + QString str( _s.c_str() ); + popup_menu_->addAction( str ); + + // store draw mode + draw_mode_names_.push_back(_s); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::slotPopupMenu(int _id) +{ + // set check status + for (int i=0; i < popup_menu_->actions().count(); ++i) + popup_menu_->actions()[i]->setChecked( i == _id ); + + // save draw mode + draw_mode_ = _id; +} + + +//---------------------------------------------------------------------------- + + +double +QGLViewerWidget::performance() +{ + setCursor( Qt::WaitCursor ); + + double fps(0.0); + + makeCurrent(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + OpenMesh::Utils::Timer timer; + + unsigned int frames = 60; + const float angle = 360.0/(float)frames; + unsigned int i; + Vec3f axis; + + glFinish(); + timer.start(); + + for (i=0, axis=Vec3f(1,0,0); i +#include +#include +#include +#include + + +//== FORWARD DECLARATIONS ===================================================== + + +class QPopupMenu; + + +//== CLASS DEFINITION ========================================================= + + +class QGLViewerWidget : public QGLWidget +{ + + Q_OBJECT + +public: + + // Default constructor. + QGLViewerWidget( QWidget* _parent=0, const char* _name=0 ); + + // Destructor. + virtual ~QGLViewerWidget(); + + /* Sets the center and size of the whole scene. + The _center is used as fixpoint for rotations and for adjusting + the camera/viewer (see view_all()). */ + void set_scene_pos( const OpenMesh::Vec3f& _center, float _radius ); + + /* view the whole scene: the eye point is moved far enough from the + center so that the whole scene is visible. */ + void view_all(); + + /// add draw mode to popup menu + void add_draw_mode(std::string _s); + + float radius() const { return radius_; } + const OpenMesh::Vec3f& center() const { return center_; } + + const GLdouble* modelview_matrix() const { return modelview_matrix_; } + const GLdouble* projection_matrix() const { return projection_matrix_; } + void set_modelview_matrix(const GLdouble _modelview_matrix[16]) + { memcpy(modelview_matrix_, _modelview_matrix, 16*sizeof(GLdouble)); } + void set_projection_matrix(const GLdouble _projection_matrix[16]) + { memcpy(projection_matrix_, _projection_matrix, 16*sizeof(GLdouble)); } + + float fovy() const { return 45.0f; } + +protected: + + // draw the scene: will be called by the painGL() method. + virtual void draw_scene(const std::string& _draw_mode); + + double performance(void); + +private slots: + + // popup menu clicked + void slotPopupMenu(int _id); + +private: // inherited + + // initialize OpenGL states (triggered by Qt) + void initializeGL(); + + // draw the scene (triggered by Qt) + void paintGL(); + + // handle resize events (triggered by Qt) + void resizeGL( int w, int h ); + +protected: + + // Qt mouse events + virtual void mousePressEvent( QMouseEvent* ); + virtual void mouseReleaseEvent( QMouseEvent* ); + virtual void mouseMoveEvent( QMouseEvent* ); + virtual void wheelEvent( QWheelEvent* ); + virtual void keyPressEvent( QKeyEvent* ); + +private: + + // updates projection matrix + void update_projection_matrix(); + +protected: + // translate the scene and update modelview matrix + void translate(const OpenMesh::Vec3f& _trans); + + // rotate the scene (around its center) and update modelview matrix + void rotate(const OpenMesh::Vec3f& _axis, float _angle); + + OpenMesh::Vec3f center_; + float radius_; + + GLdouble projection_matrix_[16], + modelview_matrix_[16]; + + + // popup menu for draw mode selection + QMenu* popup_menu_; + unsigned int draw_mode_; + unsigned int n_draw_modes_; + std::vector draw_mode_names_; + + + + // virtual trackball: map 2D screen point to unit sphere + bool map_to_sphere(const QPoint& _point, OpenMesh::Vec3f& _result); + + QPoint last_point_2D_; + OpenMesh::Vec3f last_point_3D_; + bool last_point_ok_; + +}; + + +//============================================================================= +#endif // OPENMESHAPPS_QGLVIEWERWIDGET_HH +//============================================================================= + diff --git a/Apps/Deprecated/Streaming-qt4/Client/VDPMClientViewerWidget.cc b/Apps/Deprecated/Streaming-qt4/Client/VDPMClientViewerWidget.cc new file mode 100644 index 00000000..ff8ff068 --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Client/VDPMClientViewerWidget.cc @@ -0,0 +1,1351 @@ + +//== INCLUDES ================================================================= + +#ifdef _MSC_VER +# pragma warning(disable: 4267 4311) +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include + +// #include "ImageData.h" + + +using OpenMesh::VDPM::debug_print; +using OpenMesh::VDPM::set_debug_print; + +using OpenMesh::VDPM::VHierarchyNode; +using OpenMesh::VDPM::VHierarchyNodeHandle; +using OpenMesh::VDPM::VHierarchyNodeHandleContainer; + + + +#ifdef EXAMPLE_CREATION + +static OpenMesh::Vec3uc myYellow = OpenMesh::Vec3uc(255, 255, 0); +static OpenMesh::Vec3uc myBlue = OpenMesh::Vec3uc(0, 0, 255); +std::map g_index2numdesc_map; + +void VDPMClientViewerWidget::increase_max_descendents(const VHierarchyNodeIndex &_node_index) +{ + g_index2numdesc_map[_node_index] = 2 + g_index2numdesc_map[_node_index]; + + unsigned char tree_id_bits = vhierarchy_.tree_id_bits(); + VHierarchyNodeIndex parent_index + = VHierarchyNodeIndex(_node_index.tree_id(tree_id_bits), _node_index.node_id(tree_id_bits) / 2, tree_id_bits); + + if (parent_index.is_valid(tree_id_bits) == true) + increase_max_descendents(parent_index); +} + +void VDPMClientViewerWidget::increase_cur_descendents(VHierarchyNodeHandle _node_handle) +{ + unsigned int cur_desc = vhierarchy_.node(_node_handle).cur_descendents(); + + vhierarchy_.node(_node_handle).set_cur_descendents(2 + cur_desc); + + VHierarchyNodeHandle parent_handle = vhierarchy_.parent_handle(_node_handle); + if (parent_handle.is_valid()) + increase_cur_descendents(parent_handle); +} + +void VDPMClientViewerWidget::__add_children(const VHierarchyNodeIndex &_node_index, bool update_current) +{ + if (update_current == true) + { + increase_cur_descendents(vhierarchy_.node_handle(_node_index)); + } + else + { + unsigned char tree_id_bits = vhierarchy_.tree_id_bits(); + + VHierarchyNodeIndex lchild_index + = VHierarchyNodeIndex(_node_index.tree_id(tree_id_bits), 2*_node_index.node_id(tree_id_bits), tree_id_bits); + VHierarchyNodeIndex rchild_index + = VHierarchyNodeIndex(_node_index.tree_id(tree_id_bits), 1+2*_node_index.node_id(tree_id_bits), tree_id_bits); + + g_index2numdesc_map[lchild_index] = 1; + g_index2numdesc_map[rchild_index] = 1; + + increase_max_descendents(_node_index); + } +} + +void VDPMClientViewerWidget::mesh_coloring() +{ + MyMesh::VertexIter vIt(mesh_.vertices_begin()), + vEnd(mesh_.vertices_end()); + + VHierarchyNodeHandle node_handle; + float ratio; + unsigned char r, g, b; + + for (; vIt!=vEnd; ++vIt) + { + node_handle = mesh_.data(vIt.handle()).vhierarchy_node_handle(); + ratio = vhierarchy_.node(node_handle).ratio(); + + r = (unsigned char) ((1.0f - ratio) * myYellow[0] + ratio * myBlue[0]); + g = (unsigned char) ((1.0f - ratio) * myYellow[1] + ratio * myBlue[1]); + b = (unsigned char) ((1.0f - ratio) * myYellow[2] + ratio * myBlue[2]); + + mesh_.set_color(vIt.handle(), OpenMesh::Vec3uc(r,g,b)); + } +} + +#endif + + + +void +VDPMClientViewerWidget:: +draw_scene(const std::string &_draw_mode) +{ + //std::cout << frame_ << "-th frame statistics" << std::endl; + + if (adaptive_mode_ == true) + { + + refinement_timer_.start(); + adaptive_refinement(); + refinement_timer_.stop(); + fprintf(refinement_file, "%d %d\n", frame_, (int) refinement_timer_.mseconds()); + +#ifdef EXAMPLE_CREATION + mesh_coloring(); +#endif + } + + render_timer_.start(); + MeshViewerWidget::draw_scene(_draw_mode); + render_timer_.stop(); + fprintf(render_file, "%d %d %d\n", frame_, (int) render_timer_.mseconds(), mesh_.n_faces()); + + ++frame_; +} + + +void +VDPMClientViewerWidget:: +adaptive_refinement() +{ + update_viewing_parameters(); + + MyMesh::HalfedgeHandle v0v1; + float fovy = viewing_parameters_.fovy(); + float tolerance_square = viewing_parameters_.tolerance_square(); + float tan_value = tanf(fovy / 2.0f); + kappa_square_ = 4.0f * tan_value * tan_value * tolerance_square; + + + for (vfront_.begin(); vfront_.end() != true;) + { + VHierarchyNodeHandle + node_handle = vfront_.node_handle(), + parent_handle = vhierarchy_.parent_handle(node_handle); + + if (qrefine(node_handle) == true) + { + if (vhierarchy_.is_leaf_node(node_handle) != true) + { + force_vsplit(node_handle); + } + else + { + //if (qSocket_->bytesAvailable() == 0) + if (session_running_ != true) + { + session_running_ = true; + send_viewing_information(); + } + vfront_.next(); + } + } + else if (vhierarchy_.is_root_node(node_handle) != true && + ecol_legal(parent_handle, v0v1) == true && + qrefine(parent_handle) != true) + { + ecol(parent_handle, v0v1); + } + else + { + vfront_.next(); + } + } + + // free memories taged as 'deleted' + mesh_.garbage_collection(false, true, true); + mesh_.update_face_normals(); +} + + +void +VDPMClientViewerWidget:: +current_max_resolution() +{ + for (vfront_.begin(); vfront_.end() != true;) + { + VHierarchyNodeHandle + node_handle = vfront_.node_handle(), + parent_handle = vhierarchy_.parent_handle(node_handle); + + if (vhierarchy_.is_leaf_node(node_handle) != true) + force_vsplit(node_handle); + else + vfront_.next(); + } + + // free memories taged as 'deleted' + mesh_.garbage_collection(false, true, true); + mesh_.update_face_normals(); +} + + +bool +VDPMClientViewerWidget:: +qrefine(VHierarchyNodeHandle _node_handle) +{ + VHierarchyNode &node = vhierarchy_.node(_node_handle); + OpenMesh::Vec3f p = mesh_.point(node.vertex_handle()); + OpenMesh::Vec3f eye_dir = p - viewing_parameters_.eye_pos(); + float distance = eye_dir.length(); + float distance2 = distance * distance; + float product_value = dot(eye_dir, node.normal()); + + if (outside_view_frustum(p, node.radius()) == true) + return false; + + if (oriented_away(node.sin_square(), distance2, product_value) == true) + return false; + + if (screen_space_error(node.mue_square(), + node.sigma_square(), distance2, product_value) == true) + return false; + + return true; +} + + +void +VDPMClientViewerWidget:: +force_vsplit(VHierarchyNodeHandle node_handle) +{ + MyMesh::VertexHandle vl, vr; + + get_active_cuts(node_handle, vl, vr); + + while (vl == vr) { + force_vsplit(mesh_.data(vl).vhierarchy_node_handle()); + get_active_cuts(node_handle, vl, vr); + } + + vsplit(node_handle, vl, vr); +} + + + +void +VDPMClientViewerWidget:: +vsplit(VHierarchyNodeHandle _node_handle, MyMesh::VertexHandle vl, MyMesh::VertexHandle vr) +{ + // refine + VHierarchyNodeHandle lchild_handle = vhierarchy_.lchild_handle(_node_handle); + VHierarchyNodeHandle rchild_handle = vhierarchy_.rchild_handle(_node_handle); + MyMesh::VertexHandle v0 = vhierarchy_.vertex_handle(lchild_handle); + MyMesh::VertexHandle v1 = vhierarchy_.vertex_handle(rchild_handle); + + mesh_.vertex_split(v0, v1, vl, vr); + mesh_.set_normal(v0, vhierarchy_.normal(lchild_handle)); + mesh_.set_normal(v1, vhierarchy_.normal(rchild_handle)); + mesh_.data(v0).set_vhierarchy_node_handle(lchild_handle); + mesh_.data(v1).set_vhierarchy_node_handle(rchild_handle); + mesh_.status(v0).set_deleted(false); + mesh_.status(v1).set_deleted(false); + + vfront_.remove(_node_handle); + vfront_.add(lchild_handle); + vfront_.add(rchild_handle); +} + + +void +VDPMClientViewerWidget:: +ecol(VHierarchyNodeHandle _node_handle, const MyMesh::HalfedgeHandle& v0v1) +{ + VHierarchyNodeHandle lchild_handle = vhierarchy_.lchild_handle(_node_handle); + VHierarchyNodeHandle rchild_handle = vhierarchy_.rchild_handle(_node_handle); + MyMesh::VertexHandle v0 = vhierarchy_.vertex_handle(lchild_handle); + MyMesh::VertexHandle v1 = vhierarchy_.vertex_handle(rchild_handle); + + // coarsen + mesh_.collapse(v0v1); + mesh_.set_normal(v1, vhierarchy_.normal(_node_handle)); + mesh_.data(v0).set_vhierarchy_node_handle(lchild_handle); + mesh_.data(v1).set_vhierarchy_node_handle(_node_handle); + mesh_.status(v0).set_deleted(false); + mesh_.status(v1).set_deleted(false); + + vfront_.add(_node_handle); + vfront_.remove(lchild_handle); + vfront_.remove(rchild_handle); +} + + +bool +VDPMClientViewerWidget:: +ecol_legal(VHierarchyNodeHandle _parent_handle, MyMesh::HalfedgeHandle& v0v1) +{ + VHierarchyNodeHandle lchild_handle = vhierarchy_.lchild_handle(_parent_handle); + VHierarchyNodeHandle rchild_handle = vhierarchy_.rchild_handle(_parent_handle); + + // test whether lchild & rchild present in the current vfront + if (vfront_.is_active(lchild_handle) != true || vfront_.is_active(rchild_handle) != true) + return false; + + MyMesh::VertexHandle v0, v1; + v0 = vhierarchy_.vertex_handle(lchild_handle); + v1 = vhierarchy_.vertex_handle(rchild_handle); + v0v1 = mesh_.find_halfedge(v0, v1); + + return mesh_.is_collapse_ok(v0v1); +} + +void +VDPMClientViewerWidget:: +get_active_cuts(const VHierarchyNodeHandle _node_handle, MyMesh::VertexHandle &vl, MyMesh::VertexHandle &vr) +{ + MyMesh::VertexVertexIter vv_it; + VHierarchyNodeHandle nnode_handle; + VHierarchyNodeIndex nnode_index; + VHierarchyNodeIndex fund_lcut_index = vhierarchy_.fund_lcut_index(_node_handle); + VHierarchyNodeIndex fund_rcut_index = vhierarchy_.fund_rcut_index(_node_handle); + + vl = MyMesh::InvalidVertexHandle; + vr = MyMesh::InvalidVertexHandle; + + for (vv_it=mesh_.vv_iter(vhierarchy_.vertex_handle(_node_handle)); vv_it; ++vv_it) + { + nnode_handle = mesh_.data(vv_it.handle()).vhierarchy_node_handle(); + nnode_index = vhierarchy_.node_index(nnode_handle); + + if (vl == MyMesh::InvalidVertexHandle && vhierarchy_.is_ancestor(nnode_index, fund_lcut_index) == true) + vl = vv_it.handle(); + if (vr == MyMesh::InvalidVertexHandle && vhierarchy_.is_ancestor(nnode_index, fund_rcut_index) == true) + vr = vv_it.handle(); + + /*if (vl == MyMesh::InvalidVertexHandle && nnode_index.is_ancestor_index(fund_lcut_index) == true) + vl = vv_it.handle(); + if (vr == MyMesh::InvalidVertexHandle && nnode_index.is_ancestor_index(fund_rcut_index) == true) + vr = vv_it.handle();*/ + + if (vl != MyMesh::InvalidVertexHandle && vr != MyMesh::InvalidVertexHandle) + break; + } +} + +bool +VDPMClientViewerWidget:: +outside_view_frustum(const OpenMesh::Vec3f &pos, float radius) +{ + Plane3d frustum_plane[4]; + + viewing_parameters_.frustum_planes(frustum_plane); + + for (int i = 0; i < 4; i++) { + if (frustum_plane[i].signed_distance(pos) < -radius) + return true; + } + + return false; +} + +bool +VDPMClientViewerWidget:: +oriented_away(float sin_square, float distance_square, float product_value) +{ + if (product_value > 0 && product_value*product_value > distance_square * sin_square) + return true; + else + return false; +} + +bool +VDPMClientViewerWidget:: +screen_space_error(float mue_square, float sigma_square, float distance_square, float product_value) +{ + if ((mue_square >= kappa_square_ * distance_square) || + (sigma_square * (distance_square - product_value * product_value) >= kappa_square_ * distance_square * distance_square)) + return false; + else + return true; +} + +void +VDPMClientViewerWidget:: +open_vd_prog_mesh(const char* _filename) +{ + unsigned int i; + unsigned int value; + unsigned int fvi[3]; + char fileformat[16]; + OpenMesh::Vec3f p, normal; + float radius, sin_square, mue_square, sigma_square; + VHierarchyNodeHandleContainer roots; + OpenMesh::VertexHandle vertex_handle; + VHierarchyNodeIndex node_index, lchild_node_index, rchild_node_index, fund_lcut_index, fund_rcut_index; + VHierarchyNodeHandle node_handle, lchild_handle, rchild_handle; + std::map index2handle_map; + + std::ifstream ifs(_filename, std::ios::binary); + if (!ifs) + { + std::cerr << "read error\n"; + exit(1); + } + + // + bool swap = OpenMesh::Endian::local() != OpenMesh::Endian::LSB; + + // read header + ifs.read(fileformat, 10); fileformat[10] = '\0'; + if (std::string(fileformat) != std::string("VDProgMesh")) + { + std::cerr << "Wrong file format.\n"; + ifs.close(); + exit(1); + } + OpenMesh::IO::restore(ifs, n_base_vertices_, swap); + OpenMesh::IO::restore(ifs, n_base_faces_, swap); + OpenMesh::IO::restore(ifs, n_details_, swap); + + mesh_.clear(); + vfront_.clear(); + vhierarchy_.clear(); + + vhierarchy_.set_num_roots(n_base_vertices_); + + // load base mesh + for (i=0; i index2handle_map; + + std::ifstream ifs(_filename, std::ios::binary); + if (!ifs) + { + std::cerr << "Filename : " << _filename << std::endl; + std::cerr << "read error\n"; + exit(1); + } + + // + bool swap = OpenMesh::Endian::local() != OpenMesh::Endian::LSB; + + // read header + ifs.read(fileformat, 10); fileformat[10] = '\0'; + if (std::string(fileformat) != std::string("VDProgMesh")) + { + std::cerr << "Wrong file format.\n"; + ifs.close(); + exit(1); + } + OpenMesh::IO::restore(ifs, n_base_vertices_, swap); + OpenMesh::IO::restore(ifs, n_base_faces_, swap); + OpenMesh::IO::restore(ifs, n_details_, swap); + + mesh_.clear(); + vfront_.clear(); + vhierarchy_.clear(); + + vhierarchy_.set_num_roots(n_base_vertices_); + + // load base mesh + for (i=0; ikey()) + { + case Qt::Key_Plus: + viewing_parameters_.increase_tolerance(); + std::cout << "Scree-space error tolerance^2 is increased by " + << viewing_parameters_.tolerance_square() << std::endl; + updateGL(); + break; + + case Qt::Key_Minus: + viewing_parameters_.decrease_tolerance(); + std::cout << "Screen-space error tolerance^2 is decreased by " + << viewing_parameters_.tolerance_square() << std::endl; + updateGL(); + break; + + case Qt::Key_A: + adaptive_mode_ = !(adaptive_mode_); + std::cout << "Adaptive refinement mode is " + << ((adaptive_mode_ == true) ? "on" : "off") << std::endl; + updateGL(); + break; + + case Qt::Key_D: + set_debug_print(!debug_print()); + break; + + case Qt::Key_O: + qFilename_ = QFileDialog::getOpenFileName(0,"","d:/data/models/spm/", "*.spm"); + open_vd_base_mesh( qFilename_.toStdString().c_str() ); + break; + + case Qt::Key_BracketLeft: + max_transmitted_datasize_ -= 10000; + std::cout << "Max transmitted data: " << max_transmitted_datasize_ << std::endl; + break; + + case Qt::Key_BracketRight: + max_transmitted_datasize_ += 10000; + std::cout << "Max transmitted data: " << max_transmitted_datasize_ << std::endl; + break; + + case Qt::Key_Space: + memcpy(reserved_modelview_matrix_, modelview_matrix(), 16*sizeof(GLdouble)); + memcpy(reserved_projection_matrix_, projection_matrix(), 16*sizeof(GLdouble)); + std::cout << "Reserving current view-point" << std::endl; + break; + + case Qt::Key_R: + request_base_mesh(); + break; + + case Qt::Key_S: + save_views(); + std::cout << "Saving view-points" << std::endl; + break; + + case Qt::Key_F: + frame_ = 0; + std::cout << "Frame is set to 0" << std::endl; + break; + + case Qt::Key_M: + adaptive_mode_ = false; + current_max_resolution(); + updateGL(); + std::cout << "Current max resolution mesh" << std::endl; + break; + + case Qt::Key_V: + vd_streaming_ = !(vd_streaming_); + if (vd_streaming_) + std::cout << "View-dependent streaing mode" << std::endl; + else + std::cout << "Sequential streaming mode" << std::endl; + break; + + case Qt::Key_C: + adaptive_mode_ = false; + qCameraFileName_ = QFileDialog::getOpenFileName(0, "","./", "*.cmr"); + load_views( qCameraFileName_.toStdString().c_str() ); + std::cout << "Loading view-points" << std::endl; + updateGL(); + break; + + case Qt::Key_9: + save_screen(true); + break; + + case Qt::Key_0: + std::cout << "#faces: " << mesh_.n_faces() << std::endl; + break; + + case Qt::Key_P: + if (qAnimationTimer_->isActive()) + { + qAnimationTimer_->stop(); + std::cout << "print_statistics mode is stopped!" << std::endl; + } + else + { + qAnimationTimer_->setSingleShot( true ); + qAnimationTimer_->start(0); + std::cout << "print_statistics mode is started!" << std::endl; + + adaptive_mode_ = true; + + set_scene_pos( + Vec3f(0.5f*(bbMin_[0] + bbMax_[0]), 0.9f*bbMax_[1], 0.5f*(bbMin_[2] + bbMax_[2])), + 0.15f*(bbMin_ - bbMax_).norm()); + nth_viewpoint_ = 0; + print_statistics(); + } + std::cout << "Frame: " << frame_ << std::endl; + break; + + + case Qt::Key_L: + if (qAnimationTimer_->isActive()) + { + qAnimationTimer_->stop(); + std::cout << "look_around mode is stopped!" << std::endl; + } + else + { + qAnimationTimer_->setSingleShot( true ); + qAnimationTimer_->start(0); + std::cout << "look_around mode is started!" << std::endl; + + adaptive_mode_ = true; + + set_scene_pos( + Vec3f(0.5f*(bbMin_[0] + bbMax_[0]), 0.9f*bbMax_[1], 0.5f*(bbMin_[2] + bbMax_[2])), + 0.15f*(bbMin_ - bbMax_).norm()); + frame_ = 0; + nth_viewpoint_ = 0; + look_around(); + } + + break; + + case Qt::Key_Q: + case Qt::Key_Escape: + qApp->quit(); + + default: + this->MeshViewerWidget::keyPressEvent( _event ); + } + + if (!handled) + _event->ignore(); +} + + + + + +void +VDPMClientViewerWidget:: +update_viewing_parameters() +{ + viewing_parameters_.set_fovy(fovy()); + viewing_parameters_.set_aspect((float) width() / (float) height()); + viewing_parameters_.set_modelview_matrix(modelview_matrix()); + + viewing_parameters_.update_viewing_configurations(); +} + + +///////////////////////////////////////////////// +// streaming related functions +///////////////////////////////////////////////// + + + +bool +VDPMClientViewerWidget:: +request_base_mesh() +{ + if (streaming_phase_ != kBaseMesh) + return false; + + if (qFilename_.isEmpty() == true) + { + std::cout << "Please, specify the base mesh filename." << std::endl; + return false; + } + + QDataStream qTcp(qSocket_); + + qTcp << qFilename_.length(); + qTcp << qFilename_; + qSocket_->flush(); + + return true; +} + +bool +VDPMClientViewerWidget:: +receive_base_mesh() +{ + int status; + QDataStream qTcp(qSocket_); + + while ( qSocket_->bytesAvailable() < sizeof(int) ) + qSocket_->waitForReadyRead(10); + + qTcp >> status; + if (status == 0) + { + std::cout << "There is no such a VDPM files in the server side." << std::endl; + return false; + } + + streaming_phase_ = kVSplitHeader; + + std::cout << "A view-dependent streaming is ready." << std::endl; + return true; +} + + +void +VDPMClientViewerWidget:: +send_viewing_information() +{ + session_timer_.start(); + QDataStream qTCP(qSocket_); + qTCP << modelview_matrix()[0] << modelview_matrix()[1] + << modelview_matrix()[2] << modelview_matrix()[3] + << modelview_matrix()[4] << modelview_matrix()[5] + << modelview_matrix()[6] << modelview_matrix()[7] + << modelview_matrix()[8] << modelview_matrix()[9] + << modelview_matrix()[10] << modelview_matrix()[11] + << modelview_matrix()[12] << modelview_matrix()[13] + << modelview_matrix()[14] << modelview_matrix()[15] + << viewing_parameters_.fovy() + << viewing_parameters_.aspect() + << viewing_parameters_.tolerance_square(); + + qSocket_->flush(); + session_timer_.stop(); + fprintf(session_file, "%d %d\n", frame_, (int) session_timer_.mseconds()); + + + global_timer_.stop(); + fprintf(uplink_file, "%d %ld\n", (int) global_timer_.mseconds(), 16*sizeof(double) + 3*sizeof(float)); + global_timer_.cont(); +} + +void +VDPMClientViewerWidget:: +receive_vsplit_header() +{ + if (qSocket_->bytesAvailable() < sizeof(unsigned int)) + return; + + QDataStream qTcp(qSocket_); + + // while (qSocket_->waitForMore(10) < sizeof(unsigned int)); + + qTcp >> n_vsplit_packets_; + + if (n_vsplit_packets_ > 0) + { + streaming_phase_ = kVSplits; + + if (debug_print() == true) + { + std::cout << "Server will transmit " << n_vsplit_packets_ + << " of vsplit packets to me" << std::endl; + } + + receive_vsplit_packets(); + } + else + { + session_running_ = false; + } +} + +void +VDPMClientViewerWidget:: +receive_vsplit_packets() +{ + static unsigned int n_vsplits = 0; + static unsigned int len = (int) (17 * sizeof(float) + 3 * sizeof(int)); + + if (qSocket_->bytesAvailable() < len) + return; + + QString str; + OpenMesh::Vec3f pos; + VHierarchyNodeIndex node_index, fund_lcut_index, fund_rcut_index; + float radius[2]; + OpenMesh::Vec3f normal[2]; + float sin_square[2]; + float mue_square[2]; + float sigma_square[2]; + unsigned int value[3]; + + global_timer_.stop(); + fprintf(downlink_file, "%d %ld\n", (int) global_timer_.mseconds(), qSocket_->bytesAvailable()); + global_timer_.cont(); + + session_timer_.start(); + + while ( qSocket_->bytesAvailable() >= len ) + { + if (vd_streaming_) transmitted_datasize_ += (int) len; + //if (vd_streaming_) transmitted_datasize_ += (int) 3*sizeof(int) + 3*sizeof(float); // only for non-refinement cliet + else transmitted_datasize_ += (int) 3*sizeof(int) + 3*sizeof(float); + + if (max_transmitted_datasize_ > 0) + { + if (transmitted_datasize_ > max_transmitted_datasize_) + { + if (vd_streaming_) transmitted_datasize_ -= (int) len; + //if (vd_streaming_) transmitted_datasize_ -= (int) 3*sizeof(int) + 3*sizeof(float); // only for non-refinement cliet + else transmitted_datasize_ -= (int) 3*sizeof(int) + 3*sizeof(float); + + return; + } + } + + QDataStream qTcp(qSocket_); + qTcp >> pos[0] >> pos[1] >> pos[2] + >> value[0] + >> value[1] + >> value[2] + >> radius[0] + >> (normal[0])[0] >> (normal[0])[1] >> (normal[0])[2] + >> sin_square[0] + >> mue_square[0] >> sigma_square[0] + >> radius[1] + >> (normal[1])[0] >> (normal[1])[1] >> (normal[1])[2] + >> sin_square[1] + >> mue_square[1] >> sigma_square[1]; + + node_index = VHierarchyNodeIndex(value[0]); + fund_lcut_index = VHierarchyNodeIndex(value[1]); + fund_rcut_index = VHierarchyNodeIndex(value[2]); + + update_vhierarchy(pos, + node_index, fund_lcut_index, fund_rcut_index, + radius, normal, sin_square, mue_square, sigma_square); + + + std::cout << "transmitted datasize: " << transmitted_datasize_ << std::endl; + + if (debug_print() == true) + { + std::cout << "Pkg #" << n_vsplits << std::endl; + } + + ++n_vsplits; + + if (n_vsplits >= n_vsplit_packets_) + { + n_vsplits = 0; + streaming_phase_ = kVSplitHeader; + session_running_ = false; + + if (debug_print() == true) + { + std::cout << "transmission of vsplit packets is complete" << std::endl; + } + break; + } + } + + session_timer_.stop(); + fprintf(session_file, "%d %d\n", frame_, (int) session_timer_.mseconds()); + + updateGL(); + + if (n_vsplits != n_vsplit_packets_){ + qSessionTimer_->setSingleShot( true ); + qSessionTimer_->start(300); + } +} + + +void +VDPMClientViewerWidget:: +update_vhierarchy( + const OpenMesh::Vec3f &_pos, // 3D position of v0 + const VHierarchyNodeIndex &_node_index, // vhierarchy index of v1 + const VHierarchyNodeIndex &_fund_lcut_index, // vhierarchy index of fundamental lcut + const VHierarchyNodeIndex &_fund_rcut_index, // vhierarchy index of fundamental rcut + const float _radius[2], // radius of lchild & rchild + const OpenMesh::Vec3f _normal[2], // normal of lchild & rchild + const float _sin_square[2], // sin_square of lchild & rchild + const float _mue_square[2], // mue_square of lchild & rchild + const float _sigma_square[2] // sigma_square of lchild & rchild + ) +{ + OpenMesh::VertexHandle vertex_handle; + VHierarchyNodeHandle node_handle, lchild_handle, rchild_handle; + + node_handle = vhierarchy_.node_handle(_node_index); + vhierarchy_.make_children(node_handle); + + + lchild_handle = vhierarchy_.lchild_handle(node_handle); + rchild_handle = vhierarchy_.rchild_handle(node_handle); + + vhierarchy_.node(node_handle).set_fund_lcut(_fund_lcut_index); + vhierarchy_.node(node_handle).set_fund_rcut(_fund_rcut_index); + + vertex_handle = mesh_.add_vertex(_pos); + vhierarchy_.node(lchild_handle).set_vertex_handle(vertex_handle); + vhierarchy_.node(rchild_handle).set_vertex_handle(vhierarchy_.node(node_handle).vertex_handle()); + + vhierarchy_.node(lchild_handle).set_radius(_radius[0]); + vhierarchy_.node(lchild_handle).set_normal(_normal[0]); + vhierarchy_.node(lchild_handle).set_sin_square(_sin_square[0]); + vhierarchy_.node(lchild_handle).set_mue_square(_mue_square[0]); + vhierarchy_.node(lchild_handle).set_sigma_square(_sigma_square[0]); + + vhierarchy_.node(rchild_handle).set_radius(_radius[1]); + vhierarchy_.node(rchild_handle).set_normal(_normal[1]); + vhierarchy_.node(rchild_handle).set_sin_square(_sin_square[1]); + vhierarchy_.node(rchild_handle).set_mue_square(_mue_square[1]); + vhierarchy_.node(rchild_handle).set_sigma_square(_sigma_square[1]); + +#ifdef EXAMPLE_CREATION + __add_children(_node_index); +#endif +} + + + +///////////////////////////////////////////////// +// example related functions +///////////////////////////////////////////////// + +void VDPMClientViewerWidget::save_views() +{ + FILE *camera_file = fopen("camera.cmr", "w"); + + GLdouble current_modelview_matrix[16], current_projection_matrix[16]; + + memcpy(current_modelview_matrix, modelview_matrix(), 16*sizeof(GLdouble)); + memcpy(current_projection_matrix, projection_matrix(), 16*sizeof(GLdouble)); + + + fprintf(camera_file, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n", + current_modelview_matrix[0], current_modelview_matrix[1], current_modelview_matrix[2], current_modelview_matrix[3], + current_modelview_matrix[4], current_modelview_matrix[5], current_modelview_matrix[6], current_modelview_matrix[7], + current_modelview_matrix[8], current_modelview_matrix[9], current_modelview_matrix[10], current_modelview_matrix[11], + current_modelview_matrix[12], current_modelview_matrix[13], current_modelview_matrix[14], current_modelview_matrix[15]); + + fprintf(camera_file, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n", + current_projection_matrix[0], current_projection_matrix[1], current_projection_matrix[2], current_projection_matrix[3], + current_projection_matrix[4], current_projection_matrix[5], current_projection_matrix[6], current_projection_matrix[7], + current_projection_matrix[8], current_projection_matrix[9], current_projection_matrix[10], current_projection_matrix[11], + current_projection_matrix[12], current_projection_matrix[13], current_projection_matrix[14], current_projection_matrix[15]); + + + fprintf(camera_file, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n", + reserved_modelview_matrix_[0], reserved_modelview_matrix_[1], reserved_modelview_matrix_[2], reserved_modelview_matrix_[3], + reserved_modelview_matrix_[4], reserved_modelview_matrix_[5], reserved_modelview_matrix_[6], reserved_modelview_matrix_[7], + reserved_modelview_matrix_[8], reserved_modelview_matrix_[9], reserved_modelview_matrix_[10], reserved_modelview_matrix_[11], + reserved_modelview_matrix_[12], reserved_modelview_matrix_[13], reserved_modelview_matrix_[14], reserved_modelview_matrix_[15]); + + fprintf(camera_file, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n", + reserved_projection_matrix_[0], reserved_projection_matrix_[1], reserved_projection_matrix_[2], reserved_projection_matrix_[3], + reserved_projection_matrix_[4], reserved_projection_matrix_[5], reserved_projection_matrix_[6], reserved_projection_matrix_[7], + reserved_projection_matrix_[8], reserved_projection_matrix_[9], reserved_projection_matrix_[10], reserved_projection_matrix_[11], + reserved_projection_matrix_[12], reserved_projection_matrix_[13], reserved_projection_matrix_[14], reserved_projection_matrix_[15]); + + fclose(camera_file); +} + + +void VDPMClientViewerWidget::load_views(const char *camera_filename) +{ + FILE *camera_file = fopen(camera_filename, "r"); + + GLdouble current_modelview_matrix[16], current_projection_matrix[16]; + + + fscanf(camera_file, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n", + &(current_modelview_matrix[0]), &(current_modelview_matrix[1]), &(current_modelview_matrix[2]), &(current_modelview_matrix[3]), + &(current_modelview_matrix[4]), &(current_modelview_matrix[5]), &(current_modelview_matrix[6]), &(current_modelview_matrix[7]), + &(current_modelview_matrix[8]), &(current_modelview_matrix[9]), &(current_modelview_matrix[10]), &(current_modelview_matrix[11]), + &(current_modelview_matrix[12]), &(current_modelview_matrix[13]), &(current_modelview_matrix[14]), &(current_modelview_matrix[15])); + + + fscanf(camera_file, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n", + &(current_projection_matrix[0]), &(current_projection_matrix[1]), &(current_projection_matrix[2]), &(current_projection_matrix[3]), + &(current_projection_matrix[4]), &(current_projection_matrix[5]), &(current_projection_matrix[6]), &(current_projection_matrix[7]), + &(current_projection_matrix[8]), &(current_projection_matrix[9]), &(current_projection_matrix[10]), &(current_projection_matrix[11]), + &(current_projection_matrix[12]), &(current_projection_matrix[13]), &(current_projection_matrix[14]), &(current_projection_matrix[15])); + + + fscanf(camera_file, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n", + &(reserved_modelview_matrix_[0]), &(reserved_modelview_matrix_[1]), &(reserved_modelview_matrix_[2]), &(reserved_modelview_matrix_[3]), + &(reserved_modelview_matrix_[4]), &(reserved_modelview_matrix_[5]), &(reserved_modelview_matrix_[6]), &(reserved_modelview_matrix_[7]), + &(reserved_modelview_matrix_[8]), &(reserved_modelview_matrix_[9]), &(reserved_modelview_matrix_[10]), &(reserved_modelview_matrix_[11]), + &(reserved_modelview_matrix_[12]), &(reserved_modelview_matrix_[13]), &(reserved_modelview_matrix_[14]), &(reserved_modelview_matrix_[15])); + + + fscanf(camera_file, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n", + &(reserved_projection_matrix_[0]), &(reserved_projection_matrix_[1]), &(reserved_projection_matrix_[2]), &(reserved_projection_matrix_[3]), + &(reserved_projection_matrix_[4]), &(reserved_projection_matrix_[5]), &(reserved_projection_matrix_[6]), &(reserved_projection_matrix_[7]), + &(reserved_projection_matrix_[8]), &(reserved_projection_matrix_[9]), &(reserved_projection_matrix_[10]), &(reserved_projection_matrix_[11]), + &(reserved_projection_matrix_[12]), &(reserved_projection_matrix_[13]), &(reserved_projection_matrix_[14]), &(reserved_projection_matrix_[15])); + + fclose(camera_file); + + set_modelview_matrix(current_modelview_matrix); + set_projection_matrix(current_projection_matrix); + + adaptive_mode_ = false; +} + +void VDPMClientViewerWidget::print_statistics() +{ + const float angle = 360.0/(float)n_viewpoints_; + Vec3f axis = Vec3f(0,1,0); + Vec3f delta = Vec3f(0, 0.7f*(bbMin_[1] - bbMax_[1])/n_viewpoints_, 0); + + rotate(axis, -angle); + set_scene_pos(center() + delta, 1.0f * radius() ); + + updateGL(); + + if (++nth_viewpoint_ < n_viewpoints_){ + qAnimationTimer_->setSingleShot( true ); + qAnimationTimer_->start(500); + } +} + +void VDPMClientViewerWidget::look_around() +{ + const float angle = 360.0/(float)n_viewpoints_; + Vec3f axis = Vec3f(0,1,0); + Vec3f delta = Vec3f(0, 0.7f*(bbMin_[1] - bbMax_[1])/n_viewpoints_, 0); + + rotate(axis, -angle); + set_scene_pos(center() + delta, 1.0f * radius() ); + + updateGL(); + + save_screen(true); + + if (++nth_viewpoint_ < n_viewpoints_){ + qAnimationTimer_->setSingleShot( true ); + qAnimationTimer_->start(3000); + } +} + + +void VDPMClientViewerWidget::save_screen(bool _flag) +{ + setCursor( Qt::WaitCursor ); + + if (_flag == true) // shot from the reserved view-point + { + GLdouble current_modelview_matrix[16]; + GLdouble current_projection_matrix[16]; + bool current_adaptive_mode = adaptive_mode_; + + memcpy(current_modelview_matrix, modelview_matrix(), 16*sizeof(GLdouble)); + memcpy(current_projection_matrix, projection_matrix(), 16*sizeof(GLdouble)); + + set_modelview_matrix(reserved_modelview_matrix_); + set_projection_matrix(reserved_projection_matrix_); + adaptive_mode_ = false; + + updateGL(); + + // shot from the reserved view-point + char rfilename[256]; + sprintf(rfilename, "rview%03d.bmp", nth_viewpoint_); + screen_capture(rfilename); + std::cout << "shot from the reserved view-point" << std::endl; + + + set_modelview_matrix(current_modelview_matrix); + set_projection_matrix(current_projection_matrix); + adaptive_mode_ = current_adaptive_mode; + } + + updateGL(); + + // shot from the current view-point + char cfilename[256]; + sprintf(cfilename, "cview%03d.bmp", nth_viewpoint_); + screen_capture(cfilename); + std::cout << "shot from the current view-point" << std::endl; + + + setCursor( Qt::PointingHandCursor ); +} + +void VDPMClientViewerWidget::screen_capture(const char * /* _filename */) +{ +// CImageData image(width(), height()); + +// glReadBuffer(GL_BACK); +// glReadPixels(0, 0, width(), height(), GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*) image.rgbMap()); + +// image.SaveBMP(_filename, width(), height()); +} + diff --git a/Apps/Deprecated/Streaming-qt4/Client/VDPMClientViewerWidget.hh b/Apps/Deprecated/Streaming-qt4/Client/VDPMClientViewerWidget.hh new file mode 100644 index 00000000..04a0741d --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Client/VDPMClientViewerWidget.hh @@ -0,0 +1,320 @@ +#ifndef OPENMESH_APPS_VDPMSTREAMING_CLIENT_VDPMCLIENTVIEWERWIDGET_HH +#define OPENMESH_APPS_VDPMSTREAMING_CLIENT_VDPMCLIENTVIEWERWIDGET_HH + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +//#include + + + +typedef MeshViewerWidgetT MeshViewerWidget; + + + +using OpenMesh::VDPM::VDPMStreamingPhase; +using OpenMesh::VDPM::kVSplitHeader; +using OpenMesh::VDPM::kVSplits; +using OpenMesh::VDPM::kBaseMesh; + +using OpenMesh::VDPM::Plane3d; + +using OpenMesh::VDPM::VFront; +using OpenMesh::VDPM::VHierarchy; +using OpenMesh::VDPM::VHierarchyNodeIndex; +using OpenMesh::VDPM::VHierarchyNodeHandle; +using OpenMesh::VDPM::ViewingParameters; +using OpenMesh::VDPM::set_debug_print; + + +//== CLASS DEFINITION ========================================================= + + +class VDPMClientViewerWidget : public MeshViewerWidget +{ + + Q_OBJECT + +public: + VDPMClientViewerWidget(QWidget *_parent=0, const char *_name=0) + : MeshViewerWidget(_parent, _name) + { + set_debug_print(true); + adaptive_mode_ = false; + + qSessionTimer_ = new QTimer(this); + qSocket_ = new QTcpSocket(this); + streaming_phase_ = kBaseMesh; + session_running_ = false; + + + connect(qSessionTimer_, SIGNAL(timeout()), + this, SLOT(session_timer_check())); + + connect(qSessionTimer_, SIGNAL(timeout()), + this, SLOT(socketReadyRead())); + + // connect signal-slots about QSocket + connect(qSocket_, SIGNAL(connected()), + this, SLOT(socketConnected())); + + connect(qSocket_, SIGNAL(connectionClosed()), + this, SLOT(socketConnectionClosed())); + + connect(qSocket_, SIGNAL(readyRead()), + this, SLOT(socketReadyRead())); + + connect(qSocket_, SIGNAL(error( QAbstractSocket::SocketError )), + this, SLOT(socketError( QAbstractSocket::SocketError ))); + + + look_around_mode_ = false; + frame_ = 0; + n_viewpoints_ = 60; + + global_timer_.reset(); + global_timer_.start(); + render_timer_.reset(); + refinement_timer_.reset(); + session_timer_.reset(); + + qAnimationTimer_ = new QTimer(this); + + connect(qAnimationTimer_, SIGNAL(timeout()), + this, SLOT(look_around())); + //connect(qAnimationTimer_, SIGNAL(timeout()), + // this, SLOT(print_statistics())); + + + uplink_file = fopen("uplink.txt", "w"); + downlink_file = fopen("downlink.txt", "w"); + + render_file = fopen("render.txt", "w"); + refinement_file = fopen("refinement.txt", "w"); + session_file = fopen("session.txt", "w"); + + vd_streaming_ = true; + max_transmitted_datasize_ = 0; + transmitted_datasize_ = 0; + } + + ~VDPMClientViewerWidget() + { + fclose(uplink_file); + fclose(downlink_file); + + fclose(render_file); + fclose(refinement_file); + fclose(session_file); + } + + + void connectToServer( std::string& _server_name, + int _port= VDPM_STREAMING_PORT ) + { + qSocket_->connectToHost( _server_name.c_str(), _port ); + } + + void openBaseMesh( std::string& _base_mesh ) + { + open_vd_base_mesh( _base_mesh.c_str() ); + std::cout << "spm file: " << _base_mesh << std::endl; + } + +// socket related slots +private slots: + + void closeConnection() + { + close(); + if (qSocket_->state() == QAbstractSocket::ClosingState) // we have a delayed close. + { + connect(this, SIGNAL(delayedCloseFinished()), SLOT(socketClosed())); + } + else // the qSocket is closed. + { + socketClosed(); + } + } + + void socketReadyRead() + { + switch( streaming_phase_) + { + case kVSplits: receive_vsplit_packets(); break; + case kVSplitHeader: receive_vsplit_header(); break; + case kBaseMesh: receive_base_mesh(); break; + } + + } + + void socketConnected() + { + std::cout << "Connected to server" << std::endl; + } + + void socketConnectionClosed() + { + std::cout << "Connection closed by the server" << std::endl; + } + + void socketClosed() + { + std::cout << "Connection closed" << std::endl; + } + + void socketError(QAbstractSocket::SocketError e) + { + std::cout << "Error number " << e << " occurred" << std::endl; + } + + void look_around(); + void print_statistics(); + + + void session_timer_check() + { + std::cout << "Session Timer works" << std::endl; + } + +// for view-dependent PM +private: + VHierarchy vhierarchy_; + //unsigned char tree_id_bits_; + VFront vfront_; + ViewingParameters viewing_parameters_; + float kappa_square_; + bool adaptive_mode_; + + unsigned int n_base_vertices_; + unsigned int n_base_edges_; + unsigned int n_base_faces_; + unsigned int n_details_; + +private: + + bool outside_view_frustum(const OpenMesh::Vec3f &pos, float radius); + bool oriented_away(float sin_square, float distance_square, + float product_value); + bool screen_space_error(float mue_square, float sigma_square, + float distance_square, float product_value); + void update_viewing_parameters(); + + virtual void keyPressEvent(QKeyEvent *_event); + +protected: + + /// inherited drawing method + virtual void draw_scene(const std::string& _draw_mode); + + +public: + + void open_vd_prog_mesh(const char* _filename); + + unsigned int num_base_vertices() const { return n_base_vertices_; } + unsigned int num_base_edges() const { return n_base_edges_; } + unsigned int num_base_faces() const { return n_base_faces_; } + unsigned int num_details() const { return n_details_; } + + void adaptive_refinement(); + bool qrefine(VHierarchyNodeHandle _node_handle); + void force_vsplit(VHierarchyNodeHandle _node_handle); + bool ecol_legal(VHierarchyNodeHandle _parent_handle, MyMesh::HalfedgeHandle& v0v1); + + void get_active_cuts(VHierarchyNodeHandle _node_handle, MyMesh::VertexHandle &vl, MyMesh::VertexHandle &vr); + void vsplit(VHierarchyNodeHandle _node_handle, MyMesh::VertexHandle vl, MyMesh::VertexHandle vr); + void ecol(VHierarchyNodeHandle _parent_handle, const MyMesh::HalfedgeHandle& v0v1); + + void init_vfront(); + + // streaming realted functions +private: + QTimer *qSessionTimer_; + QTcpSocket *qSocket_; + QString qFilename_; + bool session_running_; + VDPMStreamingPhase streaming_phase_; + unsigned int n_vsplit_packets_; + +public: + void connect_to_server(); + bool request_base_mesh(); + bool receive_base_mesh(); + void send_viewing_information(); + void receive_vsplit_header(); + void receive_vsplit_packets(); + void open_vd_base_mesh(const char* _filename); + void update_vhierarchy( + const OpenMesh::Vec3f &_pos, // 3D position of v0 + const VHierarchyNodeIndex &_v, // vhierarchy index of v1 + const VHierarchyNodeIndex &_fund_lcut_index, // vhierarchy index of fundamental lcut + const VHierarchyNodeIndex &_fund_rcut_index, // vhierarchy index of fundamental rcut + const float _radius[2], // radius of lchild & rchild + const OpenMesh::Vec3f _normal[2], // normal of lchild & rchild + const float _sin_square[2], // sin_square of lchild & rchild + const float _mue_square[2], // mue_square of lchild & rchild + const float _sigma_square[2] // sigma_square of lchild & rchild + ); + + + // for example +private: + QTimer *qAnimationTimer_; + QString qCameraFileName_; + MyMesh::Point bbMin_, bbMax_; + unsigned int frame_; + int max_transmitted_datasize_; + int transmitted_datasize_; + bool vd_streaming_; + + unsigned int nth_viewpoint_; + unsigned int n_viewpoints_; + bool look_around_mode_; + GLdouble reserved_modelview_matrix_[16]; + GLdouble reserved_projection_matrix_[16]; + + FILE *uplink_file; + FILE *downlink_file; + FILE *render_file; + FILE *refinement_file; + FILE *session_file; + +public: + void save_screen(bool _flag); + void save_views(); + void load_views(const char *camera_filename); + void screen_capture(const char *_filename); + void current_max_resolution(); + + OpenMesh::Utils::Timer global_timer_; + OpenMesh::Utils::Timer render_timer_; + OpenMesh::Utils::Timer refinement_timer_; + OpenMesh::Utils::Timer session_timer_; + + + +#ifdef EXAMPLE_CREATION + void increase_max_descendents(const VHierarchyNodeIndex &node_index); + void increase_cur_descendents(VHierarchyNodeHandle _node_handle); + void __add_children(const VHierarchyNodeIndex &node_index, bool update_current = true); + void mesh_coloring(); +#endif +}; + +#endif //OPENMESH_APPS_VDPMSTREAMING_CLIENT_VDPMCLIENTVIEWERWIDGET_HH defined diff --git a/Apps/Deprecated/Streaming-qt4/Client/VDPMStreamingClient.cc b/Apps/Deprecated/Streaming-qt4/Client/VDPMStreamingClient.cc new file mode 100644 index 00000000..04d87370 --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Client/VDPMStreamingClient.cc @@ -0,0 +1,72 @@ +// #ifdef _MSC_VER +// # pragma warning(disable: 4267 4311) +// #endif + +#include +#include + +#include + +//#include +#include +//#include +//#include + +#include +#include +#include + + +int main(int argc, char **argv) +{ + // OpenGL check + QApplication::setColorSpec( QApplication::CustomColor ); + QApplication app(argc,argv); + + if ( !QGLFormat::hasOpenGL() ) { + std::cerr << "This system has no OpenGL support.\n"; + return -1; + } + + // + int c; + int port = -1; + std::string bmesh = ""; + std::string sname = "localhost"; + + while ( (c=getopt(argc, argv, "b:p:s:"))!=-1 ) + { + switch(c) + { + case 'b': bmesh = optarg; break; + case 's': sname = optarg; break; + case 'p': { std::istringstream istr(optarg); istr >> port; } break; + } + } + + // create widget + VDPMClientViewerWidget* w = + new VDPMClientViewerWidget(0, "VDPMClientViewer"); + + if (port == -1) + w->connectToServer( sname ); + else + w->connectToServer( sname, port ); + + w->resize(800, 800); +// app.setMainWidget(w); + w->show(); + + w->openBaseMesh( bmesh ); + + // print usage info + std::cout << "\n\n" + << "Press Minus : Coarsen mesh\n" + << " Plus : Refine mesh\n" + << " Home : Coarsen down to base mesh\n" + << " End : Refine up to finest mesh\n" + << "\n"; + + return app.exec(); +} + diff --git a/Apps/Deprecated/Streaming-qt4/Client/camera.cmr b/Apps/Deprecated/Streaming-qt4/Client/camera.cmr new file mode 100644 index 00000000..7e58ad92 --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Client/camera.cmr @@ -0,0 +1,4 @@ +1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.016996 -0.109919 -0.370638 1.000000 +2.414214 0.000000 0.000000 0.000000 0.000000 2.414214 0.000000 0.000000 0.000000 0.000000 -1.000200 -1.000000 0.000000 0.000000 -0.002487 0.000000 +0.000000 1.000000 0.000000 176744288671350421565538919745292424325033476751523693228169963004884932940091916749086946235466103001193375847224942690972512534721986560.000000 0.000000 nan 425134321045072769729657674081032044702092994459323810191320335465371399515446481741965189098676184821816460416151892487150071042707962836116024422753449790030954505984610613125759424311663740707690994610961772976644207938664290688788945427521964959221153792.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 +0.000000 0.000000 0.000000 1.000000 0.000000 43138399251230245763880957247161123402511258100486738812232497009688599814651595596323661983776768.000000 0.000000 nan 56217166495396395288300850038172311276865324027010017909696113739489719293525015037327494588529843730643950329227434086235241736485385775424471015442015055292454325203222134784.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 diff --git a/Apps/Deprecated/Streaming-qt4/Server/ACGMakefile b/Apps/Deprecated/Streaming-qt4/Server/ACGMakefile new file mode 100644 index 00000000..4be1fea8 --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Server/ACGMakefile @@ -0,0 +1,18 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + +CXX_CFLAGS += -DQT_THREAD_SUPPORT + +SUBDIRS = $(call find-subdirs) + +PACKAGES := qt4 glut opengl + +PROJ_LIBS := OpenMesh/Core OpenMesh/Tools + +MODULES := moc4 cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Apps/Deprecated/Streaming-qt4/Server/ServerSideVDPM.cc b/Apps/Deprecated/Streaming-qt4/Server/ServerSideVDPM.cc new file mode 100644 index 00000000..12e4b975 --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Server/ServerSideVDPM.cc @@ -0,0 +1,225 @@ +#include +#include +#include +#include +#include +#include +#include "ServerSideVDPM.hh" + + +using OpenMesh::VDPM::VHierarchyNode; +using OpenMesh::VDPM::VHierarchyNodeIndex; +using OpenMesh::VDPM::VHierarchyNodeHandle; + + +void +ServerSideVDPM:: +clear() +{ + points_.clear(); + triangles_.clear(); + vhierarchy_.clear(); + + n_base_vertices_ = 0; + n_base_faces_ = 0; + n_details_ = 0; +} + +OpenMesh::VertexHandle +ServerSideVDPM:: +add_vertex(const OpenMesh::Vec3f &p) +{ + points_.push_back(p); + + return OpenMesh::VertexHandle(points_.size() - 1); +} + +OpenMesh::FaceHandle +ServerSideVDPM:: +add_face(const unsigned int _triangle[3]) +{ + OpenMesh::Vec3ui fvi; + + fvi[0] = _triangle[0]; + fvi[1] = _triangle[1]; + fvi[2] = _triangle[2]; + + triangles_.push_back(fvi); + + return OpenMesh::FaceHandle(triangles_.size() - 1); +} + + +void +ServerSideVDPM:: +vhierarchy_roots(VHierarchyNodeHandleContainer &roots) const +{ + unsigned int i; + + roots.clear(); + + for (i=0; i index2handle_map; + + std::ifstream ifs(_filename, std::ios::binary); + if (!ifs) + { + std::cerr << "read error\n"; + return false; + } + + // + bool swap = OpenMesh::Endian::local() != OpenMesh::Endian::LSB; + + // read header + ifs.read(fileformat, 10); fileformat[10] = '\0'; + if (std::string(fileformat) != std::string("VDProgMesh")) + { + std::cerr << "Wrong file format.\n"; + ifs.close(); + return false; + } + + clear(); + + OpenMesh::IO::restore(ifs, n_base_vertices_, swap); + OpenMesh::IO::restore(ifs, n_base_faces_, swap); + OpenMesh::IO::restore(ifs, n_details_, swap); + + // update tree_id_bits_ + vhierarchy_.set_num_roots(n_base_vertices_); + + + // read base_mesh + for (i=0; i +#include +#include +#include +#include + + +using OpenMesh::VDPM::VHierarchy; +using OpenMesh::VDPM::VHierarchyNodeHandleContainer; + + +class ServerSideVDPM +{ +private: + + char name_[256]; + + std::vector points_; // points related to this pm + std::vector triangles_; // base mesh triangles + VHierarchy vhierarchy_; + + unsigned int n_base_vertices_; + unsigned int n_base_faces_; + unsigned int n_details_; + unsigned char tree_id_bits_; + +public: + + ServerSideVDPM() { clear(); } + void clear(); + + const char* name() const { return name_; } + + void get_name(char _name[256]) { strcpy(_name, name_); } + void set_name(const char _name[256]) { strcpy(name_, _name); } + + + std::string + basename(const std::string& _f) + { + std::string::size_type dot = _f.rfind("/"); + if (dot == std::string::npos) + return std::string(_f); + return std::string(_f.substr(dot+1, _f.length()-(dot+1))); + } + + + bool is_same_name(const char _name[256]) + { + return (basename( name_ ) == basename( _name )); + } + + OpenMesh::VertexHandle add_vertex(const OpenMesh::Vec3f &p); + OpenMesh::FaceHandle add_face(const unsigned int _triangle[3]); + + const OpenMesh::Vec3f& point(OpenMesh::VertexHandle _vertex_handle) const + { + return points_[_vertex_handle.idx()]; + } + + OpenMesh::Vec3f& point(OpenMesh::VertexHandle _vertex_handle) + { + return points_[_vertex_handle.idx()]; + } + + const VHierarchy& vhierarchy() const { return vhierarchy_; } + VHierarchy& vhierarchy() { return vhierarchy_; } + + void vhierarchy_roots(VHierarchyNodeHandleContainer &roots) const; + + unsigned int n_base_vertices() const { return n_base_vertices_; } + unsigned int n_base_faces() const { return n_base_faces_; } + unsigned int n_details() const { return n_details_; } + + bool open_vd_prog_mesh(const char *_filename); +}; + +std::ostream& operator << ( std::ostream& _os, const ServerSideVDPM& _o ); + + +typedef std::vector ServerSideVDPMContainer; +typedef std::list ServerSideVDPMList; + +#endif //OPENMESH_APP_SERVERSIDEVDPM_HH defined + diff --git a/Apps/Deprecated/Streaming-qt4/Server/VDPMServerSession.cc b/Apps/Deprecated/Streaming-qt4/Server/VDPMServerSession.cc new file mode 100644 index 00000000..2b8ba9e2 --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Server/VDPMServerSession.cc @@ -0,0 +1,475 @@ +#include +#include +#include +#include + + +using OpenMesh::VDPM::VHierarchyNode; +using OpenMesh::VDPM::Plane3d; +using OpenMesh::VDPM::InvalidVHierarchyNodeHandle; +using OpenMesh::VDPM::debug_print; + + +bool +VDPMServerSession:: +set_vdpm(const char _vdpm_name[256]) +{ +#ifdef DEBUG_COUT + if (debug_print() == true) + { + std::cout << "Setting vdpm" << std::endl; + } +#endif + vdpm_ = ((VDPMServerViewerWidget *) ((VDPMServerSocket *) parent())->parent())->get_vdpm(_vdpm_name); + if (vdpm_ == NULL) + return false; + + vhierarchy_ = &vdpm_->vhierarchy(); + + VHierarchyNodeHandleContainer roots; + unsigned int n_details; + + vdpm_->vhierarchy_roots(roots); + n_details = vdpm_->n_details(); + + //vfront_.init(roots, n_details); + + // vertex hierarchy window + vhwindow_.set_vertex_hierarchy(vdpm_->vhierarchy()); + vhwindow_.init(roots); + + +#ifdef DEBUG_COUT + if (debug_print() == true) + { + std::cout << "setting vdpm ended" << std::endl; + } +#endif + + return true; +} + + +void +VDPMServerSession:: +sendBaseMeshToClient() +{ +#ifdef DEBUG_COUT + if (debug_print() == true) + { + std::cout << "starting sendBaseMeshToClient()" << std::endl; + } +#endif + + + +#ifdef DEBUG_COUT + if (debug_print() == true) + { + std::cout << "sendBaseMeshToClient() is done" << std::endl; + } +#endif +} + +void +VDPMServerSession:: +send_vsplit_packets() +{ + viewing_parameters_.update_viewing_configurations(); + vsplits_.clear(); + + if (((VDPMServerViewerWidget *) this->parent()->parent())->vd_streaming()) + adaptive_refinement(); + else + sequential_refinement(); + + + if (debug_print() == true) + { + std::cout << "adaptive refinement is done on the server side" << std::endl; + } + + stream_vsplits(); + + if (debug_print() == true) + { + std::cout << "streameing vsplits is done" << std::endl; + } + + if (transmission_complete_ == true) + { + std::cout << "transmission is completed" << std::endl; + } + + if (debug_print() == true) + { + std::cout << "send_vsplit_packets() is done" << std::endl; + } +} + + +void +VDPMServerSession:: +readBaseMeshRequestFromClient() +{ + int status; + unsigned int string_length; + QDataStream qTcp(socket_); + QString vdpm_name; + +// while (waitForMore(10) < sizeof(int)); + while ( socket_->bytesAvailable() < sizeof(int) ) + socket_->waitForReadyRead(10); + + qTcp >> string_length; + +// while (waitForMore(10) < (string_length*sizeof(char))); + while (socket_->bytesAvailable() < string_length*sizeof(char) ) + socket_->waitForReadyRead(10); + + qTcp >> vdpm_name; + + if (set_vdpm( vdpm_name.toStdString().c_str() ) != true) status = 0; + else status = 1; + + qTcp << status; + socket_->flush(); + + if (status == 1) + streaming_phase_ = kVSplits; +} + + +void +VDPMServerSession:: +readViewingParametersFromClient() +{ + double modelview_matrix[16]; + float fovy; + float aspect; + float tolerance_square; + +// while (waitForMore(10) < 16*sizeof(double) + 3*sizeof(float)); + while ( socket_->bytesAvailable() < 16*sizeof(double) + 3*sizeof(float) ) + socket_->waitForReadyRead(10); + + QDataStream qTCP(socket_); + qTCP >> modelview_matrix[0] + >> modelview_matrix[1] + >> modelview_matrix[2] + >> modelview_matrix[3] + >> modelview_matrix[4] + >> modelview_matrix[5] + >> modelview_matrix[6] + >> modelview_matrix[7] + >> modelview_matrix[8] + >> modelview_matrix[9] + >> modelview_matrix[10] + >> modelview_matrix[11] + >> modelview_matrix[12] + >> modelview_matrix[13] + >> modelview_matrix[14] + >> modelview_matrix[15] + >> fovy + >> aspect + >> tolerance_square; + + viewing_parameters_.set_modelview_matrix(modelview_matrix); + viewing_parameters_.set_fovy(fovy); + viewing_parameters_.set_aspect(aspect); + viewing_parameters_.set_tolerance_square(tolerance_square); + + send_vsplit_packets(); + + fprintf(mem_file, "%d %d %d\n", + memory_requirements_using_window(true), + memory_requirements_using_window(false), + memory_requirements_using_vfront()); +} + + +void +VDPMServerSession:: +PrintOutVFront() +{ +} + +void +VDPMServerSession:: +stream_vsplits() +{ + // send header (i.e., # of vsplits) + unsigned int i; + VHierarchyNodeHandle node_handle; + OpenMesh::Vec3f pos; + VHierarchyNodeIndex node_index, fund_lcut_index, fund_rcut_index; + float lchild_radius, rchild_radius; + OpenMesh::Vec3f lchild_normal, rchild_normal; + float lchild_sin_square, rchild_sin_square; + float lchild_mue_square, rchild_mue_square; + float lchild_sigma_square, rchild_sigma_square; + unsigned int n_vsplit_packets = (unsigned int) vsplits_.size(); + + QDataStream qTcp(socket_); + qTcp << n_vsplit_packets; + socket_->flush(); + + for (i=0; ilchild_handle(node_handle); + VHierarchyNodeHandle rchild_handle = vhierarchy_->rchild_handle(node_handle); + + VHierarchyNode &node = vhierarchy_->node(node_handle); + VHierarchyNode &lchild = vhierarchy_->node(lchild_handle); + VHierarchyNode &rchild = vhierarchy_->node(rchild_handle); + + pos = vdpm_->point(lchild.vertex_handle()); + node_index = node.node_index(); + fund_lcut_index = node.fund_lcut_index(); + fund_rcut_index = node.fund_rcut_index(); + lchild_radius = lchild.radius(); rchild_radius = rchild.radius(); + lchild_normal = lchild.normal(); rchild_normal = rchild.normal(); + lchild_sin_square = lchild.sin_square(); rchild_sin_square = rchild.sin_square(); + lchild_mue_square = lchild.mue_square(); rchild_mue_square = rchild.mue_square(); + lchild_sigma_square = lchild.sigma_square(); rchild_sigma_square = rchild.sigma_square(); + + qTcp << pos[0] << pos[1] << pos[2] + << node_index.value() + << fund_lcut_index.value() + << fund_rcut_index.value() + << lchild_radius + << lchild_normal[0] << lchild_normal[1] << lchild_normal[2] + << lchild_sin_square + << lchild_mue_square + << lchild_sigma_square + << rchild_radius + << rchild_normal[0] << rchild_normal[1] << rchild_normal[2] + << rchild_sin_square + << rchild_mue_square + << rchild_sigma_square; + socket_->flush(); // socket flush + + if (debug_print() == true) + { + std::cout << "Write to client " << i << "-th vsplit packets: " << std::endl; + } + + } +} + + +void +VDPMServerSession:: +adaptive_refinement() +{ + float fovy = viewing_parameters_.fovy(); + float tolerance_square = viewing_parameters_.tolerance_square(); + float tan_value = tanf(fovy / 2.0f); + kappa_square_ = 4.0f * tan_value * tan_value * tolerance_square; + + transmission_complete_ = true; + for (vhwindow_.begin(); vhwindow_.end() != true; vhwindow_.next()) + { + VHierarchyNodeHandle node_handle = vhwindow_.node_handle(); + + if (vhierarchy_->is_leaf_node(node_handle) != true) + { + transmission_complete_ = false; + if (qrefine(node_handle) == true) + { + force_vsplit(node_handle); + } + } + } +} + +void +VDPMServerSession:: +sequential_refinement() +{ + for (vhwindow_.begin(); vhwindow_.end() != true; vhwindow_.next()) + { + VHierarchyNodeHandle node_handle = vhwindow_.node_handle(); + + if (vhierarchy_->is_leaf_node(node_handle) != true) + force_vsplit(node_handle); + + if (vsplits_.size() > 10) + break; + } +} + + +bool +VDPMServerSession:: +qrefine(VHierarchyNodeHandle _node_handle) +{ + VHierarchyNode &node = vhierarchy_->node(_node_handle); + OpenMesh::Vec3f p = vdpm_->point(node.vertex_handle()); + OpenMesh::Vec3f eye_dir = p - viewing_parameters_.eye_pos(); + float distance = eye_dir.length(); + float distance2 = distance * distance; + float product_value = dot(eye_dir, node.normal()); + + if (outside_view_frustum(p, node.radius()) == true) + return false; + if (oriented_away(node.sin_square(), distance2, product_value) == true) + return false; + if (screen_space_error(node.mue_square(), node.sigma_square(), distance2, product_value) == true) + return false; + + return true; +} + + +bool +VDPMServerSession:: +outside_view_frustum(const OpenMesh::Vec3f &pos, float radius) +{ + Plane3d frustum_plane[4]; + viewing_parameters_.frustum_planes(frustum_plane); + + for (int i = 0; i < 4; i++) { + if (frustum_plane[i].signed_distance(pos) < -radius) + return true; + } + + return false; +} + +bool +VDPMServerSession:: +oriented_away(float sin_square, float distance_square, float product_value) +{ + if (product_value > 0 && product_value*product_value > distance_square * sin_square) + return true; + else + return false; +} + +bool +VDPMServerSession:: +screen_space_error(float mue_square, float sigma_square, float distance_square, float product_value) +{ + if ((mue_square >= kappa_square_ * distance_square) || + (sigma_square * (distance_square - product_value * product_value) >= kappa_square_ * distance_square * distance_square)) + return false; + else + return true; +} + + +void +VDPMServerSession:: +force_vsplit(VHierarchyNodeHandle node_handle) +{ + VHierarchyNodeHandle lcut_handle, rcut_handle; + VHierarchyNodeIndex fund_lcut_index, fund_rcut_index; + + fund_lcut_index = vhierarchy_->fund_lcut_index(node_handle); + fund_rcut_index = vhierarchy_->fund_rcut_index(node_handle); + + lcut_handle = active_ancestor_handle(fund_lcut_index); + rcut_handle = active_ancestor_handle(fund_rcut_index); + assert(lcut_handle != InvalidVHierarchyNodeHandle && rcut_handle != InvalidVHierarchyNodeHandle); + + while (lcut_handle == rcut_handle) + { + force_vsplit(lcut_handle); + lcut_handle = active_ancestor_handle(fund_lcut_index); + rcut_handle = active_ancestor_handle(fund_rcut_index); + assert(lcut_handle != InvalidVHierarchyNodeHandle && rcut_handle != InvalidVHierarchyNodeHandle); + } + + vsplit(node_handle); +} + +void +VDPMServerSession:: +vsplit(VHierarchyNodeHandle _node_handle) +{ + // refine + VHierarchyNodeHandle lchild_handle = vhierarchy_->lchild_handle(_node_handle); + VHierarchyNodeHandle rchild_handle = vhierarchy_->rchild_handle(_node_handle); + + vhwindow_.inactivate(_node_handle); + vhwindow_.activate(lchild_handle); + vhwindow_.activate(rchild_handle); + + //vfront_.remove(_node_handle); + //vfront_.add(lchild_handle); + //vfront_.add(rchild_handle); + + vsplits_.push_back(_node_handle); +} + +VHierarchyNodeHandle +VDPMServerSession:: +active_ancestor_handle(VHierarchyNodeIndex &node_index) +{ + if (node_index.is_valid(vhierarchy_->tree_id_bits()) != true) + return InvalidVHierarchyNodeHandle; + + VHierarchyNodeHandle node_handle = vhierarchy_->node_handle(node_index); + + while (node_handle != InvalidVHierarchyNodeHandle && vhwindow_.is_active(node_handle) != true) + node_handle = vhierarchy_->parent_handle(node_handle); + + return node_handle; +} + +unsigned int +VDPMServerSession:: +memory_requirements_using_window(bool _estimate) +{ + unsigned int mem = 0; + + // common + mem += sizeof(VHierarchy*); + mem += sizeof(ViewingParameters); + mem += sizeof(float); + + if (_estimate) + { + unsigned int min = vhierarchy_->num_nodes(); + unsigned int max = 0; + + for (unsigned int i = 0; i < vhierarchy_->num_nodes(); ++i) + { + if (vhwindow_.is_active(VHierarchyNodeHandle((int) i))) + { + min = std::min(min, i); + max = std::max(max, i); + } + } + + mem += (max - min) / 8; + } + else + { + mem += vhwindow_.buffer_size(); + } + + return mem; +} + +unsigned int +VDPMServerSession:: +memory_requirements_using_vfront() +{ + unsigned int mem = 0; + std::list dummy_vfront; + + mem += (unsigned int) ceil (vhierarchy_->num_nodes() / 8.0); + mem += sizeof(dummy_vfront); + + for (unsigned int i = 0; i < vhierarchy_->num_nodes(); ++i) + { + if (vhwindow_.is_active(VHierarchyNodeHandle((int) i))) + mem += 3*sizeof(int); + } + + return mem; +} + diff --git a/Apps/Deprecated/Streaming-qt4/Server/VDPMServerSession.hh b/Apps/Deprecated/Streaming-qt4/Server/VDPMServerSession.hh new file mode 100644 index 00000000..4723da31 --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Server/VDPMServerSession.hh @@ -0,0 +1,148 @@ +#ifndef OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSERVERSESSION_HH +#define OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSERVERSESSION_HH + +#include +#include +#include +#include +#include +// #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using OpenMesh::VDPM::VDPMStreamingPhase; +using OpenMesh::VDPM::kBaseMesh; +using OpenMesh::VDPM::kVSplits; + +using OpenMesh::VDPM::VHierarchyWindow; +using OpenMesh::VDPM::VHierarchyNodeIndex; +using OpenMesh::VDPM::VHierarchyNodeHandle; +using OpenMesh::VDPM::ViewingParameters; + +using OpenMesh::VDPM::set_debug_print; + +class VDPMServerSession : public QThread +{ + + Q_OBJECT + +public: + + VDPMServerSession(QTcpSocket* _socket, QObject *parent=0, const char *name=0) + { + socket_ = _socket; + + set_debug_print(true); + + streaming_phase_ = kBaseMesh; + transmission_complete_ = false; + + connect(socket_, SIGNAL(connected()), this, SLOT(socketConnected())); + QTcpSocket::connect(socket_, SIGNAL(readyRead()), this, SLOT(socketReadyRead())); + //connect(this, SIGNAL(connectionClosed()), SLOT(deleteLater())); + QTcpSocket::connect(socket_, SIGNAL(connectionClosed()), this, SLOT(delayedCloseFinished())); + +///TODO: find out how to port it from QSocket -> QTcpSocket +// setSocket(sock); + + qStatisticsTimer_ = new QTimer(this); + QTcpSocket::connect(qStatisticsTimer_, SIGNAL(timeout()), this, SLOT(print_statistics())); + + mem_file = fopen("mem.txt", "w"); + + start(); + } + + ~VDPMServerSession() + { + fclose(mem_file); + } + +// void run() +// { +// exec(); +// } + +private: + + VDPMStreamingPhase streaming_phase_; + bool transmission_complete_; + + QTcpSocket* socket_; + +private: + + void sendBaseMeshToClient(); + void send_vsplit_packets(); + void readBaseMeshRequestFromClient(); + void readViewingParametersFromClient(); + + void PrintOutVFront(); + +private slots: + + void socketConnected() + { + std::cout << "socket is connected" << std::endl; + } + + void socketReadyRead() + { + if (streaming_phase_ == kBaseMesh) + { + readBaseMeshRequestFromClient(); + } + else if (streaming_phase_ == kVSplits) + { + readViewingParametersFromClient(); + } + } + + void print_statistics() + { + //std::cout << memory_requirements(true) << " " << memory_requirements(false) << std::endl; + } + +private: + unsigned short tree_id_bits_; // obsolete + ServerSideVDPM* vdpm_; + VHierarchy* vhierarchy_; + VHierarchyWindow vhwindow_; + ViewingParameters viewing_parameters_; + float kappa_square_; + VHierarchyNodeHandleContainer vsplits_; + +private: + bool outside_view_frustum(const OpenMesh::Vec3f &pos, float radius); + bool oriented_away(float sin_square, float distance_square, float product_value); + bool screen_space_error(float mue_square, float sigma_square, float distance_square, float product_value); + + void adaptive_refinement(); + void sequential_refinement(); + bool qrefine(VHierarchyNodeHandle _node_handle); + void force_vsplit(VHierarchyNodeHandle node_handle); + void vsplit(VHierarchyNodeHandle _node_handle); + VHierarchyNodeHandle active_ancestor_handle(VHierarchyNodeIndex &node_index); + void stream_vsplits(); + +public: + bool set_vdpm(const char _vdpm_name[256]); + unsigned int memory_requirements_using_window(bool _estimate); + unsigned int memory_requirements_using_vfront(); + + // for example +private: + QTimer *qStatisticsTimer_; + FILE *mem_file; +}; + +#endif //OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSERVERSESSION_HH defined diff --git a/Apps/Deprecated/Streaming-qt4/Server/VDPMServerSocket.hh b/Apps/Deprecated/Streaming-qt4/Server/VDPMServerSocket.hh new file mode 100644 index 00000000..ab66fb6a --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Server/VDPMServerSocket.hh @@ -0,0 +1,51 @@ +#ifndef OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSERVERSOCKET_HH +#define OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSERVERSOCKET_HH + +#include +#include +#include +#include + +#include +#include +#include + + +class VDPMServerSocket : public QTcpServer +{ + Q_OBJECT + +public: + + VDPMServerSocket(QObject *parent=0) + : QTcpServer(parent) + { + setMaxPendingConnections(1); + if ( !listen(QHostAddress::Any, VDPM_STREAMING_PORT) ) + { + std::cerr << "Failed to bind to port " << VDPM_STREAMING_PORT << std::endl; + exit(1); + } + + connect(this, SIGNAL(newConnection()),this,SLOT(newConnections())); + } + +public slots: + + void newConnections() + { + VDPMServerSession *s = new VDPMServerSession(nextPendingConnection(), this); + //s->set_vdpm(); + emit newConnect(s); + std::cout << "new connection"<< /*socket << */std::endl; + } + +signals: + + void newConnect(VDPMServerSession*); + +}; + + + +#endif //OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSERVERSOCKET_HH defined diff --git a/Apps/Deprecated/Streaming-qt4/Server/VDPMServerViewerWidget.cc b/Apps/Deprecated/Streaming-qt4/Server/VDPMServerViewerWidget.cc new file mode 100644 index 00000000..7bc1e4d9 --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Server/VDPMServerViewerWidget.cc @@ -0,0 +1,81 @@ +#include +#include +#include + +bool +VDPMServerViewerWidget:: +open_vd_prog_mesh(const char *_filename) +{ + ServerSideVDPMListIter vdpm_it; + + vdpm_it = vdpms_.insert(vdpms_.end(), ServerSideVDPM()); + + ServerSideVDPM &vdpm = *vdpm_it; + + return vdpm.open_vd_prog_mesh(_filename); +} + +ServerSideVDPM* +VDPMServerViewerWidget:: +get_vdpm(const char _vdpm_name[256]) +{ + ServerSideVDPMListIter vdpm_it; + + for (vdpm_it=vdpms_.begin(); vdpm_it!=vdpms_.end(); ++vdpm_it) + { + if (vdpm_it->is_same_name(_vdpm_name) == true) + { + return &(*vdpm_it); + } + } + + return NULL; +} + +void +VDPMServerViewerWidget:: +keyPressEvent(QKeyEvent* _event) +{ + bool handled(false); + + QString filename; + + switch (_event->key()) + { + case Qt::Key_D: + set_debug_print(!debug_print()); + std::cout << "debug print mode " + << (debug_print() == true ? "on" : "off") << std::endl; + break; + + case Qt::Key_O: +#if defined(OM_CC_MSVC) + filename = QFileDialog::getOpenFileName(0, "", "d:/data/models/spm/", "*.spm"); +#else + filename = QFileDialog::getOpenFileName(0, "", "~/data/models/spm/", "*.spm"); +#endif + open_vd_prog_mesh( filename.toStdString().c_str() ); + break; + + case Qt::Key_I: + std::copy( vdpms_.begin(), vdpms_.end(), + std::ostream_iterator(std::cout, "\n") ); + break; + + case Qt::Key_V: + vd_streaming_ = !(vd_streaming_); + if (vd_streaming_) + std::cout << "View-dependent streaming mode" << std::endl; + else + std::cout << "Sequential streaming mode" << std::endl; + + break; + + case Qt::Key_Q: + case Qt::Key_Escape: + qApp->quit(); + } + + if (!handled) + _event->ignore(); +} diff --git a/Apps/Deprecated/Streaming-qt4/Server/VDPMServerViewerWidget.hh b/Apps/Deprecated/Streaming-qt4/Server/VDPMServerViewerWidget.hh new file mode 100644 index 00000000..fa6780e3 --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Server/VDPMServerViewerWidget.hh @@ -0,0 +1,72 @@ +#ifndef OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSTREAMINGSERVERWIDGET_HH +#define OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSTREAMINGSERVERWIDGET_HH + +#include +#include +#include +#include +#include +#include +#include + + +using OpenMesh::VDPM::set_debug_print; +using OpenMesh::VDPM::debug_print; + + +class VDPMServerViewerWidget : public QWidget +{ + Q_OBJECT +public: + //VDPMServerViewerWidget(QWidget *_parent) : QWidget(_parent) + VDPMServerViewerWidget() : QWidget() + { + server = new VDPMServerSocket(this); + +// connect(server, +// SIGNAL(newConnection()), +// SLOT(newConnect())); + + vd_streaming_ = true; + } + +private: + typedef ServerSideVDPMList::iterator ServerSideVDPMListIter; + ServerSideVDPMList vdpms_; + bool vd_streaming_; + VDPMServerSocket *server; + +public: + + ServerSideVDPM* get_vdpm(const char _vdpm_name[256]); + + +public: + + bool open_vd_prog_mesh(const char *_filename); + bool vd_streaming() const { return vd_streaming_; } + +private slots: + + void newConnect(VDPMServerSession *s) + { + std::cout << "New connection" << std::endl; + +// connect(s, SIGNAL(connectionClosed()), SLOT(connectionClosed())); + } + + void connectionClosed() + { + std::cout << "Client closed connection" << std::endl; + } + +protected: + + virtual void keyPressEvent(QKeyEvent* _event); + +}; + + +#endif //OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSTREAMINGSERVERWIDGET_HH defined + + diff --git a/Apps/Deprecated/Streaming-qt4/Server/VDPMStreamingServer.cc b/Apps/Deprecated/Streaming-qt4/Server/VDPMStreamingServer.cc new file mode 100644 index 00000000..15bc7df4 --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Server/VDPMStreamingServer.cc @@ -0,0 +1,34 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + + + +int main(int argc, char **argv) +{ + std::cout << "View-dependent streaming of PM server." << std::endl; + + QApplication app(argc, argv); + VDPMServerViewerWidget server_widget; + + server_widget.resize(50, 50); +// app.setMainWidget(&server_widget); + server_widget.show(); + + for (int idx=1; idx < argc; ++idx) + { + std::cout << "loading " << argv[idx] << std::endl; + server_widget.open_vd_prog_mesh( argv[idx] ) ; + } + + return app.exec(); +} + diff --git a/Apps/Deprecated/Streaming-qt4/Server/VDPMStreamingServer.hh b/Apps/Deprecated/Streaming-qt4/Server/VDPMStreamingServer.hh new file mode 100644 index 00000000..119b5939 --- /dev/null +++ b/Apps/Deprecated/Streaming-qt4/Server/VDPMStreamingServer.hh @@ -0,0 +1,6 @@ +#ifndef OPENMESH_APP_VDPMSTREAMINGSERVER_HH +#define OPENMESH_APP_VDPMSTREAMINGSERVER_HH + + + +#endif //OPENMESH_APP_VDPMSTREAMINGSERVER_HH defined diff --git a/Apps/Deprecated/Streaming-qt4/Server/bunny.pm b/Apps/Deprecated/Streaming-qt4/Server/bunny.pm new file mode 100755 index 00000000..3e049810 Binary files /dev/null and b/Apps/Deprecated/Streaming-qt4/Server/bunny.pm differ diff --git a/Apps/Deprecated/Streaming-qt4/Server/bunny.spm b/Apps/Deprecated/Streaming-qt4/Server/bunny.spm new file mode 100644 index 00000000..6df95b1b Binary files /dev/null and b/Apps/Deprecated/Streaming-qt4/Server/bunny.spm differ diff --git a/Apps/Deprecated/Streaming-qt4/Server/rockerArm.pm b/Apps/Deprecated/Streaming-qt4/Server/rockerArm.pm new file mode 100755 index 00000000..04034d92 Binary files /dev/null and b/Apps/Deprecated/Streaming-qt4/Server/rockerArm.pm differ diff --git a/Apps/Deprecated/Streaming/ACGMakefile b/Apps/Deprecated/Streaming/ACGMakefile new file mode 100644 index 00000000..d05cdf75 --- /dev/null +++ b/Apps/Deprecated/Streaming/ACGMakefile @@ -0,0 +1,16 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = $(call find-subdirs) + +PACKAGES := + +PROJ_LIBS := + +MODULES := + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Apps/Deprecated/Streaming/Client/ACGMakefile b/Apps/Deprecated/Streaming/Client/ACGMakefile new file mode 100644 index 00000000..b862f196 --- /dev/null +++ b/Apps/Deprecated/Streaming/Client/ACGMakefile @@ -0,0 +1,19 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + +CXX_CFLAGS += -DQT_THREAD_SUPPORT + +SUBDIRS = $(call find-subdirs) + +PACKAGES := qt glut opengl + +PROJ_LIBS := OpenMesh/Apps/QtViewer \ + OpenMesh/Core OpenMesh/Tools + +MODULES := moc cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Apps/Deprecated/Streaming/Client/MeshViewerWidgetT.cc b/Apps/Deprecated/Streaming/Client/MeshViewerWidgetT.cc new file mode 100644 index 00000000..457ac4f1 --- /dev/null +++ b/Apps/Deprecated/Streaming/Client/MeshViewerWidgetT.cc @@ -0,0 +1,602 @@ +//============================================================================= +// +// 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: 1800 $ +// $Date: 2008-05-19 11:51:23 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= +#define OPENMESHAPPS_MESHVIEWERWIDGET_CC + +//== INCLUDES ================================================================= + +#ifdef _MSC_VER +//# pragma warning(disable: 4267 4311) +#endif + +// +#include +#include +#include +#include +#include +#include + +using namespace OpenMesh; + + +//== IMPLEMENTATION ========================================================== + + +template +bool +MeshViewerWidgetT::open_mesh(const char* _filename, + IO::Options _opt) +{ + // load mesh + // calculate normals + // set scene center and radius + + mesh_.request_face_normals(); + mesh_.request_face_colors(); + mesh_.request_vertex_normals(); + mesh_.request_vertex_texcoords2D(); + + if ( IO::read_mesh(mesh_, _filename, _opt )) + { + opt_ = _opt; + + // update face and vertex normals + if ( ! opt_.check( IO::Options::FaceNormal ) ) + mesh_.update_face_normals(); + + if ( ! opt_.check( IO::Options::VertexNormal ) ) + mesh_.update_vertex_normals(); + + if ( mesh_.has_vertex_colors() ) + add_draw_mode("Colored"); + + if ( _opt.check( IO::Options::FaceColor ) ) + add_draw_mode("Colored Faces"); + else + mesh_.release_face_colors(); + + // bounding box + typename Mesh::ConstVertexIter vIt(mesh_.vertices_begin()); + typename Mesh::ConstVertexIter vEnd(mesh_.vertices_end()); + + typedef typename Mesh::Point Point; + using OpenMesh::Vec3f; + + Vec3f bbMin, bbMax; + + bbMin = bbMax = OpenMesh::vector_cast(mesh_.point(vIt)); + + for (size_t count=0; vIt!=vEnd; ++vIt, ++count) + { + bbMin.minimize( OpenMesh::vector_cast(mesh_.point(vIt))); + bbMax.maximize( OpenMesh::vector_cast(mesh_.point(vIt))); + + if ( ! opt_.check( IO::Options::VertexColor ) && + mesh_.has_vertex_colors() ) + { + typename Mesh::Color + c( 54, + (unsigned char)(54.5+200.0*count/mesh_.n_vertices()), + 54 ); + mesh_.set_color( vIt, c ); + } + } + + + // set center and radius + set_scene_pos( (bbMin+bbMax)*0.5, (bbMin-bbMax).norm()*0.5 ); + + // info + std::clog << mesh_.n_vertices() << " vertices, " + << mesh_.n_edges() << " edge, " + << mesh_.n_faces() << " faces\n"; + + // + { + std::clog << "Computing strips.." << std::flush; + OpenMesh::Utils::Timer t; + t.start(); + compute_strips(); + t.stop(); + std::clog << "done [" << strips_.n_strips() + << " strips created in " << t.as_string() << "]\n"; + } + +#if defined(OM_CC_MSVC) + updateGL(); +#endif + + return true; + } + return false; +} + + +//----------------------------------------------------------------------------- + +template +bool MeshViewerWidgetT::open_texture( const char *_filename ) +{ + QImage texsrc; + QString fname = _filename; + + if (texsrc.load( fname )) + { + return set_texture( texsrc ); + } + return false; +} + + +//----------------------------------------------------------------------------- + +template +bool MeshViewerWidgetT::set_texture( QImage& _texsrc ) +{ + std::clog << "set_texture\n"; + + if ( !opt_.vertex_has_texcoord() ) + return false; + + { + // adjust texture size: 2^k * 2^l + int tex_w, w( _texsrc.width() ); + int tex_h, h( _texsrc.height() ); + + for (tex_w=1; tex_w <= w; tex_w <<= 1); + for (tex_h=1; tex_h <= h; tex_h <<= 1); + tex_w >>= 1; + tex_h >>= 1; + _texsrc = _texsrc.smoothScale( tex_w, tex_h ); + } + + QImage texture( QGLWidget::convertToGLFormat ( _texsrc ) ); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ROW_LENGTH, 0); + glPixelStorei(GL_PACK_SKIP_ROWS, 0); + glPixelStorei(GL_PACK_SKIP_PIXELS, 0); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + if ( tex_id_ > 0 ) + { + glDeleteTextures(1, &tex_id_); + } + glGenTextures(1, &tex_id_); + glBindTexture(GL_TEXTURE_2D, tex_id_); + + // glTexGenfv( GL_S, GL_SPHERE_MAP, 0 ); + // glTexGenfv( GL_T, GL_SPHERE_MAP, 0 ); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glTexImage2D(GL_TEXTURE_2D, // target + 0, // level + GL_RGBA, // internal format + texture.width(), // width (2^n) + texture.height(), // height (2^m) + 0, // border + GL_RGBA, // format + GL_UNSIGNED_BYTE, // type + texture.bits() ); // pointer to pixels + + return true; +} + + +//----------------------------------------------------------------------------- + +template +void +MeshViewerWidgetT::draw_openmesh(const std::string& _draw_mode) +{ + typename Mesh::ConstFaceIter fIt(mesh_.faces_begin()), + fEnd(mesh_.faces_end()); + + typename Mesh::ConstFaceVertexIter fvIt; + +#if defined(OM_USE_OSG) && OM_USE_OSG + if (_draw_mode == "OpenSG Indices") // -------------------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); + + if ( tex_id_ && mesh_.has_vertex_texcoords2D() ) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 0, mesh_.texcoords2D()); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tex_id_); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, tex_mode_); + } + + glDrawElements(GL_TRIANGLES, + mesh_.osg_indices()->size(), + GL_UNSIGNED_INT, + &mesh_.osg_indices()->getField()[0] ); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + else +#endif + + if (_draw_mode == "Wireframe") // -------------------------------------------- + { + glBegin(GL_TRIANGLES); + for (; fIt!=fEnd; ++fIt) + { + fvIt = mesh_.cfv_iter(fIt.handle()); + glVertex3fv( &mesh_.point(fvIt)[0] ); + ++fvIt; + glVertex3fv( &mesh_.point(fvIt)[0] ); + ++fvIt; + glVertex3fv( &mesh_.point(fvIt)[0] ); + } + glEnd(); + } + + else if (_draw_mode == "Solid Flat") // ------------------------------------- + { + glBegin(GL_TRIANGLES); + for (; fIt!=fEnd; ++fIt) + { + glNormal3fv( &mesh_.normal(fIt)[0] ); + + fvIt = mesh_.cfv_iter(fIt.handle()); + glVertex3fv( &mesh_.point(fvIt)[0] ); + ++fvIt; + glVertex3fv( &mesh_.point(fvIt)[0] ); + ++fvIt; + glVertex3fv( &mesh_.point(fvIt)[0] ); + } + glEnd(); + + + } + + + else if (_draw_mode == "Solid Smooth") // ----------------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); + + if ( tex_id_ && mesh_.has_vertex_texcoords2D() ) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 0, mesh_.texcoords2D()); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tex_id_); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, tex_mode_); + } + + glBegin(GL_TRIANGLES); + for (; fIt!=fEnd; ++fIt) + { + fvIt = mesh_.cfv_iter(fIt.handle()); + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + } + glEnd(); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + if ( tex_id_ && mesh_.has_vertex_texcoords2D() ) + { + glDisable(GL_TEXTURE_2D); + } + } + + else if (_draw_mode == "Colored") // ---------------------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); + + if ( mesh_.has_vertex_colors() ) + { + glEnableClientState( GL_COLOR_ARRAY ); + glColorPointer(3, GL_UNSIGNED_BYTE, 0,mesh_.vertex_colors()); + } + + glBegin(GL_TRIANGLES); + for (; fIt!=fEnd; ++fIt) + { + fvIt = mesh_.cfv_iter(fIt.handle()); + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + } + glEnd(); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + } + + + else if (_draw_mode == "Colored Faces") // ---------------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); + + glBegin(GL_TRIANGLES); + for (; fIt!=fEnd; ++fIt) + { + glColor( fIt.handle() ); + + fvIt = mesh_.cfv_iter(fIt.handle()); + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + } + glEnd(); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + } + + + else if ( _draw_mode == "Strips'n VertexArrays" ) // ------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); + + if ( tex_id_ && mesh_.has_vertex_texcoords2D() ) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 0, mesh_.texcoords2D()); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tex_id_); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, tex_mode_); + } + + typename MyStripifier::StripsIterator strip_it = strips_.begin(); + typename MyStripifier::StripsIterator strip_last = strips_.end(); + + // Draw all strips + for (; strip_it!=strip_last; ++strip_it) + { + glDrawElements(GL_TRIANGLE_STRIP, + strip_it->size(), GL_UNSIGNED_INT, &(*strip_it)[0] ); + } + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + + + else if (_draw_mode == "Show Strips" && strips_.is_valid() ) // ------------- + { + typename MyStripifier::StripsIterator strip_it = strips_.begin(); + typename MyStripifier::StripsIterator strip_last = strips_.end(); + + float cmax = 256.0f; + int range = 220; + int base = (int)cmax-range; + int drcol = 13; + int dgcol = 31; + int dbcol = 17; + + int rcol=0, gcol=dgcol, bcol=dbcol+dbcol; + + // Draw all strips + for (; strip_it!=strip_last; ++strip_it) + { + typename MyStripifier::IndexIterator idx_it = strip_it->begin(); + typename MyStripifier::IndexIterator idx_last = strip_it->end(); + + rcol = (rcol+drcol) % range; + gcol = (gcol+dgcol) % range; + bcol = (bcol+dbcol) % range; + + glBegin(GL_TRIANGLE_STRIP); + glColor3f((rcol+base)/cmax, (gcol+base)/cmax, (bcol+base)/cmax); + for ( ;idx_it != idx_last; ++idx_it ) + glVertex3fv( &mesh_.point( OM_TYPENAME Mesh::VertexHandle(*idx_it))[0] ); + glEnd(); + } + glColor3f(1.0, 1.0, 1.0); + } + + + else if( _draw_mode == "Points" ) // ----------------------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + glDrawArrays( GL_POINTS, 0, mesh_.n_vertices() ); + glDisableClientState(GL_VERTEX_ARRAY); + } + + +} + + +//----------------------------------------------------------------------------- + + +template +void +MeshViewerWidgetT::draw_scene(const std::string& _draw_mode) +{ + + if ( ! mesh_.n_vertices() ) + return; + +#if defined(OM_USE_OSG) && OM_USE_OSG + else if ( _draw_mode == "OpenSG Indices") + { + glEnable(GL_LIGHTING); + glShadeModel(GL_SMOOTH); + draw_openmesh( _draw_mode ); + } + else +#endif + if ( _draw_mode == "Points" ) + { + glDisable(GL_LIGHTING); + draw_openmesh(_draw_mode); + } + else if (_draw_mode == "Wireframe") + { + glDisable(GL_LIGHTING); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + draw_openmesh(_draw_mode); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + + else if ( _draw_mode == "Hidden-Line" ) + { + glEnable(GL_LIGHTING); + glShadeModel(GL_SMOOTH); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDepthRange(0.01, 1.0); + draw_openmesh("Solid Smooth"); + + glDisable(GL_LIGHTING); + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE); + glColor4f( 0.4f, 0.4f, 0.4f, 1.0f ); + glDepthRange( 0.0, 1.0 ); + draw_openmesh( "Wireframe" ); + + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL); + } + + else if (_draw_mode == "Solid Flat") + { + glEnable(GL_LIGHTING); + glShadeModel(GL_FLAT); + draw_openmesh(_draw_mode); + } + + else if (_draw_mode == "Solid Smooth" || + _draw_mode == "Strips'n VertexArrays" ) + { + glEnable(GL_LIGHTING); + glShadeModel(GL_SMOOTH); + draw_openmesh(_draw_mode); + } + + else if (_draw_mode == "Show Strips") + { + glDisable(GL_LIGHTING); + draw_openmesh(_draw_mode); + } + + else if (_draw_mode == "Colored" ) + { + glDisable(GL_LIGHTING); + draw_openmesh(_draw_mode); + } + + else if (_draw_mode == "Colored Faces" ) + { + glDisable(GL_LIGHTING); + draw_openmesh(_draw_mode); + } +} + + +//----------------------------------------------------------------------------- + +#define TEXMODE( Mode ) \ + tex_mode_ = Mode; std::cout << "Texture mode set to " << #Mode << std::endl + +template +void +MeshViewerWidgetT::keyPressEvent( QKeyEvent* _event) +{ + switch( _event->key() ) + { + case Key_I: + std::cout << "\n# Vertices : " << mesh_.n_vertices() << std::endl; + std::cout << "# Edges : " << mesh_.n_edges() << std::endl; + std::cout << "# Faces : " << mesh_.n_faces() << std::endl; + std::cout << "binary input : " << opt_.check(opt_.Binary) << std::endl; + std::cout << "swapped input : " << opt_.check(opt_.Swap) << std::endl; + std::cout << "vertex normal : " + << opt_.check(opt_.VertexNormal) << std::endl; + std::cout << "vertex texcoord: " + << opt_.check(opt_.VertexTexCoord) << std::endl; + std::cout << "vertex color : " + << opt_.check(opt_.VertexColor) << std::endl; + this->QGLViewerWidget::keyPressEvent( _event ); + break; + + case Key_T: + switch( tex_mode_ ) + { + case GL_MODULATE: TEXMODE(GL_DECAL); break; + case GL_DECAL: TEXMODE(GL_BLEND); break; + case GL_BLEND: TEXMODE(GL_REPLACE); break; + case GL_REPLACE: TEXMODE(GL_MODULATE); break; + } + updateGL(); + break; + + default: + this->QGLViewerWidget::keyPressEvent( _event ); + } +} + +#undef TEXMODE + +//============================================================================= diff --git a/Apps/Deprecated/Streaming/Client/MeshViewerWidgetT.hh b/Apps/Deprecated/Streaming/Client/MeshViewerWidgetT.hh new file mode 100644 index 00000000..5172d84d --- /dev/null +++ b/Apps/Deprecated/Streaming/Client/MeshViewerWidgetT.hh @@ -0,0 +1,163 @@ +//============================================================================= +// +// 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: 1800 $ +// $Date: 2008-05-19 11:51:23 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +#ifndef OPENMESHAPPS_MESHVIEWERWIDGETT_HH +#define OPENMESHAPPS_MESHVIEWERWIDGETT_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include +#include +#include +#include + + +//== FORWARDS ================================================================= + +class QImage; + + +//== CLASS DEFINITION ========================================================= + + +template +class MeshViewerWidgetT : public QGLViewerWidget +{ +public: + typedef M Mesh; + typedef OpenMesh::StripifierT MyStripifier; + + + /// default constructor + MeshViewerWidgetT(QWidget* _parent=0, const char* _name=0) + : QGLViewerWidget(_parent, _name), + f_strips_(false), + tex_id_(0), + tex_mode_(GL_MODULATE), + strips_(mesh_) + { + add_draw_mode("Points"); + add_draw_mode("Hidden-Line"); +#if defined(OM_USE_OSG) && OM_USE_OSG + add_draw_mode("OpenSG Indices"); +#endif + } + + void enable_strips() { + f_strips_ = true; + add_draw_mode("Strips'n VertexArrays"); + add_draw_mode("Show Strips"); + } + void disable_strips() { f_strips_ = false; } + + /// destructor + ~MeshViewerWidgetT() {} + + /// open mesh + virtual bool open_mesh(const char* _filename, OpenMesh::IO::Options _opt); + + /// load texture + virtual bool open_texture( const char *_filename ); + bool set_texture( QImage& _texsrc ); + + + Mesh& mesh() { return mesh_; } + const Mesh& mesh() const { return mesh_; } + + +protected: + + /// inherited drawing method + virtual void draw_scene(const std::string& _draw_mode); + +protected: + + /// draw the mesh + virtual void draw_openmesh(const std::string& _drawmode); + + void glVertex( const typename Mesh::VertexHandle vh ) + { glVertex3fv( &mesh_.point( vh )[0] ); } + + void glNormal( const typename Mesh::VertexHandle vh ) + { glNormal3fv( &mesh_.normal( vh )[0] ); } + + void glTexCoord( const typename Mesh::VertexHandle vh ) + { glTexCoord2fv( &mesh_.texcoord(vh)[0] ); } + + void glColor( const typename Mesh::VertexHandle vh ) + { glColor3ubv( &mesh_.color(vh)[0] ); } + + void glColor( const typename Mesh::FaceHandle fh ) + { glColor3ubv( &mesh_.color(fh)[0] ); } + + + +protected: // Strip support + + void compute_strips(void) + { + if (f_strips_) + { + strips_.clear(); + strips_.stripify(); + } + } + +protected: // inherited + + virtual void keyPressEvent( QKeyEvent* _event); + +protected: + + bool f_strips_; // enable/disable strip usage + GLuint tex_id_; + GLint tex_mode_; + OpenMesh::IO::Options opt_; // mesh file contained texcoords? + + Mesh mesh_; + MyStripifier strips_; +}; + + +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESHAPPS_MESHVIEWERWIDGET_CC) +# define OPENMESH_MESHVIEWERWIDGET_TEMPLATES +# include "MeshViewerWidgetT.cc" +#endif +//============================================================================= +#endif // OPENMESHAPPS_MESHVIEWERWIDGETT_HH defined +//============================================================================= + diff --git a/Apps/Deprecated/Streaming/Client/MyMesh.hh b/Apps/Deprecated/Streaming/Client/MyMesh.hh new file mode 100644 index 00000000..b6dfdb2e --- /dev/null +++ b/Apps/Deprecated/Streaming/Client/MyMesh.hh @@ -0,0 +1,23 @@ +#ifndef OPENMESH_APPS_VDPMSTREAMING_CLIENT_MYMESH_HH +#define OPENMESH_APPS_VDPMSTREAMING_CLIENT_MYMESH_HH + +#include +#include +#include +#include + + +using OpenMesh::VDPM::MeshTraits; + + +//== CLASS DEFINITION ========================================================= + + +typedef OpenMesh::TriMesh_ArrayKernelT MyMesh; + +static QMutex mutex_; + + +//== CLASS DEFINITION ========================================================= + +#endif //OPENMESH_APPS_VDPMSTREAMING_CLIENT_MYMESH_HH defined diff --git a/Apps/Deprecated/Streaming/Client/QGLViewerWidget.cc b/Apps/Deprecated/Streaming/Client/QGLViewerWidget.cc new file mode 100644 index 00000000..c77f9a21 --- /dev/null +++ b/Apps/Deprecated/Streaming/Client/QGLViewerWidget.cc @@ -0,0 +1,621 @@ +//============================================================================= +// +// 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: 1800 $ +// $Date: 2008-05-19 11:51:23 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#ifdef _MSC_VER +# pragma warning(disable: 4267 4311 4305) +#endif + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#if !defined(M_PI) +# define M_PI 3.1415926535897931 +#endif + +using namespace OpenMesh; + + +//== IMPLEMENTATION ========================================================== + + +QGLViewerWidget::QGLViewerWidget( QWidget* _parent, const char* _name ) + : QGLWidget( _parent, _name ) +{ + // qt stuff + setBackgroundMode( NoBackground ); + setFocusPolicy(QWidget::StrongFocus); + setAcceptDrops( true ); + setCursor(pointingHandCursor); + + + // popup menu + popup_menu_ = new QPopupMenu(this, "Draw Mode Menu"); + popup_menu_->setCheckable(true); + connect( popup_menu_, SIGNAL(activated(int)), + this, SLOT(slotPopupMenu(int))); + + + // init draw modes + n_draw_modes_ = 0; + add_draw_mode("Wireframe"); + add_draw_mode("Solid Flat"); + add_draw_mode("Solid Smooth"); + + // for example + add_draw_mode("Colored"); + + slotPopupMenu(2); +} + + +//---------------------------------------------------------------------------- + + +QGLViewerWidget::~QGLViewerWidget() +{ +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::initializeGL() +{ + // OpenGL state + glClearColor(1.0, 1.0, 1.0, 0.0); + glDisable( GL_DITHER ); + glEnable( GL_DEPTH_TEST ); + glEnable( GL_CULL_FACE ); + + + // material + GLfloat mat_a[] = {0.7, 0.6, 0.5, 1.0}; + GLfloat mat_d[] = {0.8, 0.7, 0.6, 1.0}; + GLfloat mat_s[] = {1.0, 1.0, 1.0, 1.0}; + GLfloat shine[] = {120.0}; + +// GLfloat mat_a[] = {0.2, 0.2, 0.2, 1.0}; +// GLfloat mat_d[] = {0.4, 0.4, 0.4, 1.0}; +// GLfloat mat_s[] = {0.8, 0.8, 0.8, 1.0}; +// GLfloat shine[] = {128.0}; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_a); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_d); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_s); + glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shine); + + + // lighting + glLoadIdentity(); + + GLfloat pos1[] = { 0.1, 0.1, -0.02, 0.0}; + GLfloat pos2[] = {-0.1, 0.1, -0.02, 0.0}; + GLfloat pos3[] = { 0.0, 0.0, 0.1, 0.0}; + GLfloat col1[] = {.05, .05, .4, 1.0}; + GLfloat col2[] = {.4, .05, .05, 1.0}; + GLfloat col3[] = {1.0, 1.0, 1.0, 1.0}; + + glEnable(GL_LIGHT0); + glLightfv(GL_LIGHT0,GL_POSITION, pos1); + glLightfv(GL_LIGHT0,GL_DIFFUSE, col1); + glLightfv(GL_LIGHT0,GL_SPECULAR, col1); + + glEnable(GL_LIGHT1); + glLightfv(GL_LIGHT1,GL_POSITION, pos2); + glLightfv(GL_LIGHT1,GL_DIFFUSE, col2); + glLightfv(GL_LIGHT1,GL_SPECULAR, col2); + + glEnable(GL_LIGHT2); + glLightfv(GL_LIGHT2,GL_POSITION, pos3); + glLightfv(GL_LIGHT2,GL_DIFFUSE, col3); + glLightfv(GL_LIGHT2,GL_SPECULAR, col3); + + + // Fog + GLfloat fogColor[4] = { 0.4, 0.4, 0.5, 1.0 }; + glFogi(GL_FOG_MODE, GL_LINEAR); + glFogfv(GL_FOG_COLOR, fogColor); + glFogf(GL_FOG_DENSITY, 0.35); + glHint(GL_FOG_HINT, GL_DONT_CARE); + glFogf(GL_FOG_START, 5.0f); + glFogf(GL_FOG_END, 25.0f); + + // scene pos and size + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix_); + set_scene_pos(Vec3f(0.0, 0.0, 0.0), 1.0); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::resizeGL( int _w, int _h ) +{ + update_projection_matrix(); + glViewport(0, 0, _w, _h); + updateGL(); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::paintGL() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glMatrixMode( GL_PROJECTION ); + glLoadMatrixd( projection_matrix_ ); + glMatrixMode( GL_MODELVIEW ); + glLoadMatrixd( modelview_matrix_ ); + + if (draw_mode_) + { + assert(draw_mode_ <= n_draw_modes_); + draw_scene(draw_mode_names_[draw_mode_-1]); + } +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::draw_scene(const std::string& _draw_mode) +{ + if (_draw_mode == "Wireframe") + { + glDisable(GL_LIGHTING); + glutWireTeapot(0.5); + } + + else if (_draw_mode == "Solid Flat") + { + glEnable(GL_LIGHTING); + glShadeModel(GL_FLAT); + glutSolidTeapot(0.5); + } + + else if (_draw_mode == "Solid Smooth") + { + glEnable(GL_LIGHTING); + glShadeModel(GL_SMOOTH); + glutSolidTeapot(0.5); + } + +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::mousePressEvent( QMouseEvent* _event ) +{ + // popup menu + if (_event->button() == RightButton) + { + popup_menu_->exec(QCursor::pos()); + } + + else + { + last_point_ok_ = map_to_sphere( last_point_2D_=_event->pos(), + last_point_3D_ ); + } +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::mouseMoveEvent( QMouseEvent* _event ) +{ + QPoint newPoint2D = _event->pos(); + + if ( (newPoint2D.x()<0) || (newPoint2D.x()>width()) || + (newPoint2D.y()<0) || (newPoint2D.y()>height()) ) return; + + + // Left button: rotate around center_ + // Middle button: translate object + // Left & middle button: zoom in/out + + + float value_y; + Vec3f newPoint3D; + bool newPoint_hitSphere = map_to_sphere( newPoint2D, newPoint3D ); + + float dx = newPoint2D.x() - last_point_2D_.x(); + float dy = newPoint2D.y() - last_point_2D_.y(); + + float w = width(); + float h = height(); + + + + // enable GL context + makeCurrent(); + + + // move in z direction + if ( (_event->state() & LeftButton) && (_event->state() & MidButton)) + { + value_y = radius_ * dy * 3.0 / h; + translate(Vec3f(0.0, 0.0, value_y)); + } + + + // move in x,y direction + else if (_event->state() & MidButton) + { + float z = - (modelview_matrix_[ 2]*center_[0] + + modelview_matrix_[ 6]*center_[1] + + modelview_matrix_[10]*center_[2] + + modelview_matrix_[14]) / + (modelview_matrix_[ 3]*center_[0] + + modelview_matrix_[ 7]*center_[1] + + modelview_matrix_[11]*center_[2] + + modelview_matrix_[15]); + + float aspect = w / h; + float near_plane = 0.01 * radius_; + float top = tan(fovy()/2.0f*M_PI/180.0f) * near_plane; + float right = aspect*top; + + translate(Vec3f( 2.0*dx/w*right/near_plane*z, + -2.0*dy/h*top/near_plane*z, + 0.0f)); + } + + + + // rotate + else if (_event->state() & LeftButton) + { + if (last_point_ok_) + { + if (newPoint_hitSphere = map_to_sphere(newPoint2D, newPoint3D)) + { + Vec3f axis = last_point_3D_ % newPoint3D; + float cos_angle = (last_point_3D_ | newPoint3D); + if ( fabs(cos_angle) < 1.0 ) + { + float angle = 2.0 * acos( cos_angle ) * 180.0 / M_PI; + rotate( axis, angle ); + } + } + } + } + + + // remember this point + last_point_2D_ = newPoint2D; + last_point_3D_ = newPoint3D; + last_point_ok_ = newPoint_hitSphere; + + // trigger redraw + updateGL(); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::mouseReleaseEvent( QMouseEvent* /* _event */ ) +{ + last_point_ok_ = false; +} + + +//----------------------------------------------------------------------------- + + +void QGLViewerWidget::wheelEvent(QWheelEvent* _event) +{ + // Use the mouse wheel to zoom in/out + + float d = -(float)_event->delta() / 120.0 * 0.2 * radius_; + translate(Vec3f(0.0, 0.0, d)); + updateGL(); + _event->accept(); +} + + +//---------------------------------------------------------------------------- + + +void QGLViewerWidget::keyPressEvent( QKeyEvent* _event) +{ + switch( _event->key() ) + { + case Key_C: + if ( glIsEnabled( GL_CULL_FACE ) ) + { + glDisable( GL_CULL_FACE ); + std::cout << "Back face culling: disabled\n"; + } + else + { + glEnable( GL_CULL_FACE ); + std::cout << "Back face culling: enabled\n"; + } + updateGL(); + break; + + case Key_I: + std::cout << "Radius: " << radius_ << std::endl; + std::cout << "Center: " << center_ << std::endl; + break; + + case Key_Space: + case Key_M: + { + double fps = performance(); + std::cout << "fps: " +#if defined(OM_CC_GCC) && (OM_CC_VERSION < 30000) + << std::setiosflags (std::ios::fixed) +#else + << std::setiosflags (std::ios_base::fixed) +#endif + << fps << std::endl; + } + break; + + case Key_Q: + case Key_Escape: + qApp->quit(); + } + _event->ignore(); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::translate( const Vec3f& _trans ) +{ + // Translate the object by _trans + // Update modelview_matrix_ + makeCurrent(); + glLoadIdentity(); + glTranslated( _trans[0], _trans[1], _trans[2] ); + glMultMatrixd( modelview_matrix_ ); + glGetDoublev( GL_MODELVIEW_MATRIX, modelview_matrix_); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::rotate( const Vec3f& _axis, float _angle ) +{ + // Rotate around center center_, axis _axis, by angle _angle + // Update modelview_matrix_ + + Vec3f t( modelview_matrix_[0]*center_[0] + + modelview_matrix_[4]*center_[1] + + modelview_matrix_[8]*center_[2] + + modelview_matrix_[12], + modelview_matrix_[1]*center_[0] + + modelview_matrix_[5]*center_[1] + + modelview_matrix_[9]*center_[2] + + modelview_matrix_[13], + modelview_matrix_[2]*center_[0] + + modelview_matrix_[6]*center_[1] + + modelview_matrix_[10]*center_[2] + + modelview_matrix_[14] ); + + makeCurrent(); + glLoadIdentity(); + glTranslatef(t[0], t[1], t[2]); + glRotated( _angle, _axis[0], _axis[1], _axis[2]); + glTranslatef(-t[0], -t[1], -t[2]); + glMultMatrixd(modelview_matrix_); + glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix_); +} + + +//---------------------------------------------------------------------------- + + +bool +QGLViewerWidget::map_to_sphere( const QPoint& _v2D, Vec3f& _v3D ) +{ + if ( (_v2D.x() >= 0) && (_v2D.x() <= width()) && + (_v2D.y() >= 0) && (_v2D.y() <= height()) ) + { + double x = (double)(_v2D.x() - 0.5*width()) / (double)width(); + double y = (double)(0.5*height() - _v2D.y()) / (double)height(); + double sinx = sin(M_PI * x * 0.5); + double siny = sin(M_PI * y * 0.5); + double sinx2siny2 = sinx * sinx + siny * siny; + + _v3D[0] = sinx; + _v3D[1] = siny; + _v3D[2] = sinx2siny2 < 1.0 ? sqrt(1.0 - sinx2siny2) : 0.0; + + return true; + } + else return false; +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::update_projection_matrix() +{ + makeCurrent(); + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective(45.0, (GLfloat) width() / (GLfloat) height(), + 0.01*radius_, 100.0*radius_); + glGetDoublev( GL_PROJECTION_MATRIX, projection_matrix_); + glMatrixMode( GL_MODELVIEW ); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::view_all() +{ + translate( Vec3f( -(modelview_matrix_[0]*center_[0] + + modelview_matrix_[4]*center_[1] + + modelview_matrix_[8]*center_[2] + + modelview_matrix_[12]), + -(modelview_matrix_[1]*center_[0] + + modelview_matrix_[5]*center_[1] + + modelview_matrix_[9]*center_[2] + + modelview_matrix_[13]), + -(modelview_matrix_[2]*center_[0] + + modelview_matrix_[6]*center_[1] + + modelview_matrix_[10]*center_[2] + + modelview_matrix_[14] + + 3.0*radius_) ) ); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::set_scene_pos( const Vec3f& _cog, float _radius ) +{ + center_ = _cog; + radius_ = _radius; + glFogf( GL_FOG_START, _radius ); + glFogf( GL_FOG_END, 4.0*_radius ); + + update_projection_matrix(); + view_all(); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::add_draw_mode(const std::string& _s) +{ + ++n_draw_modes_; + + // insert in popup menu + popup_menu_->insertItem(_s.c_str(), n_draw_modes_); + + // store draw mode + draw_mode_names_.push_back(_s); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::slotPopupMenu(int _id) +{ + // un-check all entries + for (size_t i=1; i <= n_draw_modes_; ++i) + popup_menu_->setItemChecked(i, false); + + // save draw mode + draw_mode_ = _id; + + // check selected draw mode + popup_menu_->setItemChecked(_id, true); +} + + +//---------------------------------------------------------------------------- + + +double +QGLViewerWidget::performance() +{ + setCursor( waitCursor ); + + double fps(0.0); + + makeCurrent(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + OpenMesh::Utils::Timer timer; + + unsigned int frames = 60; + const float angle = 360.0/(float)frames; + unsigned int i; + Vec3f axis; + + glFinish(); + timer.start(); + + for (i=0, axis=Vec3f(1,0,0); i +#include +#include +#include + + +//== FORWARD DECLARATIONS ===================================================== + + +class QPopupMenu; + + +//== CLASS DEFINITION ========================================================= + + +class QGLViewerWidget : public QGLWidget +{ + + Q_OBJECT + +public: + + // Default constructor. + QGLViewerWidget( QWidget* _parent=0, const char* _name=0 ); + + // Destructor. + virtual ~QGLViewerWidget(); + + /* Sets the center and size of the whole scene. + The _center is used as fixpoint for rotations and for adjusting + the camera/viewer (see view_all()). */ + void set_scene_pos( const OpenMesh::Vec3f& _center, float _radius ); + + /* view the whole scene: the eye point is moved far enough from the + center so that the whole scene is visible. */ + void view_all(); + + /// add draw mode to popup menu + void add_draw_mode(const std::string& _s); + + float radius() const { return radius_; } + const OpenMesh::Vec3f& center() const { return center_; } + + const GLdouble* modelview_matrix() const { return modelview_matrix_; } + const GLdouble* projection_matrix() const { return projection_matrix_; } + void set_modelview_matrix(const GLdouble _modelview_matrix[16]) + { memcpy(modelview_matrix_, _modelview_matrix, 16*sizeof(GLdouble)); } + void set_projection_matrix(const GLdouble _projection_matrix[16]) + { memcpy(projection_matrix_, _projection_matrix, 16*sizeof(GLdouble)); } + + float fovy() const { return 45.0f; } + +protected: + + // draw the scene: will be called by the painGL() method. + virtual void draw_scene(const std::string& _draw_mode); + + double performance(void); + +private slots: + + // popup menu clicked + void slotPopupMenu(int _id); + +private: // inherited + + // initialize OpenGL states (triggered by Qt) + void initializeGL(); + + // draw the scene (triggered by Qt) + void paintGL(); + + // handle resize events (triggered by Qt) + void resizeGL( int w, int h ); + +protected: + + // Qt mouse events + virtual void mousePressEvent( QMouseEvent* ); + virtual void mouseReleaseEvent( QMouseEvent* ); + virtual void mouseMoveEvent( QMouseEvent* ); + virtual void wheelEvent( QWheelEvent* ); + virtual void keyPressEvent( QKeyEvent* ); + +private: + + // updates projection matrix + void update_projection_matrix(); + +protected: + // translate the scene and update modelview matrix + void translate(const OpenMesh::Vec3f& _trans); + + // rotate the scene (around its center) and update modelview matrix + void rotate(const OpenMesh::Vec3f& _axis, float _angle); + + OpenMesh::Vec3f center_; + float radius_; + + GLdouble projection_matrix_[16], + modelview_matrix_[16]; + + + // popup menu for draw mode selection + QPopupMenu* popup_menu_; + unsigned int draw_mode_; + unsigned int n_draw_modes_; + std::vector draw_mode_names_; + + + + // virtual trackball: map 2D screen point to unit sphere + bool map_to_sphere(const QPoint& _point, OpenMesh::Vec3f& _result); + + QPoint last_point_2D_; + OpenMesh::Vec3f last_point_3D_; + bool last_point_ok_; + +}; + + +//============================================================================= +#endif // OPENMESHAPPS_QGLVIEWERWIDGET_HH +//============================================================================= + diff --git a/Apps/Deprecated/Streaming/Client/VDPMClientViewerWidget.cc b/Apps/Deprecated/Streaming/Client/VDPMClientViewerWidget.cc new file mode 100644 index 00000000..4ef38de1 --- /dev/null +++ b/Apps/Deprecated/Streaming/Client/VDPMClientViewerWidget.cc @@ -0,0 +1,1340 @@ + +//== INCLUDES ================================================================= + +#ifdef _MSC_VER +# pragma warning(disable: 4267 4311) +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include + +// #include "ImageData.h" + + +using OpenMesh::VDPM::debug_print; +using OpenMesh::VDPM::set_debug_print; + +using OpenMesh::VDPM::VHierarchyNode; +using OpenMesh::VDPM::VHierarchyNodeHandle; +using OpenMesh::VDPM::VHierarchyNodeHandleContainer; + + + +#ifdef EXAMPLE_CREATION + +static OpenMesh::Vec3uc myYellow = OpenMesh::Vec3uc(255, 255, 0); +static OpenMesh::Vec3uc myBlue = OpenMesh::Vec3uc(0, 0, 255); +std::map g_index2numdesc_map; + +void VDPMClientViewerWidget::increase_max_descendents(const VHierarchyNodeIndex &_node_index) +{ + g_index2numdesc_map[_node_index] = 2 + g_index2numdesc_map[_node_index]; + + unsigned char tree_id_bits = vhierarchy_.tree_id_bits(); + VHierarchyNodeIndex parent_index + = VHierarchyNodeIndex(_node_index.tree_id(tree_id_bits), _node_index.node_id(tree_id_bits) / 2, tree_id_bits); + + if (parent_index.is_valid(tree_id_bits) == true) + increase_max_descendents(parent_index); +} + +void VDPMClientViewerWidget::increase_cur_descendents(VHierarchyNodeHandle _node_handle) +{ + unsigned int cur_desc = vhierarchy_.node(_node_handle).cur_descendents(); + + vhierarchy_.node(_node_handle).set_cur_descendents(2 + cur_desc); + + VHierarchyNodeHandle parent_handle = vhierarchy_.parent_handle(_node_handle); + if (parent_handle.is_valid()) + increase_cur_descendents(parent_handle); +} + +void VDPMClientViewerWidget::__add_children(const VHierarchyNodeIndex &_node_index, bool update_current) +{ + if (update_current == true) + { + increase_cur_descendents(vhierarchy_.node_handle(_node_index)); + } + else + { + unsigned char tree_id_bits = vhierarchy_.tree_id_bits(); + + VHierarchyNodeIndex lchild_index + = VHierarchyNodeIndex(_node_index.tree_id(tree_id_bits), 2*_node_index.node_id(tree_id_bits), tree_id_bits); + VHierarchyNodeIndex rchild_index + = VHierarchyNodeIndex(_node_index.tree_id(tree_id_bits), 1+2*_node_index.node_id(tree_id_bits), tree_id_bits); + + g_index2numdesc_map[lchild_index] = 1; + g_index2numdesc_map[rchild_index] = 1; + + increase_max_descendents(_node_index); + } +} + +void VDPMClientViewerWidget::mesh_coloring() +{ + MyMesh::VertexIter vIt(mesh_.vertices_begin()), + vEnd(mesh_.vertices_end()); + + VHierarchyNodeHandle node_handle; + float ratio; + unsigned char r, g, b; + + for (; vIt!=vEnd; ++vIt) + { + node_handle = mesh_.data(vIt.handle()).vhierarchy_node_handle(); + ratio = vhierarchy_.node(node_handle).ratio(); + + r = (unsigned char) ((1.0f - ratio) * myYellow[0] + ratio * myBlue[0]); + g = (unsigned char) ((1.0f - ratio) * myYellow[1] + ratio * myBlue[1]); + b = (unsigned char) ((1.0f - ratio) * myYellow[2] + ratio * myBlue[2]); + + mesh_.set_color(vIt.handle(), OpenMesh::Vec3uc(r,g,b)); + } +} + +#endif + + + +void +VDPMClientViewerWidget:: +draw_scene(const std::string &_draw_mode) +{ + //std::cout << frame_ << "-th frame statistics" << std::endl; + + if (adaptive_mode_ == true) + { + + refinement_timer_.start(); + adaptive_refinement(); + refinement_timer_.stop(); + fprintf(refinement_file, "%d %d\n", frame_, (int) refinement_timer_.mseconds()); + +#ifdef EXAMPLE_CREATION + mesh_coloring(); +#endif + } + + render_timer_.start(); + MeshViewerWidget::draw_scene(_draw_mode); + render_timer_.stop(); + fprintf(render_file, "%d %d %d\n", frame_, (int) render_timer_.mseconds(), mesh_.n_faces()); + + ++frame_; +} + + +void +VDPMClientViewerWidget:: +adaptive_refinement() +{ + update_viewing_parameters(); + + MyMesh::HalfedgeHandle v0v1; + float fovy = viewing_parameters_.fovy(); + float tolerance_square = viewing_parameters_.tolerance_square(); + float tan_value = tanf(fovy / 2.0f); + kappa_square_ = 4.0f * tan_value * tan_value * tolerance_square; + + + for (vfront_.begin(); vfront_.end() != true;) + { + VHierarchyNodeHandle + node_handle = vfront_.node_handle(), + parent_handle = vhierarchy_.parent_handle(node_handle); + + if (qrefine(node_handle) == true) + { + if (vhierarchy_.is_leaf_node(node_handle) != true) + { + force_vsplit(node_handle); + } + else + { + //if (qSocket_->bytesAvailable() == 0) + if (session_running_ != true) + { + session_running_ = true; + send_viewing_information(); + } + vfront_.next(); + } + } + else if (vhierarchy_.is_root_node(node_handle) != true && + ecol_legal(parent_handle, v0v1) == true && + qrefine(parent_handle) != true) + { + ecol(parent_handle, v0v1); + } + else + { + vfront_.next(); + } + } + + // free memories taged as 'deleted' + mesh_.garbage_collection(false, true, true); + mesh_.update_face_normals(); +} + + +void +VDPMClientViewerWidget:: +current_max_resolution() +{ + for (vfront_.begin(); vfront_.end() != true;) + { + VHierarchyNodeHandle + node_handle = vfront_.node_handle(), + parent_handle = vhierarchy_.parent_handle(node_handle); + + if (vhierarchy_.is_leaf_node(node_handle) != true) + force_vsplit(node_handle); + else + vfront_.next(); + } + + // free memories taged as 'deleted' + mesh_.garbage_collection(false, true, true); + mesh_.update_face_normals(); +} + + +bool +VDPMClientViewerWidget:: +qrefine(VHierarchyNodeHandle _node_handle) +{ + VHierarchyNode &node = vhierarchy_.node(_node_handle); + OpenMesh::Vec3f p = mesh_.point(node.vertex_handle()); + OpenMesh::Vec3f eye_dir = p - viewing_parameters_.eye_pos(); + float distance = eye_dir.length(); + float distance2 = distance * distance; + float product_value = dot(eye_dir, node.normal()); + + if (outside_view_frustum(p, node.radius()) == true) + return false; + + if (oriented_away(node.sin_square(), distance2, product_value) == true) + return false; + + if (screen_space_error(node.mue_square(), + node.sigma_square(), distance2, product_value) == true) + return false; + + return true; +} + + +void +VDPMClientViewerWidget:: +force_vsplit(VHierarchyNodeHandle node_handle) +{ + MyMesh::VertexHandle vl, vr; + + get_active_cuts(node_handle, vl, vr); + + while (vl == vr) { + force_vsplit(mesh_.data(vl).vhierarchy_node_handle()); + get_active_cuts(node_handle, vl, vr); + } + + vsplit(node_handle, vl, vr); +} + + + +void +VDPMClientViewerWidget:: +vsplit(VHierarchyNodeHandle _node_handle, MyMesh::VertexHandle vl, MyMesh::VertexHandle vr) +{ + // refine + VHierarchyNodeHandle lchild_handle = vhierarchy_.lchild_handle(_node_handle); + VHierarchyNodeHandle rchild_handle = vhierarchy_.rchild_handle(_node_handle); + MyMesh::VertexHandle v0 = vhierarchy_.vertex_handle(lchild_handle); + MyMesh::VertexHandle v1 = vhierarchy_.vertex_handle(rchild_handle); + + mesh_.vertex_split(v0, v1, vl, vr); + mesh_.set_normal(v0, vhierarchy_.normal(lchild_handle)); + mesh_.set_normal(v1, vhierarchy_.normal(rchild_handle)); + mesh_.data(v0).set_vhierarchy_node_handle(lchild_handle); + mesh_.data(v1).set_vhierarchy_node_handle(rchild_handle); + mesh_.status(v0).set_deleted(false); + mesh_.status(v1).set_deleted(false); + + vfront_.remove(_node_handle); + vfront_.add(lchild_handle); + vfront_.add(rchild_handle); +} + + +void +VDPMClientViewerWidget:: +ecol(VHierarchyNodeHandle _node_handle, const MyMesh::HalfedgeHandle& v0v1) +{ + VHierarchyNodeHandle lchild_handle = vhierarchy_.lchild_handle(_node_handle); + VHierarchyNodeHandle rchild_handle = vhierarchy_.rchild_handle(_node_handle); + MyMesh::VertexHandle v0 = vhierarchy_.vertex_handle(lchild_handle); + MyMesh::VertexHandle v1 = vhierarchy_.vertex_handle(rchild_handle); + + // coarsen + mesh_.collapse(v0v1); + mesh_.set_normal(v1, vhierarchy_.normal(_node_handle)); + mesh_.data(v0).set_vhierarchy_node_handle(lchild_handle); + mesh_.data(v1).set_vhierarchy_node_handle(_node_handle); + mesh_.status(v0).set_deleted(false); + mesh_.status(v1).set_deleted(false); + + vfront_.add(_node_handle); + vfront_.remove(lchild_handle); + vfront_.remove(rchild_handle); +} + + +bool +VDPMClientViewerWidget:: +ecol_legal(VHierarchyNodeHandle _parent_handle, MyMesh::HalfedgeHandle& v0v1) +{ + VHierarchyNodeHandle lchild_handle = vhierarchy_.lchild_handle(_parent_handle); + VHierarchyNodeHandle rchild_handle = vhierarchy_.rchild_handle(_parent_handle); + + // test whether lchild & rchild present in the current vfront + if (vfront_.is_active(lchild_handle) != true || vfront_.is_active(rchild_handle) != true) + return false; + + MyMesh::VertexHandle v0, v1; + v0 = vhierarchy_.vertex_handle(lchild_handle); + v1 = vhierarchy_.vertex_handle(rchild_handle); + v0v1 = mesh_.find_halfedge(v0, v1); + + return mesh_.is_collapse_ok(v0v1); +} + +void +VDPMClientViewerWidget:: +get_active_cuts(const VHierarchyNodeHandle _node_handle, MyMesh::VertexHandle &vl, MyMesh::VertexHandle &vr) +{ + MyMesh::VertexVertexIter vv_it; + VHierarchyNodeHandle nnode_handle; + VHierarchyNodeIndex nnode_index; + VHierarchyNodeIndex fund_lcut_index = vhierarchy_.fund_lcut_index(_node_handle); + VHierarchyNodeIndex fund_rcut_index = vhierarchy_.fund_rcut_index(_node_handle); + + vl = MyMesh::InvalidVertexHandle; + vr = MyMesh::InvalidVertexHandle; + + for (vv_it=mesh_.vv_iter(vhierarchy_.vertex_handle(_node_handle)); vv_it; ++vv_it) + { + nnode_handle = mesh_.data(vv_it.handle()).vhierarchy_node_handle(); + nnode_index = vhierarchy_.node_index(nnode_handle); + + if (vl == MyMesh::InvalidVertexHandle && vhierarchy_.is_ancestor(nnode_index, fund_lcut_index) == true) + vl = vv_it.handle(); + if (vr == MyMesh::InvalidVertexHandle && vhierarchy_.is_ancestor(nnode_index, fund_rcut_index) == true) + vr = vv_it.handle(); + + /*if (vl == MyMesh::InvalidVertexHandle && nnode_index.is_ancestor_index(fund_lcut_index) == true) + vl = vv_it.handle(); + if (vr == MyMesh::InvalidVertexHandle && nnode_index.is_ancestor_index(fund_rcut_index) == true) + vr = vv_it.handle();*/ + + if (vl != MyMesh::InvalidVertexHandle && vr != MyMesh::InvalidVertexHandle) + break; + } +} + +bool +VDPMClientViewerWidget:: +outside_view_frustum(const OpenMesh::Vec3f &pos, float radius) +{ + Plane3d frustum_plane[4]; + + viewing_parameters_.frustum_planes(frustum_plane); + + for (int i = 0; i < 4; i++) { + if (frustum_plane[i].signed_distance(pos) < -radius) + return true; + } + + return false; +} + +bool +VDPMClientViewerWidget:: +oriented_away(float sin_square, float distance_square, float product_value) +{ + if (product_value > 0 && product_value*product_value > distance_square * sin_square) + return true; + else + return false; +} + +bool +VDPMClientViewerWidget:: +screen_space_error(float mue_square, float sigma_square, float distance_square, float product_value) +{ + if ((mue_square >= kappa_square_ * distance_square) || + (sigma_square * (distance_square - product_value * product_value) >= kappa_square_ * distance_square * distance_square)) + return false; + else + return true; +} + +void +VDPMClientViewerWidget:: +open_vd_prog_mesh(const char* _filename) +{ + unsigned int i; + unsigned int value; + unsigned int fvi[3]; + char fileformat[16]; + OpenMesh::Vec3f p, normal; + float radius, sin_square, mue_square, sigma_square; + VHierarchyNodeHandleContainer roots; + OpenMesh::VertexHandle vertex_handle; + VHierarchyNodeIndex node_index, lchild_node_index, rchild_node_index, fund_lcut_index, fund_rcut_index; + VHierarchyNodeHandle node_handle, lchild_handle, rchild_handle; + std::map index2handle_map; + + std::ifstream ifs(_filename, std::ios::binary); + if (!ifs) + { + std::cerr << "read error\n"; + exit(1); + } + + // + bool swap = OpenMesh::Endian::local() != OpenMesh::Endian::LSB; + + // read header + ifs.read(fileformat, 10); fileformat[10] = '\0'; + if (std::string(fileformat) != std::string("VDProgMesh")) + { + std::cerr << "Wrong file format.\n"; + ifs.close(); + exit(1); + } + OpenMesh::IO::restore(ifs, n_base_vertices_, swap); + OpenMesh::IO::restore(ifs, n_base_faces_, swap); + OpenMesh::IO::restore(ifs, n_details_, swap); + + mesh_.clear(); + vfront_.clear(); + vhierarchy_.clear(); + + vhierarchy_.set_num_roots(n_base_vertices_); + + // load base mesh + for (i=0; i index2handle_map; + + std::ifstream ifs(_filename, std::ios::binary); + if (!ifs) + { + std::cerr << "read error\n"; + exit(1); + } + + // + bool swap = OpenMesh::Endian::local() != OpenMesh::Endian::LSB; + + // read header + ifs.read(fileformat, 10); fileformat[10] = '\0'; + if (std::string(fileformat) != std::string("VDProgMesh")) + { + std::cerr << "Wrong file format.\n"; + ifs.close(); + exit(1); + } + OpenMesh::IO::restore(ifs, n_base_vertices_, swap); + OpenMesh::IO::restore(ifs, n_base_faces_, swap); + OpenMesh::IO::restore(ifs, n_details_, swap); + + mesh_.clear(); + vfront_.clear(); + vhierarchy_.clear(); + + vhierarchy_.set_num_roots(n_base_vertices_); + + // load base mesh + for (i=0; ikey()) + { + case Key_Plus: + viewing_parameters_.increase_tolerance(); + std::cout << "Scree-space error tolerance^2 is increased by " + << viewing_parameters_.tolerance_square() << std::endl; + updateGL(); + break; + + case Key_Minus: + viewing_parameters_.decrease_tolerance(); + std::cout << "Screen-space error tolerance^2 is decreased by " + << viewing_parameters_.tolerance_square() << std::endl; + updateGL(); + break; + + case Key_A: + adaptive_mode_ = !(adaptive_mode_); + std::cout << "Adaptive refinement mode is " + << ((adaptive_mode_ == true) ? "on" : "off") << std::endl; + updateGL(); + break; + + case Key_D: + set_debug_print(!debug_print()); + break; + + case Key_O: + qFilename_ = QFileDialog::getOpenFileName("d:/data/models/spm/", "*.spm"); + open_vd_base_mesh(qFilename_); + break; + + case Key_BracketLeft: + max_transmitted_datasize_ -= 10000; + std::cout << "Max transmitted data: " << max_transmitted_datasize_ << std::endl; + break; + + case Key_BracketRight: + max_transmitted_datasize_ += 10000; + std::cout << "Max transmitted data: " << max_transmitted_datasize_ << std::endl; + break; + + case Key_Space: + memcpy(reserved_modelview_matrix_, modelview_matrix(), 16*sizeof(GLdouble)); + memcpy(reserved_projection_matrix_, projection_matrix(), 16*sizeof(GLdouble)); + std::cout << "Reserving current view-point" << std::endl; + break; + + case Key_R: + request_base_mesh(); + break; + + case Key_S: + save_views(); + std::cout << "Saving view-points" << std::endl; + break; + + case Key_F: + frame_ = 0; + std::cout << "Frame is set to 0" << std::endl; + break; + + case Key_M: + adaptive_mode_ = false; + current_max_resolution(); + updateGL(); + std::cout << "Current max resolution mesh" << std::endl; + break; + + case Key_V: + vd_streaming_ = !(vd_streaming_); + if (vd_streaming_) + std::cout << "View-dependent streaing mode" << std::endl; + else + std::cout << "Sequential streaming mode" << std::endl; + break; + + case Key_C: + adaptive_mode_ = false; + qCameraFileName_ = QFileDialog::getOpenFileName("./", "*.cmr"); + load_views(qCameraFileName_); + std::cout << "Loading view-points" << std::endl; + updateGL(); + break; + + case Key_9: + save_screen(true); + break; + + case Key_0: + std::cout << "#faces: " << mesh_.n_faces() << std::endl; + break; + + case Key_P: + if (qAnimationTimer_->isActive()) + { + qAnimationTimer_->stop(); + std::cout << "print_statistics mode is stopped!" << std::endl; + } + else + { + qAnimationTimer_->start(0, true); + std::cout << "print_statistics mode is started!" << std::endl; + + adaptive_mode_ = true; + + set_scene_pos( + Vec3f(0.5f*(bbMin_[0] + bbMax_[0]), 0.9f*bbMax_[1], 0.5f*(bbMin_[2] + bbMax_[2])), + 0.15f*(bbMin_ - bbMax_).norm()); + nth_viewpoint_ = 0; + print_statistics(); + } + std::cout << "Frame: " << frame_ << std::endl; + break; + + + case Key_L: + if (qAnimationTimer_->isActive()) + { + qAnimationTimer_->stop(); + std::cout << "look_around mode is stopped!" << std::endl; + } + else + { + qAnimationTimer_->start(0, true); + std::cout << "look_around mode is started!" << std::endl; + + adaptive_mode_ = true; + + set_scene_pos( + Vec3f(0.5f*(bbMin_[0] + bbMax_[0]), 0.9f*bbMax_[1], 0.5f*(bbMin_[2] + bbMax_[2])), + 0.15f*(bbMin_ - bbMax_).norm()); + frame_ = 0; + nth_viewpoint_ = 0; + look_around(); + } + + break; + + case Key_Q: + case Key_Escape: + qApp->quit(); + + default: + this->MeshViewerWidget::keyPressEvent( _event ); + } + + if (!handled) + _event->ignore(); +} + + + + + +void +VDPMClientViewerWidget:: +update_viewing_parameters() +{ + viewing_parameters_.set_fovy(fovy()); + viewing_parameters_.set_aspect((float) width() / (float) height()); + viewing_parameters_.set_modelview_matrix(modelview_matrix()); + + viewing_parameters_.update_viewing_configurations(); +} + + +///////////////////////////////////////////////// +// streaming related functions +///////////////////////////////////////////////// + + + +bool +VDPMClientViewerWidget:: +request_base_mesh() +{ + if (streaming_phase_ != kBaseMesh) + return false; + + if (qFilename_.isEmpty() == true) + { + std::cout << "Please, specify the base mesh filename." << std::endl; + return false; + } + + QDataStream qTcp(qSocket_); + + qTcp << qFilename_.length(); + qTcp << qFilename_; + qSocket_->flush(); + + return true; +} + +bool +VDPMClientViewerWidget:: +receive_base_mesh() +{ + int status; + QDataStream qTcp(qSocket_); + + while (qSocket_->waitForMore(10) < sizeof(int)); + qTcp >> status; + if (status == 0) + { + std::cout << "There is no such a VDPM files in the server side." << std::endl; + return false; + } + + streaming_phase_ = kVSplitHeader; + + std::cout << "A view-dependent streaming is ready." << std::endl; + return true; +} + + +void +VDPMClientViewerWidget:: +send_viewing_information() +{ + session_timer_.start(); + QDataStream qTCP(qSocket_); + qTCP << modelview_matrix()[0] << modelview_matrix()[1] + << modelview_matrix()[2] << modelview_matrix()[3] + << modelview_matrix()[4] << modelview_matrix()[5] + << modelview_matrix()[6] << modelview_matrix()[7] + << modelview_matrix()[8] << modelview_matrix()[9] + << modelview_matrix()[10] << modelview_matrix()[11] + << modelview_matrix()[12] << modelview_matrix()[13] + << modelview_matrix()[14] << modelview_matrix()[15] + << viewing_parameters_.fovy() + << viewing_parameters_.aspect() + << viewing_parameters_.tolerance_square(); + + qSocket_->flush(); + session_timer_.stop(); + fprintf(session_file, "%d %d\n", frame_, (int) session_timer_.mseconds()); + + + global_timer_.stop(); + fprintf(uplink_file, "%d %ld\n", (int) global_timer_.mseconds(), 16*sizeof(double) + 3*sizeof(float)); + global_timer_.cont(); +} + +void +VDPMClientViewerWidget:: +receive_vsplit_header() +{ + if (qSocket_->bytesAvailable() < sizeof(unsigned int)) + return; + + QDataStream qTcp(qSocket_); + + // while (qSocket_->waitForMore(10) < sizeof(unsigned int)); + + qTcp >> n_vsplit_packets_; + + if (n_vsplit_packets_ > 0) + { + streaming_phase_ = kVSplits; + + if (debug_print() == true) + { + std::cout << "Server will transmit " << n_vsplit_packets_ + << " of vsplit packets to me" << std::endl; + } + + receive_vsplit_packets(); + } + else + { + session_running_ = false; + } +} + +void +VDPMClientViewerWidget:: +receive_vsplit_packets() +{ + static unsigned int n_vsplits = 0; + static unsigned int len = (int) (17 * sizeof(float) + 3 * sizeof(int)); + + if (qSocket_->bytesAvailable() < len) + return; + + QString str; + OpenMesh::Vec3f pos; + VHierarchyNodeIndex node_index, fund_lcut_index, fund_rcut_index; + float radius[2]; + OpenMesh::Vec3f normal[2]; + float sin_square[2]; + float mue_square[2]; + float sigma_square[2]; + unsigned int value[3]; + + global_timer_.stop(); + fprintf(downlink_file, "%d %ld\n", (int) global_timer_.mseconds(), qSocket_->bytesAvailable()); + global_timer_.cont(); + + session_timer_.start(); + + while ( qSocket_->bytesAvailable() >= len ) + { + if (vd_streaming_) transmitted_datasize_ += (int) len; + //if (vd_streaming_) transmitted_datasize_ += (int) 3*sizeof(int) + 3*sizeof(float); // only for non-refinement cliet + else transmitted_datasize_ += (int) 3*sizeof(int) + 3*sizeof(float); + + if (max_transmitted_datasize_ > 0) + { + if (transmitted_datasize_ > max_transmitted_datasize_) + { + if (vd_streaming_) transmitted_datasize_ -= (int) len; + //if (vd_streaming_) transmitted_datasize_ -= (int) 3*sizeof(int) + 3*sizeof(float); // only for non-refinement cliet + else transmitted_datasize_ -= (int) 3*sizeof(int) + 3*sizeof(float); + + return; + } + } + + QDataStream qTcp(qSocket_); + qTcp >> pos[0] >> pos[1] >> pos[2] + >> value[0] + >> value[1] + >> value[2] + >> radius[0] + >> (normal[0])[0] >> (normal[0])[1] >> (normal[0])[2] + >> sin_square[0] + >> mue_square[0] >> sigma_square[0] + >> radius[1] + >> (normal[1])[0] >> (normal[1])[1] >> (normal[1])[2] + >> sin_square[1] + >> mue_square[1] >> sigma_square[1]; + + node_index = VHierarchyNodeIndex(value[0]); + fund_lcut_index = VHierarchyNodeIndex(value[1]); + fund_rcut_index = VHierarchyNodeIndex(value[2]); + + update_vhierarchy(pos, + node_index, fund_lcut_index, fund_rcut_index, + radius, normal, sin_square, mue_square, sigma_square); + + + std::cout << "transmitted datasize: " << transmitted_datasize_ << std::endl; + + if (debug_print() == true) + { + std::cout << "Pkg #" << n_vsplits << std::endl; + } + + ++n_vsplits; + + if (n_vsplits >= n_vsplit_packets_) + { + n_vsplits = 0; + streaming_phase_ = kVSplitHeader; + session_running_ = false; + + if (debug_print() == true) + { + std::cout << "transmission of vsplit packets is complete" << std::endl; + } + break; + } + } + + session_timer_.stop(); + fprintf(session_file, "%d %d\n", frame_, (int) session_timer_.mseconds()); + + updateGL(); + + if (n_vsplits != n_vsplit_packets_) + qSessionTimer_->start(300, true); +} + + +void +VDPMClientViewerWidget:: +update_vhierarchy( + const OpenMesh::Vec3f &_pos, // 3D position of v0 + const VHierarchyNodeIndex &_node_index, // vhierarchy index of v1 + const VHierarchyNodeIndex &_fund_lcut_index, // vhierarchy index of fundamental lcut + const VHierarchyNodeIndex &_fund_rcut_index, // vhierarchy index of fundamental rcut + const float _radius[2], // radius of lchild & rchild + const OpenMesh::Vec3f _normal[2], // normal of lchild & rchild + const float _sin_square[2], // sin_square of lchild & rchild + const float _mue_square[2], // mue_square of lchild & rchild + const float _sigma_square[2] // sigma_square of lchild & rchild + ) +{ + OpenMesh::VertexHandle vertex_handle; + VHierarchyNodeHandle node_handle, lchild_handle, rchild_handle; + + node_handle = vhierarchy_.node_handle(_node_index); + vhierarchy_.make_children(node_handle); + + + lchild_handle = vhierarchy_.lchild_handle(node_handle); + rchild_handle = vhierarchy_.rchild_handle(node_handle); + + vhierarchy_.node(node_handle).set_fund_lcut(_fund_lcut_index); + vhierarchy_.node(node_handle).set_fund_rcut(_fund_rcut_index); + + vertex_handle = mesh_.add_vertex(_pos); + vhierarchy_.node(lchild_handle).set_vertex_handle(vertex_handle); + vhierarchy_.node(rchild_handle).set_vertex_handle(vhierarchy_.node(node_handle).vertex_handle()); + + vhierarchy_.node(lchild_handle).set_radius(_radius[0]); + vhierarchy_.node(lchild_handle).set_normal(_normal[0]); + vhierarchy_.node(lchild_handle).set_sin_square(_sin_square[0]); + vhierarchy_.node(lchild_handle).set_mue_square(_mue_square[0]); + vhierarchy_.node(lchild_handle).set_sigma_square(_sigma_square[0]); + + vhierarchy_.node(rchild_handle).set_radius(_radius[1]); + vhierarchy_.node(rchild_handle).set_normal(_normal[1]); + vhierarchy_.node(rchild_handle).set_sin_square(_sin_square[1]); + vhierarchy_.node(rchild_handle).set_mue_square(_mue_square[1]); + vhierarchy_.node(rchild_handle).set_sigma_square(_sigma_square[1]); + +#ifdef EXAMPLE_CREATION + __add_children(_node_index); +#endif +} + + + +///////////////////////////////////////////////// +// example related functions +///////////////////////////////////////////////// + +void VDPMClientViewerWidget::save_views() +{ + FILE *camera_file = fopen("camera.cmr", "w"); + + GLdouble current_modelview_matrix[16], current_projection_matrix[16]; + + memcpy(current_modelview_matrix, modelview_matrix(), 16*sizeof(GLdouble)); + memcpy(current_projection_matrix, projection_matrix(), 16*sizeof(GLdouble)); + + + fprintf(camera_file, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n", + current_modelview_matrix[0], current_modelview_matrix[1], current_modelview_matrix[2], current_modelview_matrix[3], + current_modelview_matrix[4], current_modelview_matrix[5], current_modelview_matrix[6], current_modelview_matrix[7], + current_modelview_matrix[8], current_modelview_matrix[9], current_modelview_matrix[10], current_modelview_matrix[11], + current_modelview_matrix[12], current_modelview_matrix[13], current_modelview_matrix[14], current_modelview_matrix[15]); + + fprintf(camera_file, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n", + current_projection_matrix[0], current_projection_matrix[1], current_projection_matrix[2], current_projection_matrix[3], + current_projection_matrix[4], current_projection_matrix[5], current_projection_matrix[6], current_projection_matrix[7], + current_projection_matrix[8], current_projection_matrix[9], current_projection_matrix[10], current_projection_matrix[11], + current_projection_matrix[12], current_projection_matrix[13], current_projection_matrix[14], current_projection_matrix[15]); + + + fprintf(camera_file, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n", + reserved_modelview_matrix_[0], reserved_modelview_matrix_[1], reserved_modelview_matrix_[2], reserved_modelview_matrix_[3], + reserved_modelview_matrix_[4], reserved_modelview_matrix_[5], reserved_modelview_matrix_[6], reserved_modelview_matrix_[7], + reserved_modelview_matrix_[8], reserved_modelview_matrix_[9], reserved_modelview_matrix_[10], reserved_modelview_matrix_[11], + reserved_modelview_matrix_[12], reserved_modelview_matrix_[13], reserved_modelview_matrix_[14], reserved_modelview_matrix_[15]); + + fprintf(camera_file, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n", + reserved_projection_matrix_[0], reserved_projection_matrix_[1], reserved_projection_matrix_[2], reserved_projection_matrix_[3], + reserved_projection_matrix_[4], reserved_projection_matrix_[5], reserved_projection_matrix_[6], reserved_projection_matrix_[7], + reserved_projection_matrix_[8], reserved_projection_matrix_[9], reserved_projection_matrix_[10], reserved_projection_matrix_[11], + reserved_projection_matrix_[12], reserved_projection_matrix_[13], reserved_projection_matrix_[14], reserved_projection_matrix_[15]); + + fclose(camera_file); +} + + +void VDPMClientViewerWidget::load_views(const char *camera_filename) +{ + FILE *camera_file = fopen(camera_filename, "r"); + + GLdouble current_modelview_matrix[16], current_projection_matrix[16]; + + + fscanf(camera_file, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n", + &(current_modelview_matrix[0]), &(current_modelview_matrix[1]), &(current_modelview_matrix[2]), &(current_modelview_matrix[3]), + &(current_modelview_matrix[4]), &(current_modelview_matrix[5]), &(current_modelview_matrix[6]), &(current_modelview_matrix[7]), + &(current_modelview_matrix[8]), &(current_modelview_matrix[9]), &(current_modelview_matrix[10]), &(current_modelview_matrix[11]), + &(current_modelview_matrix[12]), &(current_modelview_matrix[13]), &(current_modelview_matrix[14]), &(current_modelview_matrix[15])); + + + fscanf(camera_file, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n", + &(current_projection_matrix[0]), &(current_projection_matrix[1]), &(current_projection_matrix[2]), &(current_projection_matrix[3]), + &(current_projection_matrix[4]), &(current_projection_matrix[5]), &(current_projection_matrix[6]), &(current_projection_matrix[7]), + &(current_projection_matrix[8]), &(current_projection_matrix[9]), &(current_projection_matrix[10]), &(current_projection_matrix[11]), + &(current_projection_matrix[12]), &(current_projection_matrix[13]), &(current_projection_matrix[14]), &(current_projection_matrix[15])); + + + fscanf(camera_file, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n", + &(reserved_modelview_matrix_[0]), &(reserved_modelview_matrix_[1]), &(reserved_modelview_matrix_[2]), &(reserved_modelview_matrix_[3]), + &(reserved_modelview_matrix_[4]), &(reserved_modelview_matrix_[5]), &(reserved_modelview_matrix_[6]), &(reserved_modelview_matrix_[7]), + &(reserved_modelview_matrix_[8]), &(reserved_modelview_matrix_[9]), &(reserved_modelview_matrix_[10]), &(reserved_modelview_matrix_[11]), + &(reserved_modelview_matrix_[12]), &(reserved_modelview_matrix_[13]), &(reserved_modelview_matrix_[14]), &(reserved_modelview_matrix_[15])); + + + fscanf(camera_file, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n", + &(reserved_projection_matrix_[0]), &(reserved_projection_matrix_[1]), &(reserved_projection_matrix_[2]), &(reserved_projection_matrix_[3]), + &(reserved_projection_matrix_[4]), &(reserved_projection_matrix_[5]), &(reserved_projection_matrix_[6]), &(reserved_projection_matrix_[7]), + &(reserved_projection_matrix_[8]), &(reserved_projection_matrix_[9]), &(reserved_projection_matrix_[10]), &(reserved_projection_matrix_[11]), + &(reserved_projection_matrix_[12]), &(reserved_projection_matrix_[13]), &(reserved_projection_matrix_[14]), &(reserved_projection_matrix_[15])); + + fclose(camera_file); + + set_modelview_matrix(current_modelview_matrix); + set_projection_matrix(current_projection_matrix); + + adaptive_mode_ = false; +} + +void VDPMClientViewerWidget::print_statistics() +{ + const float angle = 360.0/(float)n_viewpoints_; + Vec3f axis = Vec3f(0,1,0); + Vec3f delta = Vec3f(0, 0.7f*(bbMin_[1] - bbMax_[1])/n_viewpoints_, 0); + + rotate(axis, -angle); + set_scene_pos(center() + delta, 1.0f * radius() ); + + updateGL(); + + if (++nth_viewpoint_ < n_viewpoints_) + qAnimationTimer_->start(500, true); +} + +void VDPMClientViewerWidget::look_around() +{ + const float angle = 360.0/(float)n_viewpoints_; + Vec3f axis = Vec3f(0,1,0); + Vec3f delta = Vec3f(0, 0.7f*(bbMin_[1] - bbMax_[1])/n_viewpoints_, 0); + + rotate(axis, -angle); + set_scene_pos(center() + delta, 1.0f * radius() ); + + updateGL(); + + save_screen(true); + + if (++nth_viewpoint_ < n_viewpoints_) + qAnimationTimer_->start(3000, true); +} + + +void VDPMClientViewerWidget::save_screen(bool _flag) +{ + setCursor( waitCursor ); + + if (_flag == true) // shot from the reserved view-point + { + GLdouble current_modelview_matrix[16]; + GLdouble current_projection_matrix[16]; + bool current_adaptive_mode = adaptive_mode_; + + memcpy(current_modelview_matrix, modelview_matrix(), 16*sizeof(GLdouble)); + memcpy(current_projection_matrix, projection_matrix(), 16*sizeof(GLdouble)); + + set_modelview_matrix(reserved_modelview_matrix_); + set_projection_matrix(reserved_projection_matrix_); + adaptive_mode_ = false; + + updateGL(); + + // shot from the reserved view-point + char rfilename[256]; + sprintf(rfilename, "rview%03d.bmp", nth_viewpoint_); + screen_capture(rfilename); + std::cout << "shot from the reserved view-point" << std::endl; + + + set_modelview_matrix(current_modelview_matrix); + set_projection_matrix(current_projection_matrix); + adaptive_mode_ = current_adaptive_mode; + } + + updateGL(); + + // shot from the current view-point + char cfilename[256]; + sprintf(cfilename, "cview%03d.bmp", nth_viewpoint_); + screen_capture(cfilename); + std::cout << "shot from the current view-point" << std::endl; + + + setCursor( pointingHandCursor ); +} + +void VDPMClientViewerWidget::screen_capture(const char * /* _filename */) +{ +// CImageData image(width(), height()); + +// glReadBuffer(GL_BACK); +// glReadPixels(0, 0, width(), height(), GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*) image.rgbMap()); + +// image.SaveBMP(_filename, width(), height()); +} + diff --git a/Apps/Deprecated/Streaming/Client/VDPMClientViewerWidget.hh b/Apps/Deprecated/Streaming/Client/VDPMClientViewerWidget.hh new file mode 100644 index 00000000..d5cec4d7 --- /dev/null +++ b/Apps/Deprecated/Streaming/Client/VDPMClientViewerWidget.hh @@ -0,0 +1,320 @@ +#ifndef OPENMESH_APPS_VDPMSTREAMING_CLIENT_VDPMCLIENTVIEWERWIDGET_HH +#define OPENMESH_APPS_VDPMSTREAMING_CLIENT_VDPMCLIENTVIEWERWIDGET_HH + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +//#include + + + +typedef MeshViewerWidgetT MeshViewerWidget; + + + +using OpenMesh::VDPM::VDPMStreamingPhase; +using OpenMesh::VDPM::kVSplitHeader; +using OpenMesh::VDPM::kVSplits; +using OpenMesh::VDPM::kBaseMesh; + +using OpenMesh::VDPM::Plane3d; + +using OpenMesh::VDPM::VFront; +using OpenMesh::VDPM::VHierarchy; +using OpenMesh::VDPM::VHierarchyNodeIndex; +using OpenMesh::VDPM::VHierarchyNodeHandle; +using OpenMesh::VDPM::ViewingParameters; +using OpenMesh::VDPM::set_debug_print; + + +//== CLASS DEFINITION ========================================================= + + +class VDPMClientViewerWidget : public MeshViewerWidget +{ + + Q_OBJECT + +public: + VDPMClientViewerWidget(QWidget *_parent=0, const char *_name=0) + : MeshViewerWidget(_parent, _name) + { + set_debug_print(true); + adaptive_mode_ = false; + + qSessionTimer_ = new QTimer(this); + qSocket_ = new QSocket(this); + streaming_phase_ = kBaseMesh; + session_running_ = false; + + + connect(qSessionTimer_, SIGNAL(timeout()), + this, SLOT(session_timer_check())); + + connect(qSessionTimer_, SIGNAL(timeout()), + this, SLOT(socketReadyRead())); + + // connect signal-slots about QSocket + connect(qSocket_, SIGNAL(connected()), + this, SLOT(socketConnected())); + + connect(qSocket_, SIGNAL(connectionClosed()), + this, SLOT(socketConnectionClosed())); + + connect(qSocket_, SIGNAL(readyRead()), + this, SLOT(socketReadyRead())); + + connect(qSocket_, SIGNAL(error(int)), + this, SLOT(socketError(int))); + + + look_around_mode_ = false; + frame_ = 0; + n_viewpoints_ = 60; + + global_timer_.reset(); + global_timer_.start(); + render_timer_.reset(); + refinement_timer_.reset(); + session_timer_.reset(); + + qAnimationTimer_ = new QTimer(this); + + connect(qAnimationTimer_, SIGNAL(timeout()), + this, SLOT(look_around())); + //connect(qAnimationTimer_, SIGNAL(timeout()), + // this, SLOT(print_statistics())); + + + uplink_file = fopen("uplink.txt", "w"); + downlink_file = fopen("downlink.txt", "w"); + + render_file = fopen("render.txt", "w"); + refinement_file = fopen("refinement.txt", "w"); + session_file = fopen("session.txt", "w"); + + vd_streaming_ = true; + max_transmitted_datasize_ = 0; + transmitted_datasize_ = 0; + } + + ~VDPMClientViewerWidget() + { + fclose(uplink_file); + fclose(downlink_file); + + fclose(render_file); + fclose(refinement_file); + fclose(session_file); + } + + + void connectToServer( std::string& _server_name, + int _port= VDPM_STREAMING_PORT ) + { + qSocket_->connectToHost( _server_name.c_str(), _port ); + } + + void openBaseMesh( std::string& _base_mesh ) + { + open_vd_base_mesh( qFilename_ = _base_mesh.c_str() ); + std::cout << "spm file: " << qFilename_ << std::endl; + } + +// socket related slots +private slots: + + void closeConnection() + { + close(); + if (qSocket_->state() == QSocket::Closing) // we have a delayed close. + { + connect(this, SIGNAL(delayedCloseFinished()), SLOT(socketClosed())); + } + else // the qSocket is closed. + { + socketClosed(); + } + } + + void socketReadyRead() + { + switch( streaming_phase_) + { + case kVSplits: receive_vsplit_packets(); break; + case kVSplitHeader: receive_vsplit_header(); break; + case kBaseMesh: receive_base_mesh(); break; + } + + } + + void socketConnected() + { + std::cout << "Connected to server" << std::endl; + } + + void socketConnectionClosed() + { + std::cout << "Connection closed by the server" << std::endl; + } + + void socketClosed() + { + std::cout << "Connection closed" << std::endl; + } + + void socketError(int e) + { + std::cout << "Error number " << e << " occurred" << std::endl; + } + + void look_around(); + void print_statistics(); + + + void session_timer_check() + { + std::cout << "Session Timer works" << std::endl; + } + +// for view-dependent PM +private: + VHierarchy vhierarchy_; + //unsigned char tree_id_bits_; + VFront vfront_; + ViewingParameters viewing_parameters_; + float kappa_square_; + bool adaptive_mode_; + + unsigned int n_base_vertices_; + unsigned int n_base_edges_; + unsigned int n_base_faces_; + unsigned int n_details_; + +private: + + bool outside_view_frustum(const OpenMesh::Vec3f &pos, float radius); + bool oriented_away(float sin_square, float distance_square, + float product_value); + bool screen_space_error(float mue_square, float sigma_square, + float distance_square, float product_value); + void update_viewing_parameters(); + + virtual void keyPressEvent(QKeyEvent *_event); + +protected: + + /// inherited drawing method + virtual void draw_scene(const std::string& _draw_mode); + + +public: + + void open_vd_prog_mesh(const char* _filename); + + unsigned int num_base_vertices() const { return n_base_vertices_; } + unsigned int num_base_edges() const { return n_base_edges_; } + unsigned int num_base_faces() const { return n_base_faces_; } + unsigned int num_details() const { return n_details_; } + + void adaptive_refinement(); + bool qrefine(VHierarchyNodeHandle _node_handle); + void force_vsplit(VHierarchyNodeHandle _node_handle); + bool ecol_legal(VHierarchyNodeHandle _parent_handle, MyMesh::HalfedgeHandle& v0v1); + + void get_active_cuts(VHierarchyNodeHandle _node_handle, MyMesh::VertexHandle &vl, MyMesh::VertexHandle &vr); + void vsplit(VHierarchyNodeHandle _node_handle, MyMesh::VertexHandle vl, MyMesh::VertexHandle vr); + void ecol(VHierarchyNodeHandle _parent_handle, const MyMesh::HalfedgeHandle& v0v1); + + void init_vfront(); + + // streaming realted functions +private: + QTimer *qSessionTimer_; + QSocket *qSocket_; + QString qFilename_; + bool session_running_; + VDPMStreamingPhase streaming_phase_; + unsigned int n_vsplit_packets_; + +public: + void connect_to_server(); + bool request_base_mesh(); + bool receive_base_mesh(); + void send_viewing_information(); + void receive_vsplit_header(); + void receive_vsplit_packets(); + void open_vd_base_mesh(const char* _filename); + void update_vhierarchy( + const OpenMesh::Vec3f &_pos, // 3D position of v0 + const VHierarchyNodeIndex &_v, // vhierarchy index of v1 + const VHierarchyNodeIndex &_fund_lcut_index, // vhierarchy index of fundamental lcut + const VHierarchyNodeIndex &_fund_rcut_index, // vhierarchy index of fundamental rcut + const float _radius[2], // radius of lchild & rchild + const OpenMesh::Vec3f _normal[2], // normal of lchild & rchild + const float _sin_square[2], // sin_square of lchild & rchild + const float _mue_square[2], // mue_square of lchild & rchild + const float _sigma_square[2] // sigma_square of lchild & rchild + ); + + + // for example +private: + QTimer *qAnimationTimer_; + QString qCameraFileName_; + MyMesh::Point bbMin_, bbMax_; + unsigned int frame_; + int max_transmitted_datasize_; + int transmitted_datasize_; + bool vd_streaming_; + + unsigned int nth_viewpoint_; + unsigned int n_viewpoints_; + bool look_around_mode_; + GLdouble reserved_modelview_matrix_[16]; + GLdouble reserved_projection_matrix_[16]; + + FILE *uplink_file; + FILE *downlink_file; + FILE *render_file; + FILE *refinement_file; + FILE *session_file; + +public: + void save_screen(bool _flag); + void save_views(); + void load_views(const char *camera_filename); + void screen_capture(const char *_filename); + void current_max_resolution(); + + OpenMesh::Utils::Timer global_timer_; + OpenMesh::Utils::Timer render_timer_; + OpenMesh::Utils::Timer refinement_timer_; + OpenMesh::Utils::Timer session_timer_; + + + +#ifdef EXAMPLE_CREATION + void increase_max_descendents(const VHierarchyNodeIndex &node_index); + void increase_cur_descendents(VHierarchyNodeHandle _node_handle); + void __add_children(const VHierarchyNodeIndex &node_index, bool update_current = true); + void mesh_coloring(); +#endif +}; + +#endif //OPENMESH_APPS_VDPMSTREAMING_CLIENT_VDPMCLIENTVIEWERWIDGET_HH defined diff --git a/Apps/Deprecated/Streaming/Client/VDPMStreamingClient.cc b/Apps/Deprecated/Streaming/Client/VDPMStreamingClient.cc new file mode 100644 index 00000000..c8efcf92 --- /dev/null +++ b/Apps/Deprecated/Streaming/Client/VDPMStreamingClient.cc @@ -0,0 +1,73 @@ +// #ifdef _MSC_VER +// # pragma warning(disable: 4267 4311) +// #endif + +#include +#include + +#include +#include + +//#include +#include +//#include +//#include + +#include +#include +#include + + +int main(int argc, char **argv) +{ + // OpenGL check + QApplication::setColorSpec( QApplication::CustomColor ); + QApplication app(argc,argv); + + if ( !QGLFormat::hasOpenGL() ) { + std::cerr << "This system has no OpenGL support.\n"; + return -1; + } + + // + int c; + int port = -1; + std::string bmesh = ""; + std::string sname = "localhost"; + + while ( (c=getopt(argc, argv, "b:p:s:"))!=-1 ) + { + switch(c) + { + case 'b': bmesh = optarg; break; + case 's': sname = optarg; break; + case 'p': { std::istringstream istr(optarg); istr >> port; } break; + } + } + + // create widget + VDPMClientViewerWidget* w = + new VDPMClientViewerWidget(0, "VDPMClientViewer"); + + if (port == -1) + w->connectToServer( sname ); + else + w->connectToServer( sname, port ); + + w->resize(800, 800); + app.setMainWidget(w); + w->show(); + + w->openBaseMesh( bmesh ); + + // print usage info + std::cout << "\n\n" + << "Press Minus : Coarsen mesh\n" + << " Plus : Refine mesh\n" + << " Home : Coarsen down to base mesh\n" + << " End : Refine up to finest mesh\n" + << "\n"; + + return app.exec(); +} + diff --git a/Apps/Deprecated/Streaming/Server/ACGMakefile b/Apps/Deprecated/Streaming/Server/ACGMakefile new file mode 100644 index 00000000..b9cfe765 --- /dev/null +++ b/Apps/Deprecated/Streaming/Server/ACGMakefile @@ -0,0 +1,18 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + +CXX_CFLAGS += -DQT_THREAD_SUPPORT + +SUBDIRS = $(call find-subdirs) + +PACKAGES := qt glut opengl + +PROJ_LIBS := OpenMesh/Core OpenMesh/Tools + +MODULES := moc cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Apps/Deprecated/Streaming/Server/ServerSideVDPM.cc b/Apps/Deprecated/Streaming/Server/ServerSideVDPM.cc new file mode 100644 index 00000000..12e4b975 --- /dev/null +++ b/Apps/Deprecated/Streaming/Server/ServerSideVDPM.cc @@ -0,0 +1,225 @@ +#include +#include +#include +#include +#include +#include +#include "ServerSideVDPM.hh" + + +using OpenMesh::VDPM::VHierarchyNode; +using OpenMesh::VDPM::VHierarchyNodeIndex; +using OpenMesh::VDPM::VHierarchyNodeHandle; + + +void +ServerSideVDPM:: +clear() +{ + points_.clear(); + triangles_.clear(); + vhierarchy_.clear(); + + n_base_vertices_ = 0; + n_base_faces_ = 0; + n_details_ = 0; +} + +OpenMesh::VertexHandle +ServerSideVDPM:: +add_vertex(const OpenMesh::Vec3f &p) +{ + points_.push_back(p); + + return OpenMesh::VertexHandle(points_.size() - 1); +} + +OpenMesh::FaceHandle +ServerSideVDPM:: +add_face(const unsigned int _triangle[3]) +{ + OpenMesh::Vec3ui fvi; + + fvi[0] = _triangle[0]; + fvi[1] = _triangle[1]; + fvi[2] = _triangle[2]; + + triangles_.push_back(fvi); + + return OpenMesh::FaceHandle(triangles_.size() - 1); +} + + +void +ServerSideVDPM:: +vhierarchy_roots(VHierarchyNodeHandleContainer &roots) const +{ + unsigned int i; + + roots.clear(); + + for (i=0; i index2handle_map; + + std::ifstream ifs(_filename, std::ios::binary); + if (!ifs) + { + std::cerr << "read error\n"; + return false; + } + + // + bool swap = OpenMesh::Endian::local() != OpenMesh::Endian::LSB; + + // read header + ifs.read(fileformat, 10); fileformat[10] = '\0'; + if (std::string(fileformat) != std::string("VDProgMesh")) + { + std::cerr << "Wrong file format.\n"; + ifs.close(); + return false; + } + + clear(); + + OpenMesh::IO::restore(ifs, n_base_vertices_, swap); + OpenMesh::IO::restore(ifs, n_base_faces_, swap); + OpenMesh::IO::restore(ifs, n_details_, swap); + + // update tree_id_bits_ + vhierarchy_.set_num_roots(n_base_vertices_); + + + // read base_mesh + for (i=0; i +#include +#include +#include + + +using OpenMesh::VDPM::VHierarchy; +using OpenMesh::VDPM::VHierarchyNodeHandleContainer; + + +class ServerSideVDPM +{ +private: + + char name_[256]; + + std::vector points_; // points related to this pm + std::vector triangles_; // base mesh triangles + VHierarchy vhierarchy_; + + unsigned int n_base_vertices_; + unsigned int n_base_faces_; + unsigned int n_details_; + unsigned char tree_id_bits_; + +public: + + ServerSideVDPM() { clear(); } + void clear(); + + const char* name() const { return name_; } + + void get_name(char _name[256]) { strcpy(_name, name_); } + void set_name(const char _name[256]) { strcpy(name_, _name); } + + + std::string + basename(const std::string& _f) + { + std::string::size_type dot = _f.rfind("/"); + if (dot == std::string::npos) + return std::string(_f); + return std::string(_f.substr(dot+1, _f.length()-(dot+1))); + } + + + bool is_same_name(const char _name[256]) + { + return (basename( name_ ) == basename( _name )); + } + + OpenMesh::VertexHandle add_vertex(const OpenMesh::Vec3f &p); + OpenMesh::FaceHandle add_face(const unsigned int _triangle[3]); + + const OpenMesh::Vec3f& point(OpenMesh::VertexHandle _vertex_handle) const + { + return points_[_vertex_handle.idx()]; + } + + OpenMesh::Vec3f& point(OpenMesh::VertexHandle _vertex_handle) + { + return points_[_vertex_handle.idx()]; + } + + const VHierarchy& vhierarchy() const { return vhierarchy_; } + VHierarchy& vhierarchy() { return vhierarchy_; } + + void vhierarchy_roots(VHierarchyNodeHandleContainer &roots) const; + + unsigned int n_base_vertices() const { return n_base_vertices_; } + unsigned int n_base_faces() const { return n_base_faces_; } + unsigned int n_details() const { return n_details_; } + + bool open_vd_prog_mesh(const char *_filename); +}; + +std::ostream& operator << ( std::ostream& _os, const ServerSideVDPM& _o ); + + +typedef std::vector ServerSideVDPMContainer; +typedef std::list ServerSideVDPMList; + +#endif //OPENMESH_APP_SERVERSIDEVDPM_HH defined + diff --git a/Apps/Deprecated/Streaming/Server/VDPMServerSession.cc b/Apps/Deprecated/Streaming/Server/VDPMServerSession.cc new file mode 100644 index 00000000..2203b8ff --- /dev/null +++ b/Apps/Deprecated/Streaming/Server/VDPMServerSession.cc @@ -0,0 +1,467 @@ +#include +#include +#include +#include + + +using OpenMesh::VDPM::VHierarchyNode; +using OpenMesh::VDPM::Plane3d; +using OpenMesh::VDPM::InvalidVHierarchyNodeHandle; +using OpenMesh::VDPM::debug_print; + + +bool +VDPMServerSession:: +set_vdpm(const char _vdpm_name[256]) +{ +#ifdef DEBUG_COUT + if (debug_print() == true) + { + std::cout << "Setting vdpm" << std::endl; + } +#endif + vdpm_ = ((VDPMServerViewerWidget *) ((VDPMServerSocket *) parent())->parent())->get_vdpm(_vdpm_name); + if (vdpm_ == NULL) + return false; + + vhierarchy_ = &vdpm_->vhierarchy(); + + VHierarchyNodeHandleContainer roots; + unsigned int n_details; + + vdpm_->vhierarchy_roots(roots); + n_details = vdpm_->n_details(); + + //vfront_.init(roots, n_details); + + // vertex hierarchy window + vhwindow_.set_vertex_hierarchy(vdpm_->vhierarchy()); + vhwindow_.init(roots); + + +#ifdef DEBUG_COUT + if (debug_print() == true) + { + std::cout << "setting vdpm ended" << std::endl; + } +#endif + + return true; +} + + +void +VDPMServerSession:: +sendBaseMeshToClient() +{ +#ifdef DEBUG_COUT + if (debug_print() == true) + { + std::cout << "starting sendBaseMeshToClient()" << std::endl; + } +#endif + + + +#ifdef DEBUG_COUT + if (debug_print() == true) + { + std::cout << "sendBaseMeshToClient() is done" << std::endl; + } +#endif +} + +void +VDPMServerSession:: +send_vsplit_packets() +{ + viewing_parameters_.update_viewing_configurations(); + vsplits_.clear(); + + if (((VDPMServerViewerWidget *) this->parent()->parent())->vd_streaming()) + adaptive_refinement(); + else + sequential_refinement(); + + + if (debug_print() == true) + { + std::cout << "adaptive refinement is done on the server side" << std::endl; + } + + stream_vsplits(); + + if (debug_print() == true) + { + std::cout << "streameing vsplits is done" << std::endl; + } + + if (transmission_complete_ == true) + { + std::cout << "transmission is completed" << std::endl; + } + + if (debug_print() == true) + { + std::cout << "send_vsplit_packets() is done" << std::endl; + } +} + + +void +VDPMServerSession:: +readBaseMeshRequestFromClient() +{ + int status; + unsigned int string_length; + QDataStream qTcp(this); + QString vdpm_name; + + while (waitForMore(10) < sizeof(int)); + qTcp >> string_length; + + while (waitForMore(10) < (string_length*sizeof(char))); + qTcp >> vdpm_name; + + if (set_vdpm(vdpm_name) != true) status = 0; + else status = 1; + + qTcp << status; + flush(); + + if (status == 1) + streaming_phase_ = kVSplits; +} + + +void +VDPMServerSession:: +readViewingParametersFromClient() +{ + double modelview_matrix[16]; + float fovy; + float aspect; + float tolerance_square; + + while (waitForMore(10) < 16*sizeof(double) + 3*sizeof(float)); + + QDataStream qTCP(this); + qTCP >> modelview_matrix[0] + >> modelview_matrix[1] + >> modelview_matrix[2] + >> modelview_matrix[3] + >> modelview_matrix[4] + >> modelview_matrix[5] + >> modelview_matrix[6] + >> modelview_matrix[7] + >> modelview_matrix[8] + >> modelview_matrix[9] + >> modelview_matrix[10] + >> modelview_matrix[11] + >> modelview_matrix[12] + >> modelview_matrix[13] + >> modelview_matrix[14] + >> modelview_matrix[15] + >> fovy + >> aspect + >> tolerance_square; + + viewing_parameters_.set_modelview_matrix(modelview_matrix); + viewing_parameters_.set_fovy(fovy); + viewing_parameters_.set_aspect(aspect); + viewing_parameters_.set_tolerance_square(tolerance_square); + + send_vsplit_packets(); + + fprintf(mem_file, "%d %d %d\n", + memory_requirements_using_window(true), + memory_requirements_using_window(false), + memory_requirements_using_vfront()); +} + + +void +VDPMServerSession:: +PrintOutVFront() +{ +} + +void +VDPMServerSession:: +stream_vsplits() +{ + // send header (i.e., # of vsplits) + unsigned int i; + VHierarchyNodeHandle node_handle; + OpenMesh::Vec3f pos; + VHierarchyNodeIndex node_index, fund_lcut_index, fund_rcut_index; + float lchild_radius, rchild_radius; + OpenMesh::Vec3f lchild_normal, rchild_normal; + float lchild_sin_square, rchild_sin_square; + float lchild_mue_square, rchild_mue_square; + float lchild_sigma_square, rchild_sigma_square; + unsigned int n_vsplit_packets = (unsigned int) vsplits_.size(); + + QDataStream qTcp(this); + qTcp << n_vsplit_packets; + flush(); + + for (i=0; ilchild_handle(node_handle); + VHierarchyNodeHandle rchild_handle = vhierarchy_->rchild_handle(node_handle); + + VHierarchyNode &node = vhierarchy_->node(node_handle); + VHierarchyNode &lchild = vhierarchy_->node(lchild_handle); + VHierarchyNode &rchild = vhierarchy_->node(rchild_handle); + + pos = vdpm_->point(lchild.vertex_handle()); + node_index = node.node_index(); + fund_lcut_index = node.fund_lcut_index(); + fund_rcut_index = node.fund_rcut_index(); + lchild_radius = lchild.radius(); rchild_radius = rchild.radius(); + lchild_normal = lchild.normal(); rchild_normal = rchild.normal(); + lchild_sin_square = lchild.sin_square(); rchild_sin_square = rchild.sin_square(); + lchild_mue_square = lchild.mue_square(); rchild_mue_square = rchild.mue_square(); + lchild_sigma_square = lchild.sigma_square(); rchild_sigma_square = rchild.sigma_square(); + + qTcp << pos[0] << pos[1] << pos[2] + << node_index.value() + << fund_lcut_index.value() + << fund_rcut_index.value() + << lchild_radius + << lchild_normal[0] << lchild_normal[1] << lchild_normal[2] + << lchild_sin_square + << lchild_mue_square + << lchild_sigma_square + << rchild_radius + << rchild_normal[0] << rchild_normal[1] << rchild_normal[2] + << rchild_sin_square + << rchild_mue_square + << rchild_sigma_square; + flush(); // socket flush + + if (debug_print() == true) + { + std::cout << "Write to client " << i << "-th vsplit packets: " << std::endl; + } + + } +} + + +void +VDPMServerSession:: +adaptive_refinement() +{ + float fovy = viewing_parameters_.fovy(); + float tolerance_square = viewing_parameters_.tolerance_square(); + float tan_value = tanf(fovy / 2.0f); + kappa_square_ = 4.0f * tan_value * tan_value * tolerance_square; + + transmission_complete_ = true; + for (vhwindow_.begin(); vhwindow_.end() != true; vhwindow_.next()) + { + VHierarchyNodeHandle node_handle = vhwindow_.node_handle(); + + if (vhierarchy_->is_leaf_node(node_handle) != true) + { + transmission_complete_ = false; + if (qrefine(node_handle) == true) + { + force_vsplit(node_handle); + } + } + } +} + +void +VDPMServerSession:: +sequential_refinement() +{ + for (vhwindow_.begin(); vhwindow_.end() != true; vhwindow_.next()) + { + VHierarchyNodeHandle node_handle = vhwindow_.node_handle(); + + if (vhierarchy_->is_leaf_node(node_handle) != true) + force_vsplit(node_handle); + + if (vsplits_.size() > 10) + break; + } +} + + +bool +VDPMServerSession:: +qrefine(VHierarchyNodeHandle _node_handle) +{ + VHierarchyNode &node = vhierarchy_->node(_node_handle); + OpenMesh::Vec3f p = vdpm_->point(node.vertex_handle()); + OpenMesh::Vec3f eye_dir = p - viewing_parameters_.eye_pos(); + float distance = eye_dir.length(); + float distance2 = distance * distance; + float product_value = dot(eye_dir, node.normal()); + + if (outside_view_frustum(p, node.radius()) == true) + return false; + if (oriented_away(node.sin_square(), distance2, product_value) == true) + return false; + if (screen_space_error(node.mue_square(), node.sigma_square(), distance2, product_value) == true) + return false; + + return true; +} + + +bool +VDPMServerSession:: +outside_view_frustum(const OpenMesh::Vec3f &pos, float radius) +{ + Plane3d frustum_plane[4]; + viewing_parameters_.frustum_planes(frustum_plane); + + for (int i = 0; i < 4; i++) { + if (frustum_plane[i].signed_distance(pos) < -radius) + return true; + } + + return false; +} + +bool +VDPMServerSession:: +oriented_away(float sin_square, float distance_square, float product_value) +{ + if (product_value > 0 && product_value*product_value > distance_square * sin_square) + return true; + else + return false; +} + +bool +VDPMServerSession:: +screen_space_error(float mue_square, float sigma_square, float distance_square, float product_value) +{ + if ((mue_square >= kappa_square_ * distance_square) || + (sigma_square * (distance_square - product_value * product_value) >= kappa_square_ * distance_square * distance_square)) + return false; + else + return true; +} + + +void +VDPMServerSession:: +force_vsplit(VHierarchyNodeHandle node_handle) +{ + VHierarchyNodeHandle lcut_handle, rcut_handle; + VHierarchyNodeIndex fund_lcut_index, fund_rcut_index; + + fund_lcut_index = vhierarchy_->fund_lcut_index(node_handle); + fund_rcut_index = vhierarchy_->fund_rcut_index(node_handle); + + lcut_handle = active_ancestor_handle(fund_lcut_index); + rcut_handle = active_ancestor_handle(fund_rcut_index); + assert(lcut_handle != InvalidVHierarchyNodeHandle && rcut_handle != InvalidVHierarchyNodeHandle); + + while (lcut_handle == rcut_handle) + { + force_vsplit(lcut_handle); + lcut_handle = active_ancestor_handle(fund_lcut_index); + rcut_handle = active_ancestor_handle(fund_rcut_index); + assert(lcut_handle != InvalidVHierarchyNodeHandle && rcut_handle != InvalidVHierarchyNodeHandle); + } + + vsplit(node_handle); +} + +void +VDPMServerSession:: +vsplit(VHierarchyNodeHandle _node_handle) +{ + // refine + VHierarchyNodeHandle lchild_handle = vhierarchy_->lchild_handle(_node_handle); + VHierarchyNodeHandle rchild_handle = vhierarchy_->rchild_handle(_node_handle); + + vhwindow_.inactivate(_node_handle); + vhwindow_.activate(lchild_handle); + vhwindow_.activate(rchild_handle); + + //vfront_.remove(_node_handle); + //vfront_.add(lchild_handle); + //vfront_.add(rchild_handle); + + vsplits_.push_back(_node_handle); +} + +VHierarchyNodeHandle +VDPMServerSession:: +active_ancestor_handle(VHierarchyNodeIndex &node_index) +{ + if (node_index.is_valid(vhierarchy_->tree_id_bits()) != true) + return InvalidVHierarchyNodeHandle; + + VHierarchyNodeHandle node_handle = vhierarchy_->node_handle(node_index); + + while (node_handle != InvalidVHierarchyNodeHandle && vhwindow_.is_active(node_handle) != true) + node_handle = vhierarchy_->parent_handle(node_handle); + + return node_handle; +} + +unsigned int +VDPMServerSession:: +memory_requirements_using_window(bool _estimate) +{ + unsigned int mem = 0; + + // common + mem += sizeof(VHierarchy*); + mem += sizeof(ViewingParameters); + mem += sizeof(float); + + if (_estimate) + { + unsigned int min = vhierarchy_->num_nodes(); + unsigned int max = 0; + + for (unsigned int i = 0; i < vhierarchy_->num_nodes(); ++i) + { + if (vhwindow_.is_active(VHierarchyNodeHandle((int) i))) + { + min = std::min(min, i); + max = std::max(max, i); + } + } + + mem += (max - min) / 8; + } + else + { + mem += vhwindow_.buffer_size(); + } + + return mem; +} + +unsigned int +VDPMServerSession:: +memory_requirements_using_vfront() +{ + unsigned int mem = 0; + std::list dummy_vfront; + + mem += (unsigned int) ceil (vhierarchy_->num_nodes() / 8.0); + mem += sizeof(dummy_vfront); + + for (unsigned int i = 0; i < vhierarchy_->num_nodes(); ++i) + { + if (vhwindow_.is_active(VHierarchyNodeHandle((int) i))) + mem += 3*sizeof(int); + } + + return mem; +} + diff --git a/Apps/Deprecated/Streaming/Server/VDPMServerSession.hh b/Apps/Deprecated/Streaming/Server/VDPMServerSession.hh new file mode 100644 index 00000000..156b4822 --- /dev/null +++ b/Apps/Deprecated/Streaming/Server/VDPMServerSession.hh @@ -0,0 +1,146 @@ +#ifndef OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSERVERSESSION_HH +#define OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSERVERSESSION_HH + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using OpenMesh::VDPM::VDPMStreamingPhase; +using OpenMesh::VDPM::kBaseMesh; +using OpenMesh::VDPM::kVSplits; + +using OpenMesh::VDPM::VHierarchyWindow; +using OpenMesh::VDPM::VHierarchyNodeIndex; +using OpenMesh::VDPM::VHierarchyNodeHandle; +using OpenMesh::VDPM::ViewingParameters; + +using OpenMesh::VDPM::set_debug_print; + +class VDPMServerSession : public QSocket, public QThread +{ + + Q_OBJECT + +public: + + VDPMServerSession(int sock, QObject *parent=0, const char *name=0) + : QSocket(parent, name) + { + set_debug_print(true); + + streaming_phase_ = kBaseMesh; + transmission_complete_ = false; + + connect(this, SIGNAL(connected()), SLOT(socketConnected())); + connect(this, SIGNAL(readyRead()), SLOT(socketReadyRead())); + //connect(this, SIGNAL(connectionClosed()), SLOT(deleteLater())); + connect(this, SIGNAL(connectionClosed()), SLOT(delayedCloseFinished())); + setSocket(sock); + + + qStatisticsTimer_ = new QTimer(this); + connect(qStatisticsTimer_, SIGNAL(timeout()), this, SLOT(print_statistics())); + + mem_file = fopen("mem.txt", "w"); + + start(); + } + + ~VDPMServerSession() + { + fclose(mem_file); + } + + void run() + { + while (true) + { + sleep(1); + } + } + +private: + + VDPMStreamingPhase streaming_phase_; + bool transmission_complete_; + +private: + + void sendBaseMeshToClient(); + void send_vsplit_packets(); + void readBaseMeshRequestFromClient(); + void readViewingParametersFromClient(); + + void PrintOutVFront(); + +private slots: + + void socketConnected() + { + std::cout << "socket is connected" << std::endl; + } + + void socketReadyRead() + { + if (streaming_phase_ == kBaseMesh) + { + readBaseMeshRequestFromClient(); + } + else if (streaming_phase_ == kVSplits) + { + readViewingParametersFromClient(); + } + } + + void print_statistics() + { + //std::cout << memory_requirements(true) << " " << memory_requirements(false) << std::endl; + } + +private: + unsigned short tree_id_bits_; // obsolete + ServerSideVDPM* vdpm_; + VHierarchy* vhierarchy_; + VHierarchyWindow vhwindow_; + ViewingParameters viewing_parameters_; + float kappa_square_; + VHierarchyNodeHandleContainer vsplits_; + +private: + bool outside_view_frustum(const OpenMesh::Vec3f &pos, float radius); + bool oriented_away(float sin_square, float distance_square, float product_value); + bool screen_space_error(float mue_square, float sigma_square, float distance_square, float product_value); + + void adaptive_refinement(); + void sequential_refinement(); + bool qrefine(VHierarchyNodeHandle _node_handle); + void force_vsplit(VHierarchyNodeHandle node_handle); + void vsplit(VHierarchyNodeHandle _node_handle); + VHierarchyNodeHandle active_ancestor_handle(VHierarchyNodeIndex &node_index); + void stream_vsplits(); + +public: + bool set_vdpm(const char _vdpm_name[256]); + unsigned int memory_requirements_using_window(bool _estimate); + unsigned int memory_requirements_using_vfront(); + + // for example +private: + QTimer *qStatisticsTimer_; + FILE *mem_file; +}; + +#endif //OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSERVERSESSION_HH defined diff --git a/Apps/Deprecated/Streaming/Server/VDPMServerSocket.hh b/Apps/Deprecated/Streaming/Server/VDPMServerSocket.hh new file mode 100644 index 00000000..cb71718b --- /dev/null +++ b/Apps/Deprecated/Streaming/Server/VDPMServerSocket.hh @@ -0,0 +1,47 @@ +#ifndef OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSERVERSOCKET_HH +#define OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSERVERSOCKET_HH + +#include +#include +#include +#include + +#include +#include +#include + + +class VDPMServerSocket : public QServerSocket +{ + Q_OBJECT + +public: + + VDPMServerSocket(QObject *parent=0) + : QServerSocket(VDPM_STREAMING_PORT, 1, parent) + { + if (!ok()) + { + std::cerr << "Failed to bind to port " + << VDPM_STREAMING_PORT << std::endl; + exit(1); + } + } + + void newConnection(int socket) + { + VDPMServerSession *s = new VDPMServerSession(socket, this); + //s->set_vdpm(); + emit newConnect(s); + std::cout << "new connection with: " << socket << std::endl; + } + +signals: + + void newConnect(VDPMServerSession*); + +}; + + + +#endif //OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSERVERSOCKET_HH defined diff --git a/Apps/Deprecated/Streaming/Server/VDPMServerViewerWidget.cc b/Apps/Deprecated/Streaming/Server/VDPMServerViewerWidget.cc new file mode 100644 index 00000000..f1554bda --- /dev/null +++ b/Apps/Deprecated/Streaming/Server/VDPMServerViewerWidget.cc @@ -0,0 +1,80 @@ +#include +#include + +bool +VDPMServerViewerWidget:: +open_vd_prog_mesh(const char *_filename) +{ + ServerSideVDPMListIter vdpm_it; + + vdpm_it = vdpms_.insert(vdpms_.end(), ServerSideVDPM()); + + ServerSideVDPM &vdpm = *vdpm_it; + + return vdpm.open_vd_prog_mesh(_filename); +} + +ServerSideVDPM* +VDPMServerViewerWidget:: +get_vdpm(const char _vdpm_name[256]) +{ + ServerSideVDPMListIter vdpm_it; + + for (vdpm_it=vdpms_.begin(); vdpm_it!=vdpms_.end(); ++vdpm_it) + { + if (vdpm_it->is_same_name(_vdpm_name) == true) + { + return &(*vdpm_it); + } + } + + return NULL; +} + +void +VDPMServerViewerWidget:: +keyPressEvent(QKeyEvent* _event) +{ + bool handled(false); + + QString filename; + + switch (_event->key()) + { + case Key_D: + set_debug_print(!debug_print()); + std::cout << "debug print mode " + << (debug_print() == true ? "on" : "off") << std::endl; + break; + + case Key_O: +#if defined(OM_CC_MSVC) + filename = QFileDialog::getOpenFileName("d:/data/models/spm/", "*.spm"); +#else + filename = QFileDialog::getOpenFileName("~/data/models/spm/", "*.spm"); +#endif + open_vd_prog_mesh(filename); + break; + + case Key_I: + std::copy( vdpms_.begin(), vdpms_.end(), + std::ostream_iterator(std::cout, "\n") ); + break; + + case Key_V: + vd_streaming_ = !(vd_streaming_); + if (vd_streaming_) + std::cout << "View-dependent streaming mode" << std::endl; + else + std::cout << "Sequential streaming mode" << std::endl; + + break; + + case Key_Q: + case Key_Escape: + qApp->quit(); + } + + if (!handled) + _event->ignore(); +} diff --git a/Apps/Deprecated/Streaming/Server/VDPMServerViewerWidget.hh b/Apps/Deprecated/Streaming/Server/VDPMServerViewerWidget.hh new file mode 100644 index 00000000..5b4e7d9d --- /dev/null +++ b/Apps/Deprecated/Streaming/Server/VDPMServerViewerWidget.hh @@ -0,0 +1,70 @@ +#ifndef OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSTREAMINGSERVERWIDGET_HH +#define OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSTREAMINGSERVERWIDGET_HH + +#include +#include +#include +#include +#include +#include +#include + + +using OpenMesh::VDPM::set_debug_print; +using OpenMesh::VDPM::debug_print; + + +class VDPMServerViewerWidget : public QWidget +{ + Q_OBJECT +public: + //VDPMServerViewerWidget(QWidget *_parent) : QWidget(_parent) + VDPMServerViewerWidget() : QWidget() + { + VDPMServerSocket *server = new VDPMServerSocket(this); + connect(server, + SIGNAL(newConnect(VDPMServerSession*)), + SLOT(newConnect(VDPMServerSession*))); + + vd_streaming_ = true; + } + +private: + typedef ServerSideVDPMList::iterator ServerSideVDPMListIter; + ServerSideVDPMList vdpms_; + bool vd_streaming_; + +public: + + ServerSideVDPM* get_vdpm(const char _vdpm_name[256]); + + +public: + + bool open_vd_prog_mesh(const char *_filename); + bool vd_streaming() const { return vd_streaming_; } + +private slots: + + void newConnect(VDPMServerSession *s) + { + std::cout << "New connection" << std::endl; + + connect(s, SIGNAL(connectionClosed()), SLOT(connectionClosed())); + } + + void connectionClosed() + { + std::cout << "Client closed connection" << std::endl; + } + +protected: + + virtual void keyPressEvent(QKeyEvent* _event); + +}; + + +#endif //OPENMESH_APP_VDPMSTREAMING_SERVER_VDPMSTREAMINGSERVERWIDGET_HH defined + + diff --git a/Apps/Deprecated/Streaming/Server/VDPMStreamingServer.cc b/Apps/Deprecated/Streaming/Server/VDPMStreamingServer.cc new file mode 100644 index 00000000..e1c0219f --- /dev/null +++ b/Apps/Deprecated/Streaming/Server/VDPMStreamingServer.cc @@ -0,0 +1,34 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + + + +int main(int argc, char **argv) +{ + std::cout << "View-dependent streaming of PM server." << std::endl; + + QApplication app(argc, argv); + VDPMServerViewerWidget server_widget; + + server_widget.resize(50, 50); + app.setMainWidget(&server_widget); + server_widget.show(); + + for (int idx=1; idx < argc; ++idx) + { + std::cout << "loading " << argv[idx] << std::endl; + server_widget.open_vd_prog_mesh( argv[idx] ) ; + } + + return app.exec(); +} + diff --git a/Apps/Deprecated/Streaming/Server/VDPMStreamingServer.hh b/Apps/Deprecated/Streaming/Server/VDPMStreamingServer.hh new file mode 100644 index 00000000..119b5939 --- /dev/null +++ b/Apps/Deprecated/Streaming/Server/VDPMStreamingServer.hh @@ -0,0 +1,6 @@ +#ifndef OPENMESH_APP_VDPMSTREAMINGSERVER_HH +#define OPENMESH_APP_VDPMSTREAMINGSERVER_HH + + + +#endif //OPENMESH_APP_VDPMSTREAMINGSERVER_HH defined diff --git a/Apps/QtViewer/MeshViewerWidget.hh b/Apps/QtViewer/MeshViewerWidget.hh new file mode 100644 index 00000000..269abada --- /dev/null +++ b/Apps/QtViewer/MeshViewerWidget.hh @@ -0,0 +1,131 @@ +//============================================================================= +// +// 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: 1.1 $ +// $Date: 2008-03-11 09:19:45 $ +// +//============================================================================= + +#ifndef OPENMESHAPPS_VIEWERWIDGET_HH +#define OPENMESHAPPS_VIEWERWIDGET_HH + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include +#include +#include +#include + + +//== CLASS DEFINITION ========================================================= + +using namespace OpenMesh; +using namespace OpenMesh::Attributes; + +struct MyTraits : public OpenMesh::DefaultTraits +{ + HalfedgeAttributes(OpenMesh::Attributes::PrevHalfedge); +}; + +typedef OpenMesh::TriMesh_ArrayKernelT MyMesh; + + + +//== CLASS DEFINITION ========================================================= + +class MeshViewerWidget : public MeshViewerWidgetT +{ + Q_OBJECT +public: + /// default constructor + MeshViewerWidget(QWidget* parent=0) : MeshViewerWidgetT(parent) + {} + OpenMesh::IO::Options& options() { return _options; } + const OpenMesh::IO::Options& options() const { return _options; } + void setOptions(const OpenMesh::IO::Options& opts) { _options = opts; } + + void open_mesh_gui(QString fname) + { + OpenMesh::Utils::Timer t; + t.start(); + if ( fname.isEmpty() || !open_mesh(fname.toLocal8Bit(), _options) ) + { + QString msg = "Cannot read mesh from file:\n '"; + msg += fname; + msg += "'"; + QMessageBox::critical( NULL, windowTitle(), msg); + } + t.stop(); + std::cout << "Loaded mesh in ~" << t.as_string() << std::endl; + } + void open_texture_gui(QString fname) + { + if ( fname.isEmpty() || !open_texture( fname.toLocal8Bit() ) ) + { + QString msg = "Cannot load texture image from file:\n '"; + msg += fname; + msg += "'\n\nPossible reasons:\n"; + msg += "- Mesh file didn't provide texture coordinates\n"; + msg += "- Texture file does not exist\n"; + msg += "- Texture file is not accessible.\n"; + QMessageBox::warning( NULL, windowTitle(), msg ); + } + } + +public slots: + void query_open_mesh_file() { + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open mesh file"), + tr(""), + tr("OBJ Files (*.obj);;" + "OFF Files (*.off);;" + "STL Files (*.stl);;" + "All Files (*)")); + if (!fileName.isEmpty()) + open_mesh_gui(fileName); + } + void query_open_texture_file() { + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open texture file"), + tr(""), + tr("PNG Files (*.png);;" + "BMP Files (*.bmp);;" + "GIF Files (*.gif);;" + "JPEG Files (*.jpg);;" + "TIFF Files (*.tif);;" + "All Files (*)")); + if (!fileName.isEmpty()) + open_texture_gui(fileName); + } +private: + OpenMesh::IO::Options _options; +}; + + +#endif diff --git a/Apps/QtViewer/MeshViewerWidgetT.cc b/Apps/QtViewer/MeshViewerWidgetT.cc new file mode 100644 index 00000000..4139b750 --- /dev/null +++ b/Apps/QtViewer/MeshViewerWidgetT.cc @@ -0,0 +1,782 @@ +//============================================================================= +// +// 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: 1832 $ +// $Date: 2008-05-23 11:10:37 +0200 (Fr, 23. Mai 2008) $ +// +//============================================================================= +#define OPENMESHAPPS_MESHVIEWERWIDGET_CC + +//== INCLUDES ================================================================= + +#ifdef _MSC_VER +//# pragma warning(disable: 4267 4311) +#endif + +// +#include +#include +// -------------------- +#include +#include +#include +// -------------------- +#include +#include +#include + +using namespace OpenMesh; +using namespace Qt; + +#if defined(_MSC_VER) +# undef min +# undef max +#endif + +using namespace Qt; +//== IMPLEMENTATION ========================================================== + + +template +bool +MeshViewerWidgetT::open_mesh(const char* _filename, IO::Options _opt) +{ + // load mesh + // calculate normals + // set scene center and radius + + mesh_.request_face_normals(); + mesh_.request_face_colors(); + mesh_.request_vertex_normals(); + mesh_.request_vertex_colors(); + mesh_.request_vertex_texcoords2D(); + + std::cout << "Loading from file '" << _filename << "'\n"; + if ( IO::read_mesh(mesh_, _filename, _opt )) + { + // store read option + opt_ = _opt; + + // update face and vertex normals + if ( ! opt_.check( IO::Options::FaceNormal ) ) + mesh_.update_face_normals(); + else + std::cout << "File provides face normals\n"; + + if ( ! opt_.check( IO::Options::VertexNormal ) ) + mesh_.update_vertex_normals(); + else + std::cout << "File provides vertex normals\n"; + + + // check for possible color information + if ( opt_.check( IO::Options::VertexColor ) ) + { + std::cout << "File provides vertex colors\n"; + add_draw_mode("Colored Vertices"); + } + else + mesh_.release_vertex_colors(); + + if ( _opt.check( IO::Options::FaceColor ) ) + { + std::cout << "File provides face colors\n"; + add_draw_mode("Solid Colored Faces"); + add_draw_mode("Smooth Colored Faces"); + } + else + mesh_.release_face_colors(); + + if ( _opt.check( IO::Options::VertexTexCoord ) ) + std::cout << "File provides texture coordinates\n"; + + + // bounding box + typename Mesh::ConstVertexIter vIt(mesh_.vertices_begin()); + typename Mesh::ConstVertexIter vEnd(mesh_.vertices_end()); + + typedef typename Mesh::Point Point; + using OpenMesh::Vec3f; + + Vec3f bbMin, bbMax; + + bbMin = bbMax = OpenMesh::vector_cast(mesh_.point(vIt)); + + for (size_t count=0; vIt!=vEnd; ++vIt, ++count) + { + bbMin.minimize( OpenMesh::vector_cast(mesh_.point(vIt))); + bbMax.maximize( OpenMesh::vector_cast(mesh_.point(vIt))); + } + + + // set center and radius + set_scene_pos( (bbMin+bbMax)*0.5, (bbMin-bbMax).norm()*0.5 ); + + // for normal display + normal_scale_ = (bbMax-bbMin).min()*0.05f; + + // info + std::clog << mesh_.n_vertices() << " vertices, " + << mesh_.n_edges() << " edge, " + << mesh_.n_faces() << " faces\n"; + + // base point for displaying face normals + { + OpenMesh::Utils::Timer t; + t.start(); + mesh_.add_property( fp_normal_base_ ); + typename M::FaceIter f_it = mesh_.faces_begin(); + typename M::FaceVertexIter fv_it; + for (;f_it != mesh_.faces_end(); ++f_it) + { + typename Mesh::Point v(0,0,0); + for( fv_it=mesh_.fv_iter(f_it); fv_it; ++fv_it) + v += OpenMesh::vector_cast(mesh_.point(fv_it)); + v *= 1.0f/3.0f; + mesh_.property( fp_normal_base_, f_it ) = v; + } + t.stop(); + std::clog << "Computed base point for displaying face normals [" + << t.as_string() << "]" << std::endl; + } + + // + { + std::clog << "Computing strips.." << std::flush; + OpenMesh::Utils::Timer t; + t.start(); + compute_strips(); + t.stop(); + std::clog << "done [" << strips_.n_strips() + << " strips created in " << t.as_string() << "]\n"; + } + + // +#if defined(WIN32) + updateGL(); +#endif + + setWindowTitle(QFileInfo(_filename).fileName()); + + // loading done + return true; + } + return false; +} + + +//----------------------------------------------------------------------------- + +template +bool MeshViewerWidgetT::open_texture( const char *_filename ) +{ + QImage texsrc; + QString fname = _filename; + + if (texsrc.load( fname )) + { + return set_texture( texsrc ); + } + return false; +} + + +//----------------------------------------------------------------------------- + +template +bool MeshViewerWidgetT::set_texture( QImage& _texsrc ) +{ + if ( !opt_.vertex_has_texcoord() ) + return false; + + { + // adjust texture size: 2^k * 2^l + int tex_w, w( _texsrc.width() ); + int tex_h, h( _texsrc.height() ); + + for (tex_w=1; tex_w <= w; tex_w <<= 1) {}; + for (tex_h=1; tex_h <= h; tex_h <<= 1) {}; + tex_w >>= 1; + tex_h >>= 1; + _texsrc = _texsrc.scaled( tex_w, tex_h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); + } + + QImage texture( QGLWidget::convertToGLFormat ( _texsrc ) ); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_PACK_ROW_LENGTH, 0); + glPixelStorei(GL_PACK_SKIP_ROWS, 0); + glPixelStorei(GL_PACK_SKIP_PIXELS, 0); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + if ( tex_id_ > 0 ) + { + glDeleteTextures(1, &tex_id_); + } + glGenTextures(1, &tex_id_); + glBindTexture(GL_TEXTURE_2D, tex_id_); + + // glTexGenfv( GL_S, GL_SPHERE_MAP, 0 ); + // glTexGenfv( GL_T, GL_SPHERE_MAP, 0 ); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glTexImage2D(GL_TEXTURE_2D, // target + 0, // level + GL_RGBA, // internal format + texture.width(), // width (2^n) + texture.height(), // height (2^m) + 0, // border + GL_RGBA, // format + GL_UNSIGNED_BYTE, // type + texture.bits() ); // pointer to pixels + + std::cout << "Texture loaded\n"; + return true; +} + + +//----------------------------------------------------------------------------- + +template +void +MeshViewerWidgetT::draw_openmesh(const std::string& _draw_mode) +{ + typename Mesh::ConstFaceIter fIt(mesh_.faces_begin()), + fEnd(mesh_.faces_end()); + + typename Mesh::ConstFaceVertexIter fvIt; + +#if defined(OM_USE_OSG) && OM_USE_OSG + if (_draw_mode == "OpenSG Indices") // -------------------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); + + if ( tex_id_ && mesh_.has_vertex_texcoords2D() ) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 0, mesh_.texcoords2D()); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tex_id_); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, tex_mode_); + } + + glDrawElements(GL_TRIANGLES, + mesh_.osg_indices()->size(), + GL_UNSIGNED_INT, + &mesh_.osg_indices()->getField()[0] ); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + else +#endif + + if (_draw_mode == "Wireframe") // ------------------------------------------- + { + glBegin(GL_TRIANGLES); + for (; fIt!=fEnd; ++fIt) + { + fvIt = mesh_.cfv_iter(fIt.handle()); + glVertex3fv( &mesh_.point(fvIt)[0] ); + ++fvIt; + glVertex3fv( &mesh_.point(fvIt)[0] ); + ++fvIt; + glVertex3fv( &mesh_.point(fvIt)[0] ); + } + glEnd(); + } + + else if (_draw_mode == "Solid Flat") // ------------------------------------- + { + glBegin(GL_TRIANGLES); + for (; fIt!=fEnd; ++fIt) + { + glNormal3fv( &mesh_.normal(fIt)[0] ); + + fvIt = mesh_.cfv_iter(fIt.handle()); + glVertex3fv( &mesh_.point(fvIt)[0] ); + ++fvIt; + glVertex3fv( &mesh_.point(fvIt)[0] ); + ++fvIt; + glVertex3fv( &mesh_.point(fvIt)[0] ); + } + glEnd(); + + } + + + else if (_draw_mode == "Solid Smooth") // ----------------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); + + if ( tex_id_ && mesh_.has_vertex_texcoords2D() ) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 0, mesh_.texcoords2D()); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tex_id_); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, tex_mode_); + } + + glBegin(GL_TRIANGLES); + for (; fIt!=fEnd; ++fIt) + { + fvIt = mesh_.cfv_iter(fIt.handle()); + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + } + glEnd(); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + if ( tex_id_ && mesh_.has_vertex_texcoords2D() ) + { + glDisable(GL_TEXTURE_2D); + } + } + + else if (_draw_mode == "Colored Vertices") // -------------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); + + if ( mesh_.has_vertex_colors() ) + { + glEnableClientState( GL_COLOR_ARRAY ); + glColorPointer(3, GL_UNSIGNED_BYTE, 0,mesh_.vertex_colors()); + } + + glBegin(GL_TRIANGLES); + for (; fIt!=fEnd; ++fIt) + { + fvIt = mesh_.cfv_iter(fIt.handle()); + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + } + glEnd(); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + } + + + else if (_draw_mode == "Solid Colored Faces") // ----------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); + + glBegin(GL_TRIANGLES); + for (; fIt!=fEnd; ++fIt) + { + glColor( fIt.handle() ); + + fvIt = mesh_.cfv_iter(fIt.handle()); + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + } + glEnd(); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + } + + + else if (_draw_mode == "Smooth Colored Faces") // --------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); + + glBegin(GL_TRIANGLES); + for (; fIt!=fEnd; ++fIt) + { + glMaterial( fIt.handle() ); + + fvIt = mesh_.cfv_iter(fIt.handle()); + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + ++fvIt; + glArrayElement(fvIt.handle().idx()); + } + glEnd(); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + } + + + else if ( _draw_mode == "Strips'n VertexArrays" ) // ------------------------ + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); + + if ( tex_id_ && mesh_.has_vertex_texcoords2D() ) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 0, mesh_.texcoords2D()); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tex_id_); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, tex_mode_); + } + + typename MyStripifier::StripsIterator strip_it = strips_.begin(); + typename MyStripifier::StripsIterator strip_last = strips_.end(); + + // Draw all strips + for (; strip_it!=strip_last; ++strip_it) + { + glDrawElements(GL_TRIANGLE_STRIP, + strip_it->size(), GL_UNSIGNED_INT, &(*strip_it)[0] ); + } + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + + + else if (_draw_mode == "Show Strips" && strips_.is_valid() ) // ------------- + { + typename MyStripifier::StripsIterator strip_it = strips_.begin(); + typename MyStripifier::StripsIterator strip_last = strips_.end(); + + float cmax = 256.0f; + int range = 220; + int base = (int)cmax-range; + int drcol = 13; + int dgcol = 31; + int dbcol = 17; + + int rcol=0, gcol=dgcol, bcol=dbcol+dbcol; + + // Draw all strips + for (; strip_it!=strip_last; ++strip_it) + { + typename MyStripifier::IndexIterator idx_it = strip_it->begin(); + typename MyStripifier::IndexIterator idx_last = strip_it->end(); + + rcol = (rcol+drcol) % range; + gcol = (gcol+dgcol) % range; + bcol = (bcol+dbcol) % range; + + glBegin(GL_TRIANGLE_STRIP); + glColor3f((rcol+base)/cmax, (gcol+base)/cmax, (bcol+base)/cmax); + for ( ;idx_it != idx_last; ++idx_it ) + glVertex3fv(&mesh_.point( OM_TYPENAME Mesh::VertexHandle(*idx_it))[0]); + glEnd(); + } + glColor3f(1.0, 1.0, 1.0); + } + + + else if( _draw_mode == "Points" ) // ----------------------------------------- + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); + + if (mesh_.has_vertex_colors() && use_color_) + { + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(3, GL_UNSIGNED_BYTE, 0, mesh_.vertex_colors()); + } + + glDrawArrays( GL_POINTS, 0, mesh_.n_vertices() ); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + } + + +} + + +//----------------------------------------------------------------------------- + + +template +void +MeshViewerWidgetT::draw_scene(const std::string& _draw_mode) +{ + + if ( ! mesh_.n_vertices() ) + return; + +#if defined(OM_USE_OSG) && OM_USE_OSG + else if ( _draw_mode == "OpenSG Indices") + { + glEnable(GL_LIGHTING); + glShadeModel(GL_SMOOTH); + draw_openmesh( _draw_mode ); + } + else +#endif + if ( _draw_mode == "Points" ) + { + glDisable(GL_LIGHTING); + draw_openmesh(_draw_mode); + } + else if (_draw_mode == "Wireframe") + { + glDisable(GL_LIGHTING); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + draw_openmesh(_draw_mode); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + + else if ( _draw_mode == "Hidden-Line" ) + { + glDisable(GL_LIGHTING); + glShadeModel(GL_FLAT); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glColor4f( 0.0f, 0.0f, 0.0f, 1.0f ); + glDepthRange(0.01, 1.0); + draw_openmesh( "Wireframe" ); + + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE); + glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); + glDepthRange( 0.0, 1.0 ); + draw_openmesh( "Wireframe" ); + + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL); + } + + else if (_draw_mode == "Solid Flat") + { + glEnable(GL_LIGHTING); + glShadeModel(GL_FLAT); + draw_openmesh(_draw_mode); + } + + else if (_draw_mode == "Solid Smooth" || + _draw_mode == "Strips'n VertexArrays" ) + { + glEnable(GL_LIGHTING); + glShadeModel(GL_SMOOTH); + draw_openmesh(_draw_mode); + } + + else if (_draw_mode == "Show Strips") + { + glDisable(GL_LIGHTING); + draw_openmesh(_draw_mode); + } + + else if (_draw_mode == "Colored Vertices" ) + { + glDisable(GL_LIGHTING); + glShadeModel(GL_SMOOTH); + draw_openmesh(_draw_mode); + } + + else if (_draw_mode == "Solid Colored Faces") + { + glDisable(GL_LIGHTING); + glShadeModel(GL_FLAT); + draw_openmesh(_draw_mode); + setDefaultMaterial(); + } + + else if (_draw_mode == "Smooth Colored Faces" ) + { + glEnable(GL_LIGHTING); + glShadeModel(GL_SMOOTH); + draw_openmesh(_draw_mode); + setDefaultMaterial(); + } + + if (show_vnormals_) + { + typename Mesh::VertexIter vit; + glDisable(GL_LIGHTING); + glBegin(GL_LINES); + glColor3f(1.000f, 0.803f, 0.027f); // orange + for(vit=mesh_.vertices_begin(); vit!=mesh_.vertices_end(); ++vit) + { + glVertex( vit ); + glVertex( mesh_.point( vit ) + normal_scale_*mesh_.normal( vit ) ); + } + glEnd(); + } + + if (show_fnormals_) + { + typename Mesh::FaceIter fit; + glDisable(GL_LIGHTING); + glBegin(GL_LINES); + glColor3f(0.705f, 0.976f, 0.270f); // greenish + for(fit=mesh_.faces_begin(); fit!=mesh_.faces_end(); ++fit) + { + glVertex( mesh_.property(fp_normal_base_, fit) ); + glVertex( mesh_.property(fp_normal_base_, fit) + + normal_scale_*mesh_.normal( fit ) ); + } + glEnd(); + } +} + + +//----------------------------------------------------------------------------- + +template +void +MeshViewerWidgetT::enable_strips() +{ + if (!f_strips_) + { + f_strips_ = true; + add_draw_mode("Strips'n VertexArrays"); + add_draw_mode("Show Strips"); + } +} + +//----------------------------------------------------------------------------- + +template +void +MeshViewerWidgetT::disable_strips() +{ + if (f_strips_) + { + f_strips_ = false; + del_draw_mode("Show Strips"); + del_draw_mode("Strip'n VertexArrays"); + } +} + + +//----------------------------------------------------------------------------- + +#define TEXMODE( Mode ) \ + tex_mode_ = Mode; std::cout << "Texture mode set to " << #Mode << std::endl + +template +void +MeshViewerWidgetT::keyPressEvent( QKeyEvent* _event) +{ + switch( _event->key() ) + { + case Key_D: + if ( mesh_.has_vertex_colors() && (current_draw_mode()=="Points") ) + { + use_color_ = !use_color_; + std::cout << "use color: " << (use_color_?"yes\n":"no\n"); + if (!use_color_) + glColor3f(1.0f, 1.0f, 1.0f); + updateGL(); + } + break; + + case Key_N: + if ( _event->modifiers() & ShiftModifier ) + { + show_fnormals_ = !show_fnormals_; + std::cout << "show face normals: " << (show_fnormals_?"yes\n":"no\n"); + } + else + { + show_vnormals_ = !show_vnormals_; + std::cout << "show vertex normals: " << (show_vnormals_?"yes\n":"no\n"); + } + updateGL(); + break; + + case Key_I: + std::cout << "\n# Vertices : " << mesh_.n_vertices() << std::endl; + std::cout << "# Edges : " << mesh_.n_edges() << std::endl; + std::cout << "# Faces : " << mesh_.n_faces() << std::endl; + std::cout << "binary input : " << opt_.check(opt_.Binary) << std::endl; + std::cout << "swapped input : " << opt_.check(opt_.Swap) << std::endl; + std::cout << "vertex normal : " + << opt_.check(opt_.VertexNormal) << std::endl; + std::cout << "vertex texcoord: " + << opt_.check(opt_.VertexTexCoord) << std::endl; + std::cout << "vertex color : " + << opt_.check(opt_.VertexColor) << std::endl; + std::cout << "face normal : " + << opt_.check(opt_.FaceNormal) << std::endl; + std::cout << "face color : " + << opt_.check(opt_.FaceColor) << std::endl; + this->QGLViewerWidget::keyPressEvent( _event ); + break; + + case Key_T: + switch( tex_mode_ ) + { + case GL_MODULATE: TEXMODE(GL_DECAL); break; + case GL_DECAL: TEXMODE(GL_BLEND); break; + case GL_BLEND: TEXMODE(GL_REPLACE); break; + case GL_REPLACE: TEXMODE(GL_MODULATE); break; + } + updateGL(); + break; + + default: + this->QGLViewerWidget::keyPressEvent( _event ); + } +} + +#undef TEXMODE + +//============================================================================= + diff --git a/Apps/QtViewer/MeshViewerWidgetT.hh b/Apps/QtViewer/MeshViewerWidgetT.hh new file mode 100644 index 00000000..ae6078fc --- /dev/null +++ b/Apps/QtViewer/MeshViewerWidgetT.hh @@ -0,0 +1,187 @@ +//============================================================================= +// +// 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: 1800 $ +// $Date: 2008-05-19 11:51:23 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +#ifndef OPENMESHAPPS_MESHVIEWERWIDGETT_HH +#define OPENMESHAPPS_MESHVIEWERWIDGETT_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +//== FORWARDS ================================================================= + +class QImage; + + +//== CLASS DEFINITION ========================================================= + + +template +class MeshViewerWidgetT : public QGLViewerWidget +{ +public: + + typedef M Mesh; + typedef OpenMesh::StripifierT MyStripifier; +public: + + /// default constructor + MeshViewerWidgetT(QWidget* _parent=0) + : QGLViewerWidget(_parent), + f_strips_(false), + tex_id_(0), + tex_mode_(GL_MODULATE), + strips_(mesh_), + use_color_(true), + show_vnormals_(false), + show_fnormals_(false) + { + add_draw_mode("Points"); + add_draw_mode("Hidden-Line"); +#if defined(OM_USE_OSG) && OM_USE_OSG + add_draw_mode("OpenSG Indices"); +#endif + } + + /// destructor + ~MeshViewerWidgetT() {} + +public: + + /// open mesh + virtual bool open_mesh(const char* _filename, OpenMesh::IO::Options _opt); + + /// load texture + virtual bool open_texture( const char *_filename ); + bool set_texture( QImage& _texsrc ); + + void enable_strips(); + void disable_strips(); + + + Mesh& mesh() { return mesh_; } + const Mesh& mesh() const { return mesh_; } + +protected: + + /// inherited drawing method + virtual void draw_scene(const std::string& _draw_mode); + +protected: + + /// draw the mesh + virtual void draw_openmesh(const std::string& _drawmode); + + + void glVertex( const typename Mesh::VertexHandle _vh ) + { glVertex3fv( &mesh_.point( _vh )[0] ); } + + void glVertex( const typename Mesh::Point& _p ) + { glVertex3fv( &_p[0] ); } + + void glNormal( const typename Mesh::VertexHandle _vh ) + { glNormal3fv( &mesh_.normal( _vh )[0] ); } + + void glTexCoord( const typename Mesh::VertexHandle _vh ) + { glTexCoord2fv( &mesh_.texcoord(_vh)[0] ); } + + void glColor( const typename Mesh::VertexHandle _vh ) + { glColor3ubv( &mesh_.color(_vh)[0] ); } + + // face properties + + void glNormal( const typename Mesh::FaceHandle _fh ) + { glNormal3fv( &mesh_.normal( _fh )[0] ); } + + void glColor( const typename Mesh::FaceHandle _fh ) + { glColor3ubv( &mesh_.color(_fh)[0] ); } + + void glMaterial( const typename Mesh::FaceHandle _fh, + int _f=GL_FRONT_AND_BACK, int _m=GL_DIFFUSE ) + { + OpenMesh::Vec3f c=OpenMesh::color_cast(mesh_.color(_fh)); + OpenMesh::Vec4f m( c[0], c[1], c[2], 1.0f ); + + glMaterialfv(_f, _m, &m[0]); + } + + +protected: // Strip support + + void compute_strips(void) + { + if (f_strips_) + { + strips_.clear(); + strips_.stripify(); + } + } + +protected: // inherited + + virtual void keyPressEvent( QKeyEvent* _event); + +protected: + + bool f_strips_; // enable/disable strip usage + GLuint tex_id_; + GLint tex_mode_; + OpenMesh::IO::Options opt_; // mesh file contained texcoords? + + Mesh mesh_; + MyStripifier strips_; + bool use_color_; + bool show_vnormals_; + bool show_fnormals_; + float normal_scale_; + OpenMesh::FPropHandleT< typename Mesh::Point > fp_normal_base_; +}; + + +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESHAPPS_MESHVIEWERWIDGET_CC) +# define OPENMESH_MESHVIEWERWIDGET_TEMPLATES +# include "MeshViewerWidgetT.cc" +#endif +//============================================================================= +#endif // OPENMESHAPPS_MESHVIEWERWIDGETT_HH defined +//============================================================================= + diff --git a/Apps/QtViewer/QGLViewerWidget.cc b/Apps/QtViewer/QGLViewerWidget.cc new file mode 100644 index 00000000..1b65cd72 --- /dev/null +++ b/Apps/QtViewer/QGLViewerWidget.cc @@ -0,0 +1,849 @@ +//============================================================================= +// +// 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: 2095 $ +// $Date: 2008-06-26 12:07:09 +0200 (Do, 26. Jun 2008) $ +// +//============================================================================= + +//== INCLUDES ================================================================= + +#ifdef _MSC_VER +# pragma warning(disable: 4267 4311 4305) +#endif + +#include +#include +#include +// -------------------- +#ifdef ARCH_DARWIN +# include +#else +# include +#endif +// -------------------- +#include +#include +#include +#include +#include +#include +#include +// -------------------- +#include +#include + +#if !defined(M_PI) +# define M_PI 3.1415926535897932 +#endif + +const double TRACKBALL_RADIUS = 0.6; + + +using namespace Qt; +using namespace OpenMesh; + + +//== IMPLEMENTATION ========================================================== + +std::string QGLViewerWidget::nomode_ = ""; + +//---------------------------------------------------------------------------- + +QGLViewerWidget::QGLViewerWidget( QWidget* _parent ) + : QGLWidget( _parent ) +{ + init(); +} + +//---------------------------------------------------------------------------- + +QGLViewerWidget:: +QGLViewerWidget( QGLFormat& _fmt, QWidget* _parent ) + : QGLWidget( _fmt, _parent ) +{ + init(); +} + + +//---------------------------------------------------------------------------- + +void +QGLViewerWidget::init(void) +{ + // qt stuff + setAttribute(Qt::WA_NoSystemBackground, true); + setFocusPolicy(Qt::StrongFocus); + setAcceptDrops( true ); + setCursor(PointingHandCursor); + + + // popup menu + + popup_menu_ = new QMenu(this); + draw_modes_group_ = new QActionGroup(this); + + connect( draw_modes_group_, SIGNAL(triggered(QAction*)), + this, SLOT(slotDrawMode(QAction*))); + + + // init draw modes + n_draw_modes_ = 0; + //draw_mode_ = 3; + QAction *a; + a = add_draw_mode("Wireframe"); + a->setShortcut(QKeySequence(Key_W)); + a = add_draw_mode("Solid Flat"); + a = add_draw_mode("Solid Smooth"); + a->setShortcut(QKeySequence(Key_S)); + a->setChecked(true); + + slotDrawMode(a); +} + + +//---------------------------------------------------------------------------- + +QGLViewerWidget::~QGLViewerWidget() +{ +} + + +//---------------------------------------------------------------------------- + +void +QGLViewerWidget::setDefaultMaterial(void) +{ + GLfloat mat_a[] = {0.1, 0.1, 0.1, 1.0}; + GLfloat mat_d[] = {0.7, 0.7, 0.5, 1.0}; + GLfloat mat_s[] = {1.0, 1.0, 1.0, 1.0}; + GLfloat shine[] = {120.0}; + + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_a); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_d); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_s); + glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shine); +} + + +//---------------------------------------------------------------------------- + +void +QGLViewerWidget::setDefaultLight(void) +{ + GLfloat pos1[] = { 0.1, 0.1, -0.02, 0.0}; + GLfloat pos2[] = {-0.1, 0.1, -0.02, 0.0}; + GLfloat pos3[] = { 0.0, 0.0, 0.1, 0.0}; + GLfloat col1[] = { 0.7, 0.7, 0.8, 1.0}; + GLfloat col2[] = { 0.8, 0.7, 0.7, 1.0}; + GLfloat col3[] = { 1.0, 1.0, 1.0, 1.0}; + + glEnable(GL_LIGHT0); + glLightfv(GL_LIGHT0,GL_POSITION, pos1); + glLightfv(GL_LIGHT0,GL_DIFFUSE, col1); + glLightfv(GL_LIGHT0,GL_SPECULAR, col1); + + glEnable(GL_LIGHT1); + glLightfv(GL_LIGHT1,GL_POSITION, pos2); + glLightfv(GL_LIGHT1,GL_DIFFUSE, col2); + glLightfv(GL_LIGHT1,GL_SPECULAR, col2); + + glEnable(GL_LIGHT2); + glLightfv(GL_LIGHT2,GL_POSITION, pos3); + glLightfv(GL_LIGHT2,GL_DIFFUSE, col3); + glLightfv(GL_LIGHT2,GL_SPECULAR, col3); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::initializeGL() +{ + // OpenGL state + glClearColor(0.0, 0.0, 0.0, 0.0); + glDisable( GL_DITHER ); + glEnable( GL_DEPTH_TEST ); + + // Material + setDefaultMaterial(); + + // Lighting + glLoadIdentity(); + setDefaultLight(); + + // Fog + GLfloat fogColor[4] = { 0.3, 0.3, 0.4, 1.0 }; + glFogi(GL_FOG_MODE, GL_LINEAR); + glFogfv(GL_FOG_COLOR, fogColor); + glFogf(GL_FOG_DENSITY, 0.35); + glHint(GL_FOG_HINT, GL_DONT_CARE); + glFogf(GL_FOG_START, 5.0f); + glFogf(GL_FOG_END, 25.0f); + + // scene pos and size + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix_); + set_scene_pos(Vec3f(0.0, 0.0, 0.0), 1.0); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::resizeGL( int _w, int _h ) +{ + update_projection_matrix(); + glViewport(0, 0, _w, _h); + updateGL(); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::paintGL() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glMatrixMode( GL_PROJECTION ); + glLoadMatrixd( projection_matrix_ ); + glMatrixMode( GL_MODELVIEW ); + glLoadMatrixd( modelview_matrix_ ); + + if (draw_mode_) + { + assert(draw_mode_ <= n_draw_modes_); + draw_scene(draw_mode_names_[draw_mode_-1]); + } +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::draw_scene(const std::string& _draw_mode) +{ + if (_draw_mode == "Wireframe") + { + glDisable(GL_LIGHTING); + glutWireTeapot(0.5); + } + + else if (_draw_mode == "Solid Flat") + { + glEnable(GL_LIGHTING); + glShadeModel(GL_FLAT); + glutSolidTeapot(0.5); + } + + else if (_draw_mode == "Solid Smooth") + { + glEnable(GL_LIGHTING); + glShadeModel(GL_SMOOTH); + glutSolidTeapot(0.5); + } +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::mousePressEvent( QMouseEvent* _event ) +{ + // popup menu + if (_event->button() == RightButton && _event->buttons()== RightButton ) + { + popup_menu_->exec(QCursor::pos()); + } + + else + { + last_point_ok_ = map_to_sphere( last_point_2D_=_event->pos(), + last_point_3D_ ); + } +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::mouseMoveEvent( QMouseEvent* _event ) +{ + QPoint newPoint2D = _event->pos(); + + // Left button: rotate around center_ + // Middle button: translate object + // Left & middle button: zoom in/out + + + float value_y; + Vec3f newPoint3D; + bool newPoint_hitSphere = map_to_sphere( newPoint2D, newPoint3D ); + + float dx = newPoint2D.x() - last_point_2D_.x(); + float dy = newPoint2D.y() - last_point_2D_.y(); + + float w = width(); + float h = height(); + + + + // enable GL context + makeCurrent(); + + + // move in z direction + if ( (_event->buttons() == (LeftButton+MidButton)) || + (_event->buttons() == LeftButton && _event->modifiers() == ControlModifier)) + { + value_y = radius_ * dy * 3.0 / h; + translate(Vec3f(0.0, 0.0, value_y)); + } + + + // move in x,y direction + else if ( (_event->buttons() == MidButton) || + (_event->buttons() == LeftButton && _event->modifiers() == AltModifier) ) + { + float z = - (modelview_matrix_[ 2]*center_[0] + + modelview_matrix_[ 6]*center_[1] + + modelview_matrix_[10]*center_[2] + + modelview_matrix_[14]) / + (modelview_matrix_[ 3]*center_[0] + + modelview_matrix_[ 7]*center_[1] + + modelview_matrix_[11]*center_[2] + + modelview_matrix_[15]); + + float aspect = w / h; + float near_plane = 0.01 * radius_; + float top = tan(fovy()/2.0f*M_PI/180.0f) * near_plane; + float right = aspect*top; + + translate(Vec3f( 2.0*dx/w*right/near_plane*z, + -2.0*dy/h*top/near_plane*z, + 0.0f)); + } + + + + // rotate + else if (_event->buttons() == LeftButton) + { + if (last_point_ok_) + { + if ( (newPoint_hitSphere = map_to_sphere(newPoint2D, newPoint3D)) ) + { + Vec3f axis = last_point_3D_ % newPoint3D; + if (axis.sqrnorm() < 1e-7) { + axis = Vec3f(1,0,0); + } else { + axis.normalize(); + } + // find the amount of rotation + Vec3f d = last_point_3D_ - newPoint3D; + float t = 0.5*d.norm()/TRACKBALL_RADIUS; + if (t<-1.0) t=-1.0; + else if (t>1.0) t=1.0; + float phi = 2.0 * asin(t); + float angle = phi * 180.0 / M_PI; + rotate( axis, angle ); + } + } + } + + + // remember this point + last_point_2D_ = newPoint2D; + last_point_3D_ = newPoint3D; + last_point_ok_ = newPoint_hitSphere; + + // trigger redraw + updateGL(); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::mouseReleaseEvent( QMouseEvent* /* _event */ ) +{ + last_point_ok_ = false; +} + + +//----------------------------------------------------------------------------- + + +void QGLViewerWidget::wheelEvent(QWheelEvent* _event) +{ + // Use the mouse wheel to zoom in/out + + float d = -(float)_event->delta() / 120.0 * 0.2 * radius_; + translate(Vec3f(0.0, 0.0, d)); + updateGL(); + _event->accept(); +} + + +//---------------------------------------------------------------------------- + + +void QGLViewerWidget::keyPressEvent( QKeyEvent* _event) +{ + switch( _event->key() ) + { + case Key_Print: + slotSnapshot(); + break; + + case Key_H: + std::cout << "Keys:\n"; + std::cout << " Print\tMake snapshot\n"; + std::cout << " C\tenable/disable back face culling\n"; + std::cout << " F\tenable/disable fog\n"; + std::cout << " I\tDisplay information\n"; + std::cout << " N\tenable/disable display of vertex normals\n"; + std::cout << " Shift N\tenable/disable display of face normals\n"; + std::cout << " Shift P\tperformance check\n"; + break; + + case Key_C: + if ( glIsEnabled( GL_CULL_FACE ) ) + { + glDisable( GL_CULL_FACE ); + std::cout << "Back face culling: disabled\n"; + } + else + { + glEnable( GL_CULL_FACE ); + std::cout << "Back face culling: enabled\n"; + } + updateGL(); + break; + + case Key_F: + if ( glIsEnabled( GL_FOG ) ) + { + glDisable( GL_FOG ); + std::cout << "Fog: disabled\n"; + } + else + { + glEnable( GL_FOG ); + std::cout << "Fog: enabled\n"; + } + updateGL(); + break; + + case Key_I: + std::cout << "Scene radius: " << radius_ << std::endl; + std::cout << "Scene center: " << center_ << std::endl; + break; + + case Key_P: + if (_event->modifiers() & ShiftModifier) + { + double fps = performance(); + std::cout << "fps: " + << std::setiosflags (std::ios_base::fixed) + << fps << std::endl; + } + break; + + case Key_Q: + case Key_Escape: + qApp->quit(); + } + _event->ignore(); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::translate( const Vec3f& _trans ) +{ + // Translate the object by _trans + // Update modelview_matrix_ + makeCurrent(); + glLoadIdentity(); + glTranslated( _trans[0], _trans[1], _trans[2] ); + glMultMatrixd( modelview_matrix_ ); + glGetDoublev( GL_MODELVIEW_MATRIX, modelview_matrix_); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::rotate( const Vec3f& _axis, float _angle ) +{ + // Rotate around center center_, axis _axis, by angle _angle + // Update modelview_matrix_ + + Vec3f t( modelview_matrix_[0]*center_[0] + + modelview_matrix_[4]*center_[1] + + modelview_matrix_[8]*center_[2] + + modelview_matrix_[12], + modelview_matrix_[1]*center_[0] + + modelview_matrix_[5]*center_[1] + + modelview_matrix_[9]*center_[2] + + modelview_matrix_[13], + modelview_matrix_[2]*center_[0] + + modelview_matrix_[6]*center_[1] + + modelview_matrix_[10]*center_[2] + + modelview_matrix_[14] ); + + makeCurrent(); + glLoadIdentity(); + glTranslatef(t[0], t[1], t[2]); + glRotated( _angle, _axis[0], _axis[1], _axis[2]); + glTranslatef(-t[0], -t[1], -t[2]); + glMultMatrixd(modelview_matrix_); + glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix_); +} + + +//---------------------------------------------------------------------------- + + +bool +QGLViewerWidget::map_to_sphere( const QPoint& _v2D, Vec3f& _v3D ) +{ + // This is actually doing the Sphere/Hyperbolic sheet hybrid thing, + // based on Ken Shoemake's ArcBall in Graphics Gems IV, 1993. + double x = (2.0*_v2D.x() - width())/width(); + double y = -(2.0*_v2D.y() - height())/height(); + double xval = x; + double yval = y; + double x2y2 = xval*xval + yval*yval; + + const double rsqr = TRACKBALL_RADIUS*TRACKBALL_RADIUS; + _v3D[0] = xval; + _v3D[1] = yval; + if (x2y2 < 0.5*rsqr) { + _v3D[2] = sqrt(rsqr - x2y2); + } else { + _v3D[2] = 0.5*rsqr/sqrt(x2y2); + } + + return true; + } + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::update_projection_matrix() +{ + makeCurrent(); + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective(45.0, (GLfloat) width() / (GLfloat) height(), + 0.01*radius_, 100.0*radius_); + glGetDoublev( GL_PROJECTION_MATRIX, projection_matrix_); + glMatrixMode( GL_MODELVIEW ); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::view_all() +{ + translate( Vec3f( -(modelview_matrix_[0]*center_[0] + + modelview_matrix_[4]*center_[1] + + modelview_matrix_[8]*center_[2] + + modelview_matrix_[12]), + -(modelview_matrix_[1]*center_[0] + + modelview_matrix_[5]*center_[1] + + modelview_matrix_[9]*center_[2] + + modelview_matrix_[13]), + -(modelview_matrix_[2]*center_[0] + + modelview_matrix_[6]*center_[1] + + modelview_matrix_[10]*center_[2] + + modelview_matrix_[14] + + 3.0*radius_) ) ); +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::set_scene_pos( const Vec3f& _cog, float _radius ) +{ + center_ = _cog; + radius_ = _radius; + glFogf( GL_FOG_START, 1.5*_radius ); + glFogf( GL_FOG_END, 3.0*_radius ); + + update_projection_matrix(); + view_all(); +} + + +//---------------------------------------------------------------------------- + + +QAction* +QGLViewerWidget::add_draw_mode(const std::string& _s) +{ + ++n_draw_modes_; + draw_mode_names_.push_back(_s); + + QActionGroup *grp = draw_modes_group_; + QAction* act = new QAction(tr(_s.c_str()), this); + act->setCheckable(true); + act->setData(n_draw_modes_); + + grp->addAction(act); + popup_menu_->addAction(act); + addAction(act, _s.c_str()); + + return act; +} + +void QGLViewerWidget::addAction(QAction* act, const char * name) +{ + names_to_actions[name] = act; + Super::addAction(act); +} +void QGLViewerWidget::removeAction(QAction* act) +{ + ActionMap::iterator it = names_to_actions.begin(), e = names_to_actions.end(); + ActionMap::iterator found = e; + for(; it!=e; ++it) { + if (it->second == act) { + found = it; + break; + } + } + if (found != e) { + names_to_actions.erase(found); +} + popup_menu_->removeAction(act); + draw_modes_group_->removeAction(act); + Super::removeAction(act); +} + +void QGLViewerWidget::removeAction(const char* name) +{ + QString namestr = QString(name); + ActionMap::iterator e = names_to_actions.end(); + + ActionMap::iterator found = names_to_actions.find(namestr); + if (found != e) { + removeAction(found->second); + } +} + +QAction* QGLViewerWidget::findAction(const char* name) +{ + QString namestr = QString(name); + ActionMap::iterator e = names_to_actions.end(); + + ActionMap::iterator found = names_to_actions.find(namestr); + if (found != e) { + return found->second; + } + return 0; +} + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::del_draw_mode(const std::string& _s) +{ + QString cmp = _s.c_str(); + QList actions_ = popup_menu_->actions(); + QList::iterator it=actions_.begin(), e=actions_.end(); + for(; it!=e; ++it) { + if ((*it)->text() == cmp) { break; } + } + +#if _DEBUG + assert( it != e ); +#else + if ( it == e ) + return; +#endif + + popup_menu_->removeAction(*it); + QActionGroup *grp = draw_modes_group_; + +} + + +//---------------------------------------------------------------------------- + + +void +QGLViewerWidget::slotDrawMode(QAction* _mode) +{ + // save draw mode + draw_mode_ = _mode->data().toInt(); + updateGL(); + + // check selected draw mode + //popup_menu_->setItemChecked(draw_mode_, true); +} + + +//---------------------------------------------------------------------------- + + +double +QGLViewerWidget::performance() +{ + setCursor( Qt::WaitCursor ); + + double fps(0.0); + + makeCurrent(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + OpenMesh::Utils::Timer timer; + + unsigned int frames = 60; + const float angle = 360.0/(float)frames; + unsigned int i; + Vec3f axis; + + glFinish(); + + timer.start(); + for (i=0, axis=Vec3f(1,0,0); iprocessEvents(); + + timer.cont(); + for (i=0, axis=Vec3f(0,1,0); iprocessEvents(); + + timer.cont(); + for (i=0, axis=Vec3f(0,0,1); i fbuffer(3*w*h); + + qApp->processEvents(); + makeCurrent(); + updateGL(); + glFinish(); + + glReadBuffer( buffer ); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + paintGL(); + glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, &fbuffer[0] ); + + unsigned int x,y,offset; + + for (y=0; y +#include +#include +#include +#include + + +//== FORWARD DECLARATIONS ===================================================== + +class QMenu; +class QActionGroup; +class QAction; + +//== CLASS DEFINITION ========================================================= + + +class QGLViewerWidget : public QGLWidget +{ + + Q_OBJECT + +public: + typedef QGLWidget Super; + + // Default constructor. + QGLViewerWidget( QWidget* _parent=0 ); + + // + QGLViewerWidget( QGLFormat& _fmt, QWidget* _parent=0 ); + + // Destructor. + virtual ~QGLViewerWidget(); + +private: + + void init(void); + +public: + + /* Sets the center and size of the whole scene. + The _center is used as fixpoint for rotations and for adjusting + the camera/viewer (see view_all()). */ + void set_scene_pos( const OpenMesh::Vec3f& _center, float _radius ); + + /* view the whole scene: the eye point is moved far enough from the + center so that the whole scene is visible. */ + void view_all(); + + /// add draw mode to popup menu, and return the QAction created + QAction *add_draw_mode(const std::string& _s); + + /// delete draw mode from popup menu + void del_draw_mode(const std::string& _s); + + const std::string& current_draw_mode() const + { return draw_mode_ ? draw_mode_names_[draw_mode_-1] : nomode_; } + + float radius() const { return radius_; } + const OpenMesh::Vec3f& center() const { return center_; } + + const GLdouble* modelview_matrix() const { return modelview_matrix_; } + const GLdouble* projection_matrix() const { return projection_matrix_; } + + float fovy() const { return 45.0f; } + + QAction* findAction(const char *name); + void addAction(QAction* action, const char* name); + void removeAction(const char* name); + void removeAction(QAction* action); + +protected: + + // draw the scene: will be called by the painGL() method. + virtual void draw_scene(const std::string& _draw_mode); + + double performance(void); + + void setDefaultMaterial(void); + void setDefaultLight(void); + +private slots: + + // popup menu clicked + void slotDrawMode(QAction *_mode); + void slotSnapshot( void ); + + +private: // inherited + + // initialize OpenGL states (triggered by Qt) + void initializeGL(); + + // draw the scene (triggered by Qt) + void paintGL(); + + // handle resize events (triggered by Qt) + void resizeGL( int w, int h ); + +protected: + + // Qt mouse events + virtual void mousePressEvent( QMouseEvent* ); + virtual void mouseReleaseEvent( QMouseEvent* ); + virtual void mouseMoveEvent( QMouseEvent* ); + virtual void wheelEvent( QWheelEvent* ); + virtual void keyPressEvent( QKeyEvent* ); + +private: + + // updates projection matrix + void update_projection_matrix(); + + // translate the scene and update modelview matrix + void translate(const OpenMesh::Vec3f& _trans); + + // rotate the scene (around its center) and update modelview matrix + void rotate(const OpenMesh::Vec3f& _axis, float _angle); + + OpenMesh::Vec3f center_; + float radius_; + + GLdouble projection_matrix_[16], + modelview_matrix_[16]; + + + // popup menu for draw mode selection + QMenu* popup_menu_; + QActionGroup* draw_modes_group_; + typedef std::map ActionMap; + ActionMap names_to_actions; + unsigned int draw_mode_; + unsigned int n_draw_modes_; + std::vector draw_mode_names_; + static std::string nomode_; + + + + // virtual trackball: map 2D screen point to unit sphere + bool map_to_sphere(const QPoint& _point, OpenMesh::Vec3f& _result); + + QPoint last_point_2D_; + OpenMesh::Vec3f last_point_3D_; + bool last_point_ok_; + +}; + + +//============================================================================= +#endif // OPENMESHAPPS_QGLVIEWERWIDGET_HH +//============================================================================= + diff --git a/Apps/QtViewer/QtViewer.pro b/Apps/QtViewer/QtViewer.pro new file mode 100644 index 00000000..88445321 --- /dev/null +++ b/Apps/QtViewer/QtViewer.pro @@ -0,0 +1,25 @@ +################################################################################ +# +################################################################################ + +contains( OPENFLIPPER , OpenFlipper ){ + include( $$TOPDIR/qmake/all.include ) +} else { + include( $$TOPDIR/OpenMesh/qmake/all.include ) +} + +INCLUDEPATH += ../../.. + +Application() +glew() +glut() +openmesh() + +DIRECTORIES = . + +# Input +HEADERS += $$getFilesFromDir($$DIRECTORIES,*.hh) +SOURCES += $$getFilesFromDir($$DIRECTORIES,*.cc) +FORMS += $$getFilesFromDir($$DIRECTORIES,*.ui) + +################################################################################ diff --git a/Apps/QtViewer/meshviewer.cc b/Apps/QtViewer/meshviewer.cc new file mode 100644 index 00000000..fce3c9df --- /dev/null +++ b/Apps/QtViewer/meshviewer.cc @@ -0,0 +1,135 @@ +//============================================================================= +// +// 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: 2051 $ +// $Date: 2008-06-20 13:57:08 +0200 (Fr, 20. Jun 2008) $ +// +//============================================================================= +#ifdef _MSC_VER +# pragma warning(disable: 4267 4311) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "MeshViewerWidget.hh" + + +void create_menu(QMainWindow &w); +void usage_and_exit(int xcode); + +int main(int argc, char **argv) +{ + // OpenGL check + QApplication::setColorSpec( QApplication::CustomColor ); + QApplication app(argc,argv); + + glutInit(&argc,argv); + + if ( !QGLFormat::hasOpenGL() ) { + QString msg = "System has no OpenGL support!"; + QMessageBox::critical( 0, QString("OpenGL"), msg + QString(argv[1]) ); + return -1; + } + + int c; + OpenMesh::IO::Options opt; + + while ( (c=getopt(argc,argv,"hbs"))!=-1 ) + { + switch(c) + { + case 'b': opt += OpenMesh::IO::Options::Binary; break; + case 'h': + usage_and_exit(0); + case 's': opt += OpenMesh::IO::Options::Swap; break; + default: + usage_and_exit(1); + } + } + // create widget + QMainWindow mainWin; + MeshViewerWidget w(&mainWin); + w.setOptions(opt); + mainWin.setCentralWidget(&w); + + create_menu(mainWin); + + // static mesh, hence use strips + w.enable_strips(); + + mainWin.resize(640, 480); + mainWin.show(); + + // load scene if specified on the command line + if ( optind < argc ) + { + w.open_mesh_gui(argv[optind]); + } + + if ( ++optind < argc ) + { + w.open_texture_gui(argv[optind]); + } + + return app.exec(); +} + +void create_menu(QMainWindow &w) +{ + using namespace Qt; + QMenu *fileMenu = w.menuBar()->addMenu(w.tr("&File")); + + QAction* openAct = new QAction(w.tr("&Open mesh..."), &w); + openAct->setShortcut(w.tr("Ctrl+O")); + openAct->setStatusTip(w.tr("Open a mesh file")); + QObject::connect(openAct, SIGNAL(triggered()), w.centralWidget(), SLOT(query_open_mesh_file())); + fileMenu->addAction(openAct); + + QAction* texAct = new QAction(w.tr("Open &texture..."), &w); + texAct->setShortcut(w.tr("Ctrl+T")); + texAct->setStatusTip(w.tr("Open a texture file")); + QObject::connect(texAct, SIGNAL(triggered()), w.centralWidget(), SLOT(query_open_texture_file())); + fileMenu->addAction(texAct); +} + +void usage_and_exit(int xcode) +{ + std::cout << "Usage: meshviewer [-s] [mesh] [texture]\n" << std::endl; + std::cout << "Options:\n" + << " -b\n" + << " Assume input to be binary.\n\n" + << " -s\n" + << " Reverse byte order, when reading binary files.\n" + << std::endl; + exit(xcode); +} diff --git a/Apps/Smoothing/Smoothing.pro b/Apps/Smoothing/Smoothing.pro new file mode 100644 index 00000000..9d77aace --- /dev/null +++ b/Apps/Smoothing/Smoothing.pro @@ -0,0 +1,25 @@ +################################################################################ +# +################################################################################ + +contains( OPENFLIPPER , OpenFlipper ){ + include( $$TOPDIR/qmake/all.include ) +} else { + include( $$TOPDIR/OpenMesh/qmake/all.include ) +} + +INCLUDEPATH += ../../.. + +Application() +glew() +glut() +openmesh() + +DIRECTORIES = . + +# Input +HEADERS += $$getFilesFromDir($$DIRECTORIES,*.hh) +SOURCES += $$getFilesFromDir($$DIRECTORIES,*.cc) +FORMS += $$getFilesFromDir($$DIRECTORIES,*.ui) + +################################################################################ diff --git a/Apps/Smoothing/smooth.cc b/Apps/Smoothing/smooth.cc new file mode 100644 index 00000000..221ab519 --- /dev/null +++ b/Apps/Smoothing/smooth.cc @@ -0,0 +1,182 @@ +//============================================================================= +// +// 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: 1800 $ +// $Date: 2008-05-19 11:51:23 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +#include +#include // include before kernel type! +#include +#include +#include +#include + + +using namespace OpenMesh; +using namespace Smoother; + + +struct MyTraits : public OpenMesh::DefaultTraits +{ +#if 1 + typedef OpenMesh::Vec3f Point; + typedef OpenMesh::Vec3f Normal; +#else + typedef OpenMesh::Vec3d Point; + typedef OpenMesh::Vec3d Normal; +#endif +}; + +typedef OpenMesh::TriMesh_ArrayKernelT MyMesh; + + +//----------------------------------------------------------------------------- + +void usage_and_exit(int _xcode) +{ + std::cout << std::endl; + std::cout << "Usage: smooth [Options] \n"; + std::cout << std::endl; + std::cout << "Options \n" + << std::endl + << " -c <0|1> \t continuity (C0,C1). Default: C1\n" + << " -t \t\t smooth tangential direction. Default: Enabled\n" + << " -n \t\t smooth normal direction. Default: Enabled\n" + << std::endl; + exit(_xcode); +} + + +//----------------------------------------------------------------------------- + + +int main(int argc, char **argv) +{ + int c; + + MyMesh mesh; + OpenMesh::Utils::Timer t; + std::string ifname; + std::string ofname; + + SmootherT::Continuity + continuity = SmootherT::C1; + + SmootherT::Component + component = SmootherT::Tangential_and_Normal; + + int iterations; + + // ---------------------------------------- evaluate command line + + while ( (c=getopt(argc, argv, "tnc:h"))!=-1 ) + { + switch(c) + { + case 'c': { + switch(*optarg) + { + case '0' : continuity = SmootherT::C0; break; + case '1' : continuity = SmootherT::C1; break; + } + break; + } + case 't': + component = component==SmootherT::Normal + ? SmootherT::Tangential_and_Normal + : SmootherT::Tangential; + break; + + case 'n': + component = component==SmootherT::Tangential + ? SmootherT::Tangential_and_Normal + : SmootherT::Normal; + break; + + case 'h': usage_and_exit(0); + case '?': + default: usage_and_exit(1); + } + } + + if (argc-optind < 3) + usage_and_exit(1); + + + // # iterations + { + std::stringstream str; str << argv[optind]; str >> iterations; + } + + + // input file + ifname = argv[++optind]; + + + // output file + ofname = argv[++optind]; + + + OpenMesh::IO::Options opt; + + // ---------------------------------------- read mesh + + omout() << "read mesh..." << std::flush; + t.start(); + OpenMesh::IO::read_mesh(mesh, ifname, opt); + t.stop(); + omout() << "done (" << t.as_string() << ")\n"; + + omout() << " #V " << mesh.n_vertices() << std::endl; + + // ---------------------------------------- smooth + + JacobiLaplaceSmootherT smoother(mesh); + smoother.initialize(component,continuity); + + omout() << "smoothing..." << std::flush; + + t.start(); + smoother.smooth(iterations); + t.stop(); + + omout() << "done ("; + omout() << t.seconds() << "s ~ "; + omout() << t.as_string() << ", " + << (iterations*mesh.n_vertices())/t.seconds() << " Vertices/s)\n"; + + // ---------------------------------------- write mesh + + omout() << "write mesh..." << std::flush; + t.start(); + OpenMesh::IO::write_mesh(mesh, ofname, opt); + t.stop(); + omout() << "done (" << t.as_string() << ")\n"; + + return 0; +} diff --git a/Apps/Subdivider/MeshViewerWidget.cc b/Apps/Subdivider/MeshViewerWidget.cc new file mode 100644 index 00000000..ff488f38 --- /dev/null +++ b/Apps/Subdivider/MeshViewerWidget.cc @@ -0,0 +1,63 @@ +//============================================================================= +// +// 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: 1800 $ +// $Date: 2008-05-19 11:51:23 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#ifdef _MSC_VER +# pragma warning(disable: 4267 4311) +#endif + + +#include +#include + + +using namespace OpenMesh; + + +//== IMPLEMENTATION ========================================================== + + +bool +MeshViewerWidget::open_mesh(const char* _filename, IO::Options _opt) +{ + if ( Base::open_mesh( _filename, _opt ) ) + { + orig_mesh_ = mesh_; + return true; + } + return false; +} + + + + +//============================================================================= diff --git a/Apps/Subdivider/MeshViewerWidget.hh b/Apps/Subdivider/MeshViewerWidget.hh new file mode 100644 index 00000000..2a63dc63 --- /dev/null +++ b/Apps/Subdivider/MeshViewerWidget.hh @@ -0,0 +1,84 @@ +//============================================================================= +// +// 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: 1800 $ +// $Date: 2008-05-19 11:51:23 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +#ifndef OPENMESHAPPS_MESHVIEWERWIDGET_HH +#define OPENMESHAPPS_MESHVIEWERWIDGET_HH + + +//== INCLUDES ================================================================= + + +// -------------------- OpenMesh +#include +#include +#include + +// + +typedef OpenMesh::Subdivider::Uniform::CompositeTraits Traits; +typedef OpenMesh::TriMesh_ArrayKernelT Mesh; + + + +//== CLASS DEFINITION ========================================================= + + + +class MeshViewerWidget : public MeshViewerWidgetT +{ +public: + typedef MeshViewerWidgetT Base; + + /// default constructor + MeshViewerWidget(QWidget* _parent=0) + : Base(_parent) + {} + + /// destructor + ~MeshViewerWidget() {} + + /// open mesh + bool open_mesh(const char* _filename, OpenMesh::IO::Options); + + Mesh& orig_mesh() { return orig_mesh_; } + const Mesh& orig_mesh() const { return orig_mesh_; } + +protected: + + Mesh orig_mesh_; + +}; + + +//============================================================================= +#endif // OPENMESHAPPS_MESHVIEWERWIDGET_HH defined +//============================================================================= + diff --git a/Apps/Subdivider/SubdivideWidget.cc b/Apps/Subdivider/SubdivideWidget.cc new file mode 100644 index 00000000..66193017 --- /dev/null +++ b/Apps/Subdivider/SubdivideWidget.cc @@ -0,0 +1,373 @@ +//============================================================================= +// +// CLASS SubdivideWidget - IMPLEMENTATION +// +//============================================================================= + +#ifndef SUBDIVIDEWIDGET_CC +#define SUBDIVIDEWIDGET_CC + +//== INCLUDES ================================================================= + + +// Qt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// OpenMesh +#include +#include +#include +#include +#include +#include + +// My stuff +#include + +// + +using namespace OpenMesh::Subdivider; + +//== IMPLEMENTATION ========================================================== + + +SubdivideWidget:: +SubdivideWidget(QWidget* _parent, const char* _name) + : QWidget(_parent), + timer_(NULL), animate_step_(0), max_animate_steps_(4), msecs_(0) +{ + + setWindowTitle( QString(_name) ); + + QVBoxLayout* vbox = new QVBoxLayout(); + + cur_topo_type = SOP_Undefined; + // sel_topo_type will be set when adding the radio button.; + + // examiner widget + viewer_widget_ = new MeshViewerWidget(); + + vbox->addWidget(viewer_widget_); + + QHBoxLayout* hbox = new QHBoxLayout(); +// hbox->setFixedSize(400, 30); + vbox->addLayout(hbox); + + // insert subdivision pushbutton + QPushButton* subdiv_button = new QPushButton( "Subdivide"); + subdiv_button->setMinimumWidth(50); + QObject::connect( subdiv_button, SIGNAL( clicked() ), + this, SLOT( subdiv_slot() ) ); + hbox->addWidget(subdiv_button); + + // insert load pushbutton + QPushButton* load_button = new QPushButton( "Load Mesh"); + load_button->setMinimumWidth(50); + QObject::connect( load_button, SIGNAL( clicked() ), + this, SLOT( load_slot() ) ); + hbox->addWidget(load_button); + + // insert save pushbutton + QPushButton* save_button = new QPushButton( "Save Mesh"); + save_button->setMinimumWidth(50); + QObject::connect( save_button, SIGNAL( clicked() ), + this, SLOT( save_slot() ) ); + hbox->addWidget(save_button); + + + // insert reset pushbutton + QPushButton* reset_button = new QPushButton( "Reset"); + reset_button->setMinimumWidth(50); + QObject::connect( reset_button, SIGNAL( clicked() ), + this, SLOT( reset_slot() ) ); + hbox->addWidget(reset_button); + + + // Create an exclusive button group: Topology Operators +// QButtonGroup *bgrp1 = new QButtonGroup( 1, QGroupBox::Vertical,"Subdivision Operators:"); + + QButtonGroup* buttonGroup = new QButtonGroup(); + + buttonGroup->setExclusive( TRUE ); + + // insert 2 radiobuttons + QRadioButton* radio1 = new QRadioButton( "Comp. Loop" ); + QRadioButton* radio2 = new QRadioButton( "Comp. SQRT(3)" ); + QRadioButton* radio3 = new QRadioButton( "Loop" ); + radio3->setChecked( TRUE ); + sel_topo_type = SOP_UniformLoop; + + QRadioButton* radio4 = new QRadioButton( "Sqrt(3)" ); + + buttonGroup->addButton(radio1, SOP_UniformCompositeLoop); + buttonGroup->addButton(radio2, SOP_UniformCompositeSqrt3); + buttonGroup->addButton(radio3, SOP_UniformLoop); + buttonGroup->addButton(radio4, SOP_UniformSqrt3); + + vbox->addWidget(radio1); + vbox->addWidget(radio2); + vbox->addWidget(radio3); + vbox->addWidget(radio4); + + QObject::connect( buttonGroup, SIGNAL( buttonPressed(int) ), + this, SLOT( slot_select_sop(int) ) ); + + + status_bar = new QStatusBar(); + status_bar->setFixedHeight(20); + status_bar->showMessage("0 Faces, 0 Edges, 0 Vertices"); + vbox->addWidget(status_bar); + + + setLayout(vbox); + + + // animation + timer_ = new QTimer(this); + connect( timer_, SIGNAL( timeout() ), this, SLOT( animate_slot() ) ); + + // -------------------- + + subdivider_[SOP_UniformCompositeLoop] = new Uniform::CompositeLoopT; + subdivider_[SOP_UniformCompositeSqrt3] = new Uniform::CompositeSqrt3T; + subdivider_[SOP_UniformLoop] = new Uniform::LoopT; + subdivider_[SOP_UniformSqrt3] = new Uniform::Sqrt3T; + +} + + +//----------------------------------------------------------------------------- + +void SubdivideWidget::slot_select_sop(int i) +{ + switch(i) + { + case SOP_UniformCompositeLoop: + case SOP_UniformCompositeSqrt3: + case SOP_UniformLoop: + case SOP_UniformSqrt3: sel_topo_type = (SOPType)i; break; + default: sel_topo_type = SOP_Undefined; + } +} + + +//----------------------------------------------------------------------------- + +void SubdivideWidget::keyPressEvent( QKeyEvent *k ) +{ + bool timerStopped = false; + if ( timer_->isActive()) + { + timer_->stop(); + timerStopped = true; + } + + switch ( k->key() ) + { + case Qt::Key_R: // reset + reset_slot(); + break; + case Qt::Key_S: // save + save_slot(); + break; + case Qt::Key_L: // load + load_slot(); + break; + + case Qt::Key_A: + + if ( timerStopped ) + break; + + if (timer_->isActive()) + { + timer_->stop(); + } + else + { + reset_slot(); + timer_->setSingleShot( true ); + timer_->start(0); + } + break; + + case ' ': // subdivide + subdiv_slot(); + } +} + + + +//----------------------------------------------------------------------------- + + +void SubdivideWidget::update() +{ + unsigned int n_faces = viewer_widget_->mesh().n_faces(); + unsigned int n_edges = viewer_widget_->mesh().n_edges(); + unsigned int n_vertices = viewer_widget_->mesh().n_vertices(); + QString message(""), temp; + message.append(temp.setNum(n_faces)); + message.append(" Faces, "); + message.append(temp.setNum(n_edges)); + message.append(" Edges, "); + message.append(temp.setNum(n_vertices)); + message.append(" Vertices. "); + if (msecs_) + { + message.append(temp.setNum(msecs_/1000.0)); + message.append("s"); + } + status_bar->showMessage(message); +} + + +//----------------------------------------------------------------------------- + + +void SubdivideWidget::reset_slot() +{ + if (cur_topo_type != SOP_Undefined) + subdivider_[cur_topo_type]->detach(); + + viewer_widget_->mesh() = viewer_widget_->orig_mesh(); + viewer_widget_->mesh().update_face_normals(); + viewer_widget_->mesh().update_vertex_normals(); + viewer_widget_->updateGL(); + update(); + cur_topo_type = SOP_Undefined; +} + + + +//----------------------------------------------------------------------------- + + +void SubdivideWidget::subdiv_slot() +{ + assert( sel_topo_type != SOP_Undefined ); + + //QTime t; + using namespace OpenMesh::Subdivider::Uniform; + + status_bar->showMessage( "processing subdivision step..."); + + if (cur_topo_type != sel_topo_type) + { + if (cur_topo_type!=SOP_Undefined) + subdivider_[cur_topo_type]->detach(); + subdivider_[cur_topo_type=sel_topo_type]->attach(viewer_widget_->mesh()); + } + + std::clog << "subdiving...\n"; + (*subdivider_[sel_topo_type])(1); + std::clog << "subdiving...done\n"; + + // Update viewer + viewer_widget_->mesh().update_normals(); + viewer_widget_->updateGL(); + + // Update status bar information + update(); +} + + +//----------------------------------------------------------------------------- + +bool +SubdivideWidget::open_mesh(const char* _filename) +{ + OpenMesh::IO::Options opt; + + if (viewer_widget_->open_mesh(_filename, opt)) + { + update(); + return true; + } + + return false; +} + + +//----------------------------------------------------------------------------- + +void +SubdivideWidget::save_slot() +{ + using OpenMesh::IO::IOManager; + + QString write_filter(IOManager().qt_write_filters().c_str()); + QString filename = QFileDialog::getSaveFileName(this, "", "", write_filter); + + if (!filename.isEmpty()){ + if (OpenMesh::IO::write_mesh(viewer_widget_->mesh(), filename.toStdString(), + OpenMesh::IO::Options::Binary) ) + std::cerr << "ok\n"; + else + std::cerr << "FAILED\n"; + } +} + + +//----------------------------------------------------------------------------- + +void +SubdivideWidget::load_slot() +{ + using OpenMesh::IO::IOManager; + + QString read_filter(IOManager().qt_read_filters().c_str()); + QString filename = + QFileDialog::getOpenFileName(this, "", "", read_filter); + + if (!filename.isNull()) + { + + if (cur_topo_type != SOP_Undefined) + subdivider_[cur_topo_type]->detach(); + + OpenMesh::IO::Options opt; + std::string file( filename.toStdString() ); + + if ( !viewer_widget_->open_mesh(file.c_str() , opt) ) + { + QString msg = "Cannot read mesh from file "; + QMessageBox::critical( this,"", msg + filename, QMessageBox::Ok ); + } + + update(); + cur_topo_type = SOP_Undefined; + } +} + + +//----------------------------------------------------------------------------- + +void +SubdivideWidget::animate_slot() +{ + if (++animate_step_ < max_animate_steps_) + { + subdiv_slot(); + } + else + { + reset_slot(); + animate_step_ = 0; + } + timer_->setSingleShot(true); + timer_->start( 500 ); +} + +//============================================================================= +#endif //SUBDIVIDEWIDGET_CC deifined +//============================================================================= diff --git a/Apps/Subdivider/SubdivideWidget.hh b/Apps/Subdivider/SubdivideWidget.hh new file mode 100644 index 00000000..b8d731f4 --- /dev/null +++ b/Apps/Subdivider/SubdivideWidget.hh @@ -0,0 +1,94 @@ +//============================================================================= +// +// CLASS SubdivideWidget +// +//============================================================================= + +#ifndef SUBDIVIDEWIDGET_HH +#define SUBDIVIDEWIDGET_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + + + + +//== CLASS DEFINITION ========================================================= + +class SubdivideWidget : public QWidget +{ + Q_OBJECT + +public: + + typedef OpenMesh::Subdivider::Uniform::SubdividerT< Mesh > Subdivider; + + enum SOPType { + SOP_UniformCompositeLoop, + SOP_UniformCompositeSqrt3, + SOP_UniformLoop, + SOP_UniformSqrt3, + SOP_Undefined + }; + + typedef std::map< SOPType, Subdivider* > SubdividerPool; + +public: + + /// constructor + SubdivideWidget(QWidget* _parent=0, const char* _name=0); + + /// destructor + ~SubdivideWidget() {}; + + + /// open mesh from _filename + bool open_mesh(const char* _filename); + + void keyPressEvent( QKeyEvent *k ); + + /// Updates Status Bar Information + QStatusBar *status_bar; + void update(); + + +private slots: + + void animate_slot(void); + void slot_select_sop(int i); + void subdiv_slot(); + void reset_slot(); + void save_slot(); + void load_slot(); + +private: + + // widgets + MeshViewerWidget* viewer_widget_; + + QTimer *timer_; + + int animate_step_; + int max_animate_steps_; + int msecs_; + + // Selected and current subdivision operator + SOPType sel_topo_type; // selected operator + SOPType cur_topo_type; // active operator + + // + SubdividerPool subdivider_; + +}; + + +//============================================================================= +#endif // SUBDIVIDEWIDGET_HH defined +//============================================================================= + diff --git a/Apps/Subdivider/Subdivider.pro b/Apps/Subdivider/Subdivider.pro new file mode 100644 index 00000000..837e9af1 --- /dev/null +++ b/Apps/Subdivider/Subdivider.pro @@ -0,0 +1,26 @@ +################################################################################ +# +################################################################################ + +contains( OPENFLIPPER , OpenFlipper ){ + include( $$TOPDIR/qmake/all.include ) +} else { + include( $$TOPDIR/OpenMesh/qmake/all.include ) +} + +INCLUDEPATH += ../../.. + +Application() +glew() +glut() +openmesh() + +DIRECTORIES = . ../QtViewer + +# Input +HEADERS += $$getFilesFromDir($$DIRECTORIES,*.hh) +SOURCES += $$getFilesFromDir($$DIRECTORIES,*.cc) +SOURCES -= ../QtViewer/meshviewer.cc +FORMS += $$getFilesFromDir($$DIRECTORIES,*.ui) + +################################################################################ diff --git a/Apps/Subdivider/adaptive_subdivider.cc b/Apps/Subdivider/adaptive_subdivider.cc new file mode 100644 index 00000000..b67fb716 --- /dev/null +++ b/Apps/Subdivider/adaptive_subdivider.cc @@ -0,0 +1,467 @@ +// ============================================================================ + +// -------------------------------------------------------------- includes ---- + +// -------------------- OpenMesh +#include +#include +#include +#include +// -------------------- OpenMesh Adaptive Composite Subdivider +#include +#include +// -------------------- STL +#include +#include +#include +#if defined(OM_CC_MIPS) +# include +#else +# include + using std::pow; +#endif + + +using OpenMesh::Subdivider::Adaptive::CompositeTraits; + +// define mesh, rule interface, and subdivider types +typedef OpenMesh::TriMesh_ArrayKernelT MyMesh; +typedef OpenMesh::Subdivider::Adaptive::RuleInterfaceT Rule; +typedef OpenMesh::Subdivider::Adaptive::CompositeT Subdivider; + +// ---------------------------------------------------------------------------- + +using namespace OpenMesh::Subdivider; + +// factory function to add a RULE to a subdivider +#define ADD_FN( RULE ) \ + bool add_ ## RULE( Subdivider& _sub ) \ + { return _sub.add< Adaptive:: RULE < MyMesh > >(); } + +ADD_FN( Tvv3 ); +ADD_FN( Tvv4 ); +ADD_FN( VF ); +ADD_FN( FF ); +ADD_FN( FFc ); +ADD_FN( FV ); +ADD_FN( FVc ); +ADD_FN( VV ); +ADD_FN( VVc ); +ADD_FN( VE ); +ADD_FN( VdE ); +ADD_FN( VdEc ); +ADD_FN( EV ); +ADD_FN( EVc ); +ADD_FN( EF ); +ADD_FN( FE ); +ADD_FN( EdE ); +ADD_FN( EdEc ); + +#undef ADD_FN + +typedef bool (*add_rule_ft)( Subdivider& ); + +// map rule name to factory function +struct RuleMap : std::map< std::string, add_rule_ft > +{ + RuleMap() + { +#define ADD( RULE ) \ + (*this)[ #RULE ] = add_##RULE; + + ADD( Tvv3 ); + ADD( Tvv4 ); + ADD( VF ); + ADD( FF ); + ADD( FFc ); + ADD( FV ); + ADD( FVc ); + ADD( VV ); + ADD( VVc ); + ADD( VE ); + ADD( VdE ); + ADD( VdEc ); + ADD( EV ); + ADD( EVc ); + ADD( EF ); + ADD( FE ); + ADD( EdE ); + ADD( EdEc ); + +#undef ADD + } + +} available_rules; + + +// ---------------------------------------------------------------------------- + +std::string basename( const std::string& _fname ); +void usage_and_exit(const std::string& _fname, int xcode); + +// ---------------------------------------------------------------------------- + + +int main(int argc, char **argv) +{ + size_t n_iter = 0; // n iteration + size_t max_nv = size_t(-1); // max. number of vertices in the end + std::string ifname; // input mesh + std::string ofname; // output mesh + std::string rule_sequence = "Tvv3 VF FF FVc"; // sqrt3 default + bool uniform = false; + int c; + + // ---------------------------------------- evaluate command line + while ( (c=getopt(argc, argv, "hlm:n:r:sU"))!=-1 ) + { + switch(c) + { + case 's': rule_sequence = "Tvv3 VF FF FVc"; break; // sqrt3 + case 'l': rule_sequence = "Tvv4 VdE EVc VdE EVc"; break; // loop + case 'n': { std::stringstream s; s << optarg; s >> n_iter; } break; + case 'm': { std::stringstream s; s << optarg; s >> max_nv; } break; + case 'r': rule_sequence = optarg; break; + case 'U': uniform = true; break; + case 'h': usage_and_exit(argv[0],0); + case '?': + default: usage_and_exit(argv[0],1); + } + } + + if ( optind == argc ) + usage_and_exit(argv[0],2); + + if ( optind < argc ) + ifname = argv[optind++]; + + if ( optind < argc ) + ofname = argv[optind++]; + + // if ( optind < argc ) // too many arguments + + // ---------------------------------------- mesh and subdivider + MyMesh mesh; + Subdivider subdivider(mesh); + + + // -------------------- read mesh from file + std::cout << "Input mesh : " << ifname << std::endl; + if (!OpenMesh::IO::read_mesh(mesh, ifname)) + { + std::cerr << " Error reading file!\n"; + return 1; + } + + // store orignal size of mesh + size_t n_vertices = mesh.n_vertices(); + size_t n_edges = mesh.n_edges(); + size_t n_faces = mesh.n_faces(); + + if ( n_iter > 0 ) + std::cout << "Desired #iterations: " << n_iter << std::endl; + + if ( max_nv < size_t(-1) ) + { + std::cout << "Desired max. #V : " << max_nv << std::endl; + if (!n_iter ) + n_iter = size_t(-1); + } + + + // -------------------- Setup rule sequence + { + std::stringstream s; + std::string token; + + RuleMap::iterator it = available_rules.end(); + + for (s << rule_sequence; s >> token; ) + { + if ( (it=available_rules.find( token )) != available_rules.end() ) + { + it->second( subdivider ); + } + else if ( token[0]=='(' && (subdivider.n_rules() > 0) ) + { + std::string::size_type beg(1); + if (token.length()==1) + { + s >> token; + beg = 0; + } + + std::string::size_type + end = token.find_last_of(')'); + std::string::size_type + size = end==std::string::npos ? token.size()-beg : end-beg; + + std::stringstream v; + MyMesh::Scalar coeff; + std::cout << " " << token << std::endl; + std::cout << " " << beg << " " << end << " " << size << std::endl; + v << token.substr(beg, size); + v >> coeff; + std::cout << " coeffecient " << coeff << std::endl; + subdivider.rule( subdivider.n_rules()-1 ).set_coeff(coeff); + + if (end == std::string::npos) + { + s >> token; + if (token[0]!=')') + { + std::cerr << "Syntax error: Missing ')'\n"; + return 1; + } + } + } + else + { + std::cerr << "Syntax error: " << token << "?\n"; + return 1; + } + } + } + + std::cout << "Rule sequence : " + << subdivider.rules_as_string() << std::endl; + + // -------------------- Initialize subdivider + std::cout << "Initialize subdivider\n"; + if (!subdivider.initialize()) + { + std::cerr << " Error!\n"; + return 1; + } + + // + MyMesh::FaceFaceIter ff_it; + double quality(0.0), face_quality, temp_quality; + int valence; + + // ---------------------------------------- subdivide + std::cout << "\nSubdividing...\n"; + + OpenMesh::Utils::Timer timer, timer2; + size_t i; + + if ( uniform ) + { // unifom + MyMesh::VertexHandle vh; + MyMesh::VertexIter v_it; + MyMesh::FaceHandle fh; + MyMesh::FaceIter f_it; + + + // raise all vertices to target state + timer.start(); + + size_t n = n_iter; + size_t n_rules = subdivider.n_rules(); + + i = 0; + + // calculate target states for faces and vertices + int target1 = (n - 1) * n_rules + subdivider.subdiv_rule().number() + 1; + int target2 = n * n_rules; + + for (f_it = mesh.faces_begin(); f_it != mesh.faces_end(); ++f_it) { + + if (mesh.data(f_it).state() < target1) { + ++i; + fh = f_it.handle(); + timer2.start(); + subdivider.refine(fh); + timer2.stop(); + } + } + + for (v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it) { + + if (mesh.data(v_it).state() < target2) { + vh = v_it.handle(); + timer2.cont(); + subdivider.refine(vh); + timer2.stop(); + } + } + timer.stop(); + } + else + { // adaptive + + MyMesh::FaceIter f_it; + MyMesh::FaceHandle fh; + + std::vector __acos; + size_t buckets(3000); + double range(2.0); + double range2bucket(buckets/range); + + for (i = 0; i < buckets; ++i) + __acos.push_back( acos(-1.0 + i * range / buckets) ); + + timer.start(); // total time needed + + // n iterations or until desired number of vertices reached approx. + for (i = 0; i < n_iter && mesh.n_vertices() < max_nv; ++i) + { + mesh.update_face_normals(); + + // calculate quality + quality = 0.0; + + fh = mesh.faces_begin().handle(); + + // check every face + for (f_it = mesh.faces_begin(); f_it != mesh.faces_end(); ++f_it) { + + face_quality = 0.0; + valence = 0; + + for (ff_it = mesh.ff_iter(f_it.handle()); ff_it; ++ff_it) { + + temp_quality = OpenMesh::dot( mesh.normal(f_it), + mesh.normal(ff_it) ); + + if (temp_quality >= 1.0) + temp_quality = .99; + else if (temp_quality <= -1.0) + temp_quality = -.99; + temp_quality = (1.0+temp_quality) * range2bucket; + face_quality += __acos[int(temp_quality+.5)]; + + ++valence; + } + + face_quality /= valence; + + // calaculate face area + MyMesh::Point p1, p2, p3; + MyMesh::Scalar area; + +#define heh halfedge_handle +#define nheh next_halfedge_handle +#define tvh to_vertex_handle +#define fvh from_vertex_handle + p1 = mesh.point(mesh.tvh(mesh.heh(f_it.handle()))); + p2 = mesh.point(mesh.fvh(mesh.heh(f_it.handle()))); + p3 = mesh.point(mesh.tvh(mesh.nheh(mesh.heh(f_it.handle())))); +#undef heh +#undef nheh +#undef tvh +#undef fvh + + area = ((p2 - p1) % (p3 - p1)).norm(); + + // weight face_quality + face_quality *= pow(double(area), double(.1)); + //face_quality *= area; + + if (face_quality >= quality && !mesh.is_boundary(f_it.handle())) + { + quality = face_quality; + fh = f_it.handle(); + } + } + + // Subdivide Face + timer2.cont(); + subdivider.refine(fh); + timer2.stop(); + } + + // calculate time + timer.stop(); + + } // uniform/adaptive? + + // calculate maximum refinement level + Adaptive::state_t max_level(0); + + for (MyMesh::VertexIter v_it = mesh.vertices_begin(); + v_it != mesh.vertices_end(); ++v_it) + { + if (mesh.data(v_it).state() > max_level) + max_level = mesh.data(v_it).state(); + } + + + // output results + std::cout << "\nDid " << i << (uniform ? " uniform " : "" ) + << " subdivision steps in " + << timer.as_string() + << ", " << i/timer.seconds() << " steps/s\n"; + std::cout << " only refinement: " << timer2.as_string() + << ", " << i/timer2.seconds() << " steps/s\n\n"; + + std::cout << "Before: "; + std::cout << n_vertices << " Vertices, "; + std::cout << n_edges << " Edges, "; + std::cout << n_faces << " Faces. \n"; + + std::cout << "Now : "; + std::cout << mesh.n_vertices() << " Vertices, "; + std::cout << mesh.n_edges() << " Edges, "; + std::cout << mesh.n_faces() << " Faces. \n\n"; + + std::cout << "Maximum quality : " << quality << std::endl; + std::cout << "Maximum Subdivision Level: " << max_level/subdivider.n_rules() + << std::endl << std::endl; + + // ---------------------------------------- write mesh to file + { + if ( ofname.empty() ) + { + std::stringstream s; + + s << "result." << subdivider.rules_as_string("_") + << "-" << i << "x.off"; + s >> ofname; + } + + std::cout << "Output file: '" << ofname << "'.\n"; + if (!OpenMesh::IO::write_mesh(mesh, ofname, OpenMesh::IO::Options::Binary)) + { + std::cerr << " Error writing file!\n"; + return 1; + } + } + return 0; +} + +// ---------------------------------------------------------------------------- +// helper + +void usage_and_exit(const std::string& _fname, int xcode) +{ + using namespace std; + + cout << endl + << "Usage: " << basename(_fname) + << " [Options] input-mesh [output-mesh]\n\n"; + cout << "\tAdaptively refine an input-mesh. The refined mesh is stored in\n" + << "\ta file named \"result.XXX.off\" (binary .off), if not specified\n" + << "\texplicitely (optional 2nd parameter of command line).\n\n"; + cout << "Options:\n\n"; + cout << "-m \n\tAdaptively refine up to approx. vertices.\n\n" + << "-n \n\tAdaptively refine times.\n\n" + << "-r \n\tDefine a custom rule sequence.\n\n" + << "-l\n\tUse rule sequence for adaptive Loop.\n\n" + << "-s\n\tUse rule sequence for adaptive sqrt(3).\n\n" + << "-U\n\tRefine mesh uniformly (simulates uniform subdivision).\n\n"; + + exit(xcode); +} + +std::string basename(const std::string& _f) +{ + std::string::size_type dot = _f.rfind("/"); + if (dot == std::string::npos) + return _f; + return _f.substr(dot+1, _f.length()-(dot+1)); +} + +// ---------------------------------------------------------------------------- +// end of file +// ============================================================================ diff --git a/Apps/Subdivider/qtsubdivider.cc b/Apps/Subdivider/qtsubdivider.cc new file mode 100644 index 00000000..3deba500 --- /dev/null +++ b/Apps/Subdivider/qtsubdivider.cc @@ -0,0 +1,72 @@ +//============================================================================= +// +// 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. +// +//============================================================================= +#ifdef _MSC_VER +# pragma warning(disable: 4267 4311) +#endif + +#include +#include + +#include +#include +#include "SubdivideWidget.hh" + +#include + +int main(int argc, char **argv) +{ + // OpenGL check + QApplication::setColorSpec( QApplication::CustomColor ); + QApplication app(argc,argv); + + glutInit(&argc,argv); + + if ( !QGLFormat::hasOpenGL() ) { + QString msg = "System has no OpenGL support!"; + QMessageBox::critical( NULL, "OpenGL", msg + argv[1], QMessageBox::Ok ); + return -1; + } + + + // create widget + SubdivideWidget* w = new SubdivideWidget(0, "Subdivider"); + + w->resize(400, 400); + w->show(); + + // load scene + if (argc > 1) + { + if ( ! w->open_mesh(argv[1]) ) + { + QString msg = "Cannot read mesh from file "; + QMessageBox::critical( NULL, argv[1], msg + argv[1], QMessageBox::Ok ); + return -1; + } + } + + + return app.exec(); +} diff --git a/Apps/Subdivider/subdivider.cc b/Apps/Subdivider/subdivider.cc new file mode 100644 index 00000000..b05df693 --- /dev/null +++ b/Apps/Subdivider/subdivider.cc @@ -0,0 +1,288 @@ +//============================================================================= +// +// 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: 1800 $ +// $Date: 2008-05-19 11:51:23 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +#include +#include +// ---------------------------------------- OpenMesh Stuff +#include +#include +#include +#include +// ---------------------------------------- Subdivider +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- + +using namespace OpenMesh::Subdivider; + +typedef OpenMesh::Subdivider::Uniform::CompositeTraits CTraits; +typedef OpenMesh::TriMesh_ArrayKernelT CMesh; + +typedef OpenMesh::TriMesh_ArrayKernelT<> Mesh; +typedef Uniform::Sqrt3T< Mesh > Sqrt3; +typedef Uniform::LoopT< Mesh > Loop; +typedef Uniform::CompositeSqrt3T< CMesh > CompositeSqrt3; +typedef Uniform::CompositeLoopT< CMesh > CompositeLoop; + +using OpenMesh::Utils::Timer; + +// ---------------------------------------------------------------------------- + +std::map< std::string, double > timings; + +// ---------------------------------------------------------------------------- + +template < typename Subdivider > +bool subdivide( typename Subdivider::mesh_t& _m, size_t _n, + Timer::Format _fmt ) +{ + bool rc; + Timer t; + Subdivider subdivide; + + std::cout << "Subdivide " << _n + << " times with '" << subdivide.name() << "'\n"; + + subdivide.attach(_m); + t.start(); + rc=subdivide( _n ); + t.stop(); + subdivide.detach(); + + if (rc) + { + std::cout << " Done [" << t.as_string(_fmt) << "]\n"; + timings[subdivide.name()] = t.seconds(); + } + else + std::cout << " Failed!\n"; + return rc; +} + +// ---------------------------------------------------------------------------- + +void usage_and_exit(int _xcode); + +// ---------------------------------------------------------------------------- + +template < typename Subdivider > +int mainT( size_t _n, + const std::string& _ifname, + const std::string& _ofname, + const Timer::Format _fmt ) +{ + // -------------------- read mesh + std::cout << "Read mesh from file " << _ifname << std::endl; + + typename Subdivider::mesh_t mesh; + + if ( OpenMesh::IO::read_mesh( mesh, _ifname ) ) + std::cout << " Ok\n"; + else + { + std::cout << " Failed!\n"; + return 1; + } + + std::cout << " #V " << mesh.n_vertices() + << ", #F " << mesh.n_faces() + << ", #E " << mesh.n_edges() << std::endl; + + // -------------------- subdividing + try + { + if (!subdivide< Subdivider >( mesh, _n, _fmt )) + return 1; + } + catch(std::bad_alloc& x) + { + std::cerr << "Out of memory: " << x.what() << std::endl; + return 1; + } + catch(std::exception& x) + { + std::cerr << x.what() << std::endl; + return 1; + } + catch(...) + { + std::cerr << "Unknown exception!\n"; + return 1; + } + + // -------------------- write mesh + + std::cout << " #V " << mesh.n_vertices() + << ", #F " << mesh.n_faces() + << ", #E " << mesh.n_edges() << std::endl; + + if ( !_ofname.empty() ) + { + std::cout << "Write resulting mesh to file " << _ofname << ".."; + if (OpenMesh::IO::write_mesh(mesh, _ofname, OpenMesh::IO::Options::Binary)) + { + std::cout << "ok\n"; + } + else + { + std::cerr << "Failed! Could not write file!\n"; + return 1; + } + } + + return 0; +} + +// ---------------------------------------------------------------------------- + +int main(int argc, char **argv) +{ + int c; + + bool compare_all = false; + size_t n; + std::string ifname; + std::string ofname; + + enum { + TypeSqrt3, + TypeLoop, + TypeCompSqrt3, + TypeCompLoop + } st = TypeSqrt3; + + Timer::Format fmt = Timer::Automatic; + + while ( (c=getopt(argc, argv, "csSlLhf:"))!=-1 ) + { + switch(c) + { + case 'c': compare_all=true; break; + case 's': st = TypeSqrt3; break; + case 'S': st = TypeCompSqrt3; break; + case 'l': st = TypeLoop; break; + case 'L': st = TypeCompLoop; break; + case 'f': + { + switch(*optarg) + { + case 'm': fmt = Timer::MSeconds; break; + case 'c': fmt = Timer::HSeconds; break; + case 's': fmt = Timer::Seconds; break; + case 'a': + default: fmt = Timer::Automatic; break; + } + break; + } + case 'h': usage_and_exit(0); + case '?': + default: usage_and_exit(1); + } + } + + if (argc-optind < 2) + usage_and_exit(1); + + // # iterations + { + std::stringstream str; str << argv[optind]; str >> n; + } + + // input file + ifname = argv[++optind]; + + // output file, if provided + if ( ++optind < argc ) + ofname = argv[optind]; + + + // -------------------- + if ( compare_all ) + { + int rc; + rc = mainT ( n, ifname, "", fmt ); + rc += mainT ( n, ifname, "", fmt ); + rc += mainT( n, ifname, "", fmt ); + rc += mainT ( n, ifname, "", fmt ); + + if (rc) + return rc; + + std::cout << std::endl; + + std::map< std::string, double >::iterator it; + + std::cout << "Timings:\n"; + for(it = timings.begin();it!=timings.end();++it) + std::cout << it->first << ": " << Timer::as_string(it->second) + << std::endl; + std::cout << std::endl; + std::cout << "Ratio composite/native algorithm:\n"; + std::cout << "sqrt(3): " + << timings["Uniform Composite Sqrt3"]/timings["Uniform Sqrt3"] + << std::endl + << "loop : " + << timings["Uniform Composite Loop"]/timings["Uniform Loop"] + << std::endl; + return 0; + } + else switch(st) + { + case TypeSqrt3: + return mainT( n, ifname, ofname, fmt ); + case TypeLoop: + return mainT( n, ifname, ofname, fmt ); + case TypeCompSqrt3: + return mainT( n, ifname, ofname, fmt ); + case TypeCompLoop: + return mainT ( n, ifname, ofname, fmt ); + } + return 1; +} + +// ---------------------------------------------------------------------------- + +void usage_and_exit(int _xcode) +{ + std::cout << "Usage: subdivide [Subdivider Type] #Iterations Input [Output].\n"; + std::cout << std::endl; + std::cout << "Subdivider Type\n" + << std::endl + << " -l\tLoop\n" + << " -L\tComposite Loop\n" + << " -s\tSqrt3\n" + << " -S\tComposite Sqrt3\n" + << std::endl; + exit(_xcode); +} diff --git a/Apps/VDProgMesh/Analyzer/Analyzer.pro b/Apps/VDProgMesh/Analyzer/Analyzer.pro new file mode 100644 index 00000000..26505412 --- /dev/null +++ b/Apps/VDProgMesh/Analyzer/Analyzer.pro @@ -0,0 +1,30 @@ +################################################################################ +# +################################################################################ + +contains( OPENFLIPPER , OpenFlipper ){ + include( $$TOPDIR/qmake/all.include ) +} else { + include( $$TOPDIR/OpenMesh/qmake/all.include ) +} + +INCLUDEPATH += ../../../.. + +CONFIG += glew glut + +Application() + +LIBS += -Wl,-rpath=$${TOPDIR}/OpenMesh/Core/lib/$${BUILDDIRECTORY} -lCore +LIBS += -Wl,-rpath=$${TOPDIR}/OpenMesh/Tools/lib/$${BUILDDIRECTORY} -lTools +LIBS += -lglut +QMAKE_LIBDIR += $${TOPDIR}/OpenMesh/Core/lib/$${BUILDDIRECTORY} +QMAKE_LIBDIR += $${TOPDIR}/OpenMesh/Tools/lib/$${BUILDDIRECTORY} + +DIRECTORIES = . + +# Input +HEADERS += $$getFilesFromDir($$DIRECTORIES,*.hh) +SOURCES += $$getFilesFromDir($$DIRECTORIES,*.cc) +FORMS += $$getFilesFromDir($$DIRECTORIES,*.ui) + +################################################################################ diff --git a/Apps/VDProgMesh/Analyzer/vdpmanalyzer.cc b/Apps/VDProgMesh/Analyzer/vdpmanalyzer.cc new file mode 100644 index 00000000..d40230e4 --- /dev/null +++ b/Apps/VDProgMesh/Analyzer/vdpmanalyzer.cc @@ -0,0 +1,1161 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +// -------------------------------------------------------------- includes ---- + +#include +// -------------------- STL +#include +#include +#include +#include +#include +#include +// -------------------- OpenMesh +#include +#include +#include +#include +#include +// -------------------- OpenMesh VDPM +#include +#include +#include +#include + +// ---------------------------------------------------------------------------- + + +// ---------------------------------------------------------------------------- + +using namespace OpenMesh; + +// ---------------------------------------------------------------------------- + +// using view dependent progressive mesh +using VDPM::Plane3d; +using VDPM::VFront; +using VDPM::VHierarchy; +using VDPM::VHierarchyNode; +using VDPM::VHierarchyNodeIndex; +using VDPM::VHierarchyNodeHandle; +using VDPM::VHierarchyNodeHandleContainer; +using VDPM::ViewingParameters; + + +// ------------------------------------------------------------- mesh type ---- +// Generate an OpenMesh suitable for the analyzing task + +struct AnalyzerTraits : public DefaultTraits +{ + VertexTraits + { + public: + + VHierarchyNodeHandle vhierarchy_node_handle() + { return node_handle_; } + + void set_vhierarchy_node_handle(VHierarchyNodeHandle _node_handle) + { node_handle_ = _node_handle; } + + bool is_ancestor(const VHierarchyNodeIndex &_other) + { return false; } + + private: + + VHierarchyNodeHandle node_handle_; + + }; + + + HalfedgeTraits + { + public: + + VHierarchyNodeHandle + vhierarchy_leaf_node_handle() + { return leaf_node_handle_; } + + void + set_vhierarchy_leaf_node_handle(VHierarchyNodeHandle _leaf_node_handle) + { leaf_node_handle_ = _leaf_node_handle; } + + private: + + VHierarchyNodeHandle leaf_node_handle_; + + }; + + VertexAttributes(Attributes::Status | + Attributes::Normal); + HalfedgeAttributes(Attributes::PrevHalfedge); + EdgeAttributes(Attributes::Status); + FaceAttributes(Attributes::Status | + Attributes::Normal); + +}; + +typedef TriMesh_ArrayKernelT Mesh; + +// ----------------------------------------------------------------- types ---- + +struct PMInfo +{ + Mesh::Point p0; + Mesh::VertexHandle v0, v1, vl, vr; +}; + +typedef std::vector PMInfoContainer; +typedef PMInfoContainer::iterator PMInfoIter; +typedef std::vector VertexHandleContainer; +typedef std::vector ResidualContainer; + + +// -------------------------------------------------------------- forwards ---- + +/// open progressive mesh +void open_prog_mesh(const std::string &_filename); + +/// save view-dependent progressive mesh +void save_vd_prog_mesh(const std::string &_filename); + + +/// locate fundamental cut vertices +void locate_fund_cut_vertices(); + +void create_vertex_hierarchy(); + + +/// refine mesh up to _n vertices +void refine(unsigned int _n); + +/// coarsen mesh down to _n vertices +void coarsen(unsigned int _n); + +void vdpm_analysis(); + +void get_leaf_node_handles(VHierarchyNodeHandle node_handle, + VHierarchyNodeHandleContainer &leaf_nodes); +void compute_bounding_box(VHierarchyNodeHandle node_handle, + VHierarchyNodeHandleContainer &leaf_nodes); +void compute_cone_of_normals(VHierarchyNodeHandle node_handle, + VHierarchyNodeHandleContainer &leaf_nodes); +void compute_screen_space_error(VHierarchyNodeHandle node_handle, + VHierarchyNodeHandleContainer &leaf_nodes); +void compute_mue_sigma(VHierarchyNodeHandle node_handle, + ResidualContainer &residuals); + +Vec3f +point2triangle_residual(const Vec3f &p, + const Vec3f tri[3], float &s, float &t); + + +void PrintOutFundCuts(); +void PrintVertexNormals(); + +// --------------------------------------------------------------- globals ---- +// mesh data + +Mesh mesh_; +PMInfoContainer pminfos_; +PMInfoIter pmiter_; + +VHierarchy vhierarchy_; + +unsigned int n_base_vertices_, n_base_faces_, n_details_; +unsigned int n_current_res_; +unsigned int n_max_res_; +bool verbose = false; + + +// ---------------------------------------------------------------------------- + +void usage_and_exit(int xcode) +{ + using namespace std; + + cout << "Usage: vdpmanalyzer [-h] [-o output.spm] input.pm\n"; + + exit(xcode); +} + +// ---------------------------------------------------------------------------- + +inline +std::string& +replace_extension( std::string& _s, const std::string& _e ) +{ + std::string::size_type dot = _s.rfind("."); + if (dot == std::string::npos) + { _s += "." + _e; } + else + { _s = _s.substr(0,dot+1)+_e; } + return _s; +} + +// ---------------------------------------------------------------------------- + +inline +std::string +basename(const std::string& _f) +{ + std::string::size_type dot = _f.rfind("/"); + if (dot == std::string::npos) + return _f; + return _f.substr(dot+1, _f.length()-(dot+1)); +} + + +// ---------------------------------------------------------------------------- +// just for debugging + +typedef std::vector MyPoints; +typedef MyPoints::iterator MyPointsIter; + +MyPoints projected_points; +MyPoints original_points; + + +// ------------------------------------------------------------------ main ---- + + +int main(int argc, char **argv) +{ + int c; + std::string ifname; + std::string ofname; + + while ( (c=getopt(argc, argv, "o:"))!=-1 ) + { + switch(c) + { + case 'v': verbose = true; break; + case 'o': ofname = optarg; break; + case 'h': usage_and_exit(0); + default: usage_and_exit(1); + } + } + + if (optind >= argc) + usage_and_exit(1); + + ifname = argv[optind]; + + if (ofname == "." || ofname == ".." ) + ofname += "/" + basename(ifname); + std::string spmfname = ofname.empty() ? ifname : ofname; + replace_extension(spmfname, "spm"); + + if ( ifname.empty() || spmfname.empty() ) + { + usage_and_exit(1); + } + + try + { + open_prog_mesh(ifname); + vdpm_analysis(); + save_vd_prog_mesh(spmfname.c_str()); + } + catch( std::bad_alloc& ) + { + std::cerr << "Error: out of memory!\n" << std::endl; + return 1; + } + catch( std::exception& x ) + { + std::cerr << "Error: " << x.what() << std::endl; + return 1; + } + catch( ... ) + { + std::cerr << "Fatal! Unknown error!\n"; + return 1; + } + return 0; +} + + +// ---------------------------------------------------------------------------- + +void +open_prog_mesh(const std::string& _filename) +{ + Mesh::Point p; + unsigned int i, i0, i1, i2; + unsigned int v1, vl, vr; + char c[10]; + VertexHandle vertex_handle; + VHierarchyNodeHandle node_handle, lchild_handle, rchild_handle; + VHierarchyNodeIndex node_index; + + std::ifstream ifs(_filename.c_str(), std::ios::binary); + if (!ifs) + { + std::cerr << "read error\n"; + exit(1); + } + + // + bool swap = Endian::local() != Endian::LSB; + + // read header + ifs.read(c, 8); c[8] = '\0'; + if (std::string(c) != std::string("ProgMesh")) + { + std::cerr << "Wrong file format.\n"; + ifs.close(); + exit(1); + } + IO::restore(ifs, n_base_vertices_, swap); + IO::restore(ifs, n_base_faces_, swap); + IO::restore(ifs, n_details_, swap); + + vhierarchy_.set_num_roots(n_base_vertices_); + + for (i=0; i handle2index_map; + + std::ofstream ofs(_filename.c_str(), std::ios::binary); + if (!ofs) + { + std::cerr << "write error\n"; + exit(1); + } + + // + bool swap = Endian::local() != Endian::LSB; + + // write header + ofs << "VDProgMesh"; + + IO::store(ofs, n_base_vertices_, swap); + IO::store(ofs, n_base_faces_, swap); + IO::store(ofs, n_details_, swap); + + // write base mesh + coarsen(0); + mesh_.garbage_collection( false, true, true ); + + for (i=0; iv0, + pmiter_->v1, + pmiter_->vl, + pmiter_->vr); + + VHierarchyNodeHandle + parent_handle = mesh_.data(pmiter_->v1).vhierarchy_node_handle(); + + VHierarchyNodeHandle + lchild_handle = vhierarchy_.lchild_handle(parent_handle), + rchild_handle = vhierarchy_.rchild_handle(parent_handle); + + mesh_.data(pmiter_->v0).set_vhierarchy_node_handle(lchild_handle); + mesh_.data(pmiter_->v1).set_vhierarchy_node_handle(rchild_handle); + + ++pmiter_; + ++n_current_res_; + } +} + + +//----------------------------------------------------------------------------- + + +void coarsen(unsigned int _n) +{ + while (n_current_res_ > _n && pmiter_ != pminfos_.begin()) + { + --pmiter_; + + Mesh::HalfedgeHandle hh = + mesh_.find_halfedge(pmiter_->v0, pmiter_->v1); + mesh_.collapse(hh); + + VHierarchyNodeHandle + rchild_handle = mesh_.data(pmiter_->v1).vhierarchy_node_handle(); + + VHierarchyNodeHandle + parent_handle = vhierarchy_.parent_handle(rchild_handle); + + mesh_.data(pmiter_->v1).set_vhierarchy_node_handle(parent_handle); + + --n_current_res_; + } +} + + +//----------------------------------------------------------------------------- + + +void +vdpm_analysis() +{ + unsigned int i; + Mesh::VertexHandle vh; + Mesh::VertexIter v_it; + Mesh::HalfedgeIter h_it; + Mesh::HalfedgeHandle h, o, hn, op, hpo, on, ono; + VHierarchyNodeHandleContainer leaf_nodes; + + OpenMesh::Utils::Timer tana; + tana.start(); + + refine(n_max_res_); + + mesh_.update_face_normals(); + mesh_.update_vertex_normals(); + + std::cout << "Init view-dependent PM analysis" << std::endl; + + // initialize + for (h_it=mesh_.halfedges_begin(); h_it!=mesh_.halfedges_end(); ++h_it) + { + vh = mesh_.to_vertex_handle(h_it.handle()); + mesh_.data(h_it).set_vhierarchy_leaf_node_handle(mesh_.data(vh).vhierarchy_node_handle()); + } + + for (v_it=mesh_.vertices_begin(); v_it!=mesh_.vertices_end(); ++v_it) + { + VHierarchyNodeHandle + node_handle = mesh_.data(v_it.handle()).vhierarchy_node_handle(); + + vhierarchy_.node(node_handle).set_normal(mesh_.normal(v_it.handle())); + } + + std::cout << "Start view-dependent PM analysis" << std::endl; + + // locate fundamental cut vertices in each edge collapse + OpenMesh::Utils::Timer t; + + for (i=n_max_res_; i>0; --i) + { + t.start(); + PMInfo pminfo = pminfos_[i-1]; + + if (verbose) + std::cout << "Analyzing " << i << "-th detail vertex" << std::endl; + + // maintain leaf node pointers & locate fundamental cut vertices + h = mesh_.find_halfedge(pminfo.v0, pminfo.v1); + o = mesh_.opposite_halfedge_handle(h); + hn = mesh_.next_halfedge_handle(h); + hpo = mesh_.opposite_halfedge_handle(mesh_.prev_halfedge_handle(h)); + op = mesh_.prev_halfedge_handle(o); + on = mesh_.next_halfedge_handle(o); + ono = mesh_.opposite_halfedge_handle(on); + + VHierarchyNodeHandle + rchild_handle = mesh_.data(pminfo.v1).vhierarchy_node_handle(); + + VHierarchyNodeHandle + parent_handle = vhierarchy_.parent_handle(rchild_handle); + + if (pminfo.vl != Mesh::InvalidVertexHandle) + { + VHierarchyNodeHandle + fund_lcut_handle = mesh_.data(hn).vhierarchy_leaf_node_handle(); + + VHierarchyNodeHandle + left_leaf_handle = mesh_.data(hpo).vhierarchy_leaf_node_handle(); + + mesh_.data(hn).set_vhierarchy_leaf_node_handle(left_leaf_handle); + + vhierarchy_.node(parent_handle). + set_fund_lcut(vhierarchy_.node_index(fund_lcut_handle)); + } + + if (pminfo.vr != Mesh::InvalidVertexHandle) + { + VHierarchyNodeHandle + fund_rcut_handle = mesh_.data(on).vhierarchy_leaf_node_handle(), + right_leaf_handle = mesh_.data(ono).vhierarchy_leaf_node_handle(); + + mesh_.data(op).set_vhierarchy_leaf_node_handle(right_leaf_handle); + + vhierarchy_.node(parent_handle). + set_fund_rcut(vhierarchy_.node_index(fund_rcut_handle)); + } + + coarsen(i-1); + + leaf_nodes.clear(); + + get_leaf_node_handles(parent_handle, leaf_nodes); + compute_bounding_box(parent_handle, leaf_nodes); + compute_cone_of_normals(parent_handle, leaf_nodes); + compute_screen_space_error(parent_handle, leaf_nodes); + + t.stop(); + + if (verbose) + { + std::cout << " radius of bounding sphere: " + << vhierarchy_.node(parent_handle).radius() << std::endl; + std::cout << " direction of cone of normals: " + << vhierarchy_.node(parent_handle).normal() << std::endl; + std::cout << " sin(semi-angle of cone of normals) ^2: " + << vhierarchy_.node(parent_handle).sin_square() << std::endl; + std::cout << " (mue^2, sigma^2) : (" + << vhierarchy_.node(parent_handle).mue_square() << ", " + << vhierarchy_.node(parent_handle).sigma_square() << ")" + << std::endl; + std::cout << "- " << t.as_string() << std::endl; + } + + } // end for all collapses + + tana.stop(); + std::cout << "Analyzing step completed in " + << tana.as_string() << std::endl; +} + + +// ---------------------------------------------------------------------------- + +void +get_leaf_node_handles(VHierarchyNodeHandle node_handle, + VHierarchyNodeHandleContainer &leaf_nodes) +{ + if (vhierarchy_.node(node_handle).is_leaf()) + { + leaf_nodes.push_back(node_handle); + } + else + { + get_leaf_node_handles(vhierarchy_.node(node_handle).lchild_handle(), + leaf_nodes); + get_leaf_node_handles(vhierarchy_.node(node_handle).rchild_handle(), + leaf_nodes); + } +} + + +// ---------------------------------------------------------------------------- + +void +compute_bounding_box(VHierarchyNodeHandle node_handle, VHierarchyNodeHandleContainer &leaf_nodes) +{ + float max_distance; + Vec3f p, lp; + VHierarchyNodeHandleContainer::iterator n_it, n_end(leaf_nodes.end()); + + max_distance = 0.0f; + VertexHandle vh = vhierarchy_.node(node_handle).vertex_handle(); + p = mesh_.point(vh); + for ( n_it = leaf_nodes.begin(); n_it != n_end; ++n_it ) + { + lp = mesh_.point(vhierarchy_.vertex_handle(*n_it)); + max_distance = std::max(max_distance, (p - lp).length()); + } + + vhierarchy_.node(node_handle).set_radius(max_distance); +} + + +// ---------------------------------------------------------------------------- + +void +compute_cone_of_normals(VHierarchyNodeHandle node_handle, + VHierarchyNodeHandleContainer &leaf_nodes) +{ + float max_angle, angle; + Vec3f n, ln; + VertexHandle vh = vhierarchy_.node(node_handle).vertex_handle(); + VHierarchyNodeHandleContainer::iterator n_it, n_end(leaf_nodes.end()); + + n = mesh_.calc_vertex_normal(vh); + max_angle = 0.0f; + + n_it = leaf_nodes.begin(); + while( n_it != n_end ) + { + ln = vhierarchy_.node(*n_it).normal(); + angle = acosf( dot(n,ln) ); + max_angle = std::max(max_angle, angle ); + + ++n_it; + } + + max_angle = std::min(max_angle, float(M_PI_2)); + mesh_.set_normal(vh, n); + vhierarchy_.node(node_handle).set_normal(n); + vhierarchy_.node(node_handle).set_semi_angle(max_angle); +} + + +// ---------------------------------------------------------------------------- + +void +compute_screen_space_error(VHierarchyNodeHandle node_handle, VHierarchyNodeHandleContainer &leaf_nodes) +{ + std::vector residuals; + Mesh::VertexFaceIter vf_it; + Mesh::HalfedgeHandle heh; + Mesh::VertexHandle vh; + Vec3f residual, res; + Vec3f lp, tri[3]; + float min_distance; + float s, t; + VHierarchyNodeHandleContainer::iterator n_it, n_end(leaf_nodes.end()); + + for ( n_it = leaf_nodes.begin(); n_it != n_end; ++n_it ) + { + lp = mesh_.point(vhierarchy_.node(*n_it).vertex_handle()); + + // compute residual of a leaf-vertex from the current mesh_ + vh = vhierarchy_.node(node_handle).vertex_handle(); + residual = lp - mesh_.point(vh); + min_distance = residual.length(); + + for (vf_it=mesh_.vf_iter(vh); vf_it; ++vf_it) + { + heh = mesh_.halfedge_handle(vf_it.handle()); + tri[0] = mesh_.point(mesh_.to_vertex_handle(heh)); + heh = mesh_.next_halfedge_handle(heh); + tri[1] = mesh_.point(mesh_.to_vertex_handle(heh)); + heh = mesh_.next_halfedge_handle(heh); + tri[2] = mesh_.point(mesh_.to_vertex_handle(heh)); + + res = point2triangle_residual(lp, tri, s, t); + + if (res.length() < min_distance) + { + residual = res; + min_distance = res.length(); + } + } + + residuals.push_back(residual); + } + + compute_mue_sigma(node_handle, residuals); +} + + +// ---------------------------------------------------------------------------- + +void +compute_mue_sigma(VHierarchyNodeHandle node_handle, + ResidualContainer &residuals) +{ + Vec3f vn; + float max_inner, max_cross; + ResidualContainer::iterator r_it, r_end(residuals.end()); + + max_inner = max_cross = 0.0f; + vn = mesh_.normal(vhierarchy_.node(node_handle).vertex_handle()); + for (r_it = residuals.begin(); r_it != r_end; ++r_it) + { + float inner = fabsf(dot(*r_it, vn)); + float cross = OpenMesh::cross(*r_it, vn).length(); + + max_inner = std::max(max_inner, inner); + max_cross = std::max(max_cross, cross); + } + + if (max_cross < 1.0e-7) + { + vhierarchy_.node(node_handle).set_mue(max_cross); + vhierarchy_.node(node_handle).set_sigma(max_inner); + } + else { + float ratio = std::max(1.0f, max_inner/max_cross); + float whole_degree = acosf(1.0f/ratio); + float mue, max_mue; + float degree; + float res_length; + Vec3f res; + + max_mue = 0.0f; + for (r_it = residuals.begin(); r_it != r_end; ++r_it) + { + res = *r_it; + res_length = res.length(); + + // TODO: take care when res.length() is too small + degree = acosf(dot(vn,res) / res_length); + + if (degree < 0.0f) degree = -degree; + if (degree > float(M_PI_2)) degree = float(M_PI) - degree; + + if (degree < whole_degree) + mue = cosf(whole_degree - degree) * res_length; + else + mue = res_length; + + max_mue = std::max(max_mue, mue); + } + + vhierarchy_.node(node_handle).set_mue(max_mue); + vhierarchy_.node(node_handle).set_sigma(ratio*max_mue); + } +} + +// ---------------------------------------------------------------------------- + + +Vec3f +point2triangle_residual(const Vec3f &p, const Vec3f tri[3], float &s, float &t) +{ + OpenMesh::Vec3f B = tri[0]; // Tri.Origin(); + OpenMesh::Vec3f E0 = tri[1] - tri[0]; // rkTri.Edge0() + OpenMesh::Vec3f E1 = tri[2] - tri[0]; // rkTri.Edge1() + OpenMesh::Vec3f D = tri[0] - p; // kDiff + float a = dot(E0, E0); // fA00 + float b = dot(E0, E1); // fA01 + float c = dot(E1, E1); // fA11 + float d = dot(E0, D); // fB0 + float e = dot(E1, D); // fB1 + float f = dot(D, D); // fC + float det = fabsf(a*c - b*b); + s = b*e-c*d; + t = b*d-a*e; + + OpenMesh::Vec3f residual; + + float distance2; + + if ( s + t <= det ) + { + if ( s < 0.0f ) + { + if ( t < 0.0f ) // region 4 + { + if ( d < 0.0f ) + { + t = 0.0f; + if ( -d >= a ) + { + s = 1.0f; + distance2 = a+2.0f*d+f; + } + else + { + s = -d/a; + distance2 = d*s+f; + } + } + else + { + s = 0.0f; + if ( e >= 0.0f ) + { + t = 0.0f; + distance2 = f; + } + else if ( -e >= c ) + { + t = 1.0f; + distance2 = c+2.0f*e+f; + } + else + { + t = -e/c; + distance2 = e*t+f; + } + } + } + else // region 3 + { + s = 0.0f; + if ( e >= 0.0f ) + { + t = 0.0f; + distance2 = f; + } + else if ( -e >= c ) + { + t = 1.0f; + distance2 = c+2.0f*e+f; + } + else + { + t = -e/c; + distance2 = e*t+f; + } + } + } + else if ( t < 0.0f ) // region 5 + { + t = 0.0f; + if ( d >= 0.0f ) + { + s = 0.0f; + distance2 = f; + } + else if ( -d >= a ) + { + s = 1.0f; + distance2 = a+2.0f*d+f; + } + else + { + s = -d/a; + distance2 = d*s+f; + } + } + else // region 0 + { + // minimum at interior point + float inv_det = 1.0f/det; + s *= inv_det; + t *= inv_det; + distance2 = s*(a*s+b*t+2.0f*d) + + t*(b*s+c*t+2.0f*e)+f; + } + } + else + { + float tmp0, tmp1, numer, denom; + + if ( s < 0.0f ) // region 2 + { + tmp0 = b + d; + tmp1 = c + e; + if ( tmp1 > tmp0 ) + { + numer = tmp1 - tmp0; + denom = a-2.0f*b+c; + if ( numer >= denom ) + { + s = 1.0f; + t = 0.0f; + distance2 = a+2.0f*d+f; + } + else + { + s = numer/denom; + t = 1.0f - s; + distance2 = s*(a*s+b*t+2.0f*d) + + t*(b*s+c*t+2.0f*e)+f; + } + } + else + { + s = 0.0f; + if ( tmp1 <= 0.0f ) + { + t = 1.0f; + distance2 = c+2.0f*e+f; + } + else if ( e >= 0.0f ) + { + t = 0.0f; + distance2 = f; + } + else + { + t = -e/c; + distance2 = e*t+f; + } + } + } + else if ( t < 0.0f ) // region 6 + { + tmp0 = b + e; + tmp1 = a + d; + if ( tmp1 > tmp0 ) + { + numer = tmp1 - tmp0; + denom = a-2.0f*b+c; + if ( numer >= denom ) + { + t = 1.0f; + s = 0.0f; + distance2 = c+2.0f*e+f; + } + else + { + t = numer/denom; + s = 1.0f - t; + distance2 = s*(a*s+b*t+2.0f*d)+ t*(b*s+c*t+2.0f*e)+f; + } + } + else + { + t = 0.0f; + if ( tmp1 <= 0.0f ) + { + s = 1.0f; + distance2 = a+2.0f*d+f; + } + else if ( d >= 0.0f ) + { + s = 0.0f; + distance2 = f; + } + else + { + s = -d/a; + distance2 = d*s+f; + } + } + } + else // region 1 + { + numer = c + e - b - d; + if ( numer <= 0.0f ) + { + s = 0.0f; + t = 1.0f; + distance2 = c+2.0f*e+f; + } + else + { + denom = a-2.0f*b+c; + if ( numer >= denom ) + { + s = 1.0f; + t = 0.0f; + distance2 = a+2.0f*d+f; + } + else + { + s = numer/denom; + t = 1.0f - s; + distance2 = s*(a*s+b*t+2.0f*d) + t*(b*s+c*t+2.0f*e)+f; + } + } + } + } + + residual = p - (B + s*E0 + t*E1); + + return residual; +} + +// ============================================================================ diff --git a/Apps/VDProgMesh/Synthesizer/Synthesizer.pro b/Apps/VDProgMesh/Synthesizer/Synthesizer.pro new file mode 100644 index 00000000..9347920f --- /dev/null +++ b/Apps/VDProgMesh/Synthesizer/Synthesizer.pro @@ -0,0 +1,31 @@ +################################################################################ +# +################################################################################ + +contains( OPENFLIPPER , OpenFlipper ){ + include( $$TOPDIR/qmake/all.include ) +} else { + include( $$TOPDIR/OpenMesh/qmake/all.include ) +} + +INCLUDEPATH += ../../../.. + +CONFIG += glew glut + +Application() + +LIBS += -Wl,-rpath=$${TOPDIR}/OpenMesh/Core/lib/$${BUILDDIRECTORY} -lCore +LIBS += -Wl,-rpath=$${TOPDIR}/OpenMesh/Tools/lib/$${BUILDDIRECTORY} -lTools +LIBS += -lglut +QMAKE_LIBDIR += $${TOPDIR}/OpenMesh/Core/lib/$${BUILDDIRECTORY} +QMAKE_LIBDIR += $${TOPDIR}/OpenMesh/Tools/lib/$${BUILDDIRECTORY} + +DIRECTORIES = . ../../QtViewer + +# Input +HEADERS += $$getFilesFromDir($$DIRECTORIES,*.hh) +SOURCES += $$getFilesFromDir($$DIRECTORIES,*.cc) +SOURCES -= ../../QtViewer/meshviewer.cc +FORMS += $$getFilesFromDir($$DIRECTORIES,*.ui) + +################################################################################ diff --git a/Apps/VDProgMesh/Synthesizer/VDPMSynthesizerViewerWidget.cc b/Apps/VDProgMesh/Synthesizer/VDPMSynthesizerViewerWidget.cc new file mode 100644 index 00000000..3bee305e --- /dev/null +++ b/Apps/VDProgMesh/Synthesizer/VDPMSynthesizerViewerWidget.cc @@ -0,0 +1,596 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass - IMPLEMENTATION +// +//============================================================================= + +//== INCLUDES ================================================================= + +#ifdef _MSC_VER +# pragma warning(disable: 4267 4311) +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== IMPLEMENTATION ========================================================== + + + +void +VDPMSynthesizerViewerWidget:: +draw_scene(const std::string &_draw_mode) +{ + if (adaptive_mode_ == true) + { + adaptive_refinement(); + } + MeshViewerWidget::draw_scene(_draw_mode); +} + + +void +VDPMSynthesizerViewerWidget:: +adaptive_refinement() +{ + update_viewing_parameters(); + + VDPMMesh::HalfedgeHandle v0v1; + + float fovy = viewing_parameters_.fovy(); + + float tolerance_square = viewing_parameters_.tolerance_square(); + float tan_value = tanf(fovy / 2.0f); + + kappa_square_ = 4.0f * tan_value * tan_value * tolerance_square; + + //assert( !vfront_.end() ); + + for ( vfront_.begin(); !vfront_.end(); ) + { + VHierarchyNodeHandle + node_handle = vfront_.node_handle(), + parent_handle = vhierarchy_.parent_handle(node_handle); + + if (vhierarchy_.is_leaf_node(node_handle) != true && + qrefine(node_handle) == true) + { + force_vsplit(node_handle); + } + else if (vhierarchy_.is_root_node(node_handle) != true && + ecol_legal(parent_handle, v0v1) == true && + qrefine(parent_handle) != true) + { + ecol(parent_handle, v0v1); + } + else + { + vfront_.next(); + } + } + + // free memories tagged as 'deleted' + mesh_.garbage_collection(false, true, true); + mesh_.update_face_normals(); +} + + +bool +VDPMSynthesizerViewerWidget:: +qrefine(VHierarchyNodeHandle _node_handle) +{ + VHierarchyNode &node = vhierarchy_.node(_node_handle); + Vec3f p = mesh_.point(node.vertex_handle()); + Vec3f eye_dir = p - viewing_parameters_.eye_pos();; + + float distance = eye_dir.length(); + float distance2 = distance * distance; + float product_value = dot(eye_dir, node.normal()); + + if (outside_view_frustum(p, node.radius()) == true) + return false; + + if (oriented_away(node.sin_square(), distance2, product_value) == true) + return false; + + if (screen_space_error(node.mue_square(), + node.sigma_square(), + distance2, + product_value) == true) + return false; + + return true; +} + + +void +VDPMSynthesizerViewerWidget:: +force_vsplit(VHierarchyNodeHandle node_handle) +{ + VDPMMesh::VertexHandle vl, vr; + + get_active_cuts(node_handle, vl, vr); + + while (vl == vr) + { + force_vsplit(mesh_.data(vl).vhierarchy_node_handle()); + get_active_cuts(node_handle, vl, vr); + } + + vsplit(node_handle, vl, vr); +} + + + +void +VDPMSynthesizerViewerWidget:: +vsplit(VHierarchyNodeHandle _node_handle, + VDPMMesh::VertexHandle vl, + VDPMMesh::VertexHandle vr) +{ + // refine + VHierarchyNodeHandle + lchild_handle = vhierarchy_.lchild_handle(_node_handle), + rchild_handle = vhierarchy_.rchild_handle(_node_handle); + + VDPMMesh::VertexHandle v0 = vhierarchy_.vertex_handle(lchild_handle); + VDPMMesh::VertexHandle v1 = vhierarchy_.vertex_handle(rchild_handle); + + mesh_.vertex_split(v0, v1, vl, vr); + mesh_.set_normal(v0, vhierarchy_.normal(lchild_handle)); + mesh_.set_normal(v1, vhierarchy_.normal(rchild_handle)); + mesh_.data(v0).set_vhierarchy_node_handle(lchild_handle); + mesh_.data(v1).set_vhierarchy_node_handle(rchild_handle); + mesh_.status(v0).set_deleted(false); + mesh_.status(v1).set_deleted(false); + + vfront_.remove(_node_handle); + vfront_.add(lchild_handle); + vfront_.add(rchild_handle); +} + + +void +VDPMSynthesizerViewerWidget:: +ecol(VHierarchyNodeHandle _node_handle, const VDPMMesh::HalfedgeHandle& v0v1) +{ + VHierarchyNodeHandle + lchild_handle = vhierarchy_.lchild_handle(_node_handle), + rchild_handle = vhierarchy_.rchild_handle(_node_handle); + + VDPMMesh::VertexHandle v0 = vhierarchy_.vertex_handle(lchild_handle); + VDPMMesh::VertexHandle v1 = vhierarchy_.vertex_handle(rchild_handle); + + // coarsen + mesh_.collapse(v0v1); + mesh_.set_normal(v1, vhierarchy_.normal(_node_handle)); + mesh_.data(v0).set_vhierarchy_node_handle(lchild_handle); + mesh_.data(v1).set_vhierarchy_node_handle(_node_handle); + mesh_.status(v0).set_deleted(false); + mesh_.status(v1).set_deleted(false); + + vfront_.add(_node_handle); + vfront_.remove(lchild_handle); + vfront_.remove(rchild_handle); +} + + +bool +VDPMSynthesizerViewerWidget:: +ecol_legal(VHierarchyNodeHandle _parent_handle, VDPMMesh::HalfedgeHandle& v0v1) +{ + VHierarchyNodeHandle + lchild_handle = vhierarchy_.lchild_handle(_parent_handle), + rchild_handle = vhierarchy_.rchild_handle(_parent_handle); + + // test whether lchild & rchild present in the current vfront + if ( vfront_.is_active(lchild_handle) != true || + vfront_.is_active(rchild_handle) != true) + return false; + + VDPMMesh::VertexHandle v0, v1; + + v0 = vhierarchy_.vertex_handle(lchild_handle); + v1 = vhierarchy_.vertex_handle(rchild_handle); + + v0v1 = mesh_.find_halfedge(v0, v1); + + return mesh_.is_collapse_ok(v0v1); +} + +void +VDPMSynthesizerViewerWidget:: +get_active_cuts(const VHierarchyNodeHandle _node_handle, + VDPMMesh::VertexHandle &vl, VDPMMesh::VertexHandle &vr) +{ + VDPMMesh::VertexVertexIter vv_it; + VHierarchyNodeHandle nnode_handle; + + VHierarchyNodeIndex + nnode_index, + fund_lcut_index = vhierarchy_.fund_lcut_index(_node_handle), + fund_rcut_index = vhierarchy_.fund_rcut_index(_node_handle); + + vl = VDPMMesh::InvalidVertexHandle; + vr = VDPMMesh::InvalidVertexHandle; + + for (vv_it=mesh_.vv_iter(vhierarchy_.vertex_handle(_node_handle)); + vv_it; ++vv_it) + { + nnode_handle = mesh_.data(vv_it.handle()).vhierarchy_node_handle(); + nnode_index = vhierarchy_.node_index(nnode_handle); + + if (vl == VDPMMesh::InvalidVertexHandle && + vhierarchy_.is_ancestor(nnode_index, fund_lcut_index) == true) + vl = vv_it.handle(); + + if (vr == VDPMMesh::InvalidVertexHandle && + vhierarchy_.is_ancestor(nnode_index, fund_rcut_index) == true) + vr = vv_it.handle(); + + /*if (vl == VDPMMesh::InvalidVertexHandle && nnode_index.is_ancestor_index(fund_lcut_index) == true) + vl = vv_it.handle(); + if (vr == VDPMMesh::InvalidVertexHandle && nnode_index.is_ancestor_index(fund_rcut_index) == true) + vr = vv_it.handle();*/ + + if (vl != VDPMMesh::InvalidVertexHandle && + vr != VDPMMesh::InvalidVertexHandle) + break; + } +} + + +bool +VDPMSynthesizerViewerWidget:: +outside_view_frustum(const Vec3f &pos, float radius) +{ +#if 0 + return + (frustum_plane_[0].signed_distance(pos) < -radius) || + (frustum_plane_[1].signed_distance(pos) < -radius) || + (frustum_plane_[2].signed_distance(pos) < -radius) || + (frustum_plane_[3].signed_distance(pos) < -radius); +#else + + Plane3d frustum_plane[4]; + + viewing_parameters_.frustum_planes(frustum_plane); + + for (int i = 0; i < 4; i++) { + if (frustum_plane[i].singed_distance(pos) < -radius) + return true; + } + return false; +#endif +} + +bool +VDPMSynthesizerViewerWidget:: +oriented_away(float sin_square, float distance_square, float product_value) +{ +#if 0 + return (product_value > 0) + && ((product_value * product_value) > (distance_square * sin_square)); +#else + if (product_value > 0 && + product_value * product_value > distance_square * sin_square) + return true; + else + return false; +#endif +} + + +bool +VDPMSynthesizerViewerWidget:: +screen_space_error(float mue_square, float sigma_square, + float distance_square, float product_value) +{ +#if 0 + float ks_ds = kappa_square_ * distance_square; + float pv_pv = product_value * product_value; + return (mue_square >= ks_ds) + || (sigma_square*( distance_square - pv_pv) >= ks_ds*distance_square); +#else + if ((mue_square >= kappa_square_ * distance_square) || + (sigma_square * (distance_square - product_value * product_value) >= kappa_square_ * distance_square * distance_square)) + return false; + else + return true; +#endif +} + +void +VDPMSynthesizerViewerWidget:: +open_vd_prog_mesh(const char* _filename) +{ + unsigned int i; + unsigned int value; + unsigned int fvi[3]; + char fileformat[16]; + Vec3f p, normal; + float radius, sin_square, mue_square, sigma_square; + VHierarchyNodeHandleContainer roots; + VertexHandle vertex_handle; + VHierarchyNodeIndex node_index; + VHierarchyNodeIndex lchild_node_index, rchild_node_index; + VHierarchyNodeIndex fund_lcut_index, fund_rcut_index; + VHierarchyNodeHandle node_handle; + VHierarchyNodeHandle lchild_node_handle, rchild_node_handle; + + std::map index2handle_map; + + std::ifstream ifs(_filename, std::ios::binary); + + if (!ifs) + { + std::cerr << "read error\n"; + exit(1); + } + + // + bool swap = Endian::local() != Endian::LSB; + + // read header + ifs.read(fileformat, 10); fileformat[10] = '\0'; + if (std::string(fileformat) != std::string("VDProgMesh")) + { + std::cerr << "Wrong file format.\n"; + ifs.close(); + exit(1); + } + + IO::restore(ifs, n_base_vertices_, swap); + IO::restore(ifs, n_base_faces_, swap); + IO::restore(ifs, n_details_, swap); + + mesh_.clear(); + vfront_.clear(); + vhierarchy_.clear(); + + vhierarchy_.set_num_roots(n_base_vertices_); + + // load base mesh + for (i=0; ikey()) + { + case Key_Home: + updateGL(); + break; + + case Key_End: + updateGL(); + break; + + case Key_Plus: + viewing_parameters_.increase_tolerance(); + std::cout << "Scree-space error tolerance^2 is increased by " + << viewing_parameters_.tolerance_square() << std::endl; + updateGL(); + break; + + case Key_Minus: + viewing_parameters_.decrease_tolerance(); + std::cout << "Screen-space error tolerance^2 is decreased by " + << viewing_parameters_.tolerance_square() << std::endl; + updateGL(); + break; + + case Key_A: + adaptive_mode_ = !(adaptive_mode_); + std::cout << "Adaptive refinement mode is " + << (adaptive_mode_ ? "on" : "off") << std::endl; + updateGL(); + break; + + case Key_O: + qFilename_ = QFileDialog::getOpenFileName(0,"", "", "*.spm"); + open_vd_prog_mesh( qFilename_.toStdString().c_str() ); + break; + + default: + MeshViewerWidget::keyPressEvent( _event ); + } + +} + + + + + +void +VDPMSynthesizerViewerWidget:: +update_viewing_parameters() +{ + viewing_parameters_.set_modelview_matrix(modelview_matrix()); + viewing_parameters_.set_aspect((float) width()/ (float) height()); + viewing_parameters_.set_fovy(fovy()); + + viewing_parameters_.update_viewing_configurations(); +} + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Apps/VDProgMesh/Synthesizer/VDPMSynthesizerViewerWidget.hh b/Apps/VDProgMesh/Synthesizer/VDPMSynthesizerViewerWidget.hh new file mode 100644 index 00000000..67db41a8 --- /dev/null +++ b/Apps/VDProgMesh/Synthesizer/VDPMSynthesizerViewerWidget.hh @@ -0,0 +1,181 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= + + +#ifndef OPENMESH_VDPROGMESH_VDPMSYNTHESIZERVIEWERWIDGET_HH +#define OPENMESH_VDPROGMESH_VDPMSYNTHESIZERVIEWERWIDGET_HH + + +//== INCLUDES ================================================================= + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** \class newClass newClass.hh + + Brief Description. + + A more elaborate description follows. +*/ + + + +typedef TriMesh_ArrayKernelT VDPMMesh; +typedef MeshViewerWidgetT MeshViewerWidget; + + + // using view dependent progressive mesh + + using VDPM::Plane3d; + using VDPM::VFront; + using VDPM::VHierarchy; + using VDPM::VHierarchyNode; + using VDPM::VHierarchyNodeIndex; + using VDPM::VHierarchyNodeHandle; + using VDPM::VHierarchyNodeHandleContainer; + using VDPM::ViewingParameters; + + +//== CLASS DEFINITION ========================================================= + + +class VDPMSynthesizerViewerWidget : public MeshViewerWidget +{ +public: + + typedef MeshViewerWidget Base; + +public: + + VDPMSynthesizerViewerWidget(QWidget* _parent=0, const char* _name=0) + : MeshViewerWidget(_parent) + { + adaptive_mode_ = false; + } + + ~VDPMSynthesizerViewerWidget() + { + + } + + /// open view-dependent progressive mesh + void open_vd_prog_mesh(const char* _filename); + + +private: + + QString qFilename_; + VHierarchy vhierarchy_; + VFront vfront_; + ViewingParameters viewing_parameters_; + float kappa_square_; + bool adaptive_mode_; + + unsigned int n_base_vertices_; + unsigned int n_base_edges_; + unsigned int n_base_faces_; + unsigned int n_details_; + + +private: + + bool outside_view_frustum(const OpenMesh::Vec3f &pos, float radius); + + bool oriented_away(float sin_square, + float distance_square, + float product_value); + + bool screen_space_error(float mue_square, + float sigma_square, + float distance_square, + float product_value); + + void update_viewing_parameters(); + + virtual void keyPressEvent(QKeyEvent* _event); + +protected: + + /// inherited drawing method + virtual void draw_scene(const std::string& _draw_mode); + +public: + + void adaptive_refinement(); + + bool qrefine(VHierarchyNodeHandle _node_handle); + + void force_vsplit(VHierarchyNodeHandle _node_handle); + + bool ecol_legal(VHierarchyNodeHandle _parent_handle, + VDPMMesh::HalfedgeHandle& v0v1); + + void get_active_cuts(VHierarchyNodeHandle _node_handle, + VDPMMesh::VertexHandle &vl, VDPMMesh::VertexHandle &vr); + + void vsplit(VHierarchyNodeHandle _node_handle, + VDPMMesh::VertexHandle vl, VDPMMesh::VertexHandle vr); + + void ecol(VHierarchyNodeHandle _parent_handle, + const VDPMMesh::HalfedgeHandle& v0v1); + + void init_vfront(); + +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESHAPPS_VDPMSYNTHESIZERVIEWERWIDGET_HH defined +//============================================================================= diff --git a/Apps/VDProgMesh/Synthesizer/vdpmsynthesizer.cc b/Apps/VDProgMesh/Synthesizer/vdpmsynthesizer.cc new file mode 100644 index 00000000..9b6ce926 --- /dev/null +++ b/Apps/VDProgMesh/Synthesizer/vdpmsynthesizer.cc @@ -0,0 +1,53 @@ +#ifdef _MSC_VER +# pragma warning(disable: 4267 4311) +#endif + +#include + +#include +#include + +#include "VDPMSynthesizerViewerWidget.hh" + +#include + + +int main(int argc, char **argv) +{ + // OpenGL check + QApplication::setColorSpec( QApplication::CustomColor ); + QApplication app(argc,argv); + + glutInit(&argc,argv); + + if ( !QGLFormat::hasOpenGL() ) { + std::cerr << "This system has no OpenGL support.\n"; + return 1; + } + + // create widget + VDPMSynthesizerViewerWidget* + w = new VDPMSynthesizerViewerWidget(0, "VDPMSynthesizerViewer"); + + w->resize(400, 400); + w->show(); + + // load scene + if (argc==2) + w->open_vd_prog_mesh(argv[1]); + else + { + std::cerr << "Usage: vdpmsynthesizer \n"; + return 1; + } + + // print usage info + std::cout << "\n\n" + << "Press Minus : Coarsen mesh\n" + << " Plus : Refine mesh\n" + << " Home : Coarsen down to base mesh\n" + << " End : Refine up to finest mesh\n" + << "\n"; + + return app.exec(); +} diff --git a/Apps/VDProgMesh/mkbalancedpm/mkbalancedpm.cc b/Apps/VDProgMesh/mkbalancedpm/mkbalancedpm.cc new file mode 100644 index 00000000..0a694817 --- /dev/null +++ b/Apps/VDProgMesh/mkbalancedpm/mkbalancedpm.cc @@ -0,0 +1,320 @@ +// -------------------- STL +#include +#include +#include +// -------------------- OpenMesh +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef OpenMesh::TriMesh_ArrayKernelT<> Mesh; +typedef OpenMesh::Decimater::DecimaterT Decimater; +typedef OpenMesh::Decimater::ModNormalFlippingT ModNormalFlipping; +typedef OpenMesh::Decimater::ModQuadricT ModQuadric; +typedef OpenMesh::Decimater::ModProgMeshT ModProgMesh; +typedef OpenMesh::Decimater::ModIndependentSetsT ModIndependentSets; + +// ---------------------------------------------------------------------------- + +using namespace OpenMesh::Decimater; + +template +class ModBalancerT : public OpenMesh::Decimater::ModQuadricT +{ +public: + + typedef OpenMesh::Decimater::ModQuadricT BaseModQ; + + DECIMATING_MODULE( ModBalancerT, D, Balancer ); + +public: + + typedef size_t level_t; + +public: + + /// Constructor + ModBalancerT( D &_dec ) + : BaseModQ( _dec ), + max_level_(0), n_vertices_(0) + { + BaseModQ::mesh().add_property( level_ ); + } + + + /// Destructor + virtual ~ModBalancerT() + { + BaseModQ::mesh().remove_property( level_ ); + } + +public: + + static level_t calc_bits_for_roots( size_t _n_vertices ) + { + return level_t(std::ceil(std::log((double)_n_vertices)*inv_log2_)); + } + +public: // inherited + + void initialize(void) + { + BaseModQ::initialize(); + n_vertices_ = BaseModQ::mesh().n_vertices(); + n_roots_ = calc_bits_for_roots(n_vertices_); + } + + virtual float collapse_priority(const CollapseInfo& _ci) + { + level_t newlevel = std::max( BaseModQ::mesh().property( level_, _ci.v0 ), + BaseModQ::mesh().property( level_, _ci.v1 ) )+1; + level_t newroots = calc_bits_for_roots(n_vertices_-1); + + if ( (newroots + newlevel) < 32 ) + { + double err = BaseModQ::collapse_priority( _ci ); + + if (err!=BaseModQ::ILLEGAL_COLLAPSE) + { + return float(newlevel + err/(err+1.0)); + } + + + } + return BaseModQ::ILLEGAL_COLLAPSE; + } + + /// post-process halfedge collapse (accumulate quadrics) + void postprocess_collapse(const CollapseInfo& _ci) + { + BaseModQ::postprocess_collapse( _ci ); + + BaseModQ::mesh().property( level_, _ci.v1 ) = + std::max( BaseModQ::mesh().property( level_, _ci.v0 ), + BaseModQ::mesh().property( level_, _ci.v1 ) ) + 1; + + max_level_ = std::max( BaseModQ::mesh().property( level_, _ci.v1 ), max_level_ ); + n_roots_ = calc_bits_for_roots(--n_vertices_); + } + +public: + + level_t max_level(void) const { return max_level_; } + level_t bits_for_roots(void) const { return n_roots_; } + +private: + + /// hide this method + void set_binary(bool _b) {} + + OpenMesh::VPropHandleT level_; + + level_t max_level_; // maximum level reached + level_t n_roots_; // minimum bits for root nodes + size_t n_vertices_;// number of potential root nodes + + static const double inv_log2_; + +}; + +template +const double ModBalancerT::inv_log2_ = 1.0/std::log(2.0); + +typedef ModBalancerT ModBalancer; + + +// ---------------------------------------------------------------------------- + +inline +std::string& +replace_extension( std::string& _s, const std::string& _e ) +{ + std::string::size_type dot = _s.rfind("."); + if (dot == std::string::npos) + { _s += "." + _e; } + else + { _s = _s.substr(0,dot+1)+_e; } + return _s; +} + +inline +std::string +basename(const std::string& _f) +{ + std::string::size_type dot = _f.rfind("/"); + if (dot == std::string::npos) + return _f; + return _f.substr(dot+1, _f.length()-(dot+1)); +} + +// ---------------------------------------------------------------------------- + +void usage_and_exit(int xcode) +{ + using namespace std; + + cout << endl + << "Usage: mkbalancedpm [-n ] [-o ] " + << "\n" + << endl + << " Create a balanced progressive mesh from an input file.\n" + << " By default decimate as much as possible and write the result\n" + << " to .pm\n" + << endl + << "Options:\n" + << endl + << " -n \n" + << "\tDetermines the maximum number of decimation steps.\n" + << "\tDecimate as much as possible if the value is equal zero\n" + << "\tDefault value: 0\n" + << endl + << " -o \n" + << "\tWrite resulting progressive mesh to the file named \n" + << endl + << " -N\n" + << "\tEnable Normal Flipping\n" + << endl + << " -I\n" + << "\tEnable Independent Sets\n" + << endl; + exit(xcode); +} + +// ---------------------------------------------------------------------------- + +int main(int argc, char **argv) +{ + Mesh mesh; + + int c; + std::string ifname, ofname; + size_t decstep=0; + bool enable_modNF = false; + bool enable_modIS = false; + + while ((c=getopt(argc, argv, "n:o:NIh"))!=-1) + { + switch (c) + { + case 'o': ofname = optarg; break; + case 'n': { std::stringstream str; str << optarg; str >> decstep; } break; + case 'N': enable_modNF = true; break; + case 'I': enable_modIS = true; break; + case 'h': + usage_and_exit(0); + default: + usage_and_exit(1); + } + } + + if (optind >= argc) + usage_and_exit(1); + + ifname = argv[optind]; + + if (!OpenMesh::IO::read_mesh(mesh, ifname)) + { + std::cerr << "Error loading mesh from file '" << ifname << "'!\n"; + return 1; + } + + { + OpenMesh::Utils::Timer t; + + Decimater decimater(mesh); + + ModProgMesh::Handle modPM; + ModBalancer::Handle modB; + ModNormalFlipping::Handle modNF; + ModIndependentSets::Handle modIS; + + + decimater.add(modPM); + std::cout << "w/ progressive mesh module\n"; + decimater.add(modB); + std::cout << "w/ balancer module\n"; + + if ( enable_modNF ) + decimater.add(modNF); + std::cout << "w/" << (modNF.is_valid() ? ' ' : 'o') + << " normal flipping module\n"; + + if ( enable_modIS ) + decimater.add(modIS); + std::cout << "w/" << (modIS.is_valid() ? ' ' : 'o') + << " independent sets module\n"; + + std::cout << "Initialize decimater\n"; + t.start(); + if ( !decimater.initialize() ) + { + std::cerr << " Initialization failed!\n"; + return 1; + } + t.stop(); + std::cout << " done [" << t.as_string() << "]\n"; + t.reset(); + + int rc; + size_t nv = mesh.n_vertices(); + + std::cout << "Begin decimation (#V " << nv << ")\n"; + t.start(); + do + { + if (modIS.is_valid()) + { + Mesh::VertexIter v_it; + Mesh::FaceIter f_it; + + for (f_it = mesh.faces_begin(); f_it != mesh.faces_end(); ++f_it) + if ( !mesh.status(f_it).deleted() ) + mesh.update_normal(f_it); + + for (v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it) + if ( !mesh.status(v_it).deleted() ) + { + mesh.status(v_it).set_locked(false); + mesh.update_normal(v_it); + } + + } + + rc = decimater.decimate(decstep); + t.stop(); + std::cout << '\r' + << (nv-=rc) << " (-" << rc << ") " << std::flush; + t.cont(); + } while (rc > 0); + t.stop(); + + std::cout << "\n done [" << t.as_string() << "]\n"; + + std::cout << "Bits for : <" + << decimater.module(modB).bits_for_roots() << ", " + << decimater.module(modB).max_level() << ">" + << std::endl; + + std::cout << "Maximum level reached: " + << decimater.module(modB).max_level() << std::endl; + + if (ofname == "." || ofname == ".." ) + ofname += "/" + basename(ifname); + std::string pmfname = ofname.empty() ? ifname : ofname; + replace_extension(pmfname, "pm"); + + std::cout << "Write progressive mesh data to file " + << pmfname << std::endl; + decimater.module(modPM).write( pmfname ); + } + + + return 0; +} diff --git a/Apps/VDProgMesh/mkbalancedpm/mkbalancedpm.pro b/Apps/VDProgMesh/mkbalancedpm/mkbalancedpm.pro new file mode 100644 index 00000000..26505412 --- /dev/null +++ b/Apps/VDProgMesh/mkbalancedpm/mkbalancedpm.pro @@ -0,0 +1,30 @@ +################################################################################ +# +################################################################################ + +contains( OPENFLIPPER , OpenFlipper ){ + include( $$TOPDIR/qmake/all.include ) +} else { + include( $$TOPDIR/OpenMesh/qmake/all.include ) +} + +INCLUDEPATH += ../../../.. + +CONFIG += glew glut + +Application() + +LIBS += -Wl,-rpath=$${TOPDIR}/OpenMesh/Core/lib/$${BUILDDIRECTORY} -lCore +LIBS += -Wl,-rpath=$${TOPDIR}/OpenMesh/Tools/lib/$${BUILDDIRECTORY} -lTools +LIBS += -lglut +QMAKE_LIBDIR += $${TOPDIR}/OpenMesh/Core/lib/$${BUILDDIRECTORY} +QMAKE_LIBDIR += $${TOPDIR}/OpenMesh/Tools/lib/$${BUILDDIRECTORY} + +DIRECTORIES = . + +# Input +HEADERS += $$getFilesFromDir($$DIRECTORIES,*.hh) +SOURCES += $$getFilesFromDir($$DIRECTORIES,*.cc) +FORMS += $$getFilesFromDir($$DIRECTORIES,*.ui) + +################################################################################ diff --git a/Apps/mconvert/mconvert.cc b/Apps/mconvert/mconvert.cc new file mode 100644 index 00000000..616f49a0 --- /dev/null +++ b/Apps/mconvert/mconvert.cc @@ -0,0 +1,378 @@ +#include +#include +#include +#include +// +#include +#include +#include +#include +#include + + +struct MyTraits : public OpenMesh::DefaultTraits +{ + VertexAttributes ( OpenMesh::Attributes::Normal | + OpenMesh::Attributes::Color | + OpenMesh::Attributes::TexCoord2D ); + HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge ); + FaceAttributes ( OpenMesh::Attributes::Normal | + OpenMesh::Attributes::Color ); +}; + + +typedef OpenMesh::TriMesh_ArrayKernelT MyMesh; + +void usage_and_exit(int xcode) +{ + using std::cout; + using std::endl; + + cout << "\nUsage: mconvert [option] []\n\n"; + cout << " Convert from one 3D geometry format to another.\n" + << " Or simply display some information about the object\n" + << " stored in .\n" + << endl; + cout << "Options:\n" + << endl; + cout << " -b\tUse binary mode if supported by target format.\n" << endl; + cout << " -l\tStore least significant bit first (LSB, little endian).\n" << endl; + cout << " -m\tStore most significant bit first (MSB, big endian).\n" << endl; + cout << " -s\tSwap byte order.\n" << endl; + cout << " -B\tUse binary mode if supported by source format.\n" << endl; + cout << " -S\tSwap byte order of input data.\n" << endl; + cout << " -c\tCopy vertex color if provided by input.\n" << endl; + cout << " -d\tCopy face color if provided by input.\n" << endl; + cout << " -C\tTranslate object in its center-of-gravity.\n" << endl; + cout << " -n\tCopy vertex normals if provided by input. Else compute normals.\n" << endl; + cout << " -N\tReverse normal directions.\n" << endl; + cout << " -t\tCopy vertex texture coordinates if provided by input file.\n" << endl; + cout << " -T \"x y z\"\tTranslate object by vector (x, y, z)'\"\n" + << std::endl; + cout << endl; + + exit(xcode); +} + +// ---------------------------------------------------------------------------- + +template struct Option : std::pair< T, bool > +{ + typedef std::pair< T, bool > Base; + + Option() + { Base::second = false; } + + bool is_valid() const { return Base::second; } + bool is_empty() const { return !Base::second; } + + operator T& () { return Base::first; } + operator const T& () const { return Base::first; } + + Option& operator = ( const T& _rhs ) + { Base::first = _rhs; Base::second=true; return *this; } + + bool operator == ( const T& _rhs ) const + { return Base::first == _rhs; } + + bool operator != ( const T& _rhs ) const + { return Base::first != _rhs; } +}; + +template +std::ostream& operator << (std::ostream& _os, const Option& _opt ) +{ + if (_opt.second) _os << _opt.first; else _os << ""; + return _os; +} + +template +std::istream& operator >> (std::istream& _is, Option& _opt ) +{ + _is >> _opt.first; _opt.second = true; + return _is; +} + +// ---------------------------------------------------------------------------- + +int main(int argc, char *argv[] ) +{ + // ------------------------------------------------------------ command line + + int c; + std::string ifname, ofname; + bool rev_normals = false; + bool obj_center = false; + OpenMesh::IO::Options opt, ropt; + + Option< MyMesh::Point > tvec; + + while ( (c=getopt(argc, argv, "bBcdCi:hlmnNo:sStT:"))!=-1 ) + { + switch(c) + { + case 'b': opt += OpenMesh::IO::Options::Binary; break; + case 'B': ropt += OpenMesh::IO::Options::Binary; break; + case 'l': opt += OpenMesh::IO::Options::LSB; break; + case 'm': opt += OpenMesh::IO::Options::MSB; break; + case 's': opt += OpenMesh::IO::Options::Swap; break; + case 'S': ropt += OpenMesh::IO::Options::Swap; break; + case 'n': opt += OpenMesh::IO::Options::VertexNormal; break; + case 'N': rev_normals = true; break; + case 'C': obj_center = true; break; + case 'c': opt += OpenMesh::IO::Options::VertexColor; break; + case 'd': opt += OpenMesh::IO::Options::FaceColor; break; + case 't': opt += OpenMesh::IO::Options::VertexTexCoord; break; + case 'T': + { + std::cout << optarg << std::endl; + std::stringstream str; str << optarg; + str >> tvec; + std::cout << tvec << std::endl; + break; + } + case 'i': ifname = optarg; break; + case 'o': ofname = optarg; break; + case 'h': + usage_and_exit(0); + case '?': + default: + usage_and_exit(1); + } + } + + if (ifname.empty()) + { + if (optind < argc) + ifname = argv[optind++]; + else + usage_and_exit(1); + } + + MyMesh mesh; + OpenMesh::Utils::Timer timer; + + // ------------------------------------------------------------ read + + std::cout << "reading.." << std::endl; + { + bool rc; + timer.start(); + rc = OpenMesh::IO::read_mesh( mesh, ifname, ropt ); + timer.stop(); + if (rc) + std::cout << " read in " << timer.as_string() << std::endl; + else + { + std::cout << " read failed\n" << std::endl; + return 1; + } + timer.reset(); + } + + + // ---------------------------------------- some information about input + std::cout << (ropt.check(OpenMesh::IO::Options::Binary) + ? " source is binary\n" + : " source is ascii\n"); + + std::cout << " #V " << mesh.n_vertices() << std::endl; + std::cout << " #E " << mesh.n_edges() << std::endl; + std::cout << " #F " << mesh.n_faces() << std::endl; + + if (ropt.vertex_has_texcoord()) + std::cout << " has texture coordinates" << std::endl; + + if (ropt.vertex_has_normal()) + std::cout << " has vertex normals" << std::endl; + + if (ropt.vertex_has_color()) + std::cout << " has vertex colors" << std::endl; + + if (ropt.face_has_normal()) + std::cout << " has face normals" << std::endl; + + if (ropt.face_has_color()) + std::cout << " has face colors" << std::endl; + + // + if (ofname.empty()) + { + if ( optind < argc ) + ofname = argv[optind++]; + else + return 0; + } + + // ------------------------------------------------------------ features + + // ---------------------------------------- compute normal feature + if ( opt.vertex_has_normal() && !ropt.vertex_has_normal()) + { + std::cout << "compute normals" << std::endl; + + timer.start(); + mesh.update_face_normals(); + timer.stop(); + std::cout << " " << mesh.n_faces() + << " face normals in " << timer.as_string() << std::endl; + timer.reset(); + + timer.start(); + mesh.update_vertex_normals(); + timer.stop(); + std::cout << " " << mesh.n_vertices() + << " vertex normals in " << timer.as_string() << std::endl; + timer.reset(); + } + + + // ---------------------------------------- reverse normal feature + if ( rev_normals && ropt.vertex_has_normal() ) + { + std::cout << "reverse normal directions" << std::endl; + timer.start(); + MyMesh::VertexIter vit = mesh.vertices_begin(); + for (; vit != mesh.vertices_end(); ++vit) + mesh.set_normal( vit.handle(), -mesh.normal( vit.handle() ) ); + timer.stop(); + std::cout << " " << mesh.n_vertices() + << " vertex normals in " << timer.as_string() << std::endl; + timer.reset(); + + } + + + // ---------------------------------------- centering feature + if ( obj_center ) + { + OpenMesh::Vec3f cog(0,0,0); + size_t nv; + std::cout << "center object" << std::endl; + timer.start(); + MyMesh::VertexIter vit = mesh.vertices_begin(); + for (; vit != mesh.vertices_end(); ++vit) + cog += mesh.point( vit ); + timer.stop(); + nv = mesh.n_vertices(); + cog *= 1.0f/mesh.n_vertices(); + std::cout << " cog = [" << cog << "]'" << std::endl; + if (cog.sqrnorm() > 0.8) // actually one should consider the size of object + { + vit = mesh.vertices_begin(); + timer.cont(); + for (; vit != mesh.vertices_end(); ++vit) + mesh.set_point( vit , mesh.point( vit )-cog ); + timer.stop(); + nv += mesh.n_vertices(); + } + else + std::cout << " already centered!" << std::endl; + std::cout << " visited " << nv + << " vertices in " << timer.as_string() << std::endl; + timer.reset(); + } + + + // ---------------------------------------- translate feature + if ( tvec.is_valid() ) + { + std::cout << "Translate object by " << tvec << std::endl; + + timer.start(); + MyMesh::VertexIter vit = mesh.vertices_begin(); + for (; vit != mesh.vertices_end(); ++vit) + mesh.set_point( vit , mesh.point( vit ) + tvec.first ); + timer.stop(); + std::cout << " moved " << mesh.n_vertices() + << " vertices in " << timer.as_string() << std::endl; + } + + // ---------------------------------------- color vertices feature + if ( opt.check( OpenMesh::IO::Options::VertexColor ) && + !ropt.check( OpenMesh::IO::Options::VertexColor ) ) + { + std::cout << "Color vertices" << std::endl; + + double d = 256.0/double(mesh.n_vertices()); + double d2 = d/2.0; + double r = 0.0, g = 0.0, b = 255.0; + timer.start(); + MyMesh::VertexIter vit = mesh.vertices_begin(); + for (; vit != mesh.vertices_end(); ++vit) + { + mesh.set_color( vit , MyMesh::Color( std::min((int)(r+0.5),255), + std::min((int)(g+0.5),255), + std::max((int)(b+0.5),0) ) ); + r += d; + g += d2; + b -= d; + } + timer.stop(); + std::cout << " colored " << mesh.n_vertices() + << " vertices in " << timer.as_string() << std::endl; + } + + // ---------------------------------------- color faces feature + if ( opt.check( OpenMesh::IO::Options::FaceColor ) && + !ropt.check( OpenMesh::IO::Options::FaceColor ) ) + { + std::cout << "Color faces" << std::endl; + + double d = 256.0/double(mesh.n_faces()); + double d2 = d/2.0; + double r = 0.0, g = 50.0, b = 255.0; + timer.start(); + MyMesh::FaceIter it = mesh.faces_begin(); + for (; it != mesh.faces_end(); ++it) + { + mesh.set_color( it , MyMesh::Color( std::min((int)(r+0.5),255), + std::min((int)(g+0.5),255), + std::max((int)(b+0.5),0) ) ); + r += d2; +// g += d2; + b -= d; + } + timer.stop(); + std::cout << " colored " << mesh.n_faces() + << " faces in " << timer.as_string() << std::endl; + } + + // ------------------------------------------------------------ write + + std::cout << "writing.." << std::endl; + { + bool rc; + timer.start(); + rc = OpenMesh::IO::write_mesh( mesh, ofname, opt ); + timer.stop(); + + if (!rc) + { + std::cerr << " error writing mesh!" << std::endl; + return 1; + } + + // -------------------------------------- write output and some info + if ( opt.check(OpenMesh::IO::Options::Binary) ) + { + std::cout << " " + << OpenMesh::IO::binary_size(mesh, ofname, opt) + << std::endl; + } + if ( opt.vertex_has_normal() ) + std::cout << " with vertex normals" << std::endl; + if ( opt.vertex_has_color() ) + std::cout << " with vertex colors" << std::endl; + if ( opt.vertex_has_texcoord() ) + std::cout << " with vertex texcoord" << std::endl; + if ( opt.face_has_normal() ) + std::cout << " with face normals" << std::endl; + if ( opt.face_has_color() ) + std::cout << " with face colors" << std::endl; + std::cout << " wrote in " << timer.as_string() << std::endl; + timer.reset(); + } + + return 0; +} diff --git a/Apps/mconvert/mconvert.pro b/Apps/mconvert/mconvert.pro new file mode 100644 index 00000000..88445321 --- /dev/null +++ b/Apps/mconvert/mconvert.pro @@ -0,0 +1,25 @@ +################################################################################ +# +################################################################################ + +contains( OPENFLIPPER , OpenFlipper ){ + include( $$TOPDIR/qmake/all.include ) +} else { + include( $$TOPDIR/OpenMesh/qmake/all.include ) +} + +INCLUDEPATH += ../../.. + +Application() +glew() +glut() +openmesh() + +DIRECTORIES = . + +# Input +HEADERS += $$getFilesFromDir($$DIRECTORIES,*.hh) +SOURCES += $$getFilesFromDir($$DIRECTORIES,*.cc) +FORMS += $$getFilesFromDir($$DIRECTORIES,*.ui) + +################################################################################ diff --git a/CHANGES b/CHANGES new file mode 100644 index 00000000..a2ebd605 --- /dev/null +++ b/CHANGES @@ -0,0 +1,50 @@ +This file contains the changes, that have been made between two versions +of OpenMesh. It lists only the changes yielding incompatibilities! + +0-12-0 -> 1-0-0 +~~~~~~~~~~~~~~~ + +- Internal data storage has changed. Now each property of + each entity (vertex/face/...) is stored in a separate array. For + instance all face normals are in one array now. + +- Decimater module handling improved and corrected. + +- OBJReader has limited ability to read material files. The diffuse color + information is used to set the face color property if both are + available. + +- Added tool for View Dependent Progressive Meshes. + Demo applications are located in in OpenMesh/Apps/VDProgMesh. + +- Documentation moved to OpenMesh/Doc. + +- OpenMesh/Win/msvc7 contains an MS VC++ solution file and projects viles. + +- ASCII based file formats use C I/O functions instead of C++ I/O streams. + The change increased the speed of reading and writing by factor 2. + +- Utility to create triangle strips from a mesh. + +0-11-2 -> 0-12-0 +~~~~~~~~~~~~~~~~ + +- directory structure has changed! + Use script migrate.sh to adjust your existing sources and ACGMakefiles + software. +- OpenMesh::IO: The read/write methods need now an additional argument +- Namespace MeshIO has been renamed to IO + Use script migrate.sh to adjust your existing sources. + +1-9-6 -> 2-0 +~~~~~~~~~~~~~~~~~ + +- Reader / writer have been updated + +- Some general bugfixes + +- The usage of acgmake has become deprecated since the last release. + It has been entirely replaced by qmake. + +- Credits to Simon Floery, Canjiang Ren, Johannes Totz, Leon Kos, + Jean Pierre Charalambos, Mathieu Gauthier diff --git a/Core/ACGMakefile b/Core/ACGMakefile new file mode 100644 index 00000000..8c763067 --- /dev/null +++ b/Core/ACGMakefile @@ -0,0 +1,19 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = Geometry Utils Mesh IO Tools System + +PACKAGES := + +PROJ_LIBS := + +CXXLIB_BUILD_LIB := yes + +MODULES := cxxlib + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Core/Core.pro b/Core/Core.pro new file mode 100644 index 00000000..ac8d33e9 --- /dev/null +++ b/Core/Core.pro @@ -0,0 +1,32 @@ +################################################################################ +# +################################################################################ + +contains( OPENFLIPPER , OpenFlipper ){ + include( $$TOPDIR/qmake/all.include ) +} else { + include( $$TOPDIR/OpenMesh/qmake/all.include ) +} + +Library() + +DIRECTORIES = . Geometry IO IO/exporter IO/importer IO/reader IO/writer \ + Mesh Mesh/gen System Utils + +INCLUDEPATH += ../.. + +win32 { + DEFINES += _USE_MATH_DEFINES NOMINMAX + CONFIG += static + contains( OPENFLIPPER , OpenFlipper ){ + DESTDIR = $${TOPDIR}/OpenFlipper/$${BUILDDIRECTORY} + message(OpenMesh Library is Building for OpenFlipper ) + } +} + +# Input +HEADERS += $$getFilesFromDir($$DIRECTORIES,*.hh) +SOURCES += $$getFilesFromDir($$DIRECTORIES,*.cc) +FORMS += $$getFilesFromDir($$DIRECTORIES,*.ui) + +################################################################################ diff --git a/Core/Geometry/ACGMakefile b/Core/Geometry/ACGMakefile new file mode 100644 index 00000000..bbd4512f --- /dev/null +++ b/Core/Geometry/ACGMakefile @@ -0,0 +1,17 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = $(call find-subdirs) + +PACKAGES := + +PROJ_LIBS := + +MODULES := cxxlib + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Core/Geometry/Config.hh b/Core/Geometry/Config.hh new file mode 100644 index 00000000..d1399ddb --- /dev/null +++ b/Core/Geometry/Config.hh @@ -0,0 +1,56 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// Defines +// +//============================================================================= + +#ifndef OPENMESH_GEOMETRY_CONFIG_HH +#define OPENMESH_GEOMETRY_CONFIG_HH + + +//== INCLUDES ================================================================= + +// OpenMesh Namespace Defines +#include + + +//== NAMESPACES =============================================================== + +#define BEGIN_NS_GEOMETRY namespace geometry { +#define END_NS_GEOMETRY } + + +//============================================================================= +#endif // OPENMESH_GEOMETRY_CONFIG_HH defined +//============================================================================= diff --git a/Core/Geometry/LoopSchemeMaskT.hh b/Core/Geometry/LoopSchemeMaskT.hh new file mode 100644 index 00000000..f3c1fbc2 --- /dev/null +++ b/Core/Geometry/LoopSchemeMaskT.hh @@ -0,0 +1,172 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + +#ifndef LOOPSCHEMEMASKT_HH +#define LOOPSCHEMEMASKT_HH + +#include +#include + +#include +#include + +namespace OpenMesh +{ + +/** implements cache for the weights of the original Loop scheme + supported: + - vertex projection rule on the next level + - vertex projection rule on the limit surface + - vertex projection rule on the k-th (level) step (Barthe, Kobbelt'2003) + - vertex tangents on the limit surface +*/ + +template +class LoopSchemeMaskT +{ +public: + enum { cache_size = cache_size_ }; + typedef T_ Scalar; + +protected: + + Scalar proj_weights_[cache_size]; + Scalar limit_weights_[cache_size]; + Scalar step_weights_[cache_size]; + std::vector tang0_weights_[cache_size]; + std::vector tang1_weights_[cache_size]; + +protected: + + inline static Scalar compute_proj_weight(uint _valence) + { + //return pow(3.0 / 2.0 + cos(2.0 * M_PI / _valence), 2) / 2.0 - 1.0; + double denom = (3.0 + 2.0*cos(2.0*M_PI/(double)_valence)); + double weight = (64.0*_valence)/(40.0 - denom*denom) - _valence; + return (Scalar) weight; + } + + inline static Scalar compute_limit_weight(uint _valence) + { + double proj_weight = compute_proj_weight(_valence); + proj_weight = proj_weight/(proj_weight + _valence);//normalize the proj_weight + double weight = (3.0/8.0)/(1.0 - proj_weight + (3.0/8.0)); + return (Scalar)weight; + } + + inline static Scalar compute_step_weight(uint _valence) + { + double proj_weight = compute_proj_weight(_valence); + proj_weight = proj_weight/(proj_weight + _valence);//normalize the proj_weight + double weight = proj_weight - (3.0/8.0); + return (Scalar)weight; + } + + inline static Scalar compute_tang0_weight(uint _valence, uint _ver_id) + { + return (Scalar)cos(2.0*M_PI*(double)_ver_id/(double)_valence); + } + + inline static Scalar compute_tang1_weight(uint _valence, uint _ver_id) + { + return (Scalar)sin(2.0*M_PI*(double)_ver_id/(double)_valence); + } + + void cache_weights() + { + proj_weights_[0] = 1; + for (uint k = 1; k < cache_size; ++k) + { + proj_weights_[k] = compute_proj_weight(k); + limit_weights_[k] = compute_limit_weight(k); + step_weights_[k] = compute_step_weight(k); + tang0_weights_[k].resize(k); + tang1_weights_[k].resize(k); + for (uint i = 0; i < k; ++i) + { + tang0_weights_[k][i] = compute_tang0_weight(k,i); + tang1_weights_[k][i] = compute_tang1_weight(k,i); + } + } + } + +public: + + LoopSchemeMaskT() + { + cache_weights(); + } + + inline Scalar proj_weight(uint _valence) const + { + assert(_valence < cache_size ); + return proj_weights_[_valence]; + } + + inline Scalar limit_weight(uint _valence) const + { + assert(_valence < cache_size ); + return limit_weights_[_valence]; + } + + inline Scalar step_weight(uint _valence, uint _step) const + { + assert(_valence < cache_size); + return pow(step_weights_[_valence], (int)_step);//can be precomputed + } + + inline Scalar tang0_weight(uint _valence, uint _ver_id) const + { + assert(_valence < cache_size ); + assert(_ver_id < _valence); + return tang0_weights_[_valence][_ver_id]; + } + + inline Scalar tang1_weight(uint _valence, uint _ver_id) const + { + assert(_valence < cache_size ); + assert(_ver_id < _valence); + return tang1_weights_[_valence][_ver_id]; + } + + void dump(uint _max_valency = cache_size - 1) const + { + assert(_max_valency <= cache_size - 1); + //CConsole::printf("(k : pw_k, lw_k): "); + for (uint i = 0; i <= _max_valency; ++i) + { + //CConsole::stream() << "(" << i << " : " << proj_weight(i) << ", " << limit_weight(i) << ", " << step_weight(i,1) << "), "; + } + //CConsole::printf("\n"); + } +}; + +typedef LoopSchemeMaskT LoopSchemeMaskDouble; +typedef SingletonT LoopSchemeMaskDoubleSingleton; + +};//namespace OpenMesh + +#endif//LOOPSCHEMEMASKT_HH + diff --git a/Core/Geometry/MathDefs.hh b/Core/Geometry/MathDefs.hh new file mode 100644 index 00000000..b61e06bd --- /dev/null +++ b/Core/Geometry/MathDefs.hh @@ -0,0 +1,148 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + +#ifndef MATHDEFS_HH +#define MATHDEFS_HH + +#include +#include + +#ifndef M_PI + #define M_PI 3.14159265359 +#endif + +namespace OpenMesh +{ + +/** comparison operators with user-selected precision control +*/ +template +inline bool is_zero(const T& _a, Real _eps) +{ return fabs(_a) < _eps; } + +template +inline bool is_eq(const T1& a, const T2& b, Real _eps) +{ return is_zero(a-b, _eps); } + +template +inline bool is_gt(const T1& a, const T2& b, Real _eps) +{ return (a > b) && !is_eq(a,b,_eps); } + +template +inline bool is_ge(const T1& a, const T2& b, Real _eps) +{ return (a > b) || is_eq(a,b,_eps); } + +template +inline bool is_lt(const T1& a, const T2& b, Real _eps) +{ return (a < b) && !is_eq(a,b,_eps); } + +template +inline bool is_le(const T1& a, const T2& b, Real _eps) +{ return (a < b) || is_eq(a,b,_eps); } + +/*const float flt_eps__ = 10*FLT_EPSILON; +const double dbl_eps__ = 10*DBL_EPSILON;*/ +const float flt_eps__ = (float)1e-05; +const double dbl_eps__ = 1e-09; + +inline float eps__(float) +{ return flt_eps__; } + +inline double eps__(double) +{ return dbl_eps__; } + +template +inline bool is_zero(const T& a) +{ return is_zero(a, eps__(a)); } + +template +inline bool is_eq(const T1& a, const T2& b) +{ return is_zero(a-b); } + +template +inline bool is_gt(const T1& a, const T2& b) +{ return (a > b) && !is_eq(a,b); } + +template +inline bool is_ge(const T1& a, const T2& b) +{ return (a > b) || is_eq(a,b); } + +template +inline bool is_lt(const T1& a, const T2& b) +{ return (a < b) && !is_eq(a,b); } + +template +inline bool is_le(const T1& a, const T2& b) +{ return (a < b) || is_eq(a,b); } + +/// Trigonometry/angles - related + +template +inline T sane_aarg(T _aarg) +{ + if (_aarg < -1) + { + _aarg = -1; + } + else if (_aarg > 1) + { + _aarg = 1; + } + return _aarg; +} + +/** returns the angle determined by its cos and the sign of its sin + result is positive if the angle is in [0:pi] + and negative if it is in [pi:2pi] +*/ +template +T angle(T _cos_angle, T _sin_angle) +{//sanity checks - otherwise acos will return nan + _cos_angle = sane_aarg(_cos_angle); + return (T) _sin_angle >= 0 ? acos(_cos_angle) : -acos(_cos_angle); +} + +template +inline T positive_angle(T _angle) +{ return _angle < 0 ? (2*M_PI + _angle) : _angle; } + +template +inline T positive_angle(T _cos_angle, T _sin_angle) +{ return positive_angle(angle(_cos_angle, _sin_angle)); } + +template +inline T deg_to_rad(const T& _angle) +{ return M_PI*(_angle/180); } + +template +inline T rad_to_deg(const T& _angle) +{ return 180*(_angle/M_PI); } + +inline double log_(double _value) +{ return log(_value); } + +};//namespace OpenMesh + +#endif//MATHDEFS_HH diff --git a/Core/Geometry/Plane3d.hh b/Core/Geometry/Plane3d.hh new file mode 100644 index 00000000..1e191cf1 --- /dev/null +++ b/Core/Geometry/Plane3d.hh @@ -0,0 +1,99 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS Plane3D +// +//============================================================================= + + +#ifndef OPENMESH_PLANE3D_HH +#define OPENMESH_PLANE3D_HH + + +//== INCLUDES ================================================================= + +#include + + +//== FORWARDDECLARATIONS ====================================================== + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** \class Plane3d Plane3d.hh + + ax + by + cz + d = 0 +*/ + + +class Plane3d +{ +public: + + typedef OpenMesh::Vec3f vector_type; + typedef vector_type::value_type value_type; + +public: + + Plane3d() + : d_(0) + { } + + Plane3d(const vector_type &_dir, const vector_type &_pnt) + : n_(_dir), d_(0) + { + n_.normalize(); + d_ = -dot(n_,_pnt); + } + + value_type signed_distance(const OpenMesh::Vec3f &_p) + { + return dot(n_ , _p) + d_; + } + + // back compatibility + value_type singed_distance(const OpenMesh::Vec3f &point) + { return signed_distance( point ); } + +public: + + vector_type n_; + value_type d_; + +}; + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_PLANE3D_HH defined +//============================================================================= diff --git a/Core/Geometry/QuadricT.hh b/Core/Geometry/QuadricT.hh new file mode 100644 index 00000000..4976694c --- /dev/null +++ b/Core/Geometry/QuadricT.hh @@ -0,0 +1,260 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + +/** \file QuadricT.hh + + */ + +//============================================================================= +// +// CLASS QuadricT +// +//============================================================================= + +#ifndef OPENMESH_GEOMETRY_QUADRIC_HH +#define OPENMESH_GEOMETRY_QUADRIC_HH + + +//== INCLUDES ================================================================= + +#include "Config.hh" +#include +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { //BEGIN_NS_OPENMESH +namespace Geometry { //BEGIN_NS_GEOMETRY + + +//== CLASS DEFINITION ========================================================= + + +/** /class QuadricT QuadricT.hh + + Stores a quadric as a 4x4 symmetrix matrix. Used by the + error quadric based mesh decimation algorithms. +**/ + +template +class QuadricT +{ +public: + typedef Scalar value_type; + typedef QuadricT type; + typedef QuadricT Self; + // typedef VectorInterface > Vec3; + // typedef VectorInterface > Vec4; + //typedef Vector3Elem Vec3; + //typedef Vector4Elem Vec4; + + /// construct with upper triangle of symmetrix 4x4 matrix + QuadricT(Scalar _a, Scalar _b, Scalar _c, Scalar _d, + Scalar _e, Scalar _f, Scalar _g, + Scalar _h, Scalar _i, + Scalar _j) + : a_(_a), b_(_b), c_(_c), d_(_d), + e_(_e), f_(_f), g_(_g), + h_(_h), i_(_i), + j_(_j) + { + } + + + /// constructor from given plane equation: ax+by+cz+d_=0 + QuadricT( Scalar _a=0.0, Scalar _b=0.0, Scalar _c=0.0, Scalar _d=0.0 ) + : a_(_a*_a), b_(_a*_b), c_(_a*_c), d_(_a*_d), + e_(_b*_b), f_(_b*_c), g_(_b*_d), + h_(_c*_c), i_(_c*_d), + j_(_d*_d) + {} + + template + QuadricT(const _Point& _pt) + { + set_distance_to_point(_pt); + } + + template + QuadricT(const _Normal& _n, const _Point& _p) + { + set_distance_to_plane(_n,_p); + } + + //set operator + void set(Scalar _a, Scalar _b, Scalar _c, Scalar _d, + Scalar _e, Scalar _f, Scalar _g, + Scalar _h, Scalar _i, + Scalar _j) + { + a_ = _a; b_ = _b; c_ = _c; d_ = _d; + e_ = _e; f_ = _f; g_ = _g; + h_ = _h; i_ = _i; + j_ = _j; + } + + //sets the quadric representing the squared distance to _pt + template + void set_distance_to_point(const _Point& _pt) + { + set(1, 0, 0, -_pt[0], + 1, 0, -_pt[1], + 1, -_pt[2], + dot(_pt,_pt)); + } + + //sets the quadric representing the squared distance to the plane [_a,_b,_c,_d] + void set_distance_to_plane(Scalar _a, Scalar _b, Scalar _c, Scalar _d) + { + a_ = _a*_a; b_ = _a*_b; c_ = _a*_c; d_ = _a*_d; + e_ = _b*_b; f_ = _b*_c; g_ = _b*_d; + h_ = _c*_c; i_ = _c*_d; + j_ = _d*_d; + } + + //sets the quadric representing the squared distance to the plane + //determined by the normal _n and the point _p + template + void set_distance_to_plane(const _Normal& _n, const _Point& _p) + { + set_distance_to_plane(_n[0], _n[1], _n[2], -dot(_n,_p)); + } + + /// set all entries to zero + void clear() { a_ = b_ = c_ = d_ = e_ = f_ = g_ = h_ = i_ = j_ = 0.0; } + + /// add quadrics + QuadricT& operator+=( const QuadricT& _q ) + { + a_ += _q.a_; b_ += _q.b_; c_ += _q.c_; d_ += _q.d_; + e_ += _q.e_; f_ += _q.f_; g_ += _q.g_; + h_ += _q.h_; i_ += _q.i_; + j_ += _q.j_; + return *this; + } + + + /// multiply by scalar + QuadricT& operator*=( Scalar _s) + { + a_ *= _s; b_ *= _s; c_ *= _s; d_ *= _s; + e_ *= _s; f_ *= _s; g_ *= _s; + h_ *= _s; i_ *= _s; + j_ *= _s; + return *this; + } + + + /// multiply 4D vector from right: Q*v + template + _Vec4 operator*(const _Vec4& _v) const + { + Scalar x(_v[0]), y(_v[1]), z(_v[2]), w(_v[3]); + return _Vec4(x*a_ + y*b_ + z*c_ + w*d_, + x*b_ + y*e_ + z*f_ + w*g_, + x*c_ + y*f_ + z*h_ + w*i_, + x*d_ + y*g_ + z*i_ + w*j_); + } + + /// evaluate quadric Q at (3D or 4D) vector v: v*Q*v + template + Scalar operator()(const _Vec& _v) const + { + return evaluate(_v, GenProg::Int2Type<_Vec::size_>()); + } + + Scalar a() const { return a_; } + Scalar b() const { return b_; } + Scalar c() const { return c_; } + Scalar d() const { return d_; } + Scalar e() const { return e_; } + Scalar f() const { return f_; } + Scalar g() const { return g_; } + Scalar h() const { return h_; } + Scalar i() const { return i_; } + Scalar j() const { return j_; } + + Scalar xx() const { return a_; } + Scalar xy() const { return b_; } + Scalar xz() const { return c_; } + Scalar xw() const { return d_; } + Scalar yy() const { return e_; } + Scalar yz() const { return f_; } + Scalar yw() const { return g_; } + Scalar zz() const { return h_; } + Scalar zw() const { return i_; } + Scalar ww() const { return j_; } + +protected: + + /// evaluate quadric Q at 3D vector v: v*Q*v + template + Scalar evaluate(const _Vec3& _v, GenProg::Int2Type<3>/*_dimension*/) const + { + Scalar x(_v[0]), y(_v[1]), z(_v[2]); + return a_*x*x + 2.0*b_*x*y + 2.0*c_*x*z + 2.0*d_*x + + e_*y*y + 2.0*f_*y*z + 2.0*g_*y + + h_*z*z + 2.0*i_*z + + j_; + } + + /// evaluate quadric Q at 4D vector v: v*Q*v + template + Scalar evaluate(const _Vec4& _v, GenProg::Int2Type<4>/*_dimension*/) const + { + Scalar x(_v[0]), y(_v[1]), z(_v[2]), w(_v[3]); + return a_*x*x + 2.0*b_*x*y + 2.0*c_*x*z + 2.0*d_*x*w + + e_*y*y + 2.0*f_*y*z + 2.0*g_*y*w + + h_*z*z + 2.0*i_*z*w + + j_*w*w; + } + +private: + + Scalar a_, b_, c_, d_, + e_, f_, g_, + h_, i_, + j_; +}; + + +/// Quadric using floats +typedef QuadricT Quadricf; + +/// Quadric using double +typedef QuadricT Quadricd; + + +//============================================================================= +} // END_NS_GEOMETRY +} // END_NS_OPENMESH +//============================================================================ +#endif // OPENMESH_GEOMETRY_HH defined +//============================================================================= diff --git a/Core/Geometry/VectorT.hh b/Core/Geometry/VectorT.hh new file mode 100644 index 00000000..447ddff4 --- /dev/null +++ b/Core/Geometry/VectorT.hh @@ -0,0 +1,329 @@ +//============================================================================= +// +// 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: 4254 $ +// $Date: 2009-01-12 14:44:00 +0100 (Mo, 12. Jan 2009) $ +// +//============================================================================= + + +//============================================================================= +// +// CLASS VectorT +// +//============================================================================= + + +#ifndef OPENMESH_VECTOR_HH +#define OPENMESH_VECTOR_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include + +#if defined(__GNUC__) && defined(__SSE__) +#include +#endif + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + + +/** The N values of the template Scalar type are the only data members + of the class VectorT. This guarantees 100% compatibility + with arrays of type Scalar and size N, allowing us to define the + cast operators to and from arrays and array pointers. + + In addition, this class will be specialized for Vec4f to be 16 bit + aligned, so that aligned SSE instructions can be used on these + vectors. +*/ +template struct VectorDataT +{ + Scalar values_[N]; +}; + + +#if defined(__GNUC__) && defined(__SSE__) + +/// This specialization enables us to use aligned SSE instructions. +template <> struct VectorDataT +{ + union + { + __m128 m128; + float values_[4]; + }; +}; + +#endif + + + + +//== CLASS DEFINITION ========================================================= + + +#define DIM N +#define TEMPLATE_HEADER template +#define CLASSNAME VectorT +#define DERIVED VectorDataT +#define unroll(expr) for (int i=0; i + A vector is an array of \ values of type \. + The actual data is stored in an VectorDataT, this class just adds + the necessary operators. +*/ +#include "VectorT_inc.hh" + +#undef DIM +#undef TEMPLATE_HEADER +#undef CLASSNAME +#undef DERIVED +#undef unroll + + + + +//== PARTIAL TEMPLATE SPECIALIZATIONS ========================================= +#if OM_PARTIAL_SPECIALIZATION + + +#define TEMPLATE_HEADER template +#define CLASSNAME VectorT +#define DERIVED VectorDataT + + +#define DIM 2 +#define unroll(expr) expr(0) expr(1) +#define unroll_comb(expr, op) expr(0) op expr(1) +#define unroll_csv(expr) expr(0), expr(1) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + + +#define DIM 3 +#define unroll(expr) expr(0) expr(1) expr(2) +#define unroll_comb(expr, op) expr(0) op expr(1) op expr(2) +#define unroll_csv(expr) expr(0), expr(1), expr(2) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + + +#define DIM 4 +#define unroll(expr) expr(0) expr(1) expr(2) expr(3) +#define unroll_comb(expr, op) expr(0) op expr(1) op expr(2) op expr(3) +#define unroll_csv(expr) expr(0), expr(1), expr(2), expr(3) +#include "VectorT_inc.hh" +#undef DIM +#undef unroll +#undef unroll_comb +#undef unroll_csv + + +#undef TEMPLATE_HEADER +#undef CLASSNAME +#undef DERIVED + + + + +//== FULL TEMPLATE SPECIALIZATIONS ============================================ +#else + +# ifndef DOXY_IGNORE_THIS + +/// cross product for Vec3f +template<> +inline VectorT +VectorT::operator%(const VectorT& _rhs) const +{ + return + VectorT(values_[1]*_rhs.values_[2]-values_[2]*_rhs.values_[1], + values_[2]*_rhs.values_[0]-values_[0]*_rhs.values_[2], + values_[0]*_rhs.values_[1]-values_[1]*_rhs.values_[0]); +} + + +/// cross product for Vec3d +template<> +inline VectorT +VectorT::operator%(const VectorT& _rhs) const +{ + return + VectorT(values_[1]*_rhs.values_[2]-values_[2]*_rhs.values_[1], + values_[2]*_rhs.values_[0]-values_[0]*_rhs.values_[2], + values_[0]*_rhs.values_[1]-values_[1]*_rhs.values_[0]); +} + +# endif // DOXY_IGNORE_THIS + +#endif + + + +//== GLOBAL FUNCTIONS ========================================================= + + +/// \relates OpenMesh::VectorT +/// scalar * vector +template +inline VectorT operator*(Scalar _s, const VectorT& _v) { + return VectorT(_v) *= _s; +} + + +/// \relates OpenMesh::VectorT +/// symmetric version of the dot product +template +inline Scalar +dot(const VectorT& _v1, const VectorT& _v2) { + return (_v1 | _v2); +} + + +/// \relates OpenMesh::VectorT +/// symmetric version of the cross product +template +inline VectorT +cross(const VectorT& _v1, const VectorT& _v2) { + return (_v1 % _v2); +} + + + + +//== TYPEDEFS ================================================================= + +/** 1-byte signed vector */ +typedef VectorT Vec1c; +/** 1-byte unsigned vector */ +typedef VectorT Vec1uc; +/** 1-short signed vector */ +typedef VectorT Vec1s; +/** 1-short unsigned vector */ +typedef VectorT Vec1us; +/** 1-int signed vector */ +typedef VectorT Vec1i; +/** 1-int unsigned vector */ +typedef VectorT Vec1ui; +/** 1-float vector */ +typedef VectorT Vec1f; +/** 1-double vector */ +typedef VectorT Vec1d; + +/** 2-byte signed vector */ +typedef VectorT Vec2c; +/** 2-byte unsigned vector */ +typedef VectorT Vec2uc; +/** 2-short signed vector */ +typedef VectorT Vec2s; +/** 2-short unsigned vector */ +typedef VectorT Vec2us; +/** 2-int signed vector */ +typedef VectorT Vec2i; +/** 2-int unsigned vector */ +typedef VectorT Vec2ui; +/** 2-float vector */ +typedef VectorT Vec2f; +/** 2-double vector */ +typedef VectorT Vec2d; + +/** 3-byte signed vector */ +typedef VectorT Vec3c; +/** 3-byte unsigned vector */ +typedef VectorT Vec3uc; +/** 3-short signed vector */ +typedef VectorT Vec3s; +/** 3-short unsigned vector */ +typedef VectorT Vec3us; +/** 3-int signed vector */ +typedef VectorT Vec3i; +/** 3-int unsigned vector */ +typedef VectorT Vec3ui; +/** 3-float vector */ +typedef VectorT Vec3f; +/** 3-double vector */ +typedef VectorT Vec3d; + +/** 4-byte signed vector */ +typedef VectorT Vec4c; +/** 4-byte unsigned vector */ +typedef VectorT Vec4uc; +/** 4-short signed vector */ +typedef VectorT Vec4s; +/** 4-short unsigned vector */ +typedef VectorT Vec4us; +/** 4-int signed vector */ +typedef VectorT Vec4i; +/** 4-int unsigned vector */ +typedef VectorT Vec4ui; +/** 4-float vector */ +typedef VectorT Vec4f; +/** 4-double vector */ +typedef VectorT Vec4d; + +/** 6-byte signed vector */ +typedef VectorT Vec6c; +/** 6-byte unsigned vector */ +typedef VectorT Vec6uc; +/** 6-short signed vector */ +typedef VectorT Vec6s; +/** 6-short unsigned vector */ +typedef VectorT Vec6us; +/** 6-int signed vector */ +typedef VectorT Vec6i; +/** 6-int unsigned vector */ +typedef VectorT Vec6ui; +/** 6-float vector */ +typedef VectorT Vec6f; +/** 6-double vector */ +typedef VectorT Vec6d; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VECTOR_HH defined +//============================================================================= diff --git a/Core/Geometry/VectorT_inc.hh b/Core/Geometry/VectorT_inc.hh new file mode 100644 index 00000000..68535044 --- /dev/null +++ b/Core/Geometry/VectorT_inc.hh @@ -0,0 +1,541 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + +#if defined( OPENMESH_VECTOR_HH ) + +// ---------------------------------------------------------------------------- + +TEMPLATE_HEADER +class CLASSNAME : public DERIVED +{ +private: + typedef DERIVED Base; +public: + + //---------------------------------------------------------------- class info + + /// the type of the scalar used in this template + typedef Scalar value_type; + + /// type of this vector + typedef VectorT vector_type; + + /// returns dimension of the vector (deprecated) + static inline int dim() { return DIM; } + + /// returns dimension of the vector + static inline size_t size() { return DIM; } + + static const size_t size_ = DIM; + + + //-------------------------------------------------------------- constructors + + /// default constructor creates uninitialized values. + inline VectorT() {} + + /// special constructor for 1D vectors + explicit inline VectorT(const Scalar& v) { +// assert(DIM==1); +// values_[0] = v0; + vectorize(v); + } + + /// special constructor for 2D vectors + inline VectorT(const Scalar& v0, const Scalar& v1) { + assert(DIM==2); + Base::values_[0] = v0; Base::values_[1] = v1; + } + + /// special constructor for 3D vectors + inline VectorT(const Scalar& v0, const Scalar& v1, const Scalar& v2) { + assert(DIM==3); + Base::values_[0]=v0; Base::values_[1]=v1; Base::values_[2]=v2; + } + + /// special constructor for 4D vectors + inline VectorT(const Scalar& v0, const Scalar& v1, + const Scalar& v2, const Scalar& v3) { + assert(DIM==4); + Base::values_[0]=v0; Base::values_[1]=v1; Base::values_[2]=v2; Base::values_[3]=v3; + } + + /// special constructor for 5D vectors + inline VectorT(const Scalar& v0, const Scalar& v1, const Scalar& v2, + const Scalar& v3, const Scalar& v4) { + assert(DIM==5); + Base::values_[0]=v0; Base::values_[1]=v1;Base::values_[2]=v2; Base::values_[3]=v3; Base::values_[4]=v4; + } + + /// special constructor for 6D vectors + inline VectorT(const Scalar& v0, const Scalar& v1, const Scalar& v2, + const Scalar& v3, const Scalar& v4, const Scalar& v5) { + assert(DIM==6); + Base::values_[0]=v0; Base::values_[1]=v1; Base::values_[2]=v2; + Base::values_[3]=v3; Base::values_[4]=v4; Base::values_[5]=v5; + } + + /// construct from a value array (explicit) + explicit inline VectorT(const Scalar _values[DIM]) { + memcpy(Base::values_, _values, DIM*sizeof(Scalar)); + } + + +#ifdef OM_CC_MIPS + /// assignment from a vector of the same kind + // mipspro need this method + inline vector_type& operator=(const vector_type& _rhs) { + memcpy(Base::values_, _rhs.Base::values_, DIM*sizeof(Scalar)); + return *this; + } +#endif + + + /// copy & cast constructor (explicit) + template + explicit inline VectorT(const VectorT& _rhs) { + operator=(_rhs); + } + + + + + //--------------------------------------------------------------------- casts + + /// cast from vector with a different scalar type + template + inline vector_type& operator=(const VectorT& _rhs) { +#define expr(i) Base::values_[i] = (Scalar)_rhs[i]; + unroll(expr); +#undef expr + return *this; + } + +// /// cast to Scalar array +// inline operator Scalar*() { return Base::values_; } + +// /// cast to const Scalar array +// inline operator const Scalar*() const { return Base::values_; } + + /// access to Scalar array + inline Scalar* data() { return Base::values_; } + + /// access to const Scalar array + inline const Scalar*data() const { return Base::values_; } + + + + + //----------------------------------------------------------- element access + +// /// get i'th element read-write +// inline Scalar& operator[](int _i) { +// assert(_i>=0 && _i=0 && _i operator%(const VectorT& _rhs) const +#if DIM==3 + { + return + VectorT(Base::values_[1]*_rhs.Base::values_[2]-Base::values_[2]*_rhs.Base::values_[1], + Base::values_[2]*_rhs.Base::values_[0]-Base::values_[0]*_rhs.Base::values_[2], + Base::values_[0]*_rhs.Base::values_[1]-Base::values_[1]*_rhs.Base::values_[0]); + } +#else + ; +#endif + + + /// compute scalar product + /// \see OpenMesh::dot + inline Scalar operator|(const vector_type& _rhs) const { + Scalar p(0); +#define expr(i) p += Base::values_[i] * _rhs.Base::values_[i]; + unroll(expr); +#undef expr + return p; + } + + + + + + //------------------------------------------------------------ euclidean norm + + /// \name Euclidean norm calculations + //@{ + /// compute euclidean norm + inline Scalar norm() const { return (Scalar)sqrt(sqrnorm()); } + inline Scalar length() const { return norm(); } // OpenSG interface + + /// compute squared euclidean norm + inline Scalar sqrnorm() const + { +#if DIM==N + Scalar s(0); +#define expr(i) s += Base::values_[i] * Base::values_[i]; + unroll(expr); +#undef expr + return s; +#else +#define expr(i) Base::values_[i]*Base::values_[i] + return (unroll_comb(expr, +)); +#undef expr +#endif + } + //@} + + /** normalize vector, return normalized vector + */ + + inline vector_type& normalize() + { + *this /= norm(); + return *this; + } + + /** normalize vector, return normalized vector and avoids div by zero + */ + inline vector_type& normalize_cond() + { + Scalar n = norm(); + if (n != (Scalar)0.0) + { + *this /= n; + } + return *this; + } + + + //------------------------------------------------------------ max, min, mean + + /// return the maximal component + inline Scalar max() const + { + Scalar m(Base::values_[0]); + for(int i=1; im) m=Base::values_[i]; + return m; + } + + /// return the minimal component + inline Scalar min() const + { + Scalar m(Base::values_[0]); + for(int i=1; i Base::values_[i]) Base::values_[i] = _rhs[i]; + unroll(expr); +#undef expr + return *this; + } + + /// component-wise min + inline vector_type min(const vector_type& _rhs) { + return vector_type(*this).minimize(_rhs); + } + + /// component-wise max + inline vector_type max(const vector_type& _rhs) { + return vector_type(*this).maximize(_rhs); + } + + + + + //------------------------------------------------------------ misc functions + + /// component-wise apply function object with Scalar operator()(Scalar). + template + inline vector_type apply(const Functor& _func) const { + vector_type result; +#define expr(i) result[i] = _func(Base::values_[i]); + unroll(expr); +#undef expr + return result; + } + + /// store the same value in each component (e.g. to clear all entries) + vector_type& vectorize(const Scalar& _s) { +#define expr(i) Base::values_[i] = _s; + unroll(expr); +#undef expr + return *this; + } + + + /// store the same value in each component + static vector_type vectorized(const Scalar& _s) { + return vector_type().vectorize(_s); + } + + + /// lexicographical comparison + bool operator<(const vector_type& _rhs) const { +#define expr(i) if (Base::values_[i] != _rhs.Base::values_[i]) \ + return (Base::values_[i] < _rhs.Base::values_[i]); + unroll(expr); +#undef expr + return false; + } +}; + + + +/// read the space-separated components of a vector from a stream +TEMPLATE_HEADER +inline std::istream& +operator>>(std::istream& is, VectorT& vec) +{ +#define expr(i) is >> vec[i]; + unroll(expr); +#undef expr + return is; +} + + +/// output a vector by printing its space-separated compontens +TEMPLATE_HEADER +inline std::ostream& +operator<<(std::ostream& os, const VectorT& vec) +{ +#if DIM==N + for(int i=0; i +// -------------------- STL +#include +// -------------------- OpenMesh +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + +#ifndef DOXY_IGNORE_THIS + +//== IMPLEMENTATION =========================================================== + + +union u1 { short int s; unsigned char c[2]; } sc; +union u2 { int i; unsigned char c[4]; } ic; +union u3 { float f; unsigned char c[4]; } fc; +union u4 { double d; unsigned char c[8]; } dc; + + +//----------------------------------------------------------------------------- + +short int read_short(FILE* _in, bool _swap) +{ + fread((char*)sc.c, 1, 2, _in); + if (_swap) std::swap(sc.c[0], sc.c[1]); + return sc.s; +} + + +//----------------------------------------------------------------------------- + + +int read_int(FILE* _in, bool _swap) +{ + fread((char*)ic.c, 1, 4, _in); + if (_swap) { + std::swap(ic.c[0], ic.c[3]); + std::swap(ic.c[1], ic.c[2]); + } + return ic.i; +} + + +//----------------------------------------------------------------------------- + + +float read_float(FILE* _in, bool _swap) +{ + fread((char*)fc.c, 1, 4, _in); + if (_swap) { + std::swap(fc.c[0], fc.c[3]); + std::swap(fc.c[1], fc.c[2]); + } + return fc.f; +} + + +//----------------------------------------------------------------------------- + + +double read_double(FILE* _in, bool _swap) +{ + fread((char*)dc.c, 1, 8, _in); + if (_swap) { + std::swap(dc.c[0], dc.c[7]); + std::swap(dc.c[1], dc.c[6]); + std::swap(dc.c[2], dc.c[5]); + std::swap(dc.c[3], dc.c[4]); + } + return dc.d; +} + + +//----------------------------------------------------------------------------- + + +void write_short(short int _i, FILE* _out, bool _swap) +{ + sc.s = _i; + if (_swap) std::swap(sc.c[0], sc.c[1]); + fwrite((char*)sc.c, 1, 2, _out); +} + + +//----------------------------------------------------------------------------- + + +void write_int(int _i, FILE* _out, bool _swap) +{ + ic.i = _i; + if (_swap) { + std::swap(ic.c[0], ic.c[3]); + std::swap(ic.c[1], ic.c[2]); + } + fwrite((char*)ic.c, 1, 4, _out); +} + + +//----------------------------------------------------------------------------- + + +void write_float(float _f, FILE* _out, bool _swap) +{ + fc.f = _f; + if (_swap) { + std::swap(fc.c[0], fc.c[3]); + std::swap(fc.c[1], fc.c[2]); + } + fwrite((char*)fc.c, 1, 4, _out); +} + + +//----------------------------------------------------------------------------- + + +void write_double(double _d, FILE* _out, bool _swap) +{ + dc.d = _d; + if (_swap) { + std::swap(dc.c[0], dc.c[7]); + std::swap(dc.c[1], dc.c[6]); + std::swap(dc.c[2], dc.c[5]); + std::swap(dc.c[3], dc.c[4]); + } + fwrite((char*)dc.c, 1, 8, _out); +} + +#endif + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Core/IO/BinaryHelper.hh b/Core/IO/BinaryHelper.hh new file mode 100644 index 00000000..f24fce1c --- /dev/null +++ b/Core/IO/BinaryHelper.hh @@ -0,0 +1,115 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_BINARY_HELPER_HH +#define OPENMESH_BINARY_HELPER_HH + + +//== INCLUDES ================================================================= + +#include +// -------------------- STL +#if defined( OM_CC_MIPS ) +# include +#else +# include +#endif +#include +// -------------------- OpenMesh + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +/** \name Handling binary input/output. + These functions take care of swapping bytes to get the right Endian. +*/ +//@{ + +//----------------------------------------------------------------------------- + + +/** Binary read a \c short from \c _is and perform byte swapping if + \c _swap is true */ +short int read_short(FILE* _in, bool _swap=false); + +/** Binary read an \c int from \c _is and perform byte swapping if + \c _swap is true */ +int read_int(FILE* _in, bool _swap=false); + +/** Binary read a \c float from \c _is and perform byte swapping if + \c _swap is true */ +float read_float(FILE* _in, bool _swap=false); + +/** Binary read a \c double from \c _is and perform byte swapping if + \c _swap is true */ +double read_double(FILE* _in, bool _swap=false); + + +/** Binary write a \c short to \c _os and perform byte swapping if + \c _swap is true */ +void write_short(short int _i, FILE* _out, bool _swap=false); + +/** Binary write an \c int to \c _os and perform byte swapping if + \c _swap is true */ +void write_int(int _i, FILE* _out, bool _swap=false); + +/** Binary write a \c float to \c _os and perform byte swapping if + \c _swap is true */ +void write_float(float _f, FILE* _out, bool _swap=false); + +/** Binary write a \c double to \c _os and perform byte swapping if + \c _swap is true */ +void write_double(double _d, FILE* _out, bool _swap=false); + + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= + diff --git a/Core/IO/IOInstances.hh b/Core/IO/IOInstances.hh new file mode 100644 index 00000000..f4e548ee --- /dev/null +++ b/Core/IO/IOInstances.hh @@ -0,0 +1,91 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Helper file for static builds +// +// In opposite to dynamic builds where the instance of every reader module +// is generated within the OpenMesh library, static builds only instanciate +// objects that are at least referenced once. As all reader modules are +// never used directly, they will not be part of a static build, hence +// this file. +// +//============================================================================= + + +#ifndef __IOINSTANCES_HH__ +#define __IOINSTANCES_HH__ + +#if defined(OM_STATIC_BUILD) || defined(ARCH_DARWIN) + +//============================================================================= + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +//=== NAMESPACES ============================================================== + +namespace OpenMesh { +namespace IO { + +//============================================================================= + + +// Instanciate every Reader module +static BaseReader* OFFReaderInstance = &OFFReader(); +static BaseReader* OBJReaderInstance = &OBJReader(); +static BaseReader* PLYReaderInstance = &PLYReader(); +static BaseReader* STLReaderInstance = &STLReader(); +static BaseReader* OMReaderInstance = &OMReader(); + +// Instanciate every writer module +static BaseWriter* OBJWriterInstance = &OBJWriter(); +static BaseWriter* OFFWriterInstance = &OFFWriter(); +static BaseWriter* STLWriterInstance = &STLWriter(); +static BaseWriter* OMWriterInstance = &OMWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // static ? +#endif //__IOINSTANCES_HH__ +//============================================================================= diff --git a/Core/IO/IOManager.cc b/Core/IO/IOManager.cc new file mode 100644 index 00000000..0dba9c82 --- /dev/null +++ b/Core/IO/IOManager.cc @@ -0,0 +1,243 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements the OpenMesh IOManager singleton +// +//============================================================================= + + +//== INCLUDES ================================================================= + + +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +_IOManager_ *__IOManager_instance = 0; + + +_IOManager_& IOManager() +{ + if (!__IOManager_instance) __IOManager_instance = new _IOManager_(); + return *__IOManager_instance; +} + + +//----------------------------------------------------------------------------- + + +bool +_IOManager_:: +read(const std::string& _filename, BaseImporter& _bi, Options& _opt) +{ + std::set::const_iterator it = reader_modules_.begin(); + std::set::const_iterator it_end = reader_modules_.end(); + + // Try all registered modules + for(; it != it_end; ++it) + if ((*it)->can_u_read(_filename)) + { + _bi.prepare(); + bool ok = (*it)->read(_filename, _bi, _opt); + _bi.finish(); + return ok; + } + + // All modules failed to read + return false; +} + + +//----------------------------------------------------------------------------- + + +bool +_IOManager_:: +write(const std::string& _filename, BaseExporter& _be, Options _opt) +{ + std::set::const_iterator it = writer_modules_.begin(); + std::set::const_iterator it_end = writer_modules_.end(); + + if ( it == it_end ) + { + omerr() << "[OpenMesh::IO::_IOManager_] No writing modules available!\n"; + return false; + } + + // Try all registered modules + for(; it != it_end; ++it) + { + if ((*it)->can_u_write(_filename)) + { + return (*it)->write(_filename, _be, _opt); + } + } + + // All modules failed to save + return false; +} + + +//----------------------------------------------------------------------------- + + +bool +_IOManager_:: +can_read( const std::string& _format ) const +{ + std::set::const_iterator it = reader_modules_.begin(); + std::set::const_iterator it_end = reader_modules_.end(); + std::string filename = "dummy." + _format; + + for(; it != it_end; ++it) + if ((*it)->can_u_read(filename)) + return true; + + return false; +} + + +//----------------------------------------------------------------------------- + + +bool +_IOManager_:: +can_write( const std::string& _format ) const +{ + std::set::const_iterator it = writer_modules_.begin(); + std::set::const_iterator it_end = writer_modules_.end(); + std::string filename = "dummy." + _format; + + // Try all registered modules + for(; it != it_end; ++it) + if ((*it)->can_u_write(filename)) + return true; + + return false; +} + + +//----------------------------------------------------------------------------- + + +const BaseWriter* +_IOManager_:: +find_writer(const std::string& _format) +{ + using std::string; + + string::size_type dot = _format.rfind('.'); + + string ext; + if (dot == string::npos) + ext = _format; + else + ext = _format.substr(dot+1,_format.length()-(dot+1)); + + std::set::const_iterator it = writer_modules_.begin(); + std::set::const_iterator it_end = writer_modules_.end(); + std::string filename = "dummy." + ext; + + // Try all registered modules + for(; it != it_end; ++it) + if ((*it)->can_u_write(filename)) + return *it; + + return NULL; +} + + +//----------------------------------------------------------------------------- + + +void +_IOManager_:: +update_read_filters() +{ + std::set::const_iterator it = reader_modules_.begin(), + it_end = reader_modules_.end(); + std::string s, all, filters; + + for(; it != it_end; ++it) + { + filters += (*it)->get_description() + " ("; + + std::istringstream iss((*it)->get_extensions()); + while (iss && !iss.eof() && (iss >> s)) + { s = " *." + s; filters += s; all += s; } + + filters += " );;"; + } + + all = "All files ( " + all + " );;"; + + read_filters_ = all + filters; +} + + +//----------------------------------------------------------------------------- + + +void +_IOManager_:: +update_write_filters() +{ + std::set::const_iterator it = writer_modules_.begin(), + it_end = writer_modules_.end(); + std::string s, all, filters; + + for(; it != it_end; ++it) + { + filters += (*it)->get_description() + " ("; + + std::istringstream iss((*it)->get_extensions()); + while (iss && !iss.eof() && (iss >> s)) + { s = " *." + s; filters += s; all += s; } + + filters += " );;"; + } + all = "All files ( " + all + " );;"; + + write_filters_ = all + filters; +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Core/IO/IOManager.hh b/Core/IO/IOManager.hh new file mode 100644 index 00000000..7864ceda --- /dev/null +++ b/Core/IO/IOManager.hh @@ -0,0 +1,224 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ +// $Id: IOManager.hh,v 1.2 2007-05-18 15:17:34 habbecke Exp $ + +//============================================================================= +// +// Implements the OpenMesh IOManager singleton +// +//============================================================================= + +#ifndef __IOMANAGER_HH__ +#define __IOMANAGER_HH__ + + +//=== INCLUDES ================================================================ + + +// STL +#include +#include +#include +#include + +// OpenMesh +#include +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** This is the real IOManager class that is later encapsulated by + SingletonT to enforce its uniqueness. _IOManager_ is not meant to be used + directly by the programmer - the IOManager alias exists for this task. + + All reader/writer modules register themselves at this class. For + reading or writing data all modules are asked to do the job. If no + suitable module is found, an error is returned. + + For the sake of reading, the target data structure is hidden + behind the BaseImporter interface that takes care of adding + vertices or faces. + + Writing from a source structure is encapsulate similarly behind a + BaseExporter interface, providing iterators over vertices/faces to + the writer modules. + + \see \ref mesh_io +*/ + +class _IOManager_ +{ +private: + + _IOManager_() {} + friend _IOManager_& IOManager(); + + +public: + + + /** + Read a mesh from file _filename. The target data structure is specified + by the given BaseImporter. The \c read method consecutively queries all + of its reader modules. True is returned upon success, false if all + reader modules failed to interprete _filename. + */ + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt); + + + + /** Write a mesh to file _filename. The source data structure is specified + by the given BaseExporter. The \c save method consecutively queries all + of its writer modules. True is returned upon success, false if all + writer modules failed to write the requested format. + Options is determined by _filename's extension. + */ + bool write(const std::string& _filename, + BaseExporter& _be, + Options _opt=Options::Default); + + + + /// Returns true if the format is supported by one of the reader modules. + bool can_read( const std::string& _format ) const; + + /// Returns true if the format is supported by one of the writer modules. + bool can_write( const std::string& _format ) const; + + + size_t binary_size(const std::string& _format, + BaseExporter& _be, + Options _opt = Options::Default) + { + const BaseWriter *bw = find_writer(_format); + return bw ? bw->binary_size(_be,_opt) : 0; + } + + + +public: //-- QT convenience function ------------------------------------------ + + + /** Returns all readable file extension + descriptions in one string. + File formats are separated by ;;. + Convenience function for Qt file dialogs. + */ + const std::string& qt_read_filters() const { return read_filters_; } + + + /** Returns all writeable file extension + descriptions in one string. + File formats are separated by ;;. + Convenience function for Qt file dialogs. + */ + const std::string& qt_write_filters() const { return write_filters_; } + + + +private: + + // collect all readable file extensions + void update_read_filters(); + + + // collect all writeable file extensions + void update_write_filters(); + + + +public: //-- SYSTEM PART------------------------------------------------------ + + + /** Registers a new reader module. A call to this function should be + implemented in the constructor of all classes derived from BaseReader. + */ + bool register_module(BaseReader* _bl) + { + reader_modules_.insert(_bl); + update_read_filters(); + return true; + } + + + + /** Registers a new writer module. A call to this function should be + implemented in the constructor of all classed derived from BaseWriter. + */ + bool register_module(BaseWriter* _bw) + { + writer_modules_.insert(_bw); + update_write_filters(); + return true; + } + + +private: + + const BaseWriter *find_writer(const std::string& _format); + + // stores registered reader modules + std::set reader_modules_; + + // stores registered writer modules + std::set writer_modules_; + + // input filters (e.g. for Qt file dialog) + std::string read_filters_; + + // output filters (e.g. for Qt file dialog) + std::string write_filters_; +}; + + +//============================================================================= + + +extern _IOManager_* __IOManager_instance; + +_IOManager_& IOManager(); + + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/MeshIO.hh b/Core/IO/MeshIO.hh new file mode 100644 index 00000000..cf7f0822 --- /dev/null +++ b/Core/IO/MeshIO.hh @@ -0,0 +1,134 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +#ifndef OM_MESHIO_HH +#define OM_MESHIO_HH + + +//=== INCLUDES ================================================================ + +// -------------------- system settings +#include +// -------------------- check include order +#if defined (OPENMESH_TRIMESH_ARRAY_KERNEL_HH) || \ + defined (OPENMESH_POLYMESH_ARRAY_KERNEL_HH) +# error "Include MeshIO.hh before including a mesh type!" +#endif +// -------------------- OpenMesh +#include +#include +#include +#include + + +//== NAMESPACES ============================================================== + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** \name Mesh Reading / Writing + Convenience functions the map to IOManager functions. + \see OpenMesh::IO::_IOManager_ +*/ +//@{ + + +//----------------------------------------------------------------------------- + + +/** Read a mesh from file _filename. The file format is determined by + the file extension. */ +template +bool +read_mesh(Mesh& _mesh, + const std::string& _filename, + bool _clear = true) +{ + Options opt; + return read_mesh(_mesh, _filename, opt, _clear); +} + + +/** Read a mesh from file _filename. The file format is determined by + the file extension. */ +template +bool +read_mesh(Mesh& _mesh, + const std::string& _filename, + Options& _opt, + bool _clear = true) +{ + if (_clear) _mesh.clear(); + ImporterT importer(_mesh); + return IOManager().read(_filename, importer, _opt); +} + + +//----------------------------------------------------------------------------- + + +/** Write a mesh to the file _filename. The file format is determined + by _filename's extension. */ +template +bool write_mesh(const Mesh& _mesh, const std::string& _filename, + Options _opt = Options::Default) +{ + ExporterT exporter(_mesh); + return IOManager().write(_filename, exporter, _opt); +} + + +//----------------------------------------------------------------------------- + + +template +size_t binary_size(const Mesh& _mesh, const std::string& _format, + Options _opt = Options::Default) +{ + ExporterT exporter(_mesh); + return IOManager().binary_size(_format, exporter, _opt); +} + + +//----------------------------------------------------------------------------- + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#if defined(OM_STATIC_BUILD) || defined(ARCH_DARWIN) +# include +#endif +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/OFFFormat.hh b/Core/IO/OFFFormat.hh new file mode 100644 index 00000000..278871f1 --- /dev/null +++ b/Core/IO/OFFFormat.hh @@ -0,0 +1,76 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +#ifndef OPENMESH_IO_OFFFORMAT_HH +#define OPENMESH_IO_OFFFORMAT_HH + + +//=== INCLUDES ================================================================ + + +// OpenMesh +#include + + +//== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** \name Mesh Reading / Writing + Option for writer modules. +*/ +//@{ + + +//----------------------------------------------------------------------------- + +#ifndef DOXY_IGNORE_THIS + +struct OFFFormat +{ + typedef int integer_type; + typedef float float_type; +}; + +#endif + + + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/OMFormat.cc b/Core/IO/OMFormat.cc new file mode 100644 index 00000000..23235030 --- /dev/null +++ b/Core/IO/OMFormat.cc @@ -0,0 +1,231 @@ +//============================================================================= +// +// 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: 3166 $ +// $Date: 2008-09-26 14:49:46 +0200 (Fr, 26. Sep 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +//== INCLUDES ================================================================= + +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { +namespace OMFormat { + +//== IMPLEMENTATION =========================================================== + + Chunk::Integer_Size needed_bits( size_t s ) + { + if (s <= 0x000100) return Chunk::Integer_8; + if (s <= 0x010000) return Chunk::Integer_16; + +#if 0 + // !Not tested yet! This most probably won't work! + // NEED a 64bit system! + if ( (sizeof( size_t ) == 8) && (s >= 0x100000000) ) + return Chunk::Integer_64; +#endif + + return Chunk::Integer_32; + } + +//----------------------------------------------------------------------------- + + uint16& + operator << (uint16& val, const Chunk::Header& hdr) + { + val = 0; + val |= hdr.name_ << OMFormat::Chunk::OFF_NAME; + val |= hdr.entity_ << OMFormat::Chunk::OFF_ENTITY; + val |= hdr.type_ << OMFormat::Chunk::OFF_TYPE; + val |= hdr.signed_ << OMFormat::Chunk::OFF_SIGNED; + val |= hdr.float_ << OMFormat::Chunk::OFF_FLOAT; + val |= hdr.dim_ << OMFormat::Chunk::OFF_DIM; + val |= hdr.bits_ << OMFormat::Chunk::OFF_BITS; + return val; + } + + +//----------------------------------------------------------------------------- + + Chunk::Header& + operator << (Chunk::Header& hdr, const uint16 val) + { + hdr.reserved_ = 0; + hdr.name_ = val >> OMFormat::Chunk::OFF_NAME; + hdr.entity_ = val >> OMFormat::Chunk::OFF_ENTITY; + hdr.type_ = val >> OMFormat::Chunk::OFF_TYPE; + hdr.signed_ = val >> OMFormat::Chunk::OFF_SIGNED; + hdr.float_ = val >> OMFormat::Chunk::OFF_FLOAT; + hdr.dim_ = val >> OMFormat::Chunk::OFF_DIM; + hdr.bits_ = val >> OMFormat::Chunk::OFF_BITS; + return hdr; + } + +//----------------------------------------------------------------------------- + + const char *as_string(Chunk::Entity e) + { + switch(e) + { + case Chunk::Entity_Vertex: return "Vertex"; + case Chunk::Entity_Mesh: return "Mesh"; + case Chunk::Entity_Edge: return "Edge"; + case Chunk::Entity_Halfedge: return "Halfedge"; + case Chunk::Entity_Face: return "Face"; + default: + std::clog << "as_string(Chunk::Entity): Invalid value!"; + } + return NULL; + } + + +//----------------------------------------------------------------------------- + + const char *as_string(Chunk::Type t) + { + switch(t) + { + case Chunk::Type_Pos: return "Pos"; + case Chunk::Type_Normal: return "Normal"; + case Chunk::Type_Texcoord: return "Texcoord"; + case Chunk::Type_Status: return "Status"; + case Chunk::Type_Color: return "Color"; + case Chunk::Type_Custom: return "Custom"; + case Chunk::Type_Topology: return "Topology"; + } + return NULL; + } + + +//----------------------------------------------------------------------------- + + const char *as_string(Chunk::Dim d) + { + switch(d) + { + case Chunk::Dim_1D: return "1D"; + case Chunk::Dim_2D: return "2D"; + case Chunk::Dim_3D: return "3D"; + case Chunk::Dim_4D: return "4D"; + case Chunk::Dim_5D: return "5D"; + case Chunk::Dim_6D: return "6D"; + case Chunk::Dim_7D: return "7D"; + case Chunk::Dim_8D: return "8D"; + } + return NULL; + } + + +//----------------------------------------------------------------------------- + + const char *as_string(Chunk::Integer_Size d) + { + switch(d) + { + case Chunk::Integer_8 : return "8"; + case Chunk::Integer_16 : return "16"; + case Chunk::Integer_32 : return "32"; + case Chunk::Integer_64 : return "64"; + } + return NULL; + } + + const char *as_string(Chunk::Float_Size d) + { + switch(d) + { + case Chunk::Float_32 : return "32"; + case Chunk::Float_64 : return "64"; + case Chunk::Float_128: return "128"; + } + return NULL; + } + + +//----------------------------------------------------------------------------- + + std::ostream& operator << ( std::ostream& _os, const Chunk::Header& _c ) + { + _os << "Chunk Header : 0x" << std::setw(4) + << std::hex << (*(uint16*)(&_c)) << std::dec << std::endl; + _os << "entity = " + << as_string(Chunk::Entity(_c.entity_)) << std::endl; + _os << "type = " + << as_string(Chunk::Type(_c.type_)); + if ( Chunk::Type(_c.type_)!=Chunk::Type_Custom) + { + _os << std::endl + << "signed = " + << _c.signed_ << std::endl; + _os << "float = " + << _c.float_ << std::endl; + _os << "dim = " + << as_string(Chunk::Dim(_c.dim_)) << std::endl; + _os << "bits = " + << (_c.float_ + ? as_string(Chunk::Float_Size(_c.bits_)) + : as_string(Chunk::Integer_Size(_c.bits_))); + } + return _os; + } + + +//----------------------------------------------------------------------------- + + std::ostream& operator << ( std::ostream& _os, const Header& _h ) + { + _os << "magic = '" << _h.magic_[0] << _h.magic_[1] << "'\n" + << "mesh = '" << _h.mesh_ << "'\n" + << "version = 0x" << std::hex << (uint16)_h.version_ << std::dec + << " (" << major_version(_h.version_) + << "." << minor_version(_h.version_) << ")\n" + << "#V = " << _h.n_vertices_ << std::endl + << "#F = " << _h.n_faces_ << std::endl + << "#E = " << _h.n_edges_; + return _os; + } + + +} // namespace OMFormat + // -------------------------------------------------------------------------- + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Core/IO/OMFormat.hh b/Core/IO/OMFormat.hh new file mode 100644 index 00000000..c088e4f3 --- /dev/null +++ b/Core/IO/OMFormat.hh @@ -0,0 +1,715 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +#ifndef OPENMESH_IO_OMFORMAT_HH +#define OPENMESH_IO_OMFORMAT_HH + + +//=== INCLUDES ================================================================ + +#include +#include +#include +#include +#include +#include +// -------------------- +#include +#if defined(OM_CC_GCC) && (OM_GCC_VERSION < 30000) +# include +# define OM_MISSING_HEADER_LIMITS 1 +#else +# include +#endif + + +//== NAMESPACES ============================================================== + +#ifndef DOXY_IGNORE_THIS +namespace OpenMesh { +namespace IO { +namespace OMFormat { + + +//=== IMPLEMENTATION ========================================================== + + +/** \name Mesh Reading / Writing +*/ +//@{ + +//----------------------------------------------------------------------------- + + // <:Header> + // <:Comment> + // Chunk 0 + // <:ChunkHeader> + // <:Comment> + // data + // Chunk 1 + // <:ChunkHeader> + // <:Comment> + // data + // . + // . + // . + // Chunk N + + // + // NOTICE! + // + // The usage of data types who differ in size + // on different pc architectures (32/64 bit) and/or + // operating systems, e.g. (unsigned) long, size_t, + // is not recommended because of inconsistencies + // in case of cross writing and reading. + // + // Basic types that are supported are: + + + typedef unsigned char uchar; + typedef uint8_t uint8; + typedef uint16_t uint16; + typedef uint32_t uint32; + typedef uint64_t uint64; + typedef int8_t int8; + typedef int16_t int16; + typedef int32_t int32; + typedef int64_t int64; + typedef float32_t float32; + typedef float64_t float64; + + struct Header + { + uchar magic_[2]; // OM + uchar mesh_; // [T]riangles, [Q]uads, [P]olygonals + uint8 version_; + uint32 n_vertices_; + uint32 n_faces_; + uint32 n_edges_; + + size_t store( std::ostream& _os, bool _swap ) const + { + _os.write( (char*)this, 4); // magic_, mesh_, version_ + size_t bytes = 4; + bytes += binary::store( _os, n_vertices_, _swap ); + bytes += binary::store( _os, n_faces_, _swap ); + bytes += binary::store( _os, n_edges_, _swap ); + return bytes; + } + + size_t restore( std::istream& _is, bool _swap ) + { + if (_is.read( (char*)this, 4 ).eof()) + return 0; + + size_t bytes = 4; + bytes += binary::restore( _is, n_vertices_, _swap ); + bytes += binary::restore( _is, n_faces_, _swap ); + bytes += binary::restore( _is, n_edges_, _swap ); + return bytes; + } + + }; + + struct Chunk + { + // Hardcoded this size to an uint32 to make the system 32/64 bit compatible. + // Needs further investigation! + typedef uint32 esize_t; // element size, used for custom properties + + enum Type { + Type_Pos = 0x00, + Type_Normal = 0x01, + Type_Texcoord = 0x02, + Type_Status = 0x03, + Type_Color = 0x04, + Type_Custom = 0x06, + Type_Topology = 0x07 + }; + + enum Entity { + Entity_Vertex = 0x00, + Entity_Mesh = 0x01, + Entity_Face = 0x02, + Entity_Edge = 0x04, + Entity_Halfedge = 0x06, + }; + + enum Dim { + Dim_1D = 0x00, + Dim_2D = 0x01, + Dim_3D = 0x02, + Dim_4D = 0x03, + Dim_5D = 0x04, + Dim_6D = 0x05, + Dim_7D = 0x06, + Dim_8D = 0x07 + }; + + enum Integer_Size { + Integer_8 = 0x00, // 1 byte for (unsigned) char + Integer_16 = 0x01, // 2 bytes for short + Integer_32 = 0x02, // 4 bytes for long + Integer_64 = 0x03 // 8 bytes for long long + }; + + enum Float_Size { + Float_32 = 0x00, // 4 bytes for float + Float_64 = 0x01, // 8 bytes for double + Float_128 = 0x02 // 16 bytes for long double (an assumption!) + }; + + static const int SIZE_RESERVED = 1; // 1 + static const int SIZE_NAME = 1; // 2 + static const int SIZE_ENTITY = 3; // 5 + static const int SIZE_TYPE = 4; // 9 + + static const int SIZE_SIGNED = 1; // 10 + static const int SIZE_FLOAT = 1; // 11 + static const int SIZE_DIM = 3; // 14 + static const int SIZE_BITS = 2; // 16 + + static const int OFF_RESERVED = 0; // 0 + static const int OFF_NAME = SIZE_RESERVED + OFF_RESERVED; // 2 + static const int OFF_ENTITY = SIZE_NAME + OFF_NAME; // 3 + static const int OFF_TYPE = SIZE_ENTITY + OFF_ENTITY; // 5 + static const int OFF_SIGNED = SIZE_TYPE + OFF_TYPE; // 9 + static const int OFF_FLOAT = SIZE_SIGNED + OFF_SIGNED; // 10 + static const int OFF_DIM = SIZE_FLOAT + OFF_FLOAT; // 11 + static const int OFF_BITS = SIZE_DIM + OFF_DIM; // 14 + + // !Attention! When changing the bit size, the operators + // << (uint16, Header) and << (Header, uint16) must be changed as well + // + // Entries signed_, float_, dim_, bits_ are not used when type_ + // equals Type_Custom + // + struct Header // 16 bits long + { + unsigned reserved_: SIZE_RESERVED; + unsigned name_ : SIZE_NAME; // 1 named property, 0 anonymous + unsigned entity_ : SIZE_ENTITY; // 0 vertex, 1 mesh, 2 edge, + // 4 halfedge, 6 face + unsigned type_ : SIZE_TYPE; // 0 pos, 1 normal, 2 texcoord, + // 3 status, 4 color 6 custom 7 topology + unsigned signed_ : SIZE_SIGNED; // bool + unsigned float_ : SIZE_FLOAT; // bool + unsigned dim_ : SIZE_DIM; // 0 1D, 1 2D, 2 3D, .., 7 8D + unsigned bits_ : SIZE_BITS; // {8, 16, 32, 64} | {32, 64, 128} + // (integer) (float) + unsigned unused_ : 16; // fill up to 32 bits + }; // struct Header + + + class PropertyName : public std::string + { + public: + + static const size_t size_max = 256; + + PropertyName( ) { } + + PropertyName( const std::string& _name ) { *this = _name; } + + bool is_valid() const { return is_valid( size() ); } + + static bool is_valid( size_t _s ) { return _s <= size_max; } + + PropertyName& operator = ( const std::string& _rhs ) + { + assert( is_valid( _rhs.size() ) ); + + if ( is_valid( _rhs.size() ) ) + std::string::operator = ( _rhs ); + else + { + omerr() << "Warning! Property name too long. Will be shortened!\n"; + this->std::string::operator = ( _rhs.substr(0, size_max) ); + } + + return *this; + } + + }; + + }; // Chunk + + // ------------------------------------------------------------ Helper + + // -------------------- get size information + + /// Return size of header in bytes. + inline size_t header_size(void) { return sizeof(Header); } + + + /// Return size of chunk header in bytes. + inline size_t chunk_header_size( void ) { return sizeof(uint16); } + + + /// Return the size of a scale in bytes. + inline size_t scalar_size( const Chunk::Header& _hdr ) + { + return _hdr.float_ ? (0x01 << _hdr.bits_) : (0x04 << _hdr.bits_); + } + + + /// Return the dimension of the vector in a chunk + inline size_t dimensions(const Chunk::Header& _chdr) { return _chdr.dim_+1; } + + + /// Return the size of a vector in bytes. + inline size_t vector_size( const Chunk::Header& _chdr ) + { + return dimensions(_chdr)*scalar_size(_chdr); + } + + + /// Return the size of chunk data in bytes + inline size_t chunk_data_size( Header& _hdr, Chunk::Header& _chunk_hdr ) + { + size_t C = 0; + + switch( _chunk_hdr.entity_ ) + { + case Chunk::Entity_Vertex: C = _hdr.n_vertices_; break; + case Chunk::Entity_Face: C = _hdr.n_faces_; break; + case Chunk::Entity_Halfedge: C = _hdr.n_edges_; // no break! + case Chunk::Entity_Edge: C += _hdr.n_edges_; break; + case Chunk::Entity_Mesh: C = 1; break; + default: + std::cerr << "Invalid value in _chunk_hdr.entity_\n"; + assert( false ); + } + + return C * vector_size( _chunk_hdr ); + } + + inline size_t chunk_size( Header& _hdr, Chunk::Header& _chunk_hdr ) + { + return chunk_header_size() + chunk_data_size( _hdr, _chunk_hdr ); + } + + // -------------------- convert from Chunk::Header to storage type + + uint16& operator << (uint16& val, const Chunk::Header& hdr); + Chunk::Header& operator << (Chunk::Header& hdr, const uint16 val); + + + // -------------------- type information + + template bool is_float(const T&) + { +#if defined(OM_MISSING_HEADER_LIMITS) + return !Utils::NumLimitsT::is_integer(); +#else + return !std::numeric_limits::is_integer; +#endif + } + + template bool is_integer(const T) + { +#if defined(OM_MISSING_HEADER_LIMITS) + return Utils::NumLimitsT::is_integer(); +#else + return std::numeric_limits::is_integer; +#endif + } + + template bool is_signed(const T&) + { +#if defined(OM_MISSING_HEADER_LIMITS) + return Utils::NumLimitsT::is_signed(); +#else + return std::numeric_limits::is_signed; +#endif + } + + // -------------------- conversions (format type <- type/value) + + template + inline + Chunk::Dim dim( VecType ) + { + assert( vector_traits< VecType >::size() < 9 ); + return static_cast(vector_traits< VecType >::size() - 1); + } + + template <> + inline + Chunk::Dim dim( const Chunk::Header& _hdr ) + { + return static_cast( _hdr.dim_ ); + } + + // calc minimum (power-of-2) number of bits needed + Chunk::Integer_Size needed_bits( size_t s ); + + + // Return the storage type (Chunk::Header::bits_) + template + inline + unsigned int bits(const T& val) + { + return is_integer(val) + ? (static_cast(integer_size(val))) + : (static_cast(float_size(val))); + } + + // Convert size of type to Integer_Size +#ifdef NDEBUG + template Chunk::Integer_Size integer_size(const T&) +#else + template Chunk::Integer_Size integer_size(const T& d) +#endif + { + assert( is_integer(d) ); + + switch( sizeof(T) ) + { + case 1: return OMFormat::Chunk::Integer_8; + case 2: return OMFormat::Chunk::Integer_16; + case 4: return OMFormat::Chunk::Integer_32; + case 8: return OMFormat::Chunk::Integer_64; + } + return Chunk::Integer_Size(0); + } + + + // Convert size of type to FLoat_Size +#ifdef NDEBUG + template Chunk::Float_Size float_size(const T&) +#else + template Chunk::Float_Size float_size(const T& d) +#endif + { + assert( is_float(d) ); + + switch( sizeof(T) ) + { + case 4: return OMFormat::Chunk::Float_32; + case 8: return OMFormat::Chunk::Float_64; + case 16: return OMFormat::Chunk::Float_128; + } + return Chunk::Float_Size(0); + } + + // -------------------- create/read version + + inline uint8 mk_version(const uint16 major, const uint16 minor) + { return (major & 0x07) << 5 | (minor & 0x1f); } + + + inline uint16 major_version(const uint8 version) + { return (version >> 5) & 0x07; } + + + inline uint16 minor_version(const uint8 version) + { return (version & 0x001f); } + + + // ---------------------------------------- convenience functions + + const char *as_string(Chunk::Type t); + const char *as_string(Chunk::Entity e); + const char *as_string(Chunk::Dim d); + const char *as_string(Chunk::Integer_Size d); + const char *as_string(Chunk::Float_Size d); + + std::ostream& operator << ( std::ostream& _os, const Header& _h ); + std::ostream& operator << ( std::ostream& _os, const Chunk::Header& _c ); + +//@} +} // namespace OMFormat + + // -------------------- (re-)store header + + template <> inline + size_t store( std::ostream& _os, const OMFormat::Header& _hdr, bool _swap) + { return _hdr.store( _os, _swap ); } + + template <> inline + size_t restore( std::istream& _is, OMFormat::Header& _hdr, bool _swap ) + { return _hdr.restore( _is, _swap ); } + + + // -------------------- (re-)store chunk header + + template <> inline + size_t + store( std::ostream& _os, const OMFormat::Chunk::Header& _hdr, bool _swap) + { + OMFormat::uint16 val; val << _hdr; + return binary::store( _os, val, _swap ); + } + + template <> inline + size_t + restore( std::istream& _is, OMFormat::Chunk::Header& _hdr, bool _swap ) + { + OMFormat::uint16 val; + size_t bytes = binary::restore( _is, val, _swap ); + + _hdr << val; + + return bytes; + } + + // -------------------- (re-)store integer with wanted number of bits (bytes) + + typedef GenProg::True t_signed; + typedef GenProg::False t_unsigned; + + // helper to store a an integer + template< typename T > + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_signed); + + // helper to store a an unsigned integer + template< typename T > + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_unsigned); + + /// Store an integer with a wanted number of bits + template< typename T > + inline + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap) + { + assert( OMFormat::is_integer( _val ) ); + + if ( OMFormat::is_signed( _val ) ) + return store( _os, _val, _b, _swap, t_signed() ); + return store( _os, _val, _b, _swap, t_unsigned() ); + } + + // helper to store a an integer + template< typename T > inline + size_t restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_signed); + + // helper to store a an unsigned integer + template< typename T > inline + size_t restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_unsigned); + + /// Restore an integer with a wanted number of bits + template< typename T > + inline + size_t + restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap) + { + assert( OMFormat::is_integer( _val ) ); + + if ( OMFormat::is_signed( _val ) ) + return restore( _is, _val, _b, _swap, t_signed() ); + return restore( _is, _val, _b, _swap, t_unsigned() ); + } + + + // + // ---------------------------------------- storing vectors + template inline + size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<2>, + bool _swap ) + { + size_t bytes = store( _os, _vec[0], _swap ); + bytes += store( _os, _vec[1], _swap ); + return bytes; + } + + template inline + size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<3>, + bool _swap ) + { + size_t bytes = store( _os, _vec[0], _swap ); + bytes += store( _os, _vec[1], _swap ); + bytes += store( _os, _vec[2], _swap ); + return bytes; + } + + template inline + size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<4>, + bool _swap ) + { + size_t bytes = store( _os, _vec[0], _swap ); + bytes += store( _os, _vec[1], _swap ); + bytes += store( _os, _vec[2], _swap ); + bytes += store( _os, _vec[3], _swap ); + return bytes; + } + + template inline + size_t store( std::ostream& _os, const VecT& _vec, GenProg::Int2Type<1>, + bool _swap ) + { + return store( _os, _vec[0], _swap ); + } + + /// storing a vector type + template inline + size_t vector_store( std::ostream& _os, const VecT& _vec, bool _swap ) + { + return store( _os, _vec, + GenProg::Int2Type< vector_traits::size_ >(), + _swap ); + } + + // ---------------------------------------- restoring vectors + template + inline + size_t + restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<2>, + bool _swap ) + { + size_t bytes = restore( _is, _vec[0], _swap ); + bytes += restore( _is, _vec[1], _swap ); + return bytes; + } + + template + inline + size_t + restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<3>, + bool _swap ) + { + typedef typename vector_traits::value_type scalar_type; + size_t bytes; + + bytes = binary::restore( _is, _vec[0], _swap ); + bytes += binary::restore( _is, _vec[1], _swap ); + bytes += binary::restore( _is, _vec[2], _swap ); + return bytes; + } + + template + inline + size_t + restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<4>, + bool _swap ) + { + typedef typename vector_traits::value_type scalar_type; + size_t bytes; + + bytes = binary::restore( _is, _vec[0], _swap ); + bytes += binary::restore( _is, _vec[1], _swap ); + bytes += binary::restore( _is, _vec[2], _swap ); + bytes += binary::restore( _is, _vec[3], _swap ); + return bytes; + } + + template + inline + size_t + restore( std::istream& _is, VecT& _vec, GenProg::Int2Type<1>, + bool _swap ) + { + return restore( _is, _vec[0], _swap ); + } + + /// Restoring a vector type + template + inline + size_t + vector_restore( std::istream& _is, VecT& _vec, bool _swap ) + { + return restore( _is, _vec, + GenProg::Int2Type< vector_traits::size_ >(), + _swap ); + } + + + // ---------------------------------------- storing property names + + template <> + inline + size_t store( std::ostream& _os, const OMFormat::Chunk::PropertyName& _pn, + bool _swap ) + { + store( _os, _pn.size(), OMFormat::Chunk::Integer_8, _swap ); // 1 byte + if ( _pn.size() ) + _os.write( _pn.c_str(), _pn.size() ); // size bytes + return _pn.size() + 1; + } + + template <> + inline + size_t restore( std::istream& _is, OMFormat::Chunk::PropertyName& _pn, + bool _swap ) + { + size_t size; + + restore( _is, size, OMFormat::Chunk::Integer_8, _swap); // 1 byte + + assert( OMFormat::Chunk::PropertyName::is_valid( size ) ); + + if ( size > 0 ) + { + char buf[256]; + _is.read( buf, size ); // size bytes + buf[size] = '\0'; + _pn.resize(size); + _pn = buf; + } + return size+1; + } + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +#endif +//============================================================================= +#if defined(OM_MISSING_HEADER_LIMITS) +# undef OM_MISSING_HEADER_LIMITS +#endif +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_IO_OMFORMAT_CC) +# define OPENMESH_IO_OMFORMAT_TEMPLATES +# include "OMFormatT.cc" +#endif +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/OMFormatT.cc b/Core/IO/OMFormatT.cc new file mode 100644 index 00000000..7c1c1f63 --- /dev/null +++ b/Core/IO/OMFormatT.cc @@ -0,0 +1,224 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mon, 19 May 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#define OPENMESH_IO_OMFORMAT_CC + + +//== INCLUDES ================================================================= + +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + // helper to store a an integer + template< typename T > + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_signed) + { + assert( OMFormat::is_integer( _val ) ); + + switch( _b ) + { + case OMFormat::Chunk::Integer_8: + { + OMFormat::int8 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_16: + { + OMFormat::int16 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_32: + { + OMFormat::int32 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_64: + { + OMFormat::int64 v = static_cast(_val); + return store( _os, v, _swap ); + } + } + return 0; + } + + + // helper to store a an unsigned integer + template< typename T > + size_t + store( std::ostream& _os, + const T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_unsigned) + { + assert( OMFormat::is_integer( _val ) ); + + switch( _b ) + { + case OMFormat::Chunk::Integer_8: + { + OMFormat::uint8 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_16: + { + OMFormat::uint16 v = static_cast(_val); + return store( _os, v, _swap ); + } + case OMFormat::Chunk::Integer_32: + { + OMFormat::uint32 v = static_cast(_val); + return store( _os, v, _swap ); + } + + case OMFormat::Chunk::Integer_64: + { + OMFormat::uint64 v = static_cast(_val); + return store( _os, v, _swap ); + } + } + return 0; + } + + + // helper to store a an integer + template< typename T > + size_t + restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_signed) + { + assert( OMFormat::is_integer( _val ) ); + size_t bytes = 0; + + switch( _b ) + { + case OMFormat::Chunk::Integer_8: + { + OMFormat::int8 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_16: + { + OMFormat::int16 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + } + case OMFormat::Chunk::Integer_32: + { + OMFormat::int32 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + } + case OMFormat::Chunk::Integer_64: + { + OMFormat::int64 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + } + } + return bytes; + } + + + // helper to store a an unsigned integer + template< typename T > + size_t + restore( std::istream& _is, + T& _val, + OMFormat::Chunk::Integer_Size _b, + bool _swap, + t_unsigned) + { + assert( OMFormat::is_integer( _val ) ); + size_t bytes = 0; + + switch( _b ) + { + case OMFormat::Chunk::Integer_8: + { + OMFormat::uint8 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_16: + { + OMFormat::uint16 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + case OMFormat::Chunk::Integer_32: + { + OMFormat::uint32 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + + case OMFormat::Chunk::Integer_64: + { + OMFormat::uint64 v; + bytes = restore( _is, v, _swap ); + _val = static_cast(v); + break; + } + } + return bytes; + } + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Core/IO/Options.hh b/Core/IO/Options.hh new file mode 100644 index 00000000..c51c70b9 --- /dev/null +++ b/Core/IO/Options.hh @@ -0,0 +1,220 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +#ifndef OPENMESH_IO_OPTIONS_HH +#define OPENMESH_IO_OPTIONS_HH + + +//=== INCLUDES ================================================================ + + +// OpenMesh +#include + + +//== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** \name Mesh Reading / Writing + Option for reader and writer modules. +*/ +//@{ + + +//----------------------------------------------------------------------------- + +/** \brief Set options for reader/writer modules. + * + * The class is used in a twofold way. + * -# In combination with reader modules the class is used + * - to pass hints to the reading module, whether the input is + * binary and what byte ordering the binary data has + * - to retrieve information about the file contents after + * succesful reading. + * -# In combination with write modules the class gives directions to + * the writer module, whether to + * - use binary mode or not and what byte order to use + * - store one of the standard properties. + * + * The option are defined in \c Options::Flag as bit values and stored in + * an \c int value as a bitset. + */ +class Options +{ +public: + typedef int enum_type; + typedef enum_type value_type; + + /// Definitions of %Options for reading and writing. The options can be + /// or'ed. + enum Flag { + Default = 0x0000, ///< No options + Binary = 0x0001, ///< Set binary mode for r/w + MSB = 0x0002, ///< Assume big endian byte ordering + LSB = 0x0004, ///< Assume little endian byte ordering + Swap = 0x0006, ///< Swap byte order in binary mode + VertexNormal = 0x0010, ///< Has (r) / store (w) vertex normals + VertexColor = 0x0020, ///< Has (r) / store (w) vertex colors + VertexTexCoord = 0x0040, ///< Has (r) / store (w) texture coordinates + FaceNormal = 0x0100, ///< Has (r) / store (w) face normals + FaceColor = 0x0200, ///< Has (r) / store (w) face colors + ColorAlpha = 0x0400 ///< Has (r) / store (w) alpha values for colors + }; + +public: + + /// Default constructor + Options() : flags_( Default ) + { } + + + /// Copy constructor + Options(const Options& _opt) : flags_(_opt.flags_) + { } + + + /// Initializing constructor setting a single option + Options(Flag _flg) : flags_( _flg) + { } + + + /// Initializing constructor setting multiple options + Options(const value_type _flgs) : flags_( _flgs) + { } + + + ~Options() + { } + + /// Restore state after default constructor. + void cleanup(void) + { flags_ = Default; } + + /// Clear all bits. + void clear(void) + { flags_ = 0; } + + /// Returns true if all bits are zero. + bool is_empty(void) const { return !flags_; } + +public: + + + //@{ + /// Copy options defined in _rhs. + + Options& operator = ( const Options& _rhs ) + { flags_ = _rhs.flags_; return *this; } + + Options& operator = ( const value_type _rhs ) + { flags_ = _rhs; return *this; } + + //@} + + + //@{ + /// Unset options defined in _rhs. + + Options& operator -= ( const value_type _rhs ) + { flags_ &= ~_rhs; return *this; } + + Options& unset( const value_type _rhs) + { return (*this -= _rhs); } + + //@} + + + + //@{ + /// Set options defined in _rhs + + Options& operator += ( const value_type _rhs ) + { flags_ |= _rhs; return *this; } + + Options& set( const value_type _rhs) + { return (*this += _rhs); } + + //@} + +public: + + + // Check if an option or several options are set. + bool check(const value_type _rhs) const + { + return (flags_ & _rhs)==_rhs; + } + + bool is_binary() const { return check(Binary); } + bool vertex_has_normal() const { return check(VertexNormal); } + bool vertex_has_color() const { return check(VertexColor); } + bool vertex_has_texcoord() const { return check(VertexTexCoord); } + bool face_has_normal() const { return check(FaceNormal); } + bool face_has_color() const { return check(FaceColor); } + bool color_has_alpha() const { return check(ColorAlpha); } + + + /// Returns true if _rhs has the same options enabled. + bool operator == (const value_type _rhs) const + { return flags_ == _rhs; } + + + /// Returns true if _rhs does not have the same options enabled. + bool operator != (const value_type _rhs) const + { return flags_ != _rhs; } + + + /// Returns the option set. + operator value_type () const { return flags_; } + +private: + + bool operator && (const value_type _rhs) const; + + value_type flags_; +}; + +//----------------------------------------------------------------------------- + + + + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/SR_binary.hh b/Core/IO/SR_binary.hh new file mode 100644 index 00000000..af6430c8 --- /dev/null +++ b/Core/IO/SR_binary.hh @@ -0,0 +1,118 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_BINARY_HH +#define OPENMESH_SR_BINARY_HH + + +//== INCLUDES ================================================================= + +#include +// -------------------- STL +#include +#include +#include +#include // accumulate +// -------------------- OpenMesh + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +//----------------------------------------------------------------------------- + + const static size_t UnknownSize(size_t(-1)); + + +//----------------------------------------------------------------------------- +// struct binary, helper for storing/restoring + +#define X \ + std::ostringstream msg; \ + msg << "Type not supported: " << typeid(value_type).name(); \ + throw std::logic_error(msg.str()) + +/// \struct binary SR_binary.hh +/// +/// The struct defines how to store and restore the type T. +/// It's used by the OM reader/writer modules. +/// +/// The following specialization are provided: +/// - Fundamental types except \c long \c double +/// - %OpenMesh vector types +/// - %OpenMesh::StatusInfo +/// - std::string (max. length 65535) +/// +/// \todo Complete documentation of members +template < typename T > struct binary +{ + typedef T value_type; + + static const bool is_streamable = false; + + static size_t size_of(void) { return UnknownSize; } + static size_t size_of(const value_type&) { return UnknownSize; } + + static + size_t store( std::ostream& /* _os */, + const value_type& /* _v */, + bool /* _swap=false */) + { X; return 0; } + + static + size_t restore( std::istream& /* _is */, + value_type& /* _v */, + bool /* _swap=false */) + { X; return 0; } +}; + +#undef X + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_SR_RBO_HH defined +//============================================================================= + diff --git a/Core/IO/SR_binary_spec.hh b/Core/IO/SR_binary_spec.hh new file mode 100644 index 00000000..7c2ad3a6 --- /dev/null +++ b/Core/IO/SR_binary_spec.hh @@ -0,0 +1,277 @@ +//============================================================================= +// +// 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: 4333 $ +// $Date: 2009-01-16 17:13:47 +0100 (Fr, 16. Jan 2009) $ +// +//============================================================================= + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_BINARY_SPEC_HH +#define OPENMESH_SR_BINARY_SPEC_HH + +//== INCLUDES ================================================================= + +#include +// -------------------- STL +#include +#include +#if defined(OM_CC_GCC) && (OM_CC_VERSION < 30000) +# include +#else +# include +#endif +#include +#include // logic_error +#include // accumulate +// -------------------- OpenMesh +#include +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + +#ifndef DOXY_IGNORE_THIS + +//----------------------------------------------------------------------------- +// struct binary, helper for storing/restoring + +#define SIMPLE_BINARY( T ) \ + template <> struct binary< T > { \ + typedef T value_type; \ + static const bool is_streamable = true; \ + static size_t size_of(const value_type&) { return sizeof(value_type); } \ + static size_t size_of(void) { return sizeof(value_type); } \ + static size_t store( std::ostream& _os, const value_type& _val, \ + bool _swap=false) { \ + value_type tmp = _val; \ + if (_swap) reverse_byte_order(tmp); \ + _os.write( (const char*)&tmp, sizeof(value_type) ); \ + return _os.good() ? sizeof(value_type) : 0; \ + } \ + \ + static size_t restore( std::istream& _is, value_type& _val, \ + bool _swap=false) { \ + _is.read( (char*)&_val, sizeof(value_type) ); \ + if (_swap) reverse_byte_order(_val); \ + return _is.good() ? sizeof(value_type) : 0; \ + } \ + } + +SIMPLE_BINARY(bool); +// SIMPLE_BINARY(int); + +// Why is this needed? Should not be used as not 32 bit compatible +SIMPLE_BINARY(unsigned long); +SIMPLE_BINARY(float); +SIMPLE_BINARY(double); +SIMPLE_BINARY(long double); + +SIMPLE_BINARY(int8_t); +SIMPLE_BINARY(int16_t); +SIMPLE_BINARY(int32_t); +SIMPLE_BINARY(int64_t); +SIMPLE_BINARY(uint8_t); +SIMPLE_BINARY(uint16_t); +SIMPLE_BINARY(uint32_t); +SIMPLE_BINARY(uint64_t); + +#undef SIMPLE_BINARY + + +#define VECTORT_BINARY( T ) \ + template <> struct binary< T > { \ + typedef T value_type; \ + static const bool is_streamable = true; \ + static size_t size_of(void) { return sizeof(value_type); } \ + static size_t size_of(const value_type&) { return size_of(); } \ + static size_t store( std::ostream& _os, const value_type& _val, \ + bool _swap=false) { \ + value_type tmp = _val; \ + size_t i, b = size_of(_val), N = value_type::size_; \ + if (_swap) for (i=0; i struct binary< std::string > { + typedef std::string value_type; + typedef uint16_t length_t; + + static const bool is_streamable = true; + + static size_t size_of() { return UnknownSize; } + static size_t size_of(const value_type &_v) + { return sizeof(length_t) + _v.size(); } + + static + size_t store(std::ostream& _os, const value_type& _v, bool _swap=false) + { +#if defined(OM_CC_GCC) && (OM_CC_VERSION < 30000) + if (_v.size() < Utils::NumLimitsT::max() ) +#else + if (_v.size() < std::numeric_limits::max() ) +#endif + { + length_t len = _v.size(); + + if (_swap) reverse_byte_order(len); + + size_t bytes = binary::store( _os, len, _swap ); + _os.write( _v.data(), len ); + return _os.good() ? len+bytes : 0; + } + throw std::runtime_error("Cannot store string longer than 64Kb"); + } + + static + size_t restore(std::istream& _is, value_type& _val, bool _swap=false) + { + length_t len; + size_t bytes = binary::restore( _is, len, _swap ); + if (_swap) + reverse_byte_order(len); + _val.resize(len); + _is.read( const_cast(_val.data()), len ); + + return _is.good() ? (len+bytes) : 0; + } +}; + + +template <> struct binary +{ + typedef OpenMesh::Attributes::StatusInfo value_type; + typedef value_type::value_type status_t; + + static const bool is_streamable = true; + + static size_t size_of() { return sizeof(status_t); } + static size_t size_of(const value_type&) { return size_of(); } + + static size_t n_bytes(size_t _n_elem) + { return _n_elem*sizeof(status_t); } + + static + size_t store(std::ostream& _os, const value_type& _v, bool _swap=false) + { + status_t v=_v.bits(); + return binary::store(_os, v, _swap); + } + + static + size_t restore( std::istream& _os, value_type& _v, bool _swap=false) + { + status_t v; + size_t b = binary::restore(_os, v, _swap); + _v.set_bits(v); + return b; + } +}; + + +//----------------------------------------------------------------------------- +// std::vector specializations for struct binary<> + +template +struct FunctorStore { + FunctorStore( std::ostream& _os, bool _swap) : os_(_os), swap_(_swap) { } + size_t operator () ( size_t _v1, const T& _s2 ) + { return _v1+binary::store(os_, _s2, swap_ ); } + + std::ostream& os_; + bool swap_; +}; + + +template +struct FunctorRestore { + FunctorRestore( std::istream& _is, bool _swap) : is_(_is), swap_(_swap) { } + size_t operator () ( size_t _v1, T& _s2 ) + { return _v1+binary::restore(is_, _s2, swap_ ); } + std::istream& is_; + bool swap_; +}; + +#include +#include +#include + +// ---------------------------------------------------------------------------- + +#endif // DOXY_IGNORE_THIS + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_SR_BINARY_SPEC_HH defined +//============================================================================= + diff --git a/Core/IO/SR_binary_vector_of_bool.inl b/Core/IO/SR_binary_vector_of_bool.inl new file mode 100644 index 00000000..51f1d93d --- /dev/null +++ b/Core/IO/SR_binary_vector_of_bool.inl @@ -0,0 +1,99 @@ + +template <> struct binary< std::vector > +{ + + typedef std::vector< bool > value_type; + typedef value_type::value_type elem_type; + + static const bool is_streamable = true; + + static size_t size_of(void) { return UnknownSize; } + static size_t size_of(const value_type& _v) + { + return _v.size() / 8 + ((_v.size() % 8)!=0); + } + + static + size_t store( std::ostream& _ostr, const value_type& _v, bool ) + { + size_t bytes = 0; + + size_t N = _v.size() / 8; + size_t R = _v.size() % 8; + + size_t idx; // element index + unsigned char bits; // bitset + + for (idx=0; idx < N; ++idx) + { + bits = 0; + bits = bits | (_v[idx+0] ? 1 : 0); + bits = bits | ((_v[idx+1] ? 1 : 0) << 1); + bits = bits | ((_v[idx+2] ? 1 : 0) << 2); + bits = bits | ((_v[idx+3] ? 1 : 0) << 3); + bits = bits | ((_v[idx+4] ? 1 : 0) << 4); + bits = bits | ((_v[idx+5] ? 1 : 0) << 5); + bits = bits | ((_v[idx+6] ? 1 : 0) << 6); + bits = bits | ((_v[idx+7] ? 1 : 0) << 7); + _ostr << bits; + } + bytes = N; + + if (R) + { + bits = 0; + switch(R) + { + case 7: bits = bits | ((_v[idx+6] ? 1 : 0) << 6); + case 6: bits = bits | ((_v[idx+5] ? 1 : 0) << 5); + case 5: bits = bits | ((_v[idx+4] ? 1 : 0) << 4); + case 4: bits = bits | ((_v[idx+3] ? 1 : 0) << 3); + case 3: bits = bits | ((_v[idx+2] ? 1 : 0) << 2); + case 2: bits = bits | ((_v[idx+1] ? 1 : 0) << 1); + case 1: bits = bits | (_v[idx+0] ? 1 : 0); + } + _ostr << bits; + ++bytes; + } + + assert( bytes == size_of(_v) ); + + return bytes; + } + + static + size_t restore( std::istream& _istr, value_type& _v, bool ) + { + size_t bytes = 0; + + size_t N = _v.size() / 8; + size_t R = _v.size() % 8; + + size_t idx; // element index + unsigned char bits; // bitset + + for (idx=0; idx < N; ++idx) + { + _istr >> bits; + _v[idx+0] = ((bits & 0x01)!=0); + _v[idx+1] = ((bits & 0x02)!=0); + _v[idx+2] = ((bits & 0x04)!=0); + _v[idx+3] = ((bits & 0x08)!=0); + _v[idx+4] = ((bits & 0x10)!=0); + _v[idx+5] = ((bits & 0x20)!=0); + _v[idx+6] = ((bits & 0x40)!=0); + _v[idx+7] = ((bits & 0x80)!=0); + } + bytes = N; + + if (R) + { + _istr >> bits; + for(; idx < _v.size(); ++idx) + _v[idx] = (bits & (1 << (idx%8)))!=0; + ++bytes; + } + + return bytes; + } +}; diff --git a/Core/IO/SR_binary_vector_of_fundamentals.inl b/Core/IO/SR_binary_vector_of_fundamentals.inl new file mode 100644 index 00000000..000f9f6b --- /dev/null +++ b/Core/IO/SR_binary_vector_of_fundamentals.inl @@ -0,0 +1,53 @@ + +#define BINARY_VECTOR( T ) \ +template <> struct binary< std::vector< T > > { \ + typedef std::vector< T > value_type; \ + typedef value_type::value_type elem_type; \ + \ + static const bool is_streamable = true; \ + \ + static size_t size_of(void) \ + { return IO::UnknownSize; } \ + \ + static size_t size_of(const value_type& _v) \ + { return sizeof(elem_type)*_v.size(); } \ + \ + static \ + size_t store(std::ostream& _os, const value_type& _v, bool _swap=false) { \ + size_t bytes=0; \ + \ + if (_swap) \ + bytes = std::accumulate( _v.begin(), _v.end(), bytes, \ + FunctorStore(_os,_swap) ); \ + else { \ + bytes = size_of(_v); \ + _os.write( reinterpret_cast(&_v[0]), bytes ); \ + } \ + return _os.good() ? bytes : 0; \ + } \ + \ + static size_t restore(std::istream& _is, value_type& _v, bool _swap=false) { \ + size_t bytes=0; \ + \ + if ( _swap) \ + bytes = std::accumulate( _v.begin(), _v.end(), 0, \ + FunctorRestore(_is, _swap) ); \ + else \ + { \ + bytes = size_of(_v); \ + _is.read( reinterpret_cast(&_v[0]), bytes ); \ + } \ + return _is.good() ? bytes : 0; \ + } \ +} + +BINARY_VECTOR( short ); +BINARY_VECTOR( unsigned short ); +BINARY_VECTOR( int ); +BINARY_VECTOR( unsigned int ); +BINARY_VECTOR( long ); +BINARY_VECTOR( unsigned long ); +BINARY_VECTOR( float ); +BINARY_VECTOR( double ); + +#undef BINARY_VECTOR diff --git a/Core/IO/SR_binary_vector_of_string.inl b/Core/IO/SR_binary_vector_of_string.inl new file mode 100644 index 00000000..acf5a1db --- /dev/null +++ b/Core/IO/SR_binary_vector_of_string.inl @@ -0,0 +1,39 @@ + +template <> struct binary< std::vector< std::string > > +{ + // struct binary interface + + typedef std::vector< std::string > value_type; + typedef value_type::value_type elem_type; + + static const bool is_streamable = true; + + // Helper + + struct Sum + { + size_t operator() ( size_t _v1, const elem_type& _s2 ) + { return _v1 + binary::size_of(_s2); } + }; + + // struct binary interface + + static size_t size_of(void) { return UnknownSize; } + + static size_t size_of(const value_type& _v) + { return std::accumulate( _v.begin(), _v.end(), 0u, Sum() ); } + + static + size_t store(std::ostream& _os, const value_type& _v, bool _swap=false) + { + return std::accumulate( _v.begin(), _v.end(), 0, + FunctorStore(_os, _swap) ); + } + + static + size_t restore(std::istream& _is, value_type& _v, bool _swap=false) + { + return std::accumulate( _v.begin(), _v.end(), 0, + FunctorRestore(_is, _swap) ); + } +}; diff --git a/Core/IO/SR_rbo.hh b/Core/IO/SR_rbo.hh new file mode 100644 index 00000000..9324a2b0 --- /dev/null +++ b/Core/IO/SR_rbo.hh @@ -0,0 +1,247 @@ +//============================================================================= +// +// 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: 4333 $ +// $Date: 2009-01-16 17:13:47 +0100 (Fr, 16. Jan 2009) $ +// +//============================================================================= + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_RBO_HH +#define OPENMESH_SR_RBO_HH + + +//== INCLUDES ================================================================= + +#include +// -------------------- STL +#if defined(OM_CC_MIPS) +# include // size_t +#else +# include // size_t +#endif +#include +#include +// -------------------- OpenMesh +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +/** \name Handling binary input/output. + These functions take care of swapping bytes to get the right Endian. +*/ +//@{ + + +//----------------------------------------------------------------------------- + +/** this does not compile for g++3.4 and higher, hence we comment the +function body which will result in a linker error */ + +template < size_t N > inline +void _reverse_byte_order_N(uint8_t* _val) +{ + assert_compile(false); +// compile_time_error__only_for_fundamental_types(_val); +} + + +template <> inline +void _reverse_byte_order_N<1>(uint8_t* /*_val*/) { }; + + +template <> inline +void _reverse_byte_order_N<2>(uint8_t* _val) +{ + _val[0] ^= _val[1]; _val[1] ^= _val[0]; _val[0] ^= _val[1]; +} + + +template <> inline +void _reverse_byte_order_N<4>(uint8_t* _val) +{ + _val[0] ^= _val[3]; _val[3] ^= _val[0]; _val[0] ^= _val[3]; // 0 <-> 3 + _val[1] ^= _val[2]; _val[2] ^= _val[1]; _val[1] ^= _val[2]; // 1 <-> 2 +} + + +template <> inline +void _reverse_byte_order_N<8>(uint8_t* _val) +{ + _val[0] ^= _val[7]; _val[7] ^= _val[0]; _val[0] ^= _val[7]; // 0 <-> 7 + _val[1] ^= _val[6]; _val[6] ^= _val[1]; _val[1] ^= _val[6]; // 1 <-> 6 + _val[2] ^= _val[5]; _val[5] ^= _val[2]; _val[2] ^= _val[5]; // 2 <-> 5 + _val[3] ^= _val[4]; _val[4] ^= _val[3]; _val[3] ^= _val[4]; // 3 <-> 4 +} + + +template <> inline +void _reverse_byte_order_N<12>(uint8_t* _val) +{ + _val[0] ^= _val[11]; _val[11] ^= _val[0]; _val[0] ^= _val[11]; // 0 <-> 11 + _val[1] ^= _val[10]; _val[10] ^= _val[1]; _val[1] ^= _val[10]; // 1 <-> 10 + _val[2] ^= _val[ 9]; _val[ 9] ^= _val[2]; _val[2] ^= _val[ 9]; // 2 <-> 9 + _val[3] ^= _val[ 8]; _val[ 8] ^= _val[3]; _val[3] ^= _val[ 8]; // 3 <-> 8 + _val[4] ^= _val[ 7]; _val[ 7] ^= _val[4]; _val[4] ^= _val[ 7]; // 4 <-> 7 + _val[5] ^= _val[ 6]; _val[ 6] ^= _val[5]; _val[5] ^= _val[ 6]; // 5 <-> 6 +} + + +template <> inline +void _reverse_byte_order_N<16>(uint8_t* _val) +{ + _reverse_byte_order_N<8>(_val); + _reverse_byte_order_N<8>(_val+8); + std::swap(*(uint64_t*)_val, *(((uint64_t*)_val)+1)); +} + + +//----------------------------------------------------------------------------- +// wrapper for byte reordering + +// reverting pointers makes no sense, hence forbid it. +/** this does not compile for g++3.4 and higher, hence we comment the +function body which will result in a linker error */ +template inline T* reverse_byte_order(T* t) +{ + // Should never reach this point. If so, then some operator were not + // overloaded. Especially check for IO::binary<> specialization on + // custom data types. +// compile_time_error__cannot_do_that(a); + assert_compile(false); + return t; +} + +inline void compile_time_error__no_fundamental_type() +{ + // we should never reach this point + assert(false); +} + +// default action for byte reversal: cause an error to avoid +// surprising behaviour! +template T& reverse_byte_order( T& _t ) +{ + omerr() << "Not defined for type " << typeid(T).name() << std::endl; + compile_time_error__no_fundamental_type(); + return _t; +} + +template <> inline bool& reverse_byte_order(bool & _t) { return _t; } +template <> inline char& reverse_byte_order(char & _t) { return _t; } +#if defined(OM_CC_GCC) +template <> inline signed char& reverse_byte_order(signed char & _t) { return _t; } +#endif +template <> inline uchar& reverse_byte_order(uchar& _t) { return _t; } + +// Instead do specializations for the necessary types +#define REVERSE_FUNDAMENTAL_TYPE( T ) \ + template <> inline T& reverse_byte_order( T& _t ) {\ + _reverse_byte_order_N( reinterpret_cast(&_t) ); \ + return _t; \ + } + +// REVERSE_FUNDAMENTAL_TYPE(bool); +// REVERSE_FUNDAMENTAL_TYPE(char); +// REVERSE_FUNDAMENTAL_TYPE(uchar); +REVERSE_FUNDAMENTAL_TYPE(int16_t); +REVERSE_FUNDAMENTAL_TYPE(uint16_t); +// REVERSE_FUNDAMENTAL_TYPE(int); +// REVERSE_FUNDAMENTAL_TYPE(uint); + +REVERSE_FUNDAMENTAL_TYPE(unsigned long); +REVERSE_FUNDAMENTAL_TYPE(int32_t); +REVERSE_FUNDAMENTAL_TYPE(uint32_t); +REVERSE_FUNDAMENTAL_TYPE(int64_t); +REVERSE_FUNDAMENTAL_TYPE(uint64_t); +REVERSE_FUNDAMENTAL_TYPE(float); +REVERSE_FUNDAMENTAL_TYPE(double); +REVERSE_FUNDAMENTAL_TYPE(long double); + +#undef REVERSE_FUNDAMENTAL_TYPE + +#if 0 + +#define REVERSE_VECTORT_TYPE( T ) \ + template <> inline T& reverse_byte_order(T& _v) {\ + for (size_t i; i< T::size_; ++i) \ + _reverse_byte_order_N< sizeof(T::value_type) >( reinterpret_cast(&_v[i])); \ + return _v; \ + } + +#define REVERSE_VECTORT_TYPES( N ) \ + REVERSE_VECTORT_TYPE( Vec##N##c ) \ + REVERSE_VECTORT_TYPE( Vec##N##uc ) \ + REVERSE_VECTORT_TYPE( Vec##N##s ) \ + REVERSE_VECTORT_TYPE( Vec##N##us ) \ + REVERSE_VECTORT_TYPE( Vec##N##i ) \ + REVERSE_VECTORT_TYPE( Vec##N##ui ) \ + REVERSE_VECTORT_TYPE( Vec##N##f ) \ + REVERSE_VECTORT_TYPE( Vec##N##d ) \ + +REVERSE_VECTORT_TYPES(1) +REVERSE_VECTORT_TYPES(2) +REVERSE_VECTORT_TYPES(3) +REVERSE_VECTORT_TYPES(4) +REVERSE_VECTORT_TYPES(6) + +#undef REVERSE_VECTORT_TYPES +#undef REVERSE_VECTORT_TYPE + +#endif + +template inline +T reverse_byte_order(const T& a) +{ + compile_timer_error__const_means_const(a); + return a; +} + + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_SR_RBO_HH defined +//============================================================================= + diff --git a/Core/IO/SR_store.hh b/Core/IO/SR_store.hh new file mode 100644 index 00000000..c328fe9f --- /dev/null +++ b/Core/IO/SR_store.hh @@ -0,0 +1,54 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_STORE_HH +#define OPENMESH_SR_STORE_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include +#include + +//============================================================================= +#endif // OPENMESH_STORE_HH defined +//============================================================================= + diff --git a/Core/IO/SR_types.hh b/Core/IO/SR_types.hh new file mode 100644 index 00000000..25edb52e --- /dev/null +++ b/Core/IO/SR_types.hh @@ -0,0 +1,94 @@ +//============================================================================= +// +// 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: 3695 $ +// $Date: 2008-11-12 13:21:40 +0100 (Mi, 12. Nov 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_SR_TYPES_HH +#define OPENMESH_SR_TYPES_HH + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +/** \name Handling binary input/output. + These functions take care of swapping bytes to get the right Endian. +*/ +//@{ + +//----------------------------------------------------------------------------- + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned long ulong; + +typedef char int8_t; typedef unsigned char uint8_t; +typedef short int16_t; typedef unsigned short uint16_t; + +// Int should be 32 bit on all archs. +// long is 32 under windows but 64 under unix 64 bit +typedef int int32_t; typedef unsigned int uint32_t; +#if defined(OM_CC_MSVC) +typedef __int64 int64_t; typedef unsigned __int64 uint64_t; +#else +typedef long long int64_t; typedef unsigned long long uint64_t; +#endif + +typedef float float32_t; +typedef double float64_t; + +typedef uint8_t rgb_t[3]; +typedef uint8_t rgba_t[4]; + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= + diff --git a/Core/IO/StoreRestore.hh b/Core/IO/StoreRestore.hh new file mode 100644 index 00000000..56b01e5f --- /dev/null +++ b/Core/IO/StoreRestore.hh @@ -0,0 +1,98 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + +#ifndef OPENMESH_STORERESTORE_HH +#define OPENMESH_STORERESTORE_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + + +/** \name Handling binary input/output. + These functions take care of swapping bytes to get the right Endian. +*/ +//@{ + + +//----------------------------------------------------------------------------- +// StoreRestore definitions + +template inline +bool is_streamable(void) +{ return binary< T >::is_streamable; } + +template inline +bool is_streamable( const T& ) +{ return binary< T >::is_streamable; } + +template inline +size_t size_of( const T& _v ) +{ return binary< T >::size_of(_v); } + +template inline +size_t size_of(void) +{ return binary< T >::size_of(); } + +template inline +size_t store( std::ostream& _os, const T& _v, bool _swap=false) +{ return binary< T >::store( _os, _v, _swap ); } + +template inline +size_t restore( std::istream& _is, T& _v, bool _swap=false) +{ return binary< T >::restore( _is, _v, _swap ); } + +//@} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= diff --git a/Core/IO/exporter/ACGMakefile b/Core/IO/exporter/ACGMakefile new file mode 100644 index 00000000..6d85b985 --- /dev/null +++ b/Core/IO/exporter/ACGMakefile @@ -0,0 +1,17 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = $(call find-subdirs) + +PACKAGES := + +PROJ_LIBS := + +MODULES := cxxlib + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Core/IO/exporter/BaseExporter.hh b/Core/IO/exporter/BaseExporter.hh new file mode 100644 index 00000000..cad3496a --- /dev/null +++ b/Core/IO/exporter/BaseExporter.hh @@ -0,0 +1,114 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements the baseclass for MeshWriter exporter modules +// +//============================================================================= + + +#ifndef __BASEEXPORTER_HH__ +#define __BASEEXPORTER_HH__ + + +//=== INCLUDES ================================================================ + + +// STL +#include + +// OpenMesh +#include +#include +#include + + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== EXPORTER ================================================================ + + +/** + Base class for exporter modules. + The exporter modules provide an interface between the writer modules and + the target data structure. +*/ + +class BaseExporter +{ +public: + + virtual ~BaseExporter() { } + + + // get vertex data + virtual Vec3f point(VertexHandle _vh) const = 0; + virtual Vec3f normal(VertexHandle _vh) const = 0; + virtual Vec3uc color(VertexHandle _vh) const = 0; + virtual Vec4uc colorA(VertexHandle _vh) const = 0; + virtual Vec2f texcoord(VertexHandle _vh) const = 0; + + + // get face data + virtual unsigned int + get_vhandles(FaceHandle _fh, + std::vector& _vhandles) const=0; + virtual Vec3f normal(FaceHandle _fh) const = 0; + virtual Vec3uc color (FaceHandle _fh) const = 0; + virtual Vec4uc colorA(FaceHandle _fh) const = 0; + + // get reference to base kernel + virtual const BaseKernel* kernel() { return 0; } + + + // query number of faces, vertices, normals, texcoords + virtual size_t n_vertices() const = 0; + virtual size_t n_faces() const = 0; + virtual size_t n_edges() const = 0; + + + // property information + virtual bool is_triangle_mesh() const { return false; } + virtual bool has_vertex_normals() const { return false; } + virtual bool has_vertex_colors() const { return false; } + virtual bool has_vertex_texcoords() const { return false; } + virtual bool has_face_normals() const { return false; } + virtual bool has_face_colors() const { return false; } +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/exporter/ExporterT.hh b/Core/IO/exporter/ExporterT.hh new file mode 100644 index 00000000..3eca72f6 --- /dev/null +++ b/Core/IO/exporter/ExporterT.hh @@ -0,0 +1,183 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements an exporter module for arbitrary OpenMesh meshes +// +//============================================================================= + + +#ifndef __EXPORTERT_HH__ +#define __EXPORTERT_HH__ + + +//=== INCLUDES ================================================================ + +// C++ +#include + +// OpenMesh +#include +#include +#include +#include +#include +#include + + +//=== NAMESPACES ============================================================== + +namespace OpenMesh { +namespace IO { + + +//=== EXPORTER CLASS ========================================================== + +/** + * This class template provides an exporter module for OpenMesh meshes. + */ +template +class ExporterT : public BaseExporter +{ +public: + + // Constructor + ExporterT(const Mesh& _mesh) : mesh_(_mesh) {} + + + // get vertex data + + Vec3f point(VertexHandle _vh) const + { + return vector_cast(mesh_.point(_vh)); + } + + Vec3f normal(VertexHandle _vh) const + { + return (mesh_.has_vertex_normals() + ? vector_cast(mesh_.normal(_vh)) + : Vec3f(0.0f, 0.0f, 0.0f)); + } + + Vec3uc color(VertexHandle _vh) const + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec3uc(0, 0, 0)); + } + + Vec4uc colorA(VertexHandle _vh) const + { + return (mesh_.has_vertex_colors() + ? color_cast(mesh_.color(_vh)) + : Vec4uc(0, 0, 0, 0)); + } + + Vec2f texcoord(VertexHandle _vh) const + { +#if defined(OM_CC_GCC) && (OM_CC_VERSION<30000) + // Workaround! + // gcc 2.95.3 exits with internal compiler error at the + // code below!??? **) + if (mesh_.has_vertex_texcoords2D()) + return vector_cast(mesh_.texcoord2D(_vh)); + return Vec2f(0.0f, 0.0f); +#else // **) + return (mesh_.has_vertex_texcoords2D() + ? vector_cast(mesh_.texcoord2D(_vh)) + : Vec2f(0.0f, 0.0f)); +#endif + } + + + // get face data + + unsigned int get_vhandles(FaceHandle _fh, + std::vector& _vhandles) const + { + unsigned int count(0); + _vhandles.clear(); + for (typename Mesh::CFVIter fv_it=mesh_.cfv_iter(_fh); fv_it; ++fv_it) + { + _vhandles.push_back(fv_it.handle()); + ++count; + } + return count; + } + + Vec3f normal(FaceHandle _fh) const + { + return (mesh_.has_face_normals() + ? vector_cast(mesh_.normal(_fh)) + : Vec3f(0.0f, 0.0f, 0.0f)); + } + + Vec3uc color(FaceHandle _fh) const + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec3uc(0, 0, 0)); + } + + Vec4uc colorA(FaceHandle _fh) const + { + return (mesh_.has_face_colors() + ? color_cast(mesh_.color(_fh)) + : Vec4uc(0, 0, 0, 0)); + } + + virtual const BaseKernel* kernel() { return &mesh_; } + + + // query number of faces, vertices, normals, texcoords + size_t n_vertices() const { return mesh_.n_vertices(); } + size_t n_faces() const { return mesh_.n_faces(); } + size_t n_edges() const { return mesh_.n_edges(); } + + + // property information + bool is_triangle_mesh() const + { return Mesh::is_triangles(); } + + bool has_vertex_normals() const { return mesh_.has_vertex_normals(); } + bool has_vertex_colors() const { return mesh_.has_vertex_colors(); } + bool has_vertex_texcoords() const { return mesh_.has_vertex_texcoords2D(); } + bool has_face_normals() const { return mesh_.has_face_normals(); } + bool has_face_colors() const { return mesh_.has_face_colors(); } + +private: + + const Mesh& mesh_; +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/importer/ACGMakefile b/Core/IO/importer/ACGMakefile new file mode 100644 index 00000000..6d85b985 --- /dev/null +++ b/Core/IO/importer/ACGMakefile @@ -0,0 +1,17 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = $(call find-subdirs) + +PACKAGES := + +PROJ_LIBS := + +MODULES := cxxlib + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Core/IO/importer/BaseImporter.hh b/Core/IO/importer/BaseImporter.hh new file mode 100644 index 00000000..428ea8ca --- /dev/null +++ b/Core/IO/importer/BaseImporter.hh @@ -0,0 +1,130 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements the baseclass for IOManager importer modules +// +//============================================================================= + + +#ifndef __BASEIMPORTER_HH__ +#define __BASEIMPORTER_HH__ + + +//=== INCLUDES ================================================================ + + +// STL +#include + +// OpenMesh +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** Base class for importer modules. Importer modules provide an + * interface between the loader modules and the target data + * structure. This is basically a wrapper providing virtual versions + * for the required mesh functions. + */ +class BaseImporter +{ +public: + + // base class needs virtual destructor + virtual ~BaseImporter() {} + + + // add a vertex with coordinate \c _point + virtual VertexHandle add_vertex(const Vec3f& _point) = 0; + + // add a face with indices _indices refering to vertices + typedef std::vector VHandles; + virtual FaceHandle add_face(const VHandles& _indices) = 0; + + // set vertex normal + virtual void set_normal(VertexHandle _vh, const Vec3f& _normal) = 0; + + // set vertex color + virtual void set_color(VertexHandle _vh, const Vec3uc& _color) = 0; + + // set vertex color + virtual void set_color(VertexHandle _vh, const Vec4uc& _color) = 0; + + // set vertex texture coordinate + virtual void set_texcoord(VertexHandle _vh, const Vec2f& _texcoord) = 0; + + // set face normal + virtual void set_normal(FaceHandle _fh, const Vec3f& _normal) = 0; + + // set face color + virtual void set_color(FaceHandle _fh, const Vec3uc& _color) = 0; + + // set face color + virtual void set_color(FaceHandle _fh, const Vec4uc& _color) = 0; + + // get reference to base kernel + virtual BaseKernel* kernel() { return 0; } + + virtual bool is_triangle_mesh() const { return false; } + + // reserve mem for elements + virtual void reserve( unsigned int /* nV */, + unsigned int /* nE */, + unsigned int /* nF */) {} + + // query number of faces, vertices, normals, texcoords + virtual size_t n_vertices() const = 0; + virtual size_t n_faces() const = 0; + virtual size_t n_edges() const = 0; + + + // pre-processing + virtual void prepare() {} + + // post-processing + virtual void finish() {} +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/importer/ImporterT.hh b/Core/IO/importer/ImporterT.hh new file mode 100644 index 00000000..54cb918a --- /dev/null +++ b/Core/IO/importer/ImporterT.hh @@ -0,0 +1,235 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements an importer module for arbitrary OpenMesh meshes +// +//============================================================================= + + +#ifndef __IMPORTERT_HH__ +#define __IMPORTERT_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + * This class template provides an importer module for OpenMesh meshes. + */ +template +class ImporterT : public BaseImporter +{ +public: + + typedef typename Mesh::Point Point; + typedef typename Mesh::Normal Normal; + typedef typename Mesh::Color Color; + typedef typename Mesh::TexCoord2D TexCoord2D; + typedef std::vector VHandles; + + + ImporterT(Mesh& _mesh) : mesh_(_mesh) {} + + + virtual VertexHandle add_vertex(const Vec3f& _point) + { + return mesh_.add_vertex(vector_cast(_point)); + } + + + virtual FaceHandle add_face(const VHandles& _indices) + { + FaceHandle fh; + + if (_indices.size() > 2) + { + VHandles::const_iterator it, it2, end(_indices.end()); + + + // test for valid vertex indices + for (it=_indices.begin(); it!=end; ++it) + if (! mesh_.is_valid_handle(*it)) + { + omerr() << "ImporterT: Face contains invalid vertex index\n"; + return fh; + } + + + // don't allow double vertices + for (it=_indices.begin(); it!=end; ++it) + for (it2=it+1; it2!=end; ++it2) + if (*it == *it2) + { + omerr() << "ImporterT: Face has equal vertices\n"; + failed_faces_.push_back(_indices); + return fh; + } + + + // try to add face + fh = mesh_.add_face(_indices); + if (!fh.is_valid()) + { + failed_faces_.push_back(_indices); + return fh; + } + } + + return fh; + } + + + // vertex attributes + + virtual void set_normal(VertexHandle _vh, const Vec3f& _normal) + { + if (mesh_.has_vertex_normals()) + mesh_.set_normal(_vh, vector_cast(_normal)); + } + + virtual void set_color(VertexHandle _vh, const Vec4uc& _color) + { + if (mesh_.has_vertex_colors()) + mesh_.set_color(_vh, color_cast(_color)); + } + + virtual void set_color(VertexHandle _vh, const Vec3uc& _color) + { + if (mesh_.has_vertex_colors()) + mesh_.set_color(_vh, color_cast(_color)); + } + + + virtual void set_texcoord(VertexHandle _vh, const Vec2f& _texcoord) + { + if (mesh_.has_vertex_texcoords2D()) + mesh_.set_texcoord2D(_vh, vector_cast(_texcoord)); + } + + + // face attributes + + virtual void set_normal(FaceHandle _fh, const Vec3f& _normal) + { + if (mesh_.has_face_normals()) + mesh_.set_normal(_fh, vector_cast(_normal)); + } + + virtual void set_color(FaceHandle _fh, const Vec3uc& _color) + { + if (mesh_.has_face_colors()) + mesh_.set_color(_fh, color_cast(_color)); + } + + virtual void set_color(FaceHandle _fh, const Vec4uc& _color) + { + if (mesh_.has_face_colors()) + mesh_.set_color(_fh, color_cast(_color)); + } + + // low-level access to mesh + + virtual BaseKernel* kernel() { return &mesh_; } + + bool is_triangle_mesh() const + { return Mesh::is_triangles(); } + + void reserve(unsigned int nV, unsigned int nE, unsigned int nF) + { + mesh_.reserve(nV, nE, nF); + } + + // query number of faces, vertices, normals, texcoords + size_t n_vertices() const { return mesh_.n_vertices(); } + size_t n_faces() const { return mesh_.n_faces(); } + size_t n_edges() const { return mesh_.n_edges(); } + + + void prepare() { failed_faces_.clear(); } + + + void finish() + { + if (!failed_faces_.empty()) + { + omerr() << failed_faces_.size() + << " faces failed, adding them as isolated faces\n"; + + for (unsigned int i=0; i failed_faces_; +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/reader/ACGMakefile b/Core/IO/reader/ACGMakefile new file mode 100644 index 00000000..6d85b985 --- /dev/null +++ b/Core/IO/reader/ACGMakefile @@ -0,0 +1,17 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = $(call find-subdirs) + +PACKAGES := + +PROJ_LIBS := + +MODULES := cxxlib + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Core/IO/reader/BaseReader.cc b/Core/IO/reader/BaseReader.cc new file mode 100644 index 00000000..926517ee --- /dev/null +++ b/Core/IO/reader/BaseReader.cc @@ -0,0 +1,113 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//=== INCLUDES ================================================================ + +#include +#include +#include +#include +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +static inline char tolower(char c) +{ + using namespace std; + return ::tolower(c); +} + + +//----------------------------------------------------------------------------- + + +bool +BaseReader:: +can_u_read(const std::string& _filename) const +{ + // get file extension + std::string extension; + std::string::size_type pos(_filename.rfind(".")); + + if (pos != std::string::npos) + { + extension = _filename.substr(pos+1, _filename.length()-pos-1); + + std::transform( extension.begin(), extension.end(), + extension.begin(), tolower ); + } + + // locate extension in extension string + return (get_extensions().find(extension) != std::string::npos); +} + + +//----------------------------------------------------------------------------- + + +bool +BaseReader:: +check_extension(const std::string& _fname, const std::string& _ext) const +{ + std::string cmpExt(_ext); + + std::transform( _ext.begin(), _ext.end(), cmpExt.begin(), tolower ); + + std::string::size_type pos(_fname.rfind(".")); + + if (pos != std::string::npos && !_ext.empty() ) + { + std::string ext; + + // extension without dot! + ext = _fname.substr(pos+1, _fname.length()-pos-1); + + std::transform( ext.begin(), ext.end(), ext.begin(), tolower ); + + return ext == cmpExt; + } + return false; +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Core/IO/reader/BaseReader.hh b/Core/IO/reader/BaseReader.hh new file mode 100644 index 00000000..8f385e7b --- /dev/null +++ b/Core/IO/reader/BaseReader.hh @@ -0,0 +1,113 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements the baseclass for IOManager file access modules +// +//============================================================================= + + +#ifndef __BASEREADER_HH__ +#define __BASEREADER_HH__ + + +//=== INCLUDES ================================================================ + + +// STD C++ +#include +#include + +// OpenMesh +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Base class for reader modules. + Reader modules access persistent data and pass them to the desired + data structure by the means of a BaseImporter derivative. + All reader modules must be derived from this class. +*/ +class BaseReader +{ +public: + + /// Returns a brief description of the file type that can be parsed. + virtual std::string get_description() const = 0; + + /** Returns a string with the accepted file extensions separated by a + whitespace and in small caps. + */ + virtual std::string get_extensions() const = 0; + + /// Return magic bits used to determine file format + virtual std::string get_magic() const { return std::string(""); } + + + /** Reads a mesh given by a filename. Usually this method opens a stream + and passes it to stream read method. Acceptance checks by filename + extension can be placed here. + + Options can be passed via _opt. After execution _opt contains the Options + that were available + */ + virtual bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt) = 0; + + + /// Returns true if reader can parse _filename (checks extension) + virtual bool can_u_read(const std::string& _filename) const; + + +protected: + + // case insensitive search for _ext in _fname. + bool check_extension(const std::string& _fname, + const std::string& _ext) const; +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/reader/OBJReader.cc b/Core/IO/reader/OBJReader.cc new file mode 100644 index 00000000..50578c1b --- /dev/null +++ b/Core/IO/reader/OBJReader.cc @@ -0,0 +1,472 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//== INCLUDES ================================================================= + + +// OpenMesh +#include +#include +#include +#include +#include +// STL +#if defined(OM_CC_MIPS) +# include +/// \bug Workaround for STLPORT 4.6: isspace seems not to be in namespace std! +#elif defined(_STLPORT_VERSION) && (_STLPORT_VERSION==0x460) +# include +#else +# include +using std::isspace; +#endif + +#ifndef WIN32 +#include +#endif + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +_OBJReader_ __OBJReaderInstance; +_OBJReader_& OBJReader() { return __OBJReaderInstance; } + + +//=== IMPLEMENTATION ========================================================== + + +_OBJReader_:: +_OBJReader_() +{ + IOManager().register_module(this); +} + + +//----------------------------------------------------------------------------- + + +bool +_OBJReader_:: +read(const std::string& _filename, BaseImporter& _bi, Options& _opt) +{ + std::fstream in( _filename.c_str(), std::ios_base::in ); + + if (!in) + { + omerr() << "[OBJReader] : cannot not open file " + << _filename + << std::endl; + return false; + } + + { +#if defined(WIN32) + std::string::size_type dot = _filename.find_last_of("\\/"); +#else + std::string::size_type dot = _filename.rfind("/"); +#endif + path_ = (dot == std::string::npos) + ? "./" + : std::string(_filename.substr(0,dot+1)); + } + + bool result = read(in, _bi, _opt); + + in.close(); + return result; +} + + +//----------------------------------------------------------------------------- + +bool +_OBJReader_:: +read_material(std::fstream& _in) +{ + std::string line; + std::string keyWrd; + + std::string key; + Material mat; + float f1,f2,f3; + bool indef = false; + + + mat.cleanup(); + + while( _in && !_in.eof() ) + { + std::getline(_in,line); + if ( _in.bad() ){ + omerr() << " Warning! Could not read file properly!\n"; + return false; + } + + if ( line.empty() ) + continue; + + std::stringstream stream(line); + + stream >> keyWrd; + + if( isspace(line[0]) || line[0] == '#' ) + { + if (indef && !key.empty() && mat.is_valid()) + { + materials_[key] = mat; + mat.cleanup(); + } + } + + else if (keyWrd == "newmtl") // begin new material definition + { + stream >> key; + indef = true; + } + + else if (keyWrd == "Kd") // diffuse color + { + stream >> f1; stream >> f2; stream >> f3; + + if( !stream.fail() ) + mat.set_Kd(f1,f2,f3); + } + + else if (keyWrd == "Ka") // ambient color + { + stream >> f1; stream >> f2; stream >> f3; + + if( !stream.fail() ) + mat.set_Ka(f1,f2,f3); + } + + else if (keyWrd == "Ks") // specular color + { + stream >> f1; stream >> f2; stream >> f3; + + if( !stream.fail() ) + mat.set_Ks(f1,f2,f3); + } +#if 0 + else if (keyWrd == "illum") // diffuse/specular shading model + { + ; // just skip this + } + + else if (keyWrd == "Ns") // Shininess [0..200] + { + ; // just skip this + } + + else if (keyWrd == "map_") // map images + { + // map_Kd, diffuse map + // map_Ks, specular map + // map_Ka, ambient map + // map_Bump, bump map + // map_d, opacity map + ; // just skip this + } +#endif + + else if (keyWrd == "Tr") // transparency value + { + stream >> f1; + + if( !stream.fail() ) + mat.set_Tr(f1); + } + else if (keyWrd == "d") // transparency value + { + stream >> f1; + + if( !stream.fail() ) + mat.set_Tr(f1); + } + + if ( _in && indef && mat.is_valid() && !key.empty()) + materials_[key] = mat; + } + return true; +} + +//----------------------------------------------------------------------------- + + +bool +_OBJReader_:: +read(std::fstream& _in, BaseImporter& _bi, Options& _opt) +{ + omlog() << "[OBJReader] : read file\n"; + + + std::string line; + std::string keyWrd; + + float x, y, z, u, v; + + BaseImporter::VHandles vhandles; + std::vector normals; + std::vector texcoords; + + std::map materials; + std::string matname; + + + while( _in && !_in.eof() ) + { + std::getline(_in,line); + if ( _in.bad() ){ + omerr() << " Warning! Could not read file properly!\n"; + return false; + } + + // comment + if ( line.size() == 0 || line[0] == '#' || isspace(line[0]) ) { + continue; + } + + std::stringstream stream(line); + + stream >> keyWrd; + + // material file + if (keyWrd == "mtllib") + { + std::string matFile; + + stream >> matFile; + + matFile = path_ + matFile; + + omlog() << "Load material file " << matFile << std::endl; + + std::fstream matStream( matFile.c_str(), std::ios_base::in ); + + if ( matStream ){ + + if ( !read_material( matStream ) ) + omerr() << " Warning! Could not read file properly!\n"; + matStream.close(); + omlog() << " " << materials_.size() << " materials loaded.\n"; + + }else + omerr() << " Warning! Material file '" << matFile << "' not found!\n"; + } + + // usemtl + else if (keyWrd == "usemtl") + { + stream >> matname; + if (materials_.find(matname)==materials_.end()) + { + omerr() << "Warning! Material '" << matname + << "' not defined in material file.\n"; + matname=""; + } + } + + // vertex + else if (keyWrd == "v") + { + stream >> x; stream >> y; stream >> z; + + if ( !stream.fail() ) + _bi.add_vertex(OpenMesh::Vec3f(x,y,z)); + } + + // texture coord + else if (keyWrd == "vt") + { + stream >> u; stream >> v; + + if ( !stream.fail() ){ + + texcoords.push_back(OpenMesh::Vec2f(u, v)); + _opt += Options::VertexTexCoord; + + }else{ + + omerr() << "Only single 2D texture coordinate per vertex" + << "allowed!" << std::endl; + return false; + } + } + + + // normal + else if (keyWrd == "vn") + { + stream >> x; stream >> y; stream >> z; + + if ( !stream.fail() ){ + normals.push_back(OpenMesh::Vec3f(x,y,z)); + _opt += Options::VertexNormal; + } + } + + + // face + else if (keyWrd == "f") + { + int component(0), nV(0); + int value; + + vhandles.clear(); + + // read full line after detecting a face + std::string faceLine; + std::getline(stream,faceLine); + std::stringstream lineData( faceLine ); + + // work on the line until nothing left to read + while ( !lineData.eof() ) + { + // read one block from the line ( vertex/texCoord/normal ) + std::string vertex; + lineData >> vertex; + + do{ + + //get the component (vertex/texCoord/normal) + size_t found=vertex.find("/"); + + // parts are seperated by '/' So if no '/' found its the last component + if( found != std::string::npos ){ + + // read the index value + std::stringstream tmp( vertex.substr(0,found) ); + + // If we get an empty string this property is undefined in the file + if ( vertex.substr(0,found).empty() ) { + // Switch to next field + vertex = vertex.substr(found+1); + + // Now we are at the next component + ++component; + + // Skip further processing of this component + continue; + } + + // Read current value + tmp >> value; + + // remove the read part from the string + vertex = vertex.substr(found+1); + + } else { + + // last component of the vertex, read it. + std::stringstream tmp( vertex ); + tmp >> value; + + // Nothing to read here ( garbage at end of line ) + if ( tmp.fail() ) { + continue; + } + } + + // store the component ( each component is referenced by the index here! ) + switch (component) + { + case 0: // vertex + if ( value < 0 ) { +// std::cerr << "Handling negativ vertex index value" << std::endl; + value = _bi.n_vertices() + value + 1; + } + vhandles.push_back(VertexHandle(value-1)); + break; + + case 1: // texture coord + if ( value < 0 ) { +// std::cerr << "Handling negativ texture coordinate index value)" << std::endl; + value = _bi.n_vertices() + value + 1; + } + assert(!vhandles.empty()); + assert((unsigned int)(value-1) < texcoords.size()); + _bi.set_texcoord(vhandles.back(), texcoords[value-1]); + break; + + case 2: // normal + if ( value < 0 ) { +// std::cerr << "Handling negativ normal index value)" << std::endl; + value = _bi.n_vertices() + value + 1; + } + assert(!vhandles.empty()); + assert((unsigned int)(value-1) < normals.size()); + _bi.set_normal(vhandles.back(), normals[value-1]); + break; + } + + // Prepare for reading next component + ++component; + + } while ( vertex.find("/") != std::string::npos ); + + component = 0; + nV++; + } + + + size_t n_faces = _bi.n_faces(); + FaceHandle fh = _bi.add_face(vhandles); + + if ( !matname.empty() && materials_[matname].has_Kd() ) + { + std::vector newfaces; + + for( size_t i=0; i < _bi.n_faces()-n_faces; ++i ) + newfaces.push_back(FaceHandle(n_faces+i)); + + Material & mat = materials_[matname]; + + Vec3uc fc = color_cast(mat.Kd()); + + for (std::vector::iterator it = newfaces.begin(); + it != newfaces.end(); ++it) + _bi.set_color( *it, fc ); + + _opt += Options::FaceColor; + } + } + } + + return true; +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Core/IO/reader/OBJReader.hh b/Core/IO/reader/OBJReader.hh new file mode 100644 index 00000000..c2e3efba --- /dev/null +++ b/Core/IO/reader/OBJReader.hh @@ -0,0 +1,159 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements an reader module for OBJ files +// +//============================================================================= + + +#ifndef __OBJREADER_HH__ +#define __OBJREADER_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the OBJ format reader. +*/ +class _OBJReader_ : public BaseReader +{ +public: + + _OBJReader_(); + + virtual ~_OBJReader_() { } + + std::string get_description() const { return "Alias/Wavefront"; } + std::string get_extensions() const { return "obj"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt); + +private: + +#ifndef DOXY_IGNORE_THIS + class Material + { + public: + + Material() { cleanup(); } + + void cleanup() + { + Kd_is_set_ = false; + Ka_is_set_ = false; + Ks_is_set_ = false; + Tr_is_set_ = false; + } + + bool is_valid(void) const + { return Kd_is_set_ || Ka_is_set_ || Ks_is_set_ || Tr_is_set_; } + + bool has_Kd(void) { return Kd_is_set_; } + bool has_Ka(void) { return Ka_is_set_; } + bool has_Ks(void) { return Ks_is_set_; } + bool has_Tr(void) { return Tr_is_set_; } + + void set_Kd( float r, float g, float b ) + { Kd_=Vec3f(r,g,b); Kd_is_set_=true; } + + void set_Ka( float r, float g, float b ) + { Ka_=Vec3f(r,g,b); Ka_is_set_=true; } + + void set_Ks( float r, float g, float b ) + { Ks_=Vec3f(r,g,b); Ks_is_set_=true; } + + void set_Tr( float t ) + { Tr_=t; Tr_is_set_=true; } + + const Vec3f& Kd( void ) const { return Kd_; } + const Vec3f& Ka( void ) const { return Ka_; } + const Vec3f& Ks( void ) const { return Ks_; } + float Tr( void ) const { return Tr_; } + + private: + + Vec3f Kd_; bool Kd_is_set_; // diffuse + Vec3f Ka_; bool Ka_is_set_; // ambient + Vec3f Ks_; bool Ks_is_set_; // specular + float Tr_; bool Tr_is_set_; // transperency + }; +#endif + + typedef std::map MaterialList; + + MaterialList materials_; + + bool read_material( std::fstream& _in ); + +private: + + bool read(std::fstream& _in, BaseImporter& _bi, Options& _opt); + + std::string path_; + +}; + + +//== TYPE DEFINITION ========================================================== + + +extern _OBJReader_ __OBJReaderInstance; +_OBJReader_& OBJReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/reader/OFFReader.cc b/Core/IO/reader/OFFReader.cc new file mode 100644 index 00000000..5b6551cf --- /dev/null +++ b/Core/IO/reader/OFFReader.cc @@ -0,0 +1,597 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +#define LINE_LEN 4096 + + +//== INCLUDES ================================================================= + +// OpenMesh +#include +#include +#include +#include +#include +#include +// #include + +#include + +//STL +#include +#include + +#ifndef WIN32 +#include +#endif + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + +//=== INSTANCIATE ============================================================= + + +_OFFReader_ __OFFReaderInstance; +_OFFReader_& OFFReader() { return __OFFReaderInstance; } + + +//=== IMPLEMENTATION ========================================================== + + + +_OFFReader_::_OFFReader_() +{ + IOManager().register_module(this); +} + + +//----------------------------------------------------------------------------- + + +bool +_OFFReader_::read(const std::string& _filename, BaseImporter& _bi, + Options& _opt) +{ + std::fstream in(_filename.c_str(), (options_.is_binary() ? std::ios_base::binary | std::ios_base::in + : std::ios_base::in) ); + + if (!in) + { + omerr() << "[OFFReader] : cannot not open file " + << _filename + << std::endl; + return false; + } + + + bool result = read(in, _bi, _opt); + + + in.close(); + return result; +} + + +//----------------------------------------------------------------------------- + + +bool +_OFFReader_::read(std::fstream& _in, BaseImporter& _bi, Options& _opt ) const +{ + // filter relevant options for reading + bool swap = _opt.check( Options::Swap ); + + + userOptions_ = _opt; + + // build options to be returned + _opt.clear(); + + if (options_.vertex_has_normal() && userOptions_.vertex_has_normal()) _opt += Options::VertexNormal; + if (options_.vertex_has_texcoord() && userOptions_.vertex_has_texcoord()) _opt += Options::VertexTexCoord; + if (options_.vertex_has_color() && userOptions_.vertex_has_color()) _opt += Options::VertexColor; + if (options_.face_has_color() && userOptions_.face_has_color()) _opt += Options::FaceColor; + if (options_.is_binary()) _opt += Options::Binary; + + //force user-choice for the alpha value when reading binary + if ( options_.is_binary() && userOptions_.color_has_alpha() ) + options_ += Options::ColorAlpha; + + return (options_.is_binary() ? + read_binary(_in, _bi, swap) : + read_ascii(_in, _bi)); + +} + + + +//----------------------------------------------------------------------------- + +bool +_OFFReader_::read_ascii(std::fstream& _in, BaseImporter& _bi) const +{ + + +omlog() << "[OFFReader] : read ascii file\n"; + + unsigned int i, j, k, l, idx; + unsigned int nV, nF, dummy; + OpenMesh::Vec3f v, n; + OpenMesh::Vec2f t; + OpenMesh::Vec3i c3; + OpenMesh::Vec3f c3f; + OpenMesh::Vec4i c4; + OpenMesh::Vec4f c4f; + BaseImporter::VHandles vhandles; + VertexHandle vh; + + // read header line + std::string header; + std::getline(_in,header); + + // + #Vertice, #Faces, #Edges + _in >> nV; + _in >> nF; + _in >> dummy; + + _bi.reserve(nV, 3*nV, nF); + + // read vertices: coord [hcoord] [normal] [color] [texcoord] + for (i=0; i> v[0]; _in >> v[1]; _in >> v[2]; + + vh = _bi.add_vertex(v); + + //perhaps read NORMAL + if ( options_.vertex_has_normal() ){ + + _in >> n[0]; _in >> n[1]; _in >> n[2]; + + if ( userOptions_.vertex_has_normal() ) + _bi.set_normal(vh, n); + } + + //take the rest of the line and check how colors are defined + std::string line; + std::getline(_in,line); + + int colorType = getColorType(line, options_.vertex_has_texcoord() ); + + std::stringstream stream( line ); + + //perhaps read COLOR + if ( options_.vertex_has_color() ){ + + std::string trash; + + switch (colorType){ + case 0 : break; //no color + case 1 : stream >> trash; break; //one int (isn't handled atm) + case 2 : stream >> trash; stream >> trash; break; //corrupt format (ignore) + // rgb int + case 3 : stream >> c3[0]; stream >> c3[1]; stream >> c3[2]; + if ( userOptions_.vertex_has_color() ) + _bi.set_color( vh, Vec3uc( c3 ) ); + break; + // rgba int + case 4 : stream >> c4[0]; stream >> c4[1]; stream >> c4[2]; stream >> c4[3]; + if ( userOptions_.vertex_has_color() ) + _bi.set_color( vh, Vec4uc( c4 ) ); + break; + // rgb floats + case 5 : stream >> c3f[0]; stream >> c3f[1]; stream >> c3f[2]; + if ( userOptions_.vertex_has_color() ) + _bi.set_color( vh, color_cast(c3f) ); + break; + // rgba floats + case 6 : stream >> c4f[0]; stream >> c4f[1]; stream >> c4f[2]; stream >> c4f[3]; + if ( userOptions_.vertex_has_color() ) + _bi.set_color( vh, color_cast(c4f) ); + break; + + default: + std::cerr << "Error in file format (colorType = " << colorType << ")\n"; + } + } + //perhaps read TEXTURE COORDs + if ( options_.vertex_has_texcoord() ){ + stream >> t[0]; stream >> t[1]; + if ( userOptions_.vertex_has_texcoord() ) + _bi.set_texcoord(vh, t); + } + } + + // faces + // #N .. [color spec] + for (i=0; i> nV; + + if (nV == 3) + { + vhandles.resize(3); + _in >> j; + _in >> k; + _in >> l; + + vhandles[0] = VertexHandle(j); + vhandles[1] = VertexHandle(k); + vhandles[2] = VertexHandle(l); + } + else + { + vhandles.clear(); + for (j=0; j> idx; + vhandles.push_back(VertexHandle(idx)); + } + } + + FaceHandle fh = _bi.add_face(vhandles); + + //perhaps read face COLOR + if ( options_.face_has_color() ){ + + //take the rest of the line and check how colors are defined + std::string line; + std::getline(_in,line); + + int colorType = getColorType(line, false ); + + std::stringstream stream( line ); + + std::string trash; + + switch (colorType){ + case 0 : break; //no color + case 1 : stream >> trash; break; //one int (isn't handled atm) + case 2 : stream >> trash; stream >> trash; break; //corrupt format (ignore) + // rgb int + case 3 : stream >> c3[0]; stream >> c3[1]; stream >> c3[2]; + if ( userOptions_.face_has_color() ) + _bi.set_color( fh, Vec3uc( c3 ) ); + break; + // rgba int + case 4 : stream >> c4[0]; stream >> c4[1]; stream >> c4[2]; stream >> c4[3]; + if ( userOptions_.face_has_color() ) + _bi.set_color( fh, Vec4uc( c4 ) ); + break; + // rgb floats + case 5 : stream >> c3f[0]; stream >> c3f[1]; stream >> c3f[2]; + if ( userOptions_.face_has_color() ) + _bi.set_color( fh, color_cast(c3f) ); + break; + // rgba floats + case 6 : stream >> c4f[0]; stream >> c4f[1]; stream >> c4f[2]; stream >> c4f[3]; + if ( userOptions_.face_has_color() ) + _bi.set_color( fh, color_cast(c4f) ); + break; + + default: + std::cerr << "Error in file format (colorType = " << colorType << ")\n"; + } + } + } + + // File was successfully parsed. + return true; +} + + +//----------------------------------------------------------------------------- + +int _OFFReader_::getColorType(std::string& _line, bool _texCoordsAvailable) const +{ +/* + 0 : no Color + 1 : one int (e.g colormap index) + 2 : two items (error!) + 3 : 3 ints + 4 : 3 ints + 5 : 3 floats + 6 : 4 floats + +*/ + // Check if we have any additional information here + if ( _line.size() < 1 ) + return 0; + + //first remove spaces at start/end of the line + while (_line[0] == ' ') + _line = _line.substr(1); + while (_line[ _line.length()-1 ] == ' ') + _line = _line.substr(0, _line.length()-2); + + //count the remaining items in the line + size_t found; + int count = 0; + + found=_line.find_first_of(" "); + while (found!=std::string::npos){ + count++; + found=_line.find_first_of(" ",found+1); + } + + if (_line != "") count++; + + if (_texCoordsAvailable) count -= 2; + + if (count == 3 || count == 4){ + //get first item + found = _line.find(" "); + std::string c1 = _line.substr (0,found); + + if (c1.find(".") != std::string::npos){ + if (count == 3) + count = 5; + else + count = 6; + } + } + return count; +} + +void _OFFReader_::readValue(std::fstream& _in, float& _value) const{ + float32_t tmp; + + restore( _in , tmp, false ); //assuming LSB byte order + _value = tmp; +} + +void _OFFReader_::readValue(std::fstream& _in, int& _value) const{ + uint32_t tmp; + + restore( _in , tmp, false ); //assuming LSB byte order + _value = tmp; +} + +void _OFFReader_::readValue(std::fstream& _in, unsigned int& _value) const{ + uint32_t tmp; + + restore( _in , tmp, false ); //assuming LSB byte order + _value = tmp; +} + +bool +_OFFReader_::read_binary(std::fstream& _in, BaseImporter& _bi, bool /*_swap*/) const +{ + omlog() << "[OFFReader] : read binary file\n"; + + unsigned int i, j, k, l, idx; + unsigned int nV, nF, dummy; + OpenMesh::Vec3f v, n; + OpenMesh::Vec3i c; + OpenMesh::Vec4i cA; + OpenMesh::Vec2f t; + BaseImporter::VHandles vhandles; + VertexHandle vh; + + // read header line + std::string header; + std::getline(_in,header); + + // + #Vertice, #Faces, #Edges + readValue(_in, nV); + readValue(_in, nF); + readValue(_in, dummy); + + _bi.reserve(nV, 3*nV, nF); + + // read vertices: coord [hcoord] [normal] [color] [texcoord] + for (i=0; i .. [color spec] + // So far color spec is unsupported! + for (i=0; i 1 ) && ( p[0] == 'S' && p[1] == 'T') ) + { options_ += Options::VertexTexCoord; p += 2; remainingChars -= 2; } + + if ( ( remainingChars > 0 ) && ( p[0] == 'C') ) + { options_ += Options::VertexColor; + options_ += Options::FaceColor; ++p; --remainingChars; } + + if ( ( remainingChars > 0 ) && ( p[0] == 'N') ) + { options_ += Options::VertexNormal; ++p; --remainingChars; } + + if ( ( remainingChars > 0 ) && (p[0] == '4' ) ) + { vertexDimensionTooHigh = true; ++p; --remainingChars; } + + if ( ( remainingChars > 0 ) && ( p[0] == 'n') ) + { vertexDimensionTooHigh = true; ++p; --remainingChars; } + + if ( ( remainingChars < 3 ) || (!(p[0] == 'O' && p[1] == 'F' && p[2] == 'F') ) ) + return false; + + p += 4; + remainingChars -= 4; + + if ( ( remainingChars >= 6 ) && ( strncmp(p, "BINARY", 6) == 0 ) ) + options_+= Options::Binary; + + // vertex Dimensions != 3 are currently not supported + if (vertexDimensionTooHigh) + return false; + + return true; +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Core/IO/reader/OFFReader.hh b/Core/IO/reader/OFFReader.hh new file mode 100644 index 00000000..072a2dd7 --- /dev/null +++ b/Core/IO/reader/OFFReader.hh @@ -0,0 +1,150 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements a reader module for OFF files +// +//============================================================================= + + +#ifndef __OFFREADER_HH__ +#define __OFFREADER_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include +#include +#include + +#include +#include +#include + +#ifndef WIN32 +#include +#endif + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//== FORWARDS ================================================================= + + +class BaseImporter; + + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the OFF format reader. This class is singleton'ed by + SingletonT to OFFReader. + + By passing Options to the read function you can manipulate the reading behavoir. + The following options can be set: + + VertexNormal + VertexColor + VertexTexCoord + FaceColor + ColorAlpha [only when reading binary] + + These options define if the corresponding data should be read (if available) + or if it should be omitted. + + After execution of the read function. The options object contains information about + what was actually read. + + e.g. if VertexNormal was true when the read function was called, but the file + did not contain vertex normals then it is false afterwards. + + When reading a binary off with Color Flag in the header it is assumed that all vertices + and faces have colors in the format "int int int". + If ColorAlpha is set the format "int int int int" is assumed. + +*/ + +class _OFFReader_ : public BaseReader +{ +public: + + _OFFReader_(); + + std::string get_description() const { return "Object File Format"; } + std::string get_extensions() const { return "off"; } + std::string get_magic() const { return "OFF"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt); + + bool can_u_read(const std::string& _filename) const; + + + +private: + + bool can_u_read(std::istream& _is) const; + + bool read(std::fstream& _in, BaseImporter& _bi, Options& _opt ) const; + bool read_ascii(std::fstream& _in, BaseImporter& _bi) const; + bool read_binary(std::fstream& _in, BaseImporter& _bi, bool swap) const; + + void readValue(std::fstream& _in, float& _value) const; + void readValue(std::fstream& _in, int& _value) const; + void readValue(std::fstream& _in, unsigned int& _value) const; + + int getColorType(std::string & _line, bool _texCoordsAvailable) const; + + //available options for reading + mutable Options options_; + //options that the user wants to read + mutable Options userOptions_; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OFF reader +extern _OFFReader_ __OFFReaderInstance; +_OFFReader_& OFFReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/reader/OMReader.cc b/Core/IO/reader/OMReader.cc new file mode 100644 index 00000000..6f24770e --- /dev/null +++ b/Core/IO/reader/OMReader.cc @@ -0,0 +1,628 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//== INCLUDES ================================================================= + + +//STL +#include + +// OpenMesh +#include +#include +#include +#include +#include + + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the OMReader singleton with MeshReader +_OMReader_ __OMReaderInstance; +_OMReader_& OMReader() { return __OMReaderInstance; } + + + +//=== IMPLEMENTATION ========================================================== + + +_OMReader_::_OMReader_() +{ + IOManager().register_module(this); +} + + +//----------------------------------------------------------------------------- + + +bool +_OMReader_::read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt) +{ + // check whether importer can give us an OpenMesh BaseKernel + if (!_bi.kernel()) return false; + + + _opt += Options::Binary; // only binary format supported! + + // Open file + std::ifstream ifs( _filename.c_str(), std::ios::binary ); + if (!ifs.is_open()) + { + omerr() << "[OMReader] : cannot not open file " + << _filename + << std::endl; + return false; + } + + // Pass stream to read method, remember result + bool result = read(ifs, _bi, _opt); + + // close input stream + ifs.close(); + + return result; +} + + +//----------------------------------------------------------------------------- + + +bool +_OMReader_::read(std::istream& _is, BaseImporter& _bi, Options& _opt ) const +{ + // currently only binary file format is supported + _opt += Options::Binary; + + return read_binary( _is, _bi, _opt ); +} + + + +//----------------------------------------------------------------------------- + +bool +_OMReader_::read_ascii( std::istream& /* _is */, BaseImporter& /* _bi */, + Options& /* _opt */) const +{ + // not supported yet! + return false; +} + + +//----------------------------------------------------------------------------- + +bool +_OMReader_::read_binary( std::istream& _is, BaseImporter& _bi, + Options& _opt) const +{ + bool swap = _opt.check(Options::Swap) || (Endian::local() == Endian::MSB); + + // intialize byte counter + bytes_ = 0; + + bytes_ += restore( _is, header_, swap ); + + size_t data_bytes; + + while( !_is.eof() ) + { + bytes_ += restore( _is, chunk_header_, swap ); + + if ( _is.eof() ) + break; + + // Is this a named property restore the name + if ( chunk_header_.name_ ) + { + OMFormat::Chunk::PropertyName pn; + bytes_ += restore( _is, property_name_, swap ); + } + + // Read in the property data. If it is an anonymous or unknown named + // property, then skip data. + data_bytes = bytes_; + switch( chunk_header_.entity_ ) + { + case OMFormat::Chunk::Entity_Vertex: + if (!read_binary_vertex_chunk( _is, _bi, _opt, swap )) + return false; + break; + case OMFormat::Chunk::Entity_Face: + if (!read_binary_face_chunk( _is, _bi, _opt, swap )) + return false; + break; + case OMFormat::Chunk::Entity_Edge: + if (!read_binary_edge_chunk( _is, _bi, _opt, swap )) + return false; + break; + case OMFormat::Chunk::Entity_Halfedge: + if (!read_binary_halfedge_chunk( _is, _bi, _opt, swap )) + return false; + break; + case OMFormat::Chunk::Entity_Mesh: + if (!read_binary_mesh_chunk( _is, _bi, _opt, swap )) + return false; + break; + default: + return false; + } + data_bytes = bytes_ - data_bytes; + } + + // File was successfully parsed. + return true; +} + + +//----------------------------------------------------------------------------- + +bool +_OMReader_::can_u_read(const std::string& _filename) const +{ + // !!! Assuming BaseReader::can_u_parse( std::string& ) + // does not call BaseReader::read_magic()!!! + if ( this->BaseReader::can_u_read( _filename ) ) + { + std::ifstream ifile( _filename.c_str() ); + if ( ifile && can_u_read( ifile ) ) + return true; + } + return false; +} + +//----------------------------------------------------------------------------- + +bool +_OMReader_::can_u_read(std::istream& _is) const +{ + std::vector evt; + evt.reserve(20); + + // read first 4 characters into a buffer + while( evt.size() < 4 ) + evt.push_back( static_cast(_is.get()) ); + + // put back all read characters + std::vector::reverse_iterator it = evt.rbegin(); + while (it != evt.rend() ) + _is.putback( *it++ ); + + + // evaluate header information + OMFormat::Header *hdr = (OMFormat::Header*)&evt[0]; + + // first two characters must be 'OM' + if (hdr->magic_[0] != 'O' || hdr->magic_[1] != 'M') + return false; + + // 3rd characters defines the mesh type: + switch(hdr->mesh_) + { + case 'T': // Triangle Mesh + case 'Q': // Quad Mesh + case 'P': // Polygonal Mesh + break; + default: // ? + return false; + } + + // 4th characters encodes the version + return supports( hdr->version_ ); +} + +//----------------------------------------------------------------------------- + +bool +_OMReader_::supports( const OMFormat::uint8 /* version */ ) const +{ + return true; +} + + +//----------------------------------------------------------------------------- + +bool +_OMReader_::read_binary_vertex_chunk( std::istream &_is, + BaseImporter &_bi, + Options &_opt, + bool _swap) const +{ + using OMFormat::Chunk; + + assert( chunk_header_.entity_ == Chunk::Entity_Vertex ); + + OpenMesh::Vec3f v3f; + OpenMesh::Vec2f v2f; + OpenMesh::Vec3uc v3uc; // rgb + + OMFormat::Chunk::PropertyName custom_prop; + + size_t vidx=0; + switch (chunk_header_.type_) + { + case Chunk::Type_Pos: + assert( OMFormat::dimensions(chunk_header_) + == size_t(OpenMesh::Vec3f::dim()) ); + + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) + { + bytes_ += vector_restore( _is, v3f, _swap ); + _bi.add_vertex(v3f); + } + break; + + + case Chunk::Type_Normal: + assert( OMFormat::dimensions(chunk_header_) + == size_t(OpenMesh::Vec3f::dim()) ); + + _opt += Options::VertexNormal; + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) + { + bytes_ += vector_restore( _is, v3f, _swap ); + _bi.set_normal(VertexHandle(vidx), v3f); + } + break; + + + case Chunk::Type_Texcoord: + assert( OMFormat::dimensions(chunk_header_) + == size_t(OpenMesh::Vec2f::dim()) ); + + _opt += Options::VertexTexCoord; + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) + { + bytes_ += vector_restore( _is, v2f, _swap ); + _bi.set_texcoord(VertexHandle(vidx), v2f); + } + break; + + case Chunk::Type_Color: + + assert( OMFormat::dimensions(chunk_header_) == 3 ); + + _opt += Options::VertexColor; + + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) + { + bytes_ += vector_restore( _is, v3uc, _swap ); + _bi.set_color( VertexHandle(vidx), v3uc ); + } + break; + + case Chunk::Type_Custom: + + bytes_ += + restore_binary_custom_data( _is, + _bi.kernel()->_get_vprop( property_name_ ), + header_.n_vertices_, + _swap ); + + vidx = header_.n_vertices_; + + break; + + default: // skip unknown chunks + { + omerr() << "Unknown chunk type ignored!\n"; + size_t size_of = header_.n_vertices_ + * OMFormat::vector_size(chunk_header_); + _is.ignore( size_of ); + bytes_ += size_of; + } + } + + // all chunk data has been read..?! + return vidx == header_.n_vertices_; +} + + +//----------------------------------------------------------------------------- + +bool +_OMReader_::read_binary_face_chunk( std::istream &_is, + BaseImporter &_bi, + Options &_opt, + bool _swap ) const +{ + using OMFormat::Chunk; + + assert( chunk_header_.entity_ == Chunk::Entity_Face ); + + size_t fidx=0; + OpenMesh::Vec3f v3f; // normal + OpenMesh::Vec3uc v3uc; // rgb + + switch( chunk_header_.type_ ) + { + case Chunk::Type_Topology: + { + BaseImporter::VHandles vhandles; + size_t nV = 0; + size_t vidx = 0; + + switch( header_.mesh_ ) + { + case 'T': nV = 3; break; + case 'Q': nV = 4; break; + } + + for (; fidx < header_.n_faces_; ++fidx) + { + if ( header_.mesh_ == 'P' ) + bytes_ += restore( _is, nV, Chunk::Integer_16, _swap ); + + vhandles.clear(); + for (size_t j=0; j_get_fprop( property_name_ ), + header_.n_faces_, + _swap ); + + fidx = header_.n_faces_; + + break; + + default: // skip unknown chunks + { + omerr() << "Unknown chunk type ignore!\n"; + size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_); + _is.ignore( size_of ); + bytes_ += size_of; + } + } + return fidx == header_.n_faces_; +} + + +//----------------------------------------------------------------------------- + +bool +_OMReader_::read_binary_edge_chunk( std::istream &_is, + BaseImporter &_bi, + Options &/*_opt */, + bool _swap ) const +{ + using OMFormat::Chunk; + + assert( chunk_header_.entity_ == Chunk::Entity_Edge ); + + size_t b=bytes_; + + switch( chunk_header_.type_ ) + { + case Chunk::Type_Custom: + + bytes_ += + restore_binary_custom_data( _is, + _bi.kernel()->_get_eprop( property_name_ ), + header_.n_edges_, + _swap ); + + break; + + default: + // skip unknown type + size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_); + _is.ignore( size_of ); + bytes_ += size_of; + } + + return b < bytes_; +} + + +//----------------------------------------------------------------------------- + +bool +_OMReader_::read_binary_halfedge_chunk( std::istream &_is, + BaseImporter &_bi, + Options &/* _opt */, + bool _swap ) const +{ + using OMFormat::Chunk; + + assert( chunk_header_.entity_ == Chunk::Entity_Halfedge ); + + size_t b = bytes_; + + switch( chunk_header_.type_ ) + { + case Chunk::Type_Custom: + + bytes_ += + restore_binary_custom_data( _is, + _bi.kernel()->_get_hprop( property_name_ ), + 2*header_.n_edges_, + _swap ); + break; + + default: + // skip unknown chunk + omerr() << "Unknown chunk type ignored!\n"; + size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_); + _is.ignore( size_of ); + bytes_ += size_of; + } + + return b < bytes_; +} + + +//----------------------------------------------------------------------------- + +bool +_OMReader_::read_binary_mesh_chunk( std::istream &_is, + BaseImporter &_bi, + Options & /* _opt */, + bool _swap ) const +{ + using OMFormat::Chunk; + + assert( chunk_header_.entity_ == Chunk::Entity_Mesh ); + + size_t b = bytes_; + + switch( chunk_header_.type_ ) + { + case Chunk::Type_Custom: + + bytes_ += + restore_binary_custom_data( _is, + _bi.kernel()->_get_mprop( property_name_ ), + 1, + _swap ); + + break; + + default: + // skip unknown chunk + size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_); + _is.ignore( size_of ); + bytes_ += size_of; + } + + return b < bytes_; +} + + +//----------------------------------------------------------------------------- + + +size_t +_OMReader_::restore_binary_custom_data( std::istream& _is, BaseProperty* _bp, + size_t _n_elem, bool _swap) const +{ + assert( !_bp || (_bp->name() == property_name_) ); + + using OMFormat::Chunk; + + size_t bytes = 0; + Chunk::esize_t block_size; + Chunk::PropertyName custom_prop; + + bytes += binary::restore( _is, block_size, _swap ); + + + if ( _bp ) + { +#if defined(OM_DEBUG) + size_t b; +#endif + size_t n_bytes = _bp->size_of( _n_elem ); + + if ( ((n_bytes == BaseProperty::UnknownSize) || (n_bytes == block_size)) && + (_bp->element_size() == BaseProperty::UnknownSize || + (_n_elem * _bp->element_size() == block_size) ) ) + { +#if defined(OM_DEBUG) + bytes += (b=_bp->restore( _is, _swap )); +#else + bytes += _bp->restore( _is, _swap ); +#endif +#if defined(OM_DEBUG) + assert( block_size == b ); +#endif + assert( block_size == _bp->size_of() ); + + block_size = 0; + } + else + { + omerr() << "Warning! Property " << _bp->name() << " not loaded: " + << "Mismatching data sizes!n"; + } + } + + if (block_size) + { + _is.ignore( block_size ); + bytes += block_size; + } + + return bytes; +} + + +//----------------------------------------------------------------------------- + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Core/IO/reader/OMReader.hh b/Core/IO/reader/OMReader.hh new file mode 100644 index 00000000..d03e0bfb --- /dev/null +++ b/Core/IO/reader/OMReader.hh @@ -0,0 +1,150 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements a reader module for OFF files +// +//============================================================================= + + +#ifndef __OMREADER_HH__ +#define __OMREADER_HH__ + + +//=== INCLUDES ================================================================ + +// OpenMesh +#include +#include +#include +#include +#include +#include + +// STD C++ +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the OM format reader. This class is singleton'ed by + SingletonT to OMReader. +*/ +class _OMReader_ : public BaseReader +{ +public: + + _OMReader_(); + virtual ~_OMReader_() { } + + std::string get_description() const { return "OpenMesh File Format"; } + std::string get_extensions() const { return "om"; } + std::string get_magic() const { return "OM"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt ); + + virtual bool can_u_read(const std::string& _filename) const; + virtual bool can_u_read(std::istream& _is) const; + + +private: + + bool supports( const OMFormat::uint8 version ) const; + + bool read(std::istream& _is, BaseImporter& _bi, Options& _opt ) const; + bool read_ascii(std::istream& _is, BaseImporter& _bi, Options& _opt) const; + bool read_binary(std::istream& _is, BaseImporter& _bi, Options& _opt) const; + + typedef OMFormat::Header Header; + typedef OMFormat::Chunk::Header ChunkHeader; + typedef OMFormat::Chunk::PropertyName PropertyName; + + // initialized/updated by read_binary*/read_ascii* + mutable size_t bytes_; + mutable Header header_; + mutable ChunkHeader chunk_header_; + mutable PropertyName property_name_; + + bool read_binary_vertex_chunk( std::istream &_is, + BaseImporter &_bi, + Options &_opt, + bool _swap) const; + + bool read_binary_face_chunk( std::istream &_is, + BaseImporter &_bi, + Options &_opt, + bool _swap) const; + + bool read_binary_edge_chunk( std::istream &_is, + BaseImporter &_bi, + Options &_opt, + bool _swap) const; + + bool read_binary_halfedge_chunk( std::istream &_is, + BaseImporter &_bi, + Options &_opt, + bool _swap) const; + + bool read_binary_mesh_chunk( std::istream &_is, + BaseImporter &_bi, + Options &_opt, + bool _swap) const; + + size_t restore_binary_custom_data( std::istream& _is, + BaseProperty* _bp, + size_t _n_elem, + bool _swap) const; + +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OM reader. +extern _OMReader_ __OMReaderInstance; +_OMReader_& OMReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/reader/PLYReader.cc b/Core/IO/reader/PLYReader.cc new file mode 100644 index 00000000..a2590b09 --- /dev/null +++ b/Core/IO/reader/PLYReader.cc @@ -0,0 +1,683 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +#define LINE_LEN 4096 + + +//== INCLUDES ================================================================= + +// OpenMesh +#include +#include +#include +#include +#include +#include +#include + +//STL +#include +#include + +#ifndef WIN32 +#include +#endif + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//============================================================================= + +//=== INSTANCIATE ============================================================= + + +_PLYReader_ __PLYReaderInstance; +_PLYReader_& PLYReader() { return __PLYReaderInstance; } + + +//=== IMPLEMENTATION ========================================================== + + + +_PLYReader_::_PLYReader_() +{ + IOManager().register_module(this); +} + + +//----------------------------------------------------------------------------- + + +bool +_PLYReader_::read(const std::string& _filename, BaseImporter& _bi, + Options& _opt) +{ + std::fstream in(_filename.c_str(), (options_.is_binary() ? std::ios_base::binary | std::ios_base::in + : std::ios_base::in) ); + + if (!in) + { + omerr() << "[PLYReader] : cannot not open file " + << _filename + << std::endl; + return false; + } + + + bool result = read(in, _bi, _opt); + + + in.close(); + return result; +} + + +//----------------------------------------------------------------------------- + + +bool +_PLYReader_::read(std::fstream& _in, BaseImporter& _bi, Options& _opt ) const +{ + // filter relevant options for reading + bool swap = _opt.check( Options::Swap ); + + + userOptions_ = _opt; + + // build options to be returned + _opt.clear(); + + if (options_.vertex_has_normal() && userOptions_.vertex_has_normal()) _opt += Options::VertexNormal; + if (options_.vertex_has_texcoord() && userOptions_.vertex_has_texcoord()) _opt += Options::VertexTexCoord; + if (options_.vertex_has_color() && userOptions_.vertex_has_color()) _opt += Options::VertexColor; + if (options_.face_has_color() && userOptions_.face_has_color()) _opt += Options::FaceColor; + if (options_.is_binary()) _opt += Options::Binary; + +// //force user-choice for the alpha value when reading binary +// if ( options_.is_binary() && userOptions_.color_has_alpha() ) +// options_ += Options::ColorAlpha; + + return (options_.is_binary() ? + read_binary(_in, _bi, swap) : + read_ascii(_in, _bi)); + +} + + + +//----------------------------------------------------------------------------- + +bool +_PLYReader_::read_ascii(std::fstream& _in, BaseImporter& _bi) const +{ + + + omlog() << "[PLYReader] : read ascii file\n"; + + // Reparse the header + if ( !can_u_read(_in) ) { + omerr() << "[PLYReader] : Unable to parse header\n"; + return false; + } + + + + unsigned int i, j, k, l, idx; + unsigned int nV; + OpenMesh::Vec3f v; + std::string trash; +// OpenMesh::Vec2f t; + OpenMesh::Vec4i c; + float tmp; + BaseImporter::VHandles vhandles; + VertexHandle vh; + + + _bi.reserve(vertexCount_, 3*vertexCount_, faceCount_); + + std::cerr << "Vertices : " << vertexCount_ << std::endl; + if ( vertexDimension_ != 3 ) { + omerr() << "[PLYReader] : Only vertex dimension 3 is supported." << std::endl; + return false; + } + + // read vertices: + for (i=0; i< vertexCount_ && !_in.eof(); ++i) + { + v[0] = 0.0; + v[1] = 0.0; + v[2] = 0.0; + + c[0] = 0; + c[1] = 0; + c[2] = 0; + c[3] = 255; + + for ( uint propertyIndex = 0 ; propertyIndex < vertexPropertyCount_; ++propertyIndex ) { + switch ( vertexPropertyMap_ [ propertyIndex].first ) { + case XCOORD: + _in >> v[0]; + break; + case YCOORD: + _in >> v[1]; + break; + case ZCOORD: + _in >> v[2]; + break; + case COLORRED: + if ( vertexPropertyMap_ [ propertyIndex].second == ValueTypeFLOAT32 ){ + _in >> tmp; c[0] = tmp * 255.0f; + }else + _in >> c[0]; + break; + case COLORGREEN: + if ( vertexPropertyMap_ [ propertyIndex].second == ValueTypeFLOAT32 ){ + _in >> tmp; c[1] = tmp * 255.0f; + }else + _in >> c[1]; + break; + case COLORBLUE: + if ( vertexPropertyMap_ [ propertyIndex].second == ValueTypeFLOAT32 ){ + _in >> tmp; c[2] = tmp * 255.0f; + }else + _in >> c[2]; + break; + case COLORALPHA: + if ( vertexPropertyMap_ [ propertyIndex].second == ValueTypeFLOAT32 ){ + _in >> tmp; c[3] = tmp * 255.0f; + }else + _in >> c[3]; + break; + default : + _in >> trash; + break; + } + } + + vh = _bi.add_vertex(v); + _bi.set_color( vh, Vec4uc( c ) ); + } + + // faces + // #N .. [color spec] + for (i=0; i> nV; + + if (nV == 3) + { + vhandles.resize(3); + _in >> j; + _in >> k; + _in >> l; + + vhandles[0] = VertexHandle(j); + vhandles[1] = VertexHandle(k); + vhandles[2] = VertexHandle(l); + } + else + { + vhandles.clear(); + for (j=0; j> idx; + vhandles.push_back(VertexHandle(idx)); + } + } + + FaceHandle fh = _bi.add_face(vhandles); + + } + + // File was successfully parsed. + return true; +} + + +//----------------------------------------------------------------------------- + +void _PLYReader_::readValue(ValueType _type , std::fstream& _in, float& _value) const{ + + switch (_type) { + case ValueTypeFLOAT32: + case ValueTypeFLOAT: + float32_t tmp; + restore( _in , tmp, options_.check(Options::MSB) ); + _value = tmp; + break; + default : + _value = 0.0; + std::cerr << "unsupported conversion type to float: " << _type << std::endl; + break; + } +} + +void _PLYReader_::readValue(ValueType _type , std::fstream& _in, unsigned int& _value) const{ + + int32_t tmp_int32_t; + uint8_t tmp_uchar; + + switch (_type) { + case ValueTypeINT: + case ValueTypeINT32: + restore( _in , tmp_int32_t, options_.check(Options::MSB) ); + _value = tmp_int32_t; + break; + case ValueTypeUCHAR: + restore( _in , tmp_uchar, options_.check(Options::MSB) ); + _value = tmp_uchar; + break; + default : + _value = 0; + std::cerr << "unsupported conversion type to int: " << _type << std::endl; + break; + } +} + +void _PLYReader_::readValue(ValueType _type , std::fstream& _in, int& _value) const{ + + int32_t tmp_int32_t; + uint8_t tmp_uchar; + + switch (_type) { + case ValueTypeINT: + case ValueTypeINT32: + restore( _in , tmp_int32_t, options_.check(Options::MSB) ); + _value = tmp_int32_t; + break; + case ValueTypeUCHAR: + restore( _in , tmp_uchar, options_.check(Options::MSB) ); + _value = tmp_uchar; + break; + default : + _value = 0; + std::cerr << "unsupported conversion type to int: " << _type << std::endl; + break; + } +} + +bool +_PLYReader_::read_binary(std::fstream& _in, BaseImporter& _bi, bool /*_swap*/) const +{ + + omlog() << "[PLYReader] : read binary file format\n"; + + // Reparse the header + if ( !can_u_read(_in) ) { + omerr() << "[PLYReader] : Unable to parse header\n"; + return false; + } + + unsigned int i, j, k, l, idx; + unsigned int nV; + OpenMesh::Vec3f v; + BaseImporter::VHandles vhandles; + VertexHandle vh; + OpenMesh::Vec4i c; + float tmp; + + _bi.reserve(vertexCount_, 3*vertexCount_, faceCount_); + + // read vertices: + for (i=0; i< vertexCount_ && !_in.eof(); ++i) + { + v[0] = 0.0; + v[1] = 0.0; + v[2] = 0.0; + + c[0] = 0; + c[1] = 0; + c[2] = 0; + c[3] = 255; + + for ( uint propertyIndex = 0 ; propertyIndex < vertexPropertyCount_; ++propertyIndex ) { + switch ( vertexPropertyMap_ [ propertyIndex].first ) { + case XCOORD: + readValue(vertexPropertyMap_ [ propertyIndex].second,_in,v[0]); + break; + case YCOORD: + readValue(vertexPropertyMap_ [ propertyIndex].second,_in,v[1]); + break; + case ZCOORD: + readValue(vertexPropertyMap_ [ propertyIndex].second,_in,v[2]); + break; + case COLORRED: + if ( vertexPropertyMap_ [ propertyIndex].second == ValueTypeFLOAT32 ){ + readValue(vertexPropertyMap_ [ propertyIndex].second,_in,tmp); + c[0] = tmp * 255.0f; + }else + readValue(vertexPropertyMap_ [ propertyIndex].second,_in,c[0]); + break; + case COLORGREEN: + if ( vertexPropertyMap_ [ propertyIndex].second == ValueTypeFLOAT32 ){ + readValue(vertexPropertyMap_ [ propertyIndex].second,_in,tmp); + c[1] = tmp * 255.0f; + }else + readValue(vertexPropertyMap_ [ propertyIndex].second,_in,c[1]); + break; + case COLORBLUE: + if ( vertexPropertyMap_ [ propertyIndex].second == ValueTypeFLOAT32 ){ + readValue(vertexPropertyMap_ [ propertyIndex].second,_in,tmp); + c[2] = tmp * 255.0f; + }else + readValue(vertexPropertyMap_ [ propertyIndex].second,_in,c[2]); + break; + case COLORALPHA: + if ( vertexPropertyMap_ [ propertyIndex].second == ValueTypeFLOAT32 ){ + readValue(vertexPropertyMap_ [ propertyIndex].second,_in,tmp); + c[3] = tmp * 255.0f; + }else + readValue(vertexPropertyMap_ [ propertyIndex].second,_in,c[3]); + break; + default : + break; + } + + } + + vh = _bi.add_vertex(v); + _bi.set_color( vh, Vec4uc( c ) ); + } + + for (i=0; i> keyword; + _is >> fileType; + _is >> version; + + if ( _is.bad() ) { + omerr() << "Defect PLY header detected" << std::endl; + return false; + } + + if ( fileType == "ascii" ) { + options_ -= Options::Binary; + } else if ( fileType == "binary_little_endian" ){ + options_ += Options::Binary; + options_ += Options::LSB; + } else if ( fileType == "binary_big_endian" ){ + options_ += Options::Binary; + options_ += Options::MSB; + } else { + omerr() << "Unsupported PLY format: " << fileType << std::endl; + return false; + } + + unsigned int streamPos = _is.tellg(); + _is >> keyword; + while ( keyword != "end_header") { + + if ( keyword == "comment" ) { + std::getline(_is,line); + omlog() << "PLY header comment : " << line << std::endl; + } else if ( keyword == "element") { + _is >> elementName; + if ( elementName == "vertex" ) { + _is >> vertexCount_; + } else if ( elementName == "face" ){ + _is >> faceCount_; + } else { + omerr() << "PLY header unsupported element type: " << elementName << std::endl; + } + } else if ( keyword == "property") { + std::string tmp1; + std::string tmp2; + + // Read first keyword, as it might be a list + _is >> tmp1; + + if ( tmp1 == "list" ) { + if ( elementName == "vertex" ) { + omerr() << "List type not supported for vertices!" << std::endl; + } else if ( elementName == "face" ) { + _is >> listIndexType; + _is >> listEntryType; + _is >> propertyName; + + if ( listIndexType == "uint8" ) { + faceIndexType_ = ValueTypeUINT8; + } else if ( listIndexType == "uchar" ) { + faceIndexType_ = ValueTypeUCHAR; + } else { + omerr() << "Unsupported Index type for face list: " << listIndexType << std::endl; + } + + if ( listEntryType == "int32" ) { + faceEntryType_ = ValueTypeINT32; + } else if ( listEntryType == "int" ) { + faceEntryType_ = ValueTypeINT; + } else { + omerr() << "Unsupported Entry type for face list: " << listEntryType << std::endl; + } + + } + } else { + // as this is not a list property, read second value of property + _is >> tmp2; + + if ( elementName == "vertex" ) { + // Extract name and type of property + // As the order seems to be different in some files, autodetect it. + ValueType valueType = get_property_type(tmp1,tmp2); + propertyName = get_property_name(tmp1,tmp2); + + std::cerr << "property " << propertyName << " Type " << valueType << std::endl; + + if ( propertyName == "x" ) { + std::pair< VertexProperty, ValueType> entry(XCOORD,valueType); + vertexPropertyMap_[vertexPropertyCount_] = entry; + vertexDimension_++; + } else if ( propertyName == "y" ) { + std::pair< VertexProperty, ValueType> entry(YCOORD,valueType); + vertexPropertyMap_[vertexPropertyCount_] = entry; + vertexDimension_++; + } else if ( propertyName == "z" ) { + std::pair< VertexProperty, ValueType> entry(ZCOORD,valueType); + vertexPropertyMap_[vertexPropertyCount_] = entry; + vertexDimension_++; + } else if ( propertyName == "red" ) { + std::pair< VertexProperty, ValueType> entry(COLORRED,valueType); + vertexPropertyMap_[vertexPropertyCount_] = entry; + options_ += Options::VertexColor; + } else if ( propertyName == "green" ) { + std::pair< VertexProperty, ValueType> entry(COLORGREEN,valueType); + vertexPropertyMap_[vertexPropertyCount_] = entry; + options_ += Options::VertexColor; + } else if ( propertyName == "blue" ) { + std::pair< VertexProperty, ValueType> entry(COLORBLUE,valueType); + vertexPropertyMap_[vertexPropertyCount_] = entry; + options_ += Options::VertexColor; + } else if ( propertyName == "alpha" ) { + std::pair< VertexProperty, ValueType> entry(COLORALPHA,valueType); + vertexPropertyMap_[vertexPropertyCount_] = entry; + options_ += Options::VertexColor; + options_ += Options::ColorAlpha; + } else { + std::cerr << "Unsupported property : " << propertyName << std::endl; + } + + vertexPropertyCount_++; + + } else if ( elementName == "face" ) { + omerr() << "Properties not supported for faces " << std::endl; + } + + } + + } else { + omlog() << "Unsupported keyword : " << keyword << std::endl; + } + + streamPos = _is.tellg(); + _is >> keyword; + if ( _is.bad() ) { + omerr() << "Error while reading PLY file header" << std::endl; + return false; + } + } + + // As the binary data is directy after the end_header keyword + // and the stream removes too many bytes, seek back to the right position + if ( options_.is_binary() ) { + _is.seekg(streamPos + 12); + } + + return true; +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Core/IO/reader/PLYReader.hh b/Core/IO/reader/PLYReader.hh new file mode 100644 index 00000000..f661e5ae --- /dev/null +++ b/Core/IO/reader/PLYReader.hh @@ -0,0 +1,154 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements a reader module for OFF files +// +//============================================================================= + + +#ifndef __PLYREADER_HH__ +#define __PLYREADER_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include +#include +#include + +#include +#include +#include + +#ifndef WIN32 +#include +#endif + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//== FORWARDS ================================================================= + + +class BaseImporter; + + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the PLY format reader. This class is singleton'ed by + SingletonT to OFFReader. + +*/ + +class _PLYReader_ : public BaseReader +{ +public: + + _PLYReader_(); + + std::string get_description() const { return "PLY polygon file format"; } + std::string get_extensions() const { return "ply"; } + std::string get_magic() const { return "PLY"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt); + + bool can_u_read(const std::string& _filename) const; + + enum ValueType { + Unsupported , + ValueTypeFLOAT32, ValueTypeFLOAT, + ValueTypeUINT8, ValueTypeINT32, ValueTypeINT , + ValueTypeUCHAR + }; + +private: + + bool can_u_read(std::istream& _is) const; + + bool read(std::fstream& _in, BaseImporter& _bi, Options& _opt ) const; + bool read_ascii(std::fstream& _in, BaseImporter& _bi) const; + bool read_binary(std::fstream& _in, BaseImporter& _bi, bool swap) const; + + float readToFloatValue(ValueType _type , std::fstream& _in) const; + + void readValue(ValueType _type , std::fstream& _in, float& _value) const; + void readValue(ValueType _type , std::fstream& _in, unsigned int& _value) const; + void readValue(ValueType _type , std::fstream& _in, int& _value) const; + + //available options for reading + mutable Options options_; + //options that the user wants to read + mutable Options userOptions_; + + mutable unsigned int vertexCount_; + mutable unsigned int faceCount_; + + mutable ValueType vertexType_; + mutable uint vertexDimension_; + + mutable ValueType faceIndexType_; + mutable ValueType faceEntryType_; + + enum VertexProperty { + XCOORD,YCOORD,ZCOORD, + TEXX,TEXY, + COLORRED,COLORGREEN,COLORBLUE,COLORALPHA + }; + + + // number of vertex properties + mutable unsigned int vertexPropertyCount_; + mutable std::map< int , std::pair< VertexProperty, ValueType> > vertexPropertyMap_; + +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the PLY reader +extern _PLYReader_ __PLYReaderInstance; +_PLYReader_& PLYReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/reader/STLReader.cc b/Core/IO/reader/STLReader.cc new file mode 100644 index 00000000..2791912b --- /dev/null +++ b/Core/IO/reader/STLReader.cc @@ -0,0 +1,369 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//== INCLUDES ================================================================= + + +// STL +#include + +#include + +// OpenMesh +#include +#include +#include +#include +#include +#include + + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the STLReader singleton with MeshReader +_STLReader_ __STLReaderInstance; +_STLReader_& STLReader() { return __STLReaderInstance; } + + +//=== IMPLEMENTATION ========================================================== + + +_STLReader_:: +_STLReader_() + : eps_(FLT_MIN) +{ + IOManager().register_module(this); +} + + +//----------------------------------------------------------------------------- + + +bool +_STLReader_:: +read(const std::string& _filename, BaseImporter& _bi, Options& _opt) +{ + bool result = false; + + STL_Type file_type = NONE; + + if ( check_extension( _filename, "stla" ) ) + { + file_type = STLA; + } + + else if ( check_extension( _filename, "stlb" ) ) + { + file_type = STLB; + } + + else if ( check_extension( _filename, "stl" ) ) + { + file_type = check_stl_type(_filename); + } + + + switch (file_type) + { + case STLA: + { + result = read_stla(_filename, _bi); + _opt -= Options::Binary; + break; + } + + case STLB: + { + result = read_stlb(_filename, _bi); + _opt += Options::Binary; + break; + } + + default: + { + result = false; + break; + } + } + + + return result; +} + + +//----------------------------------------------------------------------------- + + +#ifndef DOXY_IGNORE_THIS + +class CmpVec +{ +public: + + CmpVec(float _eps=FLT_MIN) : eps_(_eps) {} + + bool operator()( const Vec3f& _v0, const Vec3f& _v1 ) const + { + if (fabs(_v0[0] - _v1[0]) <= eps_) + { + if (fabs(_v0[1] - _v1[1]) <= eps_) + { + return (_v0[2] < _v1[2] - eps_); + } + else return (_v0[1] < _v1[1] - eps_); + } + else return (_v0[0] < _v1[0] - eps_); + } + +private: + float eps_; +}; + +#endif + + +//----------------------------------------------------------------------------- + + +bool +_STLReader_:: +read_stla(const std::string& _filename, BaseImporter& _bi) const +{ + omlog() << "[STLReader] : read ascii file\n"; + + + FILE* in = fopen(_filename.c_str(), "r"); + if (!in) + { + omerr() << "[STLReader] : cannot not open file " + << _filename + << std::endl; + return false; + } + + + + char line[100], *p; + unsigned int i; + OpenMesh::Vec3f v; + unsigned int cur_idx(0); + BaseImporter::VHandles vhandles; + + CmpVec comp(eps_); + std::map vMap(comp); + std::map::iterator vMapIt; + + + while (in && !feof(in) && fgets(line, 100, in)) + { + for (p=line; isspace(*p) && *p!='\0'; ++p) {}; // skip white-space + + if ((strncmp(p, "outer", 5) == 0) || (strncmp(p, "OUTER", 5) == 0)) + { + vhandles.clear(); + + for (i=0; i<3; ++i) + { + fgets(line, 100, in); + for (p=line; isspace(*p) && *p!='\0'; ++p) {}; // skip white-space + sscanf(p+6, "%f %f %f", &v[0], &v[1], &v[2]); + + // has vector been referenced before? + if ((vMapIt=vMap.find(v)) == vMap.end()) + { + // No : add vertex and remember idx/vector mapping + _bi.add_vertex(v); + vhandles.push_back(VertexHandle(cur_idx)); + vMap[v] = VertexHandle(cur_idx++); + } + else + // Yes : get index from map + vhandles.push_back(vMapIt->second); + } + + // Add face only if it is not degenerated + if ((vhandles[0] != vhandles[1]) && + (vhandles[0] != vhandles[2]) && + (vhandles[1] != vhandles[2])) + _bi.add_face(vhandles); + } + } + + + fclose(in); + + + // In general a file has data, there the number of vertices cannot be 0. + return _bi.n_vertices() != 0; +} + + +//----------------------------------------------------------------------------- + + +bool +_STLReader_:: +read_stlb(const std::string& _filename, BaseImporter& _bi) const +{ + omlog() << "[STLReader] : read binary file\n"; + + + FILE* in = fopen(_filename.c_str(), "rb"); + if (!in) + { + omerr() << "[STLReader] : cannot not open file " + << _filename + << std::endl; + return false; + } + + + char dummy[100]; + bool swapFlag; + unsigned int i, nT; + OpenMesh::Vec3f v; + unsigned int cur_idx(0); + BaseImporter::VHandles vhandles; + + std::map vMap; + std::map::iterator vMapIt; + + + // check size of types + if ((sizeof(float) != 4) || (sizeof(int) != 4)) { + omerr() << "[STLReader] : wrong type size\n"; + return false; + } + + // determine endian mode + union { unsigned int i; unsigned char c[4]; } endian_test; + endian_test.i = 1; + swapFlag = (endian_test.c[3] == 1); + + // read number of triangles + fread(dummy, 1, 80, in); + nT = read_int(in, swapFlag); + + // read triangles + while (nT) + { + vhandles.clear(); + + // skip triangle normal + fread(dummy, 1, 12, in); + + // triangle's vertices + for (i=0; i<3; ++i) + { + v[0] = read_float(in, swapFlag); + v[1] = read_float(in, swapFlag); + v[2] = read_float(in, swapFlag); + + // has vector been referenced before? + if ((vMapIt=vMap.find(v)) == vMap.end()) + { + // No : add vertex and remember idx/vector mapping + _bi.add_vertex(v); + vhandles.push_back(VertexHandle(cur_idx)); + vMap[v] = VertexHandle(cur_idx++); + } + else + // Yes : get index from map + vhandles.push_back(vMapIt->second); + } + + + // Add face only if it is not degenerated + if ((vhandles[0] != vhandles[1]) && + (vhandles[0] != vhandles[2]) && + (vhandles[1] != vhandles[2])) + _bi.add_face(vhandles); + + fread(dummy, 1, 2, in); + --nT; + } + + return true; +} + + +//----------------------------------------------------------------------------- + + +_STLReader_::STL_Type +_STLReader_:: +check_stl_type(const std::string& _filename) const +{ + // assume it's binary stl, then file size is known from #triangles + // if size matches, it's really binary + + + // open file + FILE* in = fopen(_filename.c_str(), "rb"); + if (!in) return NONE; + + + // determine endian mode + union { unsigned int i; unsigned char c[4]; } endian_test; + endian_test.i = 1; + bool swapFlag = (endian_test.c[3] == 1); + + + // read number of triangles + char dummy[100]; + fread(dummy, 1, 80, in); + unsigned int nT = read_int(in, swapFlag); + + + // compute file size from nT + unsigned int binary_size = 84 + nT*50; + + + // get actual file size + unsigned int file_size(0); + rewind(in); + while (!feof(in)) + file_size += fread(dummy, 1, 100, in); + fclose(in); + + + // if sizes match -> it's STLB + return (binary_size == file_size ? STLB : STLA); +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Core/IO/reader/STLReader.hh b/Core/IO/reader/STLReader.hh new file mode 100644 index 00000000..6aca8dd0 --- /dev/null +++ b/Core/IO/reader/STLReader.hh @@ -0,0 +1,124 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements an reader module for STL files +// +//============================================================================= + + +#ifndef __STLREADER_HH__ +#define __STLREADER_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include + +#include +#include +#include + +#ifndef WIN32 +#include +#endif + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + +//== FORWARDS ================================================================= + +class BaseImporter; + +//== IMPLEMENTATION =========================================================== + + +/** + Implementation of the STL format reader. This class is singleton'ed by + SingletonT to STLReader. +*/ +class _STLReader_ : public BaseReader +{ +public: + + // constructor + _STLReader_(); + + + std::string get_description() const + { return "Stereolithography Interface Format"; } + std::string get_extensions() const { return "stl stla stlb"; } + + bool read(const std::string& _filename, + BaseImporter& _bi, + Options& _opt); + + + /** Set the threshold to be used for considering two point to be equal. + Can be used to merge small gaps */ + void set_epsilon(float _eps) { eps_=_eps; } + + /// Returns the threshold to be used for considering two point to be equal. + float epsilon() const { return eps_; } + + + +private: + + enum STL_Type { STLA, STLB, NONE }; + STL_Type check_stl_type(const std::string& _filename) const; + + bool read_stla(const std::string& _filename, BaseImporter& _bi) const; + bool read_stlb(const std::string& _filename, BaseImporter& _bi) const; + + +private: + + float eps_; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the STL reader +extern _STLReader_ __STLReaderInstance; +_STLReader_& STLReader(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/writer/ACGMakefile b/Core/IO/writer/ACGMakefile new file mode 100644 index 00000000..6d85b985 --- /dev/null +++ b/Core/IO/writer/ACGMakefile @@ -0,0 +1,17 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = $(call find-subdirs) + +PACKAGES := + +PROJ_LIBS := + +MODULES := cxxlib + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Core/IO/writer/BaseWriter.cc b/Core/IO/writer/BaseWriter.cc new file mode 100644 index 00000000..12b13fb5 --- /dev/null +++ b/Core/IO/writer/BaseWriter.cc @@ -0,0 +1,88 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//=== INCLUDES ================================================================ + + +#include +#include +#include +#include +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + +#ifndef DOXY_IGNORE_THIS + +static inline char tolower(char c) +{ + using namespace std; + return ::tolower(c); +} + +#endif + +//----------------------------------------------------------------------------- + + +bool +BaseWriter:: +can_u_write(const std::string& _filename) const +{ + // get file extension + std::string extension; + std::string::size_type pos(_filename.rfind(".")); + + if (pos != std::string::npos) + { + extension = _filename.substr(pos+1, _filename.length()-pos-1); + + std::transform( extension.begin(), extension.end(), + extension.begin(), tolower ); + } + + // locate extension in extension string + return (get_extensions().find(extension) != std::string::npos); +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Core/IO/writer/BaseWriter.hh b/Core/IO/writer/BaseWriter.hh new file mode 100644 index 00000000..4f45245a --- /dev/null +++ b/Core/IO/writer/BaseWriter.hh @@ -0,0 +1,108 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements the baseclass for IOManager writer modules +// +//============================================================================= + + +#ifndef __BASEWRITER_HH__ +#define __BASEWRITER_HH__ + + +//=== INCLUDES ================================================================ + + +// STD C++ +#include +#include + +// OpenMesh +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Base class for all writer modules. The module should register itself at + the IOManager by calling the register_module function. +*/ +class BaseWriter +{ +public: + + typedef unsigned int Option; + + /// Return short description of the supported file format. + virtual std::string get_description() const = 0; + + /// Return file format's extension. + virtual std::string get_extensions() const = 0; + + /// Returns true if writer can parse _filename (checks extension) + virtual bool can_u_write(const std::string& _filename) const; + + /// Write to file _filename. Data source specified by BaseExporter _be. + virtual bool write(const std::string& _filename, + BaseExporter& _be, + Options _opt) const = 0; + + /// Returns expected size of file if binary format is supported else 0. + virtual size_t binary_size(BaseExporter&, Options) const { return 0; } + + + +protected: + + bool check(BaseExporter& _be, Options _opt) const + { + return (_opt.check(Options::VertexNormal ) <= _be.has_vertex_normals()) + && (_opt.check(Options::VertexTexCoord)<= _be.has_vertex_texcoords()) + && (_opt.check(Options::VertexColor) <= _be.has_vertex_colors()) + && (_opt.check(Options::FaceNormal) <= _be.has_face_normals()) + && (_opt.check(Options::FaceColor) <= _be.has_face_colors()); + } +}; + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/writer/OBJWriter.cc b/Core/IO/writer/OBJWriter.cc new file mode 100644 index 00000000..09cfa512 --- /dev/null +++ b/Core/IO/writer/OBJWriter.cc @@ -0,0 +1,303 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//== INCLUDES ================================================================= + + +//STL +#include + +// OpenMesh +#include +#include +#include +#include +#include +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the OBJLoader singleton with MeshLoader +_OBJWriter_ __OBJWriterinstance; +_OBJWriter_& OBJWriter() { return __OBJWriterinstance; } + + +//=== IMPLEMENTATION ========================================================== + + +_OBJWriter_::_OBJWriter_() { IOManager().register_module(this); } + + +//----------------------------------------------------------------------------- + + +bool +_OBJWriter_:: +write(const std::string& _filename, BaseExporter& _be, Options _opt) const +{ + std::fstream out(_filename.c_str(), std::ios_base::out ); + + if (!out) + { + omerr() << "[OBJWriter] : cannot open file " + << _filename << std::endl; + return false; + } + + { +#if defined(WIN32) + std::string::size_type dot = _filename.find_last_of("\\/"); +#else + std::string::size_type dot = _filename.rfind("/"); +#endif + + if (dot == std::string::npos){ + path_ = "./"; + objName_ = _filename; + }else{ + path_ = _filename.substr(0,dot+1); + objName_ = _filename.substr(dot+1); + } + + //remove the file extension + dot = _filename.find_last_of("."); + + if(dot != std::string::npos) + objName_ = objName_.substr(0,dot-1); + } + + bool result = write(out, _be, _opt); + + out.close(); + return result; +} + +//----------------------------------------------------------------------------- + +int _OBJWriter_::getMaterial(OpenMesh::Vec3f _color) const +{ + for (uint i=0; i < material_.size(); i++) + if(material_[i] == _color) + return i; + + //not found add new material + material_.push_back( _color ); + return material_.size()-1; +} + +//----------------------------------------------------------------------------- + +int _OBJWriter_::getMaterial(OpenMesh::Vec4f _color) const +{ + for (uint i=0; i < materialA_.size(); i++) + if(materialA_[i] == _color) + return i; + + //not found add new material + materialA_.push_back( _color ); + return materialA_.size()-1; +} + +//----------------------------------------------------------------------------- + +bool +_OBJWriter_:: +writeMaterial(std::fstream& _out, BaseExporter& _be, Options _opt) const +{ + OpenMesh::Vec3f c; + OpenMesh::Vec4f cA; + + material_.clear(); + materialA_.clear(); + + //iterate over faces + for (int i=0, nF=_be.n_faces(); i (_be.colorA( FaceHandle(i) )); + getMaterial(cA); + }else{ + //and without alpha + c = color_cast (_be.color( FaceHandle(i) )); + getMaterial(c); + } + } + + //write the materials + if ( _opt.color_has_alpha() ) + for (uint i=0; i < materialA_.size(); i++){ + _out << "newmtl " << "mat" << i << std::endl; + _out << "Ka 0.5000 0.5000 0.5000" << std::endl; + _out << "Kd " << materialA_[i][0] << materialA_[i][1] << materialA_[i][2] << std::endl;; + _out << "Tr " << materialA_[i][3] << std::endl; + _out << "illum 1" << std::endl; + } + else + for (uint i=0; i < material_.size(); i++){ + _out << "newmtl " << "mat" << i << std::endl; + _out << "Ka 0.5000 0.5000 0.5000" << std::endl; + _out << "Kd " << material_[i][0] << material_[i][1] << material_[i][2] << std::endl;; + _out << "illum 1" << std::endl; + } + + return true; +} + +//----------------------------------------------------------------------------- + + +bool +_OBJWriter_:: +write(std::fstream& _out, BaseExporter& _be, Options _opt) const +{ + unsigned int i, j, nV, nF, idx; + Vec3f v, n; + Vec2f t; + VertexHandle vh; + std::vector vhandles; + bool useMatrial = false; + OpenMesh::Vec3f c; + OpenMesh::Vec4f cA; + + omlog() << "[OBJWriter] : write file\n"; + + + // check exporter features + if (!check( _be, _opt)) + return false; + + + // check writer features + if ( _opt.check(Options::Binary) || // not supported by format + _opt.check(Options::FaceNormal) || + _opt.check(Options::FaceColor)) + return false; + + + //create material file if needed + if ( _opt.check(Options::FaceColor) ){ + + std::string matFile = path_ + objName_ + ".mat"; + + std::fstream matStream(matFile.c_str(), std::ios_base::out ); + + if (!_out) + { + omerr() << "[OBJWriter] : cannot write material file " << matFile << std::endl; + + }else{ + useMatrial = writeMaterial(matStream, _be, _opt); + + matStream.close(); + } + } + + // header + _out << "# " << _be.n_vertices() << " vertices, "; + _out << _be.n_faces() << " faces" << std::endl; + + // material file + if (useMatrial && _opt.check(Options::FaceColor) ) + _out << "mtllib " << objName_ << ".mat" << std::endl; + + // vertex data (point, normals, texcoords) + for (i=0, nV=_be.n_vertices(); i (_be.colorA( FaceHandle(i) )); + i = getMaterial(cA); + }else{ + //and without alpha + c = color_cast (_be.color( FaceHandle(i) )); + i = getMaterial(c); + } + + if(lastMat != i) + _out << "usemtl mat" << i << std::endl; + } + + _out << "f"; + + _be.get_vhandles(FaceHandle(i), vhandles); + + for (j=0; j< vhandles.size(); ++j) + { + idx = vhandles[j].idx() + 1; + _out << " " << idx; + + if (_opt.check(Options::VertexTexCoord)) + _out << "/" << idx; + + if ( _opt.check(Options::VertexNormal) ) + _out << "/" << idx; + } + + _out << std::endl; + } + + material_.clear(); + materialA_.clear(); + + return true; +} + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Core/IO/writer/OBJWriter.hh b/Core/IO/writer/OBJWriter.hh new file mode 100644 index 00000000..491fe076 --- /dev/null +++ b/Core/IO/writer/OBJWriter.hh @@ -0,0 +1,108 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements an IOManager writer module for OBJ files +// +//============================================================================= + + +#ifndef __OBJWRITER_HH__ +#define __OBJWRITER_HH__ + + +//=== INCLUDES ================================================================ + + +#include +#include + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + This class defines the OBJ writer. This class is further singleton'ed + by SingletonT to OBJWriter. +*/ +class _OBJWriter_ : public BaseWriter +{ +public: + + _OBJWriter_(); + + std::string get_description() const { return "Alias/Wavefront"; } + std::string get_extensions() const { return "obj"; } + + bool write(const std::string&, BaseExporter&, Options) const; + + size_t binary_size(BaseExporter&, Options) const { return 0; } + +private: + + mutable std::string path_; + mutable std::string objName_; + + mutable std::vector< OpenMesh::Vec3f > material_; + mutable std::vector< OpenMesh::Vec4f > materialA_; + + int getMaterial(OpenMesh::Vec3f _color) const; + + int getMaterial(OpenMesh::Vec4f _color) const; + + bool writeMaterial(std::fstream& _out, BaseExporter&, Options) const; + + bool write(std::fstream& _out, BaseExporter&, Options) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OBJ writer +extern _OBJWriter_ __OBJWriterinstance; +_OBJWriter_& OBJWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/writer/OFFWriter.cc b/Core/IO/writer/OFFWriter.cc new file mode 100644 index 00000000..a67fa6e8 --- /dev/null +++ b/Core/IO/writer/OFFWriter.cc @@ -0,0 +1,432 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include + +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the OFFLoader singleton with MeshLoader +_OFFWriter_ __OFFWriterInstance; +_OFFWriter_& OFFWriter() { return __OFFWriterInstance; } + + +//=== IMPLEMENTATION ========================================================== + + +_OFFWriter_::_OFFWriter_() { IOManager().register_module(this); } + + +//----------------------------------------------------------------------------- + + +bool +_OFFWriter_:: +write(const std::string& _filename, BaseExporter& _be, Options _opt) const +{ + // check exporter features + if ( !check( _be, _opt ) ) + return false; + + + // check writer features + if ( _opt.check(Options::FaceNormal) ) // not supported by format + return false; + + // open file + std::fstream out(_filename.c_str(), (_opt.check(Options::Binary) ? std::ios_base::binary | std::ios_base::out + : std::ios_base::out) ); + if (!out) + { + omerr() << "[OFFWriter] : cannot open file " + << _filename + << std::endl; + return false; + } + + + // write header line + if (_opt.check(Options::VertexTexCoord)) out << "ST"; + if (_opt.check(Options::VertexColor) || _opt.check(Options::FaceColor)) out << "C"; + if (_opt.check(Options::VertexNormal)) out << "N"; + out << "OFF"; + if (_opt.check(Options::Binary)) out << " BINARY"; + out << "\n"; + + + // write to file + bool result = (_opt.check(Options::Binary) ? + write_binary(out, _be, _opt) : + write_ascii(out, _be, _opt)); + + + // return result + out.close(); + return result; +} + + +//----------------------------------------------------------------------------- + + +bool +_OFFWriter_:: +write_ascii(std::fstream& _out, BaseExporter& _be, Options _opt) const +{ + omlog() << "[OFFWriter] : write ascii file\n"; + + + unsigned int i, j, nV, nF; + Vec3f v, n; + Vec2f t; + OpenMesh::Vec3i c; + OpenMesh::Vec4i cA; + VertexHandle vh; + std::vector vhandles; + + + // #vertices, #faces + _out << _be.n_vertices() << " "; + _out << _be.n_faces() << " "; + _out << 0 << "\n"; + + + // vertex data (point, normals, colors, texcoords) + for (i=0, nV=_be.n_vertices(); i vhandles; + + + // #vertices, #faces + writeValue(_out, (uint)_be.n_vertices() ); + writeValue(_out, (uint) _be.n_faces() ); + writeValue(_out, 0 ); + + + // vertex data (point, normals, texcoords) + for (i=0, nV=_be.n_vertices(); i vhandles; + + for (i=0, nF=_be.n_faces(); i +#include +#include + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Implementation of the OFF format writer. This class is singleton'ed by + SingletonT to OFFWriter. + + By passing Options to the write function you can manipulate the writing behavoir. + The following options can be set: + + Binary + VertexNormal + VertexColor + VertexTexCoord + FaceColor + ColorAlpha + +*/ +class _OFFWriter_ : public BaseWriter +{ +public: + + _OFFWriter_(); + + std::string get_description() const { return "no description"; } + std::string get_extensions() const { return "off"; } + + bool write(const std::string&, BaseExporter&, Options) const; + + size_t binary_size(BaseExporter& _be, Options _opt) const; + + +protected: + void writeValue(std::fstream& _out, int value) const; + void writeValue(std::fstream& _out, unsigned int value) const; + void writeValue(std::fstream& _out, float value) const; + + bool write_ascii(std::fstream& _in, BaseExporter&, Options) const; + bool write_binary(std::fstream& _in, BaseExporter&, Options) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OFF writer. +extern _OFFWriter_ __OFFWriterInstance; +_OFFWriter_& OFFWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/writer/OMWriter.cc b/Core/IO/writer/OMWriter.cc new file mode 100644 index 00000000..85d617a5 --- /dev/null +++ b/Core/IO/writer/OMWriter.cc @@ -0,0 +1,504 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//== INCLUDES ================================================================= + +#include +// -------------------- STL +#if defined( OM_CC_MIPS ) +# include +# include +#else +# include +# include +#endif +#include +// -------------------- OpenMesh +#include +#include +#include +#include +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the OMLoader singleton with MeshLoader +_OMWriter_ __OMWriterInstance; +_OMWriter_& OMWriter() { return __OMWriterInstance; } + + +//=== IMPLEMENTATION ========================================================== + + +const OMFormat::uchar _OMWriter_::magic_[3] = "OM"; +const OMFormat::uint8 _OMWriter_::version_ = OMFormat::mk_version(1,2); + + +_OMWriter_:: +_OMWriter_() +{ + IOManager().register_module(this); +} + + +bool +_OMWriter_::write(const std::string& _filename, BaseExporter& _be, + Options _opt) const +{ + // check whether exporter can give us an OpenMesh BaseKernel + if (!_be.kernel()) return false; + + + // check for om extension in filename, we can only handle OM + if (_filename.rfind(".om") == std::string::npos) + return false; + + _opt += Options::Binary; // only binary format supported + + std::ofstream ofs(_filename.c_str(), std::ios::binary); + + // check if file is open + if (!ofs.is_open()) + { + omerr() << "[OMWriter] : cannot open file " << _filename << std::endl; + return false; + } + + // call stream save method + bool rc = write(ofs, _be, _opt); + + // close filestream + ofs.close(); + + // return success/failure notice + return rc; +} + + +//----------------------------------------------------------------------------- + +bool +_OMWriter_::write(std::ostream& _os, BaseExporter& _be, Options _opt) const +{ +// std::clog << "[OMWriter]::write( stream )\n"; + + // check exporter features + if ( !check( _be, _opt ) ) + { + omerr() << "[OMWriter]: exporter does not support wanted feature!\n"; + return false; + } + + // Maybe an ascii version will be implemented in the future. + // For now, support only a binary format + if ( !_opt.check( Options::Binary ) ) + _opt += Options::Binary; + + // Ignore LSB/MSB bit. Always store in LSB (little endian) + _opt += Options::LSB; + _opt -= Options::MSB; + +// if ( _opt.check(Options::Binary) ) +// { + return write_binary(_os, _be, _opt); +// } +// else +// { +// return write_ascii(_os, _be, _opt); +// } +} + + +//----------------------------------------------------------------------------- + + +// bool _OMWriter_::write_ascii(std::ostream& _os, BaseExporter& _be, +// Options _opt) const +// { +// return false; +// } + +//----------------------------------------------------------------------------- + + +#ifndef DOXY_IGNORE_THIS +template struct Enabler +{ + Enabler( T& obj ) : obj_(obj) + {} + + ~Enabler() { obj_.enable(); } + + T& obj_; +}; +#endif + + +bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, + Options _opt) const +{ + Enabler enabler(omlog()); + + omlog() << "[OMWriter] : write binary file\n"; + + size_t bytes = 0; + + bool swap = _opt.check(Options::Swap) || (Endian::local() == Endian::MSB); + + unsigned int i, nV, nF; + Vec3f v; + Vec2f t; + std::vector vhandles; + + + // -------------------- write header + OMFormat::Header header; + + header.magic_[0] = 'O'; + header.magic_[1] = 'M'; + header.mesh_ = _be.is_triangle_mesh() ? 'T' : 'P'; + header.version_ = version_; + header.n_vertices_ = _be.n_vertices(); + header.n_faces_ = _be.n_faces(); + header.n_edges_ = _be.n_edges(); + + bytes += store( _os, header, swap ); + + // ---------------------------------------- write chunks + + OMFormat::Chunk::Header chunk_header; + + + // -------------------- write vertex data + + // ---------- write vertex position + if (_be.n_vertices()) + { + v = _be.point(VertexHandle(0)); + chunk_header.reserved_ = 0; + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex; + chunk_header.type_ = OMFormat::Chunk::Type_Pos; + chunk_header.signed_ = OMFormat::is_signed(v[0]); + chunk_header.float_ = OMFormat::is_float(v[0]); + chunk_header.dim_ = OMFormat::dim(v); + chunk_header.bits_ = OMFormat::bits(v[0]); + + bytes += store( _os, chunk_header, swap ); + for (i=0, nV=_be.n_vertices(); istore(_os, swap ); + } + else + return false; +#endif +#undef NEW_STYLE + } + + + // ---------- write face color + + if (_be.has_face_colors() && _opt.check( Options::FaceColor )) + { +#define NEW_STYLE 0 +#if NEW_STYLE + const BaseProperty *bp = _be.kernel()._get_fprop("f:colors"); + + if (bp) + { +#endif + Vec3uc c; + + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Face; + chunk_header.type_ = OMFormat::Chunk::Type_Color; + chunk_header.signed_ = OMFormat::is_signed( c[0] ); + chunk_header.float_ = OMFormat::is_float( c[0] ); + chunk_header.dim_ = OMFormat::dim( c ); + chunk_header.bits_ = OMFormat::bits( c[0] ); + + bytes += store( _os, chunk_header, swap ); +#if !NEW_STYLE + for (i=0, nF=_be.n_faces(); istore(_os, swap); + } + else + return false; +#endif + } + + // -------------------- write custom properties + + + BaseKernel::const_prop_iterator prop; + + for (prop = _be.kernel()->vprops_begin(); + prop != _be.kernel()->vprops_end(); ++prop) + { + if ( !*prop ) continue; + if ( (*prop)->name()[1]==':') continue; + bytes += store_binary_custom_chunk(_os, **prop, + OMFormat::Chunk::Entity_Vertex, swap ); + } + for (prop = _be.kernel()->fprops_begin(); + prop != _be.kernel()->fprops_end(); ++prop) + { + if ( !*prop ) continue; + if ( (*prop)->name()[1]==':') continue; + bytes += store_binary_custom_chunk(_os, **prop, + OMFormat::Chunk::Entity_Face, swap ); + } + for (prop = _be.kernel()->eprops_begin(); + prop != _be.kernel()->eprops_end(); ++prop) + { + if ( !*prop ) continue; + if ( (*prop)->name()[1]==':') continue; + bytes += store_binary_custom_chunk(_os, **prop, + OMFormat::Chunk::Entity_Edge, swap ); + } + for (prop = _be.kernel()->hprops_begin(); + prop != _be.kernel()->hprops_end(); ++prop) + { + if ( !*prop ) continue; + if ( (*prop)->name()[1]==':') continue; + bytes += store_binary_custom_chunk(_os, **prop, + OMFormat::Chunk::Entity_Halfedge, swap ); + } + for (prop = _be.kernel()->mprops_begin(); + prop != _be.kernel()->mprops_end(); ++prop) + { + if ( !*prop ) continue; + if ( (*prop)->name()[1]==':') continue; + bytes += store_binary_custom_chunk(_os, **prop, + OMFormat::Chunk::Entity_Mesh, swap ); + } + +// std::clog << "#bytes written: " << bytes << std::endl; + + return true; +} + +// ---------------------------------------------------------------------------- + +size_t _OMWriter_::store_binary_custom_chunk(std::ostream& _os, + const BaseProperty& _bp, + OMFormat::Chunk::Entity _entity, + bool _swap) const +{ + omlog() << "Custom Property " << OMFormat::as_string(_entity) << " property [" + << _bp.name() << "]" << std::endl; + + // Don't store if + // 1. it is not persistent + // 2. it's name is empty + if ( !_bp.persistent() || _bp.name().empty() ) + { + omlog() << " skipped\n"; + return 0; + } + + size_t bytes = 0; + + OMFormat::Chunk::esize_t element_size = _bp.element_size(); + OMFormat::Chunk::Header chdr; + + // set header + chdr.name_ = true; + chdr.entity_ = _entity; + chdr.type_ = OMFormat::Chunk::Type_Custom; + chdr.signed_ = 0; + chdr.float_ = 0; + chdr.dim_ = OMFormat::Chunk::Dim_1D; // ignored + chdr.bits_ = element_size; + + + // write custom chunk + + // 1. chunk header + bytes += store( _os, chdr, _swap ); + + // 2. property name + bytes += store( _os, OMFormat::Chunk::PropertyName(_bp.name()), _swap ); + + // 3. block size + bytes += store( _os, _bp.size_of(), _swap ); + omlog() << " n_bytes = " << _bp.size_of() << std::endl; + + // 4. data + { + size_t b; + bytes += ( b=_bp.store( _os, _swap ) ); + omlog() << " b = " << b << std::endl; + assert( b == _bp.size_of() ); + } + return bytes; +} + +// ---------------------------------------------------------------------------- + +size_t _OMWriter_::binary_size(BaseExporter& /* _be */, Options /* _opt */) const +{ + // std::clog << "[OMWriter]: binary_size()" << std::endl; + size_t bytes = sizeof( OMFormat::Header ); + + // !!!TODO!!! + + return bytes; +} + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/Core/IO/writer/OMWriter.hh b/Core/IO/writer/OMWriter.hh new file mode 100644 index 00000000..78235520 --- /dev/null +++ b/Core/IO/writer/OMWriter.hh @@ -0,0 +1,119 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements a writer module for OM files +// +//============================================================================= + + +#ifndef __OMWRITER_HH__ +#define __OMWRITER_HH__ + + +//=== INCLUDES ================================================================ + + +// STD C++ +#include +#include + +// OpenMesh +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + +//=== FORWARDS ================================================================ + + +class BaseExporter; + + +//=== IMPLEMENTATION ========================================================== + + +/** + * Implementation of the OM format writer. This class is singleton'ed by + * SingletonT to OMWriter. + */ +class _OMWriter_ : public BaseWriter +{ +public: + + // constructor + _OMWriter_(); + + std::string get_description() const + { return "OpenMesh Format"; } + + std::string get_extensions() const + { return "om"; } + + bool write(std::ostream&, BaseExporter&, Options) const; + + + size_t binary_size(BaseExporter& _be, Options _opt) const; + + +protected: + + static const OMFormat::uchar magic_[3]; + static const OMFormat::uint8 version_; + + bool write(const std::string&, BaseExporter&, Options) const; + + bool write_binary(std::ostream&, BaseExporter&, Options) const; + + size_t store_binary_custom_chunk( std::ostream&, const BaseProperty&, + OMFormat::Chunk::Entity, bool) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the OM writer. +extern _OMWriter_ __OMWriterInstance; +_OMWriter_& OMWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/writer/PLYWriter.cc b/Core/IO/writer/PLYWriter.cc new file mode 100644 index 00000000..4398ef52 --- /dev/null +++ b/Core/IO/writer/PLYWriter.cc @@ -0,0 +1,476 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include + +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +// register the PLYLoader singleton with MeshLoader +_PLYWriter_ __PLYWriterInstance; +_PLYWriter_& PLYWriter() { return __PLYWriterInstance; } + + +//=== IMPLEMENTATION ========================================================== + + +_PLYWriter_::_PLYWriter_() { IOManager().register_module(this); } + + +//----------------------------------------------------------------------------- + + +bool +_PLYWriter_:: +write(const std::string& _filename, BaseExporter& _be, Options _opt) const +{ + // check exporter features + if ( !check( _be, _opt ) ) + return false; + + + // check writer features + if ( _opt.check(Options::FaceNormal) || _opt.check(Options::FaceColor) ) // not supported yet + return false; + + options_ = _opt; + + // open file + std::fstream out(_filename.c_str(), (_opt.check(Options::Binary) ? std::ios_base::binary | std::ios_base::out + : std::ios_base::out) ); + if (!out) + { + omerr() << "[PLYWriter] : cannot open file " + << _filename + << std::endl; + return false; + } + + // write to file + bool result = (_opt.check(Options::Binary) ? + write_binary(out, _be, _opt) : + write_ascii(out, _be, _opt)); + + // return result + out.close(); + return result; +} + + +//----------------------------------------------------------------------------- + + +bool +_PLYWriter_:: +write_ascii(std::fstream& _out, BaseExporter& _be, Options _opt) const +{ + omlog() << "[PLYWriter] : write ascii file\n"; + + + unsigned int i, j, nV, nF; + Vec3f v, n; + Vec2f t; + OpenMesh::Vec3f c; + OpenMesh::Vec4f cA; + VertexHandle vh; + std::vector vhandles; + + //writing header + _out << "ply" << std::endl; + _out << "format ascii 1.0" << std::endl; + _out << "element vertex " << _be.n_vertices() << std::endl; + + _out << "property float32 x" << std::endl; + _out << "property float32 y" << std::endl; + _out << "property float32 z" << std::endl; + + if ( _opt.vertex_has_color() ){ + _out << "property int32 red" << std::endl; + _out << "property int32 green" << std::endl; + _out << "property int32 blue" << std::endl; + + if ( _opt.color_has_alpha() ) + _out << "property int32 alpha" << std::endl; + } + + _out << "element face " << _be.n_faces() << std::endl; + _out << "property list uint8 int32 vertex_indices" << std::endl; + _out << "end_header" << std::endl; + + // vertex data (point, normals, colors, texcoords) + for (i=0, nV=_be.n_vertices(); i vhandles; + + + //writing header + _out << "ply" << std::endl; + _out << "format "; + + if ( options_.check(Options::MSB) ) + _out << "binary_big_endian "; + else + _out << "binary_little_endian "; + + _out << "1.0" << std::endl; + + _out << "element vertex " << _be.n_vertices() << std::endl; + + _out << "property float32 x" << std::endl; + _out << "property float32 y" << std::endl; + _out << "property float32 z" << std::endl; + + if ( _opt.vertex_has_color() ){ + _out << "property int32 red" << std::endl; + _out << "property int32 green" << std::endl; + _out << "property int32 blue" << std::endl; + + if ( _opt.color_has_alpha() ) + _out << "property int32 alpha" << std::endl; + } + + _out << "element face " << _be.n_faces() << std::endl; + _out << "property list uchar int32 vertex_indices" << std::endl; + _out << "end_header" << std::endl; + + // vertex data (point, normals, texcoords) + for (i=0, nV=_be.n_vertices(); i vhandles; + + for (i=0, nF=_be.n_faces(); i +#include +#include + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Implementation of the PLY format writer. This class is singleton'ed by + SingletonT to PLYWriter. + + currently supported options: + - VertexColors + - Binary + - Binary -> MSB +*/ +class _PLYWriter_ : public BaseWriter +{ +public: + + _PLYWriter_(); + + std::string get_description() const { return "PLY polygon file format"; } + std::string get_extensions() const { return "ply"; } + + bool write(const std::string&, BaseExporter&, Options) const; + + size_t binary_size(BaseExporter& _be, Options _opt) const; + + enum ValueType { + Unsupported , + ValueTypeFLOAT32, ValueTypeFLOAT, + ValueTypeUINT8, ValueTypeINT32, ValueTypeINT , + ValueTypeUCHAR + }; + +private: + mutable Options options_; + +protected: + void writeValue(ValueType _type, std::fstream& _out, int value) const; + void writeValue(ValueType _type, std::fstream& _out, unsigned int value) const; + void writeValue(ValueType _type, std::fstream& _out, float value) const; + + bool write_ascii(std::fstream& _in, BaseExporter&, Options) const; + bool write_binary(std::fstream& _in, BaseExporter&, Options) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +/// Declare the single entity of the PLY writer. +extern _PLYWriter_ __PLYWriterInstance; +_PLYWriter_& PLYWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/IO/writer/STLWriter.cc b/Core/IO/writer/STLWriter.cc new file mode 100644 index 00000000..816d4c9a --- /dev/null +++ b/Core/IO/writer/STLWriter.cc @@ -0,0 +1,278 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//== INCLUDES ================================================================= + + +//STL +#include + +// OpenMesh +#include +#include +#include +#include +#include +#include + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== INSTANCIATE ============================================================= + + +_STLWriter_ __STLWriterInstance; +_STLWriter_& STLWriter() { return __STLWriterInstance; } + + +//=== IMPLEMENTATION ========================================================== + + +_STLWriter_::_STLWriter_() { IOManager().register_module(this); } + + +//----------------------------------------------------------------------------- + + +bool +_STLWriter_:: +write(const std::string& _filename, BaseExporter& _be, Options _opt) const +{ + // check exporter features + if (!check(_be, _opt)) return false; + + + // check writer features + if (_opt.check(Options::VertexNormal) || + _opt.check(Options::VertexTexCoord) || + _opt.check(Options::FaceColor)) + return false; + + + // binary or ascii ? + if (_filename.rfind(".stla") != std::string::npos) + { + _opt -= Options::Binary; + return write_stla(_filename, _be, _opt); + } + else if (_filename.rfind(".stlb") != std::string::npos) + { + _opt += Options::Binary; + return write_stlb(_filename, _be, _opt); + } + else if (_filename.rfind(".stl") != std::string::npos) + { + return (_opt.check( Options::Binary ) + ? write_stlb(_filename, _be, _opt) + : write_stla(_filename, _be, _opt) ); + } + + return false; +} + + +//----------------------------------------------------------------------------- + + +bool +_STLWriter_:: +write_stla(const std::string& _filename, BaseExporter& _be, Options /* _opt */) const +{ + omlog() << "[STLWriter] : write ascii file\n"; + + + // open file + FILE* out = fopen(_filename.c_str(), "w"); + if (!out) + { + omerr() << "[STLWriter] : cannot open file " << _filename << std::endl; + return false; + } + + + + + unsigned int i, nF(_be.n_faces()), nV; + Vec3f a, b, c, n; + std::vector vhandles; + FaceHandle fh; + + + // header + fprintf(out, "solid\n"); + + + // write face set + for (i=0; i vhandles; + FaceHandle fh; + + + // write header + const char header[80] = + "binary stl file" + " "; + fwrite(header, 1, 80, out); + + + // number of faces + write_int(_be.n_faces(), out); + + + // write face set + for (i=0; i vhandles; + + for (i=0; i +#else +# include +#endif +#include +// -------------------- OpenMesh +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace IO { + + +//=== IMPLEMENTATION ========================================================== + + +/** + Implementation of the STL format writer. This class is singleton'ed by + SingletonT to STLWriter. +*/ +class _STLWriter_ : public BaseWriter +{ +public: + + _STLWriter_(); + + std::string get_description() const { return "Stereolithography Format"; } + std::string get_extensions() const { return "stla stlb"; } + + bool write(const std::string&, BaseExporter&, Options) const; + + size_t binary_size(BaseExporter&, Options) const; + +private: + bool write_stla(const std::string&, BaseExporter&, Options) const; + bool write_stlb(const std::string&, BaseExporter&, Options) const; +}; + + +//== TYPE DEFINITION ========================================================== + + +// Declare the single entity of STL writer. +extern _STLWriter_ __STLWriterInstance; +_STLWriter_& STLWriter(); + + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/Mesh/ACGMakefile b/Core/Mesh/ACGMakefile new file mode 100644 index 00000000..6d85b985 --- /dev/null +++ b/Core/Mesh/ACGMakefile @@ -0,0 +1,17 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = $(call find-subdirs) + +PACKAGES := + +PROJ_LIBS := + +MODULES := cxxlib + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Core/Mesh/ArrayItems.hh b/Core/Mesh/ArrayItems.hh new file mode 100644 index 00000000..52300805 --- /dev/null +++ b/Core/Mesh/ArrayItems.hh @@ -0,0 +1,112 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + +#ifndef OPENMESH_ARRAY_ITEMS_HH +#define OPENMESH_ARRAY_ITEMS_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/// Definition of mesh items for use in the ArrayKernel +struct ArrayItems +{ + + //------------------------------------------------------ internal vertex type + + /// The vertex item + class Vertex + { + friend class ArrayKernel; + HalfedgeHandle halfedge_handle_; + }; + + + //---------------------------------------------------- internal halfedge type + +#ifndef DOXY_IGNORE_THIS + class Halfedge_without_prev + { + friend class ArrayKernel; + FaceHandle face_handle_; + VertexHandle vertex_handle_; + HalfedgeHandle next_halfedge_handle_; + }; +#endif + +#ifndef DOXY_IGNORE_THIS + class Halfedge_with_prev : public Halfedge_without_prev + { + friend class ArrayKernel; + HalfedgeHandle prev_halfedge_handle_; + }; +#endif + + //TODO: should be selected with config.h define + typedef Halfedge_with_prev Halfedge; + typedef GenProg::Bool2Type HasPrevHalfedge; + + //-------------------------------------------------------- internal edge type +#ifndef DOXY_IGNORE_THIS + class Edge + { + friend class ArrayKernel; + Halfedge halfedges_[2]; + }; +#endif + + //-------------------------------------------------------- internal face type +#ifndef DOXY_IGNORE_THIS + class Face + { + friend class ArrayKernel; + HalfedgeHandle halfedge_handle_; + }; +}; +#endif + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ITEMS_HH defined +//============================================================================= diff --git a/Core/Mesh/ArrayKernel.cc b/Core/Mesh/ArrayKernel.cc new file mode 100644 index 00000000..da9bcd5b --- /dev/null +++ b/Core/Mesh/ArrayKernel.cc @@ -0,0 +1,297 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2004 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. * + * * +\*===========================================================================*/ + +#include + +namespace OpenMesh +{ + +ArrayKernel::ArrayKernel() +: refcount_vstatus_(0), refcount_hstatus_(0), + refcount_estatus_(0), refcount_fstatus_(0) +{ + init_bit_masks(); //Status bit masks initialization +} + +ArrayKernel::~ArrayKernel() +{ + clear(); +} + +// ArrayKernel::ArrayKernel(const ArrayKernel& _rhs) +// : BaseKernel(_rhs), +// vertices_(_rhs.vertices_), edges_(_rhs.edges_), faces_(_rhs.faces_), +// vertex_status_(_rhs.vertex_status_), halfedge_status_(_rhs.halfedge_status_), +// edge_status_(_rhs.edge_status_), face_status_(_rhs.face_status_), +// refcount_vstatus_(_rhs.refcount_vstatus_), refcount_hstatus_(_rhs.refcount_hstatus_), +// refcount_estatus_(_rhs.refcount_estatus_), refcount_fstatus_(_rhs.refcount_fstatus_) +// {} + + +void ArrayKernel::assign_connectivity(const ArrayKernel& _other) +{ + vertices_ = _other.vertices_; + edges_ = _other.edges_; + faces_ = _other.faces_; + + vprops_resize(n_vertices()); + hprops_resize(n_halfedges()); + eprops_resize(n_edges()); + fprops_resize(n_faces()); + +#define COPY_STATUS_PROPERTY(ENTITY) \ + if (_other.ENTITY##_status_.is_valid()) \ + { \ + if (!ENTITY##_status_.is_valid()) \ + { \ + request_##ENTITY##_status(); \ + } \ + property(ENTITY##_status_) = _other.property(_other.ENTITY##_status_); \ + } + COPY_STATUS_PROPERTY(vertex) + COPY_STATUS_PROPERTY(halfedge) + COPY_STATUS_PROPERTY(edge) + COPY_STATUS_PROPERTY(face) + +#undef COPY_STATUS_PROPERTY +} + +uint ArrayKernel::delete_isolated_vertices() +{ + assert(has_vertex_status());//this function requires vertex status property + uint n_isolated = 0; + for (KernelVertexIter v_it = vertices_begin(); v_it != vertices_end(); ++v_it) + { + if (is_isolated(handle(*v_it))) + { + status(handle(*v_it)).set_deleted(true); + n_isolated++; + } + } + return n_isolated; +} + +void ArrayKernel::garbage_collection(bool _v, bool _e, bool _f) +{ + int i, i0, i1, nV(n_vertices()), nE(n_edges()), nH(2*n_edges()), nF(n_faces()); + + std::vector vh_map; + std::vector hh_map; + std::vector fh_map; + + // setup handle mapping: + vh_map.reserve(nV); + for (i=0; i 0) + { + i0=0; i1=nV-1; + + while (1) + { + // find 1st deleted and last un-deleted + while (!status(VertexHandle(i0)).deleted() && i0 < i1) ++i0; + while ( status(VertexHandle(i1)).deleted() && i0 < i1) --i1; + if (i0 >= i1) break; + + // swap + std::swap(vertices_[i0], vertices_[i1]); + std::swap(vh_map[i0], vh_map[i1]); + vprops_swap(i0, i1); + }; + + vertices_.resize(status(VertexHandle(i0)).deleted() ? i0 : i0+1); + vprops_resize(n_vertices()); + } + + + // remove deleted edges + if (_e && n_edges() > 0) + { + i0=0; i1=nE-1; + + while (1) + { + // find 1st deleted and last un-deleted + while (!status(EdgeHandle(i0)).deleted() && i0 < i1) ++i0; + while ( status(EdgeHandle(i1)).deleted() && i0 < i1) --i1; + if (i0 >= i1) break; + + // swap + std::swap(edges_[i0], edges_[i1]); + std::swap(hh_map[2*i0], hh_map[2*i1]); + std::swap(hh_map[2*i0+1], hh_map[2*i1+1]); + eprops_swap(i0, i1); + hprops_swap(2*i0, 2*i1); + hprops_swap(2*i0+1, 2*i1+1); + }; + + edges_.resize(status(EdgeHandle(i0)).deleted() ? i0 : i0+1); + eprops_resize(n_edges()); + hprops_resize(n_halfedges()); + } + + + // remove deleted faces + if (_f && n_faces() > 0) + { + i0=0; i1=nF-1; + + while (1) + { + // find 1st deleted and last un-deleted + while (!status(FaceHandle(i0)).deleted() && i0 < i1) ++i0; + while ( status(FaceHandle(i1)).deleted() && i0 < i1) --i1; + if (i0 >= i1) break; + + // swap + std::swap(faces_[i0], faces_[i1]); + std::swap(fh_map[i0], fh_map[i1]); + fprops_swap(i0, i1); + }; + + faces_.resize(status(FaceHandle(i0)).deleted() ? i0 : i0+1); + fprops_resize(n_faces()); + } + + + // update handles of vertices + if (_e) + { + KernelVertexIter v_it(vertices_begin()), v_end(vertices_end()); + VertexHandle vh; + + for (; v_it!=v_end; ++v_it) + { + vh = handle(*v_it); + if (!is_isolated(vh)) + { + set_halfedge_handle(vh, hh_map[halfedge_handle(vh).idx()]); + } + } + } + + HalfedgeHandle hh; + // update handles of halfedges + for (KernelEdgeIter e_it(edges_begin()); e_it != edges_end(); ++e_it) + {//in the first pass update the (half)edges vertices + hh = halfedge_handle(handle(*e_it), 0); + set_vertex_handle(hh, vh_map[to_vertex_handle(hh).idx()]); + hh = halfedge_handle(handle(*e_it), 1); + set_vertex_handle(hh, vh_map[to_vertex_handle(hh).idx()]); + } + for (KernelEdgeIter e_it(edges_begin()); e_it != edges_end(); ++e_it) + {//in the second pass update the connectivity of the (half)edges + hh = halfedge_handle(handle(*e_it), 0); + set_next_halfedge_handle(hh, hh_map[next_halfedge_handle(hh).idx()]); + if (!is_boundary(hh)) + { + set_face_handle(hh, fh_map[face_handle(hh).idx()]); + } + hh = halfedge_handle(handle(*e_it), 1); + set_next_halfedge_handle(hh, hh_map[next_halfedge_handle(hh).idx()]); + if (!is_boundary(hh)) + { + set_face_handle(hh, fh_map[face_handle(hh).idx()]); + } + } + + // update handles of faces + if (_e) + { + KernelFaceIter f_it(faces_begin()), f_end(faces_end()); + FaceHandle fh; + + for (; f_it!=f_end; ++f_it) + { + fh = handle(*f_it); + set_halfedge_handle(fh, hh_map[halfedge_handle(fh).idx()]); + } + } +} + +void ArrayKernel::clear() +{ + vertices_.clear(); + edges_.clear(); + faces_.clear(); + + vprops_resize(0); + eprops_resize(0); + hprops_resize(0); + fprops_resize(0); +} + +void ArrayKernel::resize( uint _n_vertices, uint _n_edges, uint _n_faces ) +{ + vertices_.resize(_n_vertices); + edges_.resize(_n_edges); + faces_.resize(_n_faces); + + vprops_resize(n_vertices()); + hprops_resize(n_halfedges()); + eprops_resize(n_edges()); + fprops_resize(n_faces()); +} + +void ArrayKernel::reserve(uint _n_vertices, uint _n_edges, uint _n_faces ) +{ + vertices_.reserve(_n_vertices); + edges_.reserve(_n_edges); + faces_.reserve(_n_faces); + + vprops_reserve(_n_vertices); + hprops_reserve(_n_edges*2); + eprops_reserve(_n_edges); + fprops_reserve(_n_faces); +} + +// Status Sets API +void ArrayKernel::init_bit_masks(BitMaskContainer& _bmc) +{ + for (uint i = Attributes::UNUSED; i != 0; i <<= 1) + { + _bmc.push_back(i); + } +} + +void ArrayKernel::init_bit_masks() +{ + init_bit_masks(vertex_bit_masks_); + edge_bit_masks_ = vertex_bit_masks_;//init_bit_masks(edge_bit_masks_); + face_bit_masks_ = vertex_bit_masks_;//init_bit_masks(face_bit_masks_); + halfedge_bit_masks_= vertex_bit_masks_;//init_bit_masks(halfedge_bit_masks_); +} + + +}; + diff --git a/Core/Mesh/ArrayKernel.hh b/Core/Mesh/ArrayKernel.hh new file mode 100644 index 00000000..af1b6dca --- /dev/null +++ b/Core/Mesh/ArrayKernel.hh @@ -0,0 +1,786 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// CLASS ArrayKernel +// +//============================================================================= + + +#ifndef OPENMESH_ARRAY_KERNEL_HH +#define OPENMESH_ARRAY_KERNEL_HH + + +//== INCLUDES ================================================================= +#include + +#include +#include + +#include +#include +#include + +//== NAMESPACES =============================================================== +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= +/** \ingroup mesh_kernels_group + + Mesh kernel using arrays for mesh item storage. + + This mesh kernel uses the std::vector as container to store the + mesh items. Therefore all handle types are internally represented + by integers. To get the index from a handle use the handle's \c + idx() method. + + \note For a description of the minimal kernel interface see + OpenMesh::Mesh::BaseKernel. + \note You do not have to use this class directly, use the predefined + mesh-kernel combinations in \ref mesh_types_group. + \see OpenMesh::Concepts::KernelT, \ref mesh_type +*/ + +class ArrayKernel : public BaseKernel, public ArrayItems +{ +public: + + // handles + typedef OpenMesh::VertexHandle VertexHandle; + typedef OpenMesh::HalfedgeHandle HalfedgeHandle; + typedef OpenMesh::EdgeHandle EdgeHandle; + typedef OpenMesh::FaceHandle FaceHandle; + typedef Attributes::StatusInfo StatusInfo; + typedef VPropHandleT VertexStatusPropertyHandle; + typedef HPropHandleT HalfedgeStatusPropertyHandle; + typedef EPropHandleT EdgeStatusPropertyHandle; + typedef FPropHandleT FaceStatusPropertyHandle; + +public: + + // --- constructor/destructor --- + ArrayKernel(); + virtual ~ArrayKernel(); + + /** ArrayKernel uses the default copy constructor and assignment operator, which means + that the connectivity and all properties are copied, including reference + counters, allocated bit status masks, etc.. In contrast assign_connectivity + copies only the connectivity, i.e. vertices, edges, faces and their status fields. + NOTE: The geometry (the points property) is NOT copied. Poly/TriConnectivity + override(and hide) that function to provide connectivity consistence.*/ + void assign_connectivity(const ArrayKernel& _other); + + // --- handle -> item --- + VertexHandle handle(const Vertex& _v) const + {return VertexHandle(&_v - &vertices_.front()); } + + HalfedgeHandle handle(const Halfedge& _he) const + { + uint eh(((char*)&edges_.front() - (char*)&_he) % sizeof(Edge)); + assert((&_he == &edges_[eh].halfedges_[0]) || + (&_he == &edges_[eh].halfedges_[1])); + return ((&_he == &edges_[eh].halfedges_[0]) ? + HalfedgeHandle(eh<<1) : HalfedgeHandle((eh<<1)+1)); + } + + EdgeHandle handle(const Edge& _e) const + { return EdgeHandle(&_e - &edges_.front()); } + + FaceHandle handle(const Face& _f) const + { return FaceHandle(&_f - &faces_.front()); } + +#define SIGNED(x) signed( (x) ) + //checks handle validity - useful for debugging + bool is_valid_handle(VertexHandle _vh) const + { return 0 <= _vh.idx() && _vh.idx() < SIGNED(n_vertices()); } + + bool is_valid_handle(HalfedgeHandle _heh) const + { return 0 <= _heh.idx() && _heh.idx() < SIGNED(n_edges()*2); } + + bool is_valid_handle(EdgeHandle _eh) const + { return 0 <= _eh.idx() && _eh.idx() < SIGNED(n_edges()); } + + bool is_valid_handle(FaceHandle _fh) const + { return 0 <= _fh.idx() && _fh.idx() < SIGNED(n_faces()); } + + // --- item -> handle --- + const Vertex& vertex(VertexHandle _vh) const + { + assert(is_valid_handle(_vh)); + return vertices_[_vh.idx()]; + } + + Vertex& vertex(VertexHandle _vh) + { + assert(is_valid_handle(_vh)); + return vertices_[_vh.idx()]; + } + + const Halfedge& halfedge(HalfedgeHandle _heh) const + { + assert(is_valid_handle(_heh)); + return edges_[_heh.idx() >> 1].halfedges_[_heh.idx() & 1]; + } + + Halfedge& halfedge(HalfedgeHandle _heh) + { + assert(is_valid_handle(_heh)); + return edges_[_heh.idx() >> 1].halfedges_[_heh.idx() & 1]; + } + + const Edge& edge(EdgeHandle _eh) const + { + assert(is_valid_handle(_eh)); + return edges_[_eh.idx()]; + } + + Edge& edge(EdgeHandle _eh) + { + assert(is_valid_handle(_eh)); + return edges_[_eh.idx()]; + } + + const Face& face(FaceHandle _fh) const + { + assert(is_valid_handle(_fh)); + return faces_[_fh.idx()]; + } + + Face& face(FaceHandle _fh) + { + assert(is_valid_handle(_fh)); + return faces_[_fh.idx()]; + } + +#undef SIGNED + + // --- get i'th items --- + + VertexHandle vertex_handle(uint _i) const + { return (_i < n_vertices()) ? handle( vertices_[_i] ) : VertexHandle(); } + + HalfedgeHandle halfedge_handle(uint _i) const + { + return (_i < n_halfedges()) ? + halfedge_handle(edge_handle(_i/2), _i%2) : HalfedgeHandle(); + } + + EdgeHandle edge_handle(uint _i) const + { return (_i < n_edges()) ? handle(edges_[_i]) : EdgeHandle(); } + + FaceHandle face_handle(uint _i) const + { return (_i < n_faces()) ? handle(faces_[_i]) : FaceHandle(); } + +public: + + inline VertexHandle new_vertex() + { + vertices_.push_back(Vertex()); + vprops_resize(n_vertices());//TODO:should it be push_back()? + + return handle(vertices_.back()); + } + + inline HalfedgeHandle new_edge(VertexHandle _start_vh, VertexHandle _end_vh) + { +// assert(_start_vh != _end_vh); + edges_.push_back(Edge()); + eprops_resize(n_edges());//TODO:should it be push_back()? + hprops_resize(n_halfedges());//TODO:should it be push_back()? + + EdgeHandle eh(handle(edges_.back())); + HalfedgeHandle heh0(halfedge_handle(eh, 0)); + HalfedgeHandle heh1(halfedge_handle(eh, 1)); + set_vertex_handle(heh0, _end_vh); + set_vertex_handle(heh1, _start_vh); + return heh0; + } + + inline FaceHandle new_face() + { + faces_.push_back(Face()); + fprops_resize(n_faces()); + return handle(faces_.back()); + } + + inline FaceHandle new_face(const Face& _f) + { + faces_.push_back(_f); + fprops_resize(n_faces()); + return handle(faces_.back()); + } + +public: + // --- resize/reserve --- + void resize( uint _n_vertices, uint _n_edges, uint _n_faces ); + void reserve(uint _n_vertices, uint _n_edges, uint _n_faces ); + + // --- deletion --- + void garbage_collection(bool _v=true, bool _e=true, bool _f=true); + void clear(); + + // --- number of items --- + uint n_vertices() const { return vertices_.size(); } + uint n_halfedges() const { return 2*edges_.size(); } + uint n_edges() const { return edges_.size(); } + uint n_faces() const { return faces_.size(); } + + bool vertices_empty() const { return vertices_.empty(); } + bool halfedges_empty() const { return edges_.empty(); } + bool edges_empty() const { return edges_.empty(); } + bool faces_empty() const { return faces_.empty(); } + + // --- vertex connectivity --- + + HalfedgeHandle halfedge_handle(VertexHandle _vh) const + { return vertex(_vh).halfedge_handle_; } + + void set_halfedge_handle(VertexHandle _vh, HalfedgeHandle _heh) + { +// assert(is_valid_handle(_heh)); + vertex(_vh).halfedge_handle_ = _heh; + } + + bool is_isolated(VertexHandle _vh) const + { return !halfedge_handle(_vh).is_valid(); } + + void set_isolated(VertexHandle _vh) + { vertex(_vh).halfedge_handle_.invalidate(); } + + uint delete_isolated_vertices(); + + // --- halfedge connectivity --- + VertexHandle to_vertex_handle(HalfedgeHandle _heh) const + { return halfedge(_heh).vertex_handle_; } + + VertexHandle from_vertex_handle(HalfedgeHandle _heh) const + { return to_vertex_handle(opposite_halfedge_handle(_heh)); } + + void set_vertex_handle(HalfedgeHandle _heh, VertexHandle _vh) + { +// assert(is_valid_handle(_vh)); + halfedge(_heh).vertex_handle_ = _vh; + } + + FaceHandle face_handle(HalfedgeHandle _heh) const + { return halfedge(_heh).face_handle_; } + + void set_face_handle(HalfedgeHandle _heh, FaceHandle _fh) + { +// assert(is_valid_handle(_fh)); + halfedge(_heh).face_handle_ = _fh; + } + + void set_boundary(HalfedgeHandle _heh) + { halfedge(_heh).face_handle_.invalidate(); } + + /// Is halfedge _heh a boundary halfedge (is its face handle invalid) ? + bool is_boundary(HalfedgeHandle _heh) const + { return !face_handle(_heh).is_valid(); } + + HalfedgeHandle next_halfedge_handle(HalfedgeHandle _heh) const + { return halfedge(_heh).next_halfedge_handle_; } + + void set_next_halfedge_handle(HalfedgeHandle _heh, HalfedgeHandle _nheh) + { + assert(is_valid_handle(_nheh)); +// assert(to_vertex_handle(_heh) == from_vertex_handle(_nheh)); + halfedge(_heh).next_halfedge_handle_ = _nheh; + set_prev_halfedge_handle(_nheh, _heh); + } + + + void set_prev_halfedge_handle(HalfedgeHandle _heh, HalfedgeHandle _pheh) + { + assert(is_valid_handle(_pheh)); + set_prev_halfedge_handle(_heh, _pheh, HasPrevHalfedge()); + } + + void set_prev_halfedge_handle(HalfedgeHandle _heh, HalfedgeHandle _pheh, + GenProg::True) + { halfedge(_heh).prev_halfedge_handle_ = _pheh; } + + void set_prev_halfedge_handle(HalfedgeHandle /* _heh */, HalfedgeHandle /* _pheh */, + GenProg::False) + {} + + HalfedgeHandle prev_halfedge_handle(HalfedgeHandle _heh) const + { return prev_halfedge_handle(_heh, HasPrevHalfedge() ); } + + HalfedgeHandle prev_halfedge_handle(HalfedgeHandle _heh, GenProg::True) const + { return halfedge(_heh).prev_halfedge_handle_; } + + HalfedgeHandle prev_halfedge_handle(HalfedgeHandle _heh, GenProg::False) const + { + if (is_boundary(_heh)) + {//iterating around the vertex should be faster than iterating the boundary + HalfedgeHandle curr_heh(opposite_halfedge_handle(_heh)); + HalfedgeHandle next_heh(next_halfedge_handle(curr_heh)); + do + { + curr_heh = opposite_halfedge_handle(next_heh); + next_heh = next_halfedge_handle(curr_heh); + } + while (next_heh != _heh); + return curr_heh; + } + else + { + HalfedgeHandle heh(_heh); + HalfedgeHandle next_heh(next_halfedge_handle(heh)); + while (next_heh != _heh) { + heh = next_heh; + next_heh = next_halfedge_handle(next_heh); + } + return heh; + } + } + + + HalfedgeHandle opposite_halfedge_handle(HalfedgeHandle _heh) const + { return HalfedgeHandle((_heh.idx() & 1) ? _heh.idx()-1 : _heh.idx()+1); } + + + HalfedgeHandle ccw_rotated_halfedge_handle(HalfedgeHandle _heh) const + { return opposite_halfedge_handle(prev_halfedge_handle(_heh)); } + + + HalfedgeHandle cw_rotated_halfedge_handle(HalfedgeHandle _heh) const + { return next_halfedge_handle(opposite_halfedge_handle(_heh)); } + + // --- edge connectivity --- + HalfedgeHandle halfedge_handle(EdgeHandle _eh, uint _i) const + { + assert(_i<=1); + return HalfedgeHandle((_eh.idx() << 1) + _i); + } + + EdgeHandle edge_handle(HalfedgeHandle _heh) const + { return EdgeHandle(_heh.idx() >> 1); } + + // --- face connectivity --- + HalfedgeHandle halfedge_handle(FaceHandle _fh) const + { return face(_fh).halfedge_handle_; } + + void set_halfedge_handle(FaceHandle _fh, HalfedgeHandle _heh) + { +// assert(is_valid_handle(_heh)); + face(_fh).halfedge_handle_ = _heh; + } + + /// Status Query API + //------------------------------------------------------------ vertex status + const StatusInfo& status(VertexHandle _vh) const + { return property(vertex_status_, _vh); } + + StatusInfo& status(VertexHandle _vh) + { return property(vertex_status_, _vh); } + + //----------------------------------------------------------- halfedge status + const StatusInfo& status(HalfedgeHandle _hh) const + { return property(halfedge_status_, _hh); } + + StatusInfo& status(HalfedgeHandle _hh) + { return property(halfedge_status_, _hh); } + + //--------------------------------------------------------------- edge status + const StatusInfo& status(EdgeHandle _eh) const + { return property(edge_status_, _eh); } + + StatusInfo& status(EdgeHandle _eh) + { return property(edge_status_, _eh); } + + //--------------------------------------------------------------- face status + const StatusInfo& status(FaceHandle _fh) const + { return property(face_status_, _fh); } + + StatusInfo& status(FaceHandle _fh) + { return property(face_status_, _fh); } + + inline bool has_vertex_status() const + { return vertex_status_.is_valid(); } + + inline bool has_halfedge_status() const + { return halfedge_status_.is_valid(); } + + inline bool has_edge_status() const + { return edge_status_.is_valid(); } + + inline bool has_face_status() const + { return face_status_.is_valid(); } + + inline VertexStatusPropertyHandle vertex_status_pph() const + { return vertex_status_; } + + inline HalfedgeStatusPropertyHandle halfedge_status_pph() const + { return halfedge_status_; } + + inline EdgeStatusPropertyHandle edge_status_pph() const + { return edge_status_; } + + inline FaceStatusPropertyHandle face_status_pph() const + { return face_status_; } + + /// status property by handle + inline VertexStatusPropertyHandle status_pph(VertexHandle /*_hnd*/) const + { return vertex_status_pph(); } + + inline HalfedgeStatusPropertyHandle status_pph(HalfedgeHandle /*_hnd*/) const + { return halfedge_status_pph(); } + + inline EdgeStatusPropertyHandle status_pph(EdgeHandle /*_hnd*/) const + { return edge_status_pph(); } + + inline FaceStatusPropertyHandle status_pph(FaceHandle /*_hnd*/) const + { return face_status_pph(); } + + /// Status Request API + void request_vertex_status() + { + if (!refcount_vstatus_++) + add_property( vertex_status_, "v:status" ); + } + + void request_halfedge_status() + { + if (!refcount_hstatus_++) + add_property( halfedge_status_, "h:status" ); + } + + void request_edge_status() + { + if (!refcount_estatus_++) + add_property( edge_status_, "e:status" ); + } + + void request_face_status() + { + if (!refcount_fstatus_++) + add_property( face_status_, "f:status" ); + } + + /// Status Release API + void release_vertex_status() + { + if ((refcount_vstatus_ > 0) && (! --refcount_vstatus_)) + remove_property(vertex_status_); + } + + void release_halfedge_status() + { + if ((refcount_hstatus_ > 0) && (! --refcount_hstatus_)) + remove_property(halfedge_status_); + } + + void release_edge_status() + { + if ((refcount_estatus_ > 0) && (! --refcount_estatus_)) + remove_property(edge_status_); + } + + void release_face_status() + { + if ((refcount_fstatus_ > 0) && (! --refcount_fstatus_)) + remove_property(face_status_); + } + + /// --- StatusSet API --- + + template + class StatusSetT + { + protected: + ArrayKernel& kernel_; + + public: + const uint bit_mask_; + + public: + StatusSetT(ArrayKernel& _kernel, uint _bit_mask) + : kernel_(_kernel), bit_mask_(_bit_mask) + {} + + ~StatusSetT() + {} + + inline bool is_in(Handle _hnd) const + { return kernel_.status(_hnd).is_bit_set(bit_mask_); } + + inline void insert(Handle _hnd) + { return kernel_.status(_hnd).set_bit(bit_mask_); } + + inline void erase(Handle _hnd) + { return kernel_.status(_hnd).unset_bit(bit_mask_); } + + /// Note: 0(n) complexity + uint size() const + { + uint n_elements = kernel_.status_pph(Handle()).is_valid() ? + kernel_.property(kernel_.status_pph(Handle())).n_elements() : 0; + uint sz = 0; + for (uint i = 0; i < n_elements; ++i) + { + sz += (uint)is_in(Handle(i)); + } + return sz; + } + + /// Note: O(n) complexity + void clear() + { + uint n_elements = kernel_.status_pph(Handle()).is_valid() ? + kernel_.property(kernel_.status_pph(Handle())).n_elements() : 0; + for (uint i = 0; i < n_elements; ++i) + { + erase(Handle(i)); + } + } + }; + + friend class StatusSetT; + friend class StatusSetT; + friend class StatusSetT; + friend class StatusSetT; + + /// --- AutoStatusSet API --- + + template + class AutoStatusSetT : public StatusSetT + { + private: + typedef StatusSetT Base; + public: + AutoStatusSetT(ArrayKernel& _kernel) + : StatusSetT(_kernel, _kernel.pop_bit_mask(Handle())) + { /*assert(size() == 0);*/ } //the set should be empty on creation + + ~AutoStatusSetT() + { + //assert(size() == 0);//the set should be empty on leave? + Base::kernel_.push_bit_mask(Handle(), Base::bit_mask_); + } + }; + + friend class AutoStatusSetT; + friend class AutoStatusSetT; + friend class AutoStatusSetT; + friend class AutoStatusSetT; + + typedef AutoStatusSetT VertexStatusSet; + typedef AutoStatusSetT EdgeStatusSet; + typedef AutoStatusSetT FaceStatusSet; + typedef AutoStatusSetT HalfedgeStatusSet; + + /// --- ExtStatusSet API --- (hybrid between a set and an array) + + template + class ExtStatusSetT : public AutoStatusSetT + { + public: + typedef AutoStatusSetT Base; + + protected: + typedef std::vector HandleContainer; + HandleContainer handles_; + + public: + typedef typename HandleContainer::iterator + iterator; + typedef typename HandleContainer::const_iterator + const_iterator; + public: + ExtStatusSetT(ArrayKernel& _kernel, uint _capacity_hint = 0) + : Base(_kernel) + { handles_.reserve(_capacity_hint); } + + ~ExtStatusSetT() + { clear(); } + + //set API + // Complexity: O(1) + inline void insert(Handle _hnd) + { + if (!is_in(_hnd)) + { + Base::insert(_hnd); + handles_.push_back(_hnd); + } + } + + // Complexity: O(k), (k - number of the elements in the set) + inline void erase(Handle _hnd) + { + if (is_in(_hnd)) + { + iterator it = std::find(begin(), end(), _hnd); + erase(it); + } + } + + // Complexity: O(1) + inline void erase(iterator _it) + { + assert(_it != end() && is_in(*_it)); + clear(*_it); + *_it = handles_.back(); + *_it.pop_back(); + } + + inline void clear() + { + for (iterator it = begin(); it != end(); ++it) + { + assert(is_in(*it)); + Base::erase(*it); + } + handles_.clear(); + } + + /// Complexity: 0(1) + inline uint size() const + { return handles_.size(); } + inline bool empty() const + { return handles_.empty(); } + + //Vector API + inline iterator begin() + { return handles_.begin(); } + inline const_iterator begin() const + { return handles_.begin(); } + + inline iterator end() + { return handles_.end(); } + inline const_iterator end() const + { return handles_.end(); } + + inline Handle& front() + { return handles_.front(); } + inline const Handle& front() const + { return handles_.front(); } + + inline Handle& back() + { return handles_.back(); } + inline const Handle& back() const + { return handles_.back(); } + }; + + typedef ExtStatusSetT ExtFaceStatusSet; + typedef ExtStatusSetT ExtVertexStatusSet; + typedef ExtStatusSetT ExtEdgeStatusSet; + typedef ExtStatusSetT ExtHalfedgeStatusSet; + +private: + // iterators + typedef std::vector VertexContainer; + typedef std::vector EdgeContainer; + typedef std::vector FaceContainer; + typedef VertexContainer::iterator KernelVertexIter; + typedef VertexContainer::const_iterator KernelConstVertexIter; + typedef EdgeContainer::iterator KernelEdgeIter; + typedef EdgeContainer::const_iterator KernelConstEdgeIter; + typedef FaceContainer::iterator KernelFaceIter; + typedef FaceContainer::const_iterator KernelConstFaceIter; + typedef std::vector BitMaskContainer; + + + KernelVertexIter vertices_begin() { return vertices_.begin(); } + KernelConstVertexIter vertices_begin() const { return vertices_.begin(); } + KernelVertexIter vertices_end() { return vertices_.end(); } + KernelConstVertexIter vertices_end() const { return vertices_.end(); } + + KernelEdgeIter edges_begin() { return edges_.begin(); } + KernelConstEdgeIter edges_begin() const { return edges_.begin(); } + KernelEdgeIter edges_end() { return edges_.end(); } + KernelConstEdgeIter edges_end() const { return edges_.end(); } + + KernelFaceIter faces_begin() { return faces_.begin(); } + KernelConstFaceIter faces_begin() const { return faces_.begin(); } + KernelFaceIter faces_end() { return faces_.end(); } + KernelConstFaceIter faces_end() const { return faces_.end(); } + + /// bit mask container by handle + inline BitMaskContainer& bit_masks(VertexHandle /*_dummy_hnd*/) + { return vertex_bit_masks_; } + inline BitMaskContainer& bit_masks(EdgeHandle /*_dummy_hnd*/) + { return edge_bit_masks_; } + inline BitMaskContainer& bit_masks(FaceHandle /*_dummy_hnd*/) + { return face_bit_masks_; } + inline BitMaskContainer& bit_masks(HalfedgeHandle /*_dummy_hnd*/) + { return halfedge_bit_masks_; } + + template + uint pop_bit_mask(Handle _hnd) + { + assert(!bit_masks(_hnd).empty());//check if the client request too many status sets + uint bit_mask = bit_masks(_hnd).back(); + bit_masks(_hnd).pop_back(); + return bit_mask; + } + + template + void push_bit_mask(Handle _hnd, uint _bit_mask) + { + assert(std::find(bit_masks(_hnd).begin(), bit_masks(_hnd).end(), _bit_mask) == + bit_masks(_hnd).end());//this mask should be not already used + bit_masks(_hnd).push_back(_bit_mask); + } + + void init_bit_masks(BitMaskContainer& _bmc); + void init_bit_masks(); + +private: + VertexContainer vertices_; + EdgeContainer edges_; + FaceContainer faces_; + + VertexStatusPropertyHandle vertex_status_; + HalfedgeStatusPropertyHandle halfedge_status_; + EdgeStatusPropertyHandle edge_status_; + FaceStatusPropertyHandle face_status_; + + uint refcount_vstatus_; + uint refcount_hstatus_; + uint refcount_estatus_; + uint refcount_fstatus_; + + BitMaskContainer halfedge_bit_masks_; + BitMaskContainer edge_bit_masks_; + BitMaskContainer vertex_bit_masks_; + BitMaskContainer face_bit_masks_; +}; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ARRAY_KERNEL_HH defined +//============================================================================= diff --git a/Core/Mesh/AttribKernelT.hh b/Core/Mesh/AttribKernelT.hh new file mode 100644 index 00000000..108f07e8 --- /dev/null +++ b/Core/Mesh/AttribKernelT.hh @@ -0,0 +1,651 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_ATTRIBKERNEL_HH +#define OPENMESH_ATTRIBKERNEL_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + +/// This class adds the standard properties to the mesh type. +/// +/// The attribute kernel adds all standard properties to the kernel. Therefore +/// the functions/types defined here provide a subset of the kernel +/// interface as described in Concepts::KernelT. +/// +/// \see Concepts::KernelT +template +class AttribKernelT : public Connectivity +{ +public: + + //---------------------------------------------------------------- item types + + typedef typename Connectivity::Vertex Vertex; + typedef typename Connectivity::Halfedge Halfedge; + typedef typename Connectivity::Edge Edge; + typedef typename Connectivity::Face Face; + + typedef typename MeshItems::Point Point; + typedef typename MeshItems::Normal Normal; + typedef typename MeshItems::Color Color; + typedef typename MeshItems::TexCoord1D TexCoord1D; + typedef typename MeshItems::TexCoord2D TexCoord2D; + typedef typename MeshItems::TexCoord3D TexCoord3D; + typedef typename MeshItems::Scalar Scalar; + typedef typename MeshItems::TextureIndex TextureIndex; + + typedef typename MeshItems::VertexData VertexData; + typedef typename MeshItems::HalfedgeData HalfedgeData; + typedef typename MeshItems::EdgeData EdgeData; + typedef typename MeshItems::FaceData FaceData; + + typedef AttribKernelT AttribKernel; + + enum Attribs { + VAttribs = MeshItems::VAttribs, + HAttribs = MeshItems::HAttribs, + EAttribs = MeshItems::EAttribs, + FAttribs = MeshItems::FAttribs, + }; + + typedef VPropHandleT DataVPropHandle; + typedef HPropHandleT DataHPropHandle; + typedef EPropHandleT DataEPropHandle; + typedef FPropHandleT DataFPropHandle; + +public: + + //-------------------------------------------------- constructor / destructor + + AttribKernelT() + : refcount_vnormals_(0), + refcount_vcolors_(0), + refcount_vtexcoords1D_(0), + refcount_vtexcoords2D_(0), + refcount_vtexcoords3D_(0), + refcount_htexcoords1D_(0), + refcount_htexcoords2D_(0), + refcount_htexcoords3D_(0), + refcount_fnormals_(0), + refcount_fcolors_(0), + refcount_ftextureIndex_(0) + { + add_property( points_, "v:points" ); + + if (VAttribs & Attributes::Normal) + request_vertex_normals(); + + if (VAttribs & Attributes::Color) + request_vertex_colors(); + + if (VAttribs & Attributes::TexCoord1D) + request_vertex_texcoords1D(); + + if (VAttribs & Attributes::TexCoord2D) + request_vertex_texcoords2D(); + + if (VAttribs & Attributes::TexCoord3D) + request_vertex_texcoords3D(); + + if (HAttribs & Attributes::TexCoord1D) + request_halfedge_texcoords1D(); + + if (HAttribs & Attributes::TexCoord2D) + request_halfedge_texcoords2D(); + + if (HAttribs & Attributes::TexCoord3D) + request_halfedge_texcoords3D(); + + if (VAttribs & Attributes::Status) + Connectivity::request_vertex_status(); + + if (HAttribs & Attributes::Status) + Connectivity::request_halfedge_status(); + + if (EAttribs & Attributes::Status) + Connectivity::request_edge_status(); + + if (FAttribs & Attributes::Normal) + request_face_normals(); + + if (FAttribs & Attributes::Color) + request_face_colors(); + + if (FAttribs & Attributes::Status) + Connectivity::request_face_status(); + + if (FAttribs & Attributes::TextureIndex) + request_face_texture_index(); + + //FIXME: data properties might actually cost storage even + //if there are no data traits?? + add_property(data_vpph_); + add_property(data_fpph_); + add_property(data_hpph_); + add_property(data_epph_); + } + + virtual ~AttribKernelT() + { + // should remove properties, but this will be done in + // BaseKernel's destructor anyway... + } + +// Martin: This below does not make any sense, right? + // -------------------------------------------------------- copy & assignment +// AttribKernelT(const AttribKernelT& _rhs) +// : BaseKernel(_rhs) +// { operator=(_rhs); } +// +// AttribKernelT& operator=(const AttribKernelT& _rhs) +// { +// // remove old properties +// remove_property(points_); +// remove_property(vertex_normals_); +// remove_property(vertex_colors_); +// remove_property(vertex_texcoords_); +// remove_property(vertex_status_); +// remove_property(halfedge_status_); +// remove_property(edge_status_); +// remove_property(face_normals_); +// remove_property(face_colors_); +// remove_property(face_status_); +// +// // parent deep-copies properties +// BaseKernel::operator=(_rhs); +// +// // copy property handles +// points_ = _rhs.points_; +// vertex_normals_ = _rhs.vertex_normals_; +// vertex_colors_ = _rhs.vertex_colors_; +// vertex_texcoords_ = _rhs.vertex_texcoords_; +// vertex_status_ = _rhs.vertex_status_; +// halfedge_status_ = _rhs.halfedge_status_; +// edge_status_ = _rhs.edge_status_; +// face_normals_ = _rhs.face_normals_; +// face_colors_ = _rhs.face_colors_; +// face_status_ = _rhs.face_status_; +// +// // copy ref-counts +// refcount_vnormals_ = _rhs.refcount_vnormals_; +// refcount_vcolors_ = _rhs.refcount_vcolors_; +// refcount_vtexcoords_ = _rhs.refcount_vtexcoords_; +// refcount_vstatus_ = _rhs.refcount_vstatus_; +// refcount_hstatus_ = _rhs.refcount_hstatus_; +// refcount_estatus_ = _rhs.refcount_estatus_; +// refcount_fnormals_ = _rhs.refcount_fnormals_; +// refcount_fcolors_ = _rhs.refcount_fcolors_; +// refcount_fstatus_ = _rhs.refcount_fstatus_; +// +// return *this; +// } + + /** Assignment from another mesh of \em another type. + \note All that's copied is connectivity and vertex positions. + All other information (like e.g. attributes or additional + elements from traits classes) is not copied. + \note If you want to copy all information, including *custom* properties, + use PolyMeshT::operator=() instead. + TODO: version which copies standard properties specified by the user + */ + template + void assign(const _AttribKernel& _other) + { + assign_connectivity(_other); + for (typename Connectivity::VertexIter v_it = Connectivity::vertices_begin(); + v_it != Connectivity::vertices_end(); ++v_it) + {//assumes Point constructor supports cast from _AttribKernel::Point + set_point(v_it, (Point)_other.point(v_it)); + } + } + + //-------------------------------------------------------------------- points + + const Point* points() const + { return property(points_).data(); } + + const Point& point(VertexHandle _vh) const + { return property(points_, _vh); } + + Point& point(VertexHandle _vh) + { return property(points_, _vh); } + + void set_point(VertexHandle _vh, const Point& _p) + { property(points_, _vh) = _p; } + + + //------------------------------------------------------------ vertex normals + + const Normal* vertex_normals() const + { return property(vertex_normals_).data(); } + + const Normal& normal(VertexHandle _vh) const + { return property(vertex_normals_, _vh); } + + void set_normal(VertexHandle _vh, const Normal& _n) + { property(vertex_normals_, _vh) = _n; } + + + //------------------------------------------------------------- vertex colors + + const Color* vertex_colors() const + { return property(vertex_colors_).data(); } + + const Color& color(VertexHandle _vh) const + { return property(vertex_colors_, _vh); } + + void set_color(VertexHandle _vh, const Color& _c) + { property(vertex_colors_, _vh) = _c; } + + + //------------------------------------------------------- vertex 1D texcoords + + const TexCoord1D* texcoords1D() const { + return property(vertex_texcoords1D_).data(); + } + + const TexCoord1D& texcoord1D(VertexHandle _vh) const { + return property(vertex_texcoords1D_, _vh); + } + + void set_texcoord1D(VertexHandle _vh, const TexCoord1D& _t) { + property(vertex_texcoords1D_, _vh) = _t; + } + + + //------------------------------------------------------- vertex 2D texcoords + + const TexCoord2D* texcoords2D() const { + return property(vertex_texcoords2D_).data(); + } + + const TexCoord2D& texcoord2D(VertexHandle _vh) const { + return property(vertex_texcoords2D_, _vh); + } + + void set_texcoord2D(VertexHandle _vh, const TexCoord2D& _t) { + property(vertex_texcoords2D_, _vh) = _t; + } + + + //------------------------------------------------------- vertex 3D texcoords + + const TexCoord3D* texcoords3D() const { + return property(vertex_texcoords3D_).data(); + } + + const TexCoord3D& texcoord3D(VertexHandle _vh) const { + return property(vertex_texcoords3D_, _vh); + } + + void set_texcoord3D(VertexHandle _vh, const TexCoord3D& _t) { + property(vertex_texcoords3D_, _vh) = _t; + } + + //.------------------------------------------------------ halfedge 1D texcoords + + const TexCoord1D* htexcoords1D() const { + return property(halfedge_texcoords1D_).data(); + } + + const TexCoord1D& texcoord1D(HalfedgeHandle _heh) const { + return property(halfedge_texcoords1D_, _heh); + } + + void set_texcoord1D(HalfedgeHandle _heh, const TexCoord1D& _t) { + property(halfedge_texcoords1D_, _heh) = _t; + } + + + //------------------------------------------------------- halfedge 2D texcoords + + const TexCoord2D* htexcoords2D() const { + return property(halfedge_texcoords2D_).data(); + } + + const TexCoord2D& texcoord2D(HalfedgeHandle _heh) const { + return property(halfedge_texcoords2D_, _heh); + } + + void set_texcoord2D(HalfedgeHandle _heh, const TexCoord2D& _t) { + property(halfedge_texcoords2D_, _heh) = _t; + } + + + //------------------------------------------------------- halfedge 3D texcoords + + const TexCoord3D* htexcoords3D() const { + return property(halfedge_texcoords3D_).data(); + } + + const TexCoord3D& texcoord3D(HalfedgeHandle _heh) const { + return property(halfedge_texcoords3D_, _heh); + } + + void set_texcoord3D(HalfedgeHandle _heh, const TexCoord3D& _t) { + property(halfedge_texcoords3D_, _heh) = _t; + } + + //-------------------------------------------------------------- face normals + + const Normal& normal(FaceHandle _fh) const + { return property(face_normals_, _fh); } + + void set_normal(FaceHandle _fh, const Normal& _n) + { property(face_normals_, _fh) = _n; } + + //-------------------------------------------------------------- per Face Texture index + + const TextureIndex& texture_index(FaceHandle _fh) const + { return property(face_texture_index_, _fh); } + + void set_texture_index(FaceHandle _fh, const TextureIndex& _t) + { property(face_texture_index_, _fh) = _t; } + + //--------------------------------------------------------------- face colors + + const Color& color(FaceHandle _fh) const + { return property(face_colors_, _fh); } + + void set_color(FaceHandle _fh, const Color& _c) + { property(face_colors_, _fh) = _c; } + + //------------------------------------------------ request / alloc properties + + void request_vertex_normals() + { + if (!refcount_vnormals_++) + add_property( vertex_normals_, "v:normals" ); + } + + void request_vertex_colors() + { + if (!refcount_vcolors_++) + add_property( vertex_colors_, "v:colors" ); + } + + void request_vertex_texcoords1D() + { + if (!refcount_vtexcoords1D_++) + add_property( vertex_texcoords1D_, "v:texcoords1D" ); + } + + void request_vertex_texcoords2D() + { + if (!refcount_vtexcoords2D_++) + add_property( vertex_texcoords2D_, "v:texcoords2D" ); + } + + void request_vertex_texcoords3D() + { + if (!refcount_vtexcoords3D_++) + add_property( vertex_texcoords3D_, "v:texcoords3D" ); + } + + void request_halfedge_texcoords1D() + { + if (!refcount_htexcoords1D_++) + add_property( halfedge_texcoords1D_, "h:texcoords1D" ); + } + + void request_halfedge_texcoords2D() + { + if (!refcount_htexcoords2D_++) + add_property( halfedge_texcoords2D_, "h:texcoords2D" ); + } + + void request_halfedge_texcoords3D() + { + if (!refcount_htexcoords3D_++) + add_property( halfedge_texcoords3D_, "h:texcoords3D" ); + } + + void request_face_normals() + { + if (!refcount_fnormals_++) + add_property( face_normals_, "f:normals" ); + } + + void request_face_colors() + { + if (!refcount_fcolors_++) + add_property( face_colors_, "f:colors" ); + } + + void request_face_texture_index() + { + if (!refcount_ftextureIndex_++) + add_property( face_texture_index_, "f:textureindex" ); + } + + //------------------------------------------------- release / free properties + + void release_vertex_normals() + { + if ((refcount_vnormals_ > 0) && (! --refcount_vnormals_)) + remove_property(vertex_normals_); + } + + void release_vertex_colors() + { + if ((refcount_vcolors_ > 0) && (! --refcount_vcolors_)) + remove_property(vertex_colors_); + } + + void release_vertex_texcoords1D() { + if ((refcount_vtexcoords1D_ > 0) && (! --refcount_vtexcoords1D_)) + remove_property(vertex_texcoords1D_); + } + + void release_vertex_texcoords2D() { + if ((refcount_vtexcoords2D_ > 0) && (! --refcount_vtexcoords2D_)) + remove_property(vertex_texcoords2D_); + } + + void release_vertex_texcoords3D() { + if ((refcount_vtexcoords3D_ > 0) && (! --refcount_vtexcoords3D_)) + remove_property(vertex_texcoords3D_); + } + + void release_halfedge_texcoords1D() { + if ((refcount_htexcoords1D_ > 0) && (! --refcount_htexcoords1D_)) + remove_property(halfedge_texcoords1D_); + } + + void release_halfedge_texcoords2D() { + if ((refcount_htexcoords2D_ > 0) && (! --refcount_htexcoords2D_)) + remove_property(halfedge_texcoords2D_); + } + + void release_halfedge_texcoords3D() { + if ((refcount_htexcoords3D_ > 0) && (! --refcount_htexcoords3D_)) + remove_property(halfedge_texcoords3D_); + } + + void release_face_normals() + { + if ((refcount_fnormals_ > 0) && (! --refcount_fnormals_)) + remove_property(face_normals_); + } + + void release_face_colors() + { + if ((refcount_fcolors_ > 0) && (! --refcount_fcolors_)) + remove_property(face_colors_); + } + + void release_face_texture_index() + { + if ((refcount_ftextureIndex_ > 0) && (! --refcount_ftextureIndex_)) + remove_property(face_texture_index_); + } + + //---------------------------------------------- dynamic check for properties + + bool has_vertex_normals() const { return vertex_normals_.is_valid(); } + bool has_vertex_colors() const { return vertex_colors_.is_valid(); } + bool has_vertex_texcoords1D() const { return vertex_texcoords1D_.is_valid(); } + bool has_vertex_texcoords2D() const { return vertex_texcoords2D_.is_valid(); } + bool has_vertex_texcoords3D() const { return vertex_texcoords3D_.is_valid(); } + bool has_halfedge_texcoords1D() const { return halfedge_texcoords1D_.is_valid();} + bool has_halfedge_texcoords2D() const { return halfedge_texcoords2D_.is_valid();} + bool has_halfedge_texcoords3D() const { return halfedge_texcoords3D_.is_valid();} + bool has_face_normals() const { return face_normals_.is_valid(); } + bool has_face_colors() const { return face_colors_.is_valid(); } + bool has_face_texture_index() const { return face_texture_index_.is_valid(); } + +public: + + typedef VPropHandleT PointsPropertyHandle; + typedef VPropHandleT VertexNormalsPropertyHandle; + typedef VPropHandleT VertexColorsPropertyHandle; + typedef VPropHandleT VertexTexCoords1DPropertyHandle; + typedef VPropHandleT VertexTexCoords2DPropertyHandle; + typedef VPropHandleT VertexTexCoords3DPropertyHandle; + typedef HPropHandleT HalfedgeTexCoords1DPropertyHandle; + typedef HPropHandleT HalfedgeTexCoords2DPropertyHandle; + typedef HPropHandleT HalfedgeTexCoords3DPropertyHandle; + typedef FPropHandleT FaceNormalsPropertyHandle; + typedef FPropHandleT FaceColorsPropertyHandle; + typedef FPropHandleT FaceTextureIndexPropertyHandle; + +public: + //standard vertex properties + PointsPropertyHandle points_pph() const + { return points_; } + + VertexNormalsPropertyHandle vertex_normals_pph() const + { return vertex_normals_; } + + VertexColorsPropertyHandle vertex_colors_pph() const + { return vertex_colors_; } + + VertexTexCoords1DPropertyHandle vertex_texcoords1D_pph() const + { return vertex_texcoords1D_; } + + VertexTexCoords2DPropertyHandle vertex_texcoords2D_pph() const + { return vertex_texcoords2D_; } + + VertexTexCoords3DPropertyHandle vertex_texcoords3D_pph() const + { return vertex_texcoords3D_; } + + //standard halfedge properties + HalfedgeTexCoords1DPropertyHandle halfedge_texcoords1D_pph() const + { return halfedge_texcoords1D_; } + + HalfedgeTexCoords2DPropertyHandle halfedge_texcoords2D_pph() const + { return halfedge_texcoords2D_; } + + HalfedgeTexCoords3DPropertyHandle halfedge_texcoords3D_pph() const + { return halfedge_texcoords3D_; } + + //standard face properties + FaceNormalsPropertyHandle face_normals_pph() const + { return face_normals_; } + + FaceColorsPropertyHandle face_colors_pph() const + { return face_colors_; } + + FaceTextureIndexPropertyHandle face_texture_index_pph() const + { return face_texture_index_; } + + VertexData& data(VertexHandle _vh) + { return property(data_vpph_, _vh); } + + const VertexData& data(VertexHandle _vh) const + { return property(data_vpph_, _vh); } + + FaceData& data(FaceHandle _fh) + { return property(data_fpph_, _fh); } + + const FaceData& data(FaceHandle _fh) const + { return property(data_fpph_, _fh); } + + EdgeData& data(EdgeHandle _eh) + { return property(data_epph_, _eh); } + + const EdgeData& data(EdgeHandle _eh) const + { return property(data_epph_, _eh); } + + HalfedgeData& data(HalfedgeHandle _heh) + { return property(data_hpph_, _heh); } + + const HalfedgeData& data(HalfedgeHandle _heh) const + { return property(data_hpph_, _heh); } + +private: + //standard vertex properties + PointsPropertyHandle points_; + VertexNormalsPropertyHandle vertex_normals_; + VertexColorsPropertyHandle vertex_colors_; + VertexTexCoords1DPropertyHandle vertex_texcoords1D_; + VertexTexCoords2DPropertyHandle vertex_texcoords2D_; + VertexTexCoords3DPropertyHandle vertex_texcoords3D_; + //standard halfedge properties + HalfedgeTexCoords1DPropertyHandle halfedge_texcoords1D_; + HalfedgeTexCoords2DPropertyHandle halfedge_texcoords2D_; + HalfedgeTexCoords3DPropertyHandle halfedge_texcoords3D_; + //standard face properties + FaceNormalsPropertyHandle face_normals_; + FaceColorsPropertyHandle face_colors_; + FaceTextureIndexPropertyHandle face_texture_index_; + //data properties handles + DataVPropHandle data_vpph_; + DataHPropHandle data_hpph_; + DataEPropHandle data_epph_; + DataFPropHandle data_fpph_; + + unsigned int refcount_vnormals_; + unsigned int refcount_vcolors_; + unsigned int refcount_vtexcoords1D_; + unsigned int refcount_vtexcoords2D_; + unsigned int refcount_vtexcoords3D_; + unsigned int refcount_htexcoords1D_; + unsigned int refcount_htexcoords2D_; + unsigned int refcount_htexcoords3D_; + unsigned int refcount_fnormals_; + unsigned int refcount_fcolors_; + unsigned int refcount_ftextureIndex_; +}; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ATTRIBKERNEL_HH defined +//============================================================================= diff --git a/Core/Mesh/Attributes.hh b/Core/Mesh/Attributes.hh new file mode 100644 index 00000000..ffed5fe4 --- /dev/null +++ b/Core/Mesh/Attributes.hh @@ -0,0 +1,85 @@ +//============================================================================= +// +// 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: 3794 $ +// $Date: 2008-11-25 19:25:02 +0100 (Di, 25. Nov 2008) $ +// +//============================================================================= + + +/** + \file Attributes.hh + This file provides some macros containing attribute usage. +*/ + + +#ifndef OPENMESH_ATTRIBUTES_HH +#define OPENMESH_ATTRIBUTES_HH + + +//== INCLUDES ================================================================= + + +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Attributes { + + +//== CLASS DEFINITION ======================================================== + +/** Attribute bits + * + * Use the bits to define a standard property at compile time using traits. + * + * \include traits5.cc + * + * \see \ref mesh_type + */ +enum AttributeBits +{ + None = 0, ///< Clear all attribute bits + Normal = 1, ///< Add normals to mesh item (vertices/faces) + Color = 2, ///< Add colors to mesh item (vertices/faces) + PrevHalfedge = 4, ///< Add storage for previous halfedge (halfedges). The bit is set by default in the DefaultTraits. + Status = 8, ///< Add status to mesh item (all items) + TexCoord1D = 16, ///< Add 1D texture coordinates (vertices, halfedges) + TexCoord2D = 32, ///< Add 2D texture coordinates (vertices, halfedges) + TexCoord3D = 64, ///< Add 3D texture coordinates (vertices, halfedges) + TextureIndex = 128 ///< Add texture index (faces) +}; + + +//============================================================================= +} // namespace Attributes +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ATTRIBUTES_HH defined +//============================================================================= diff --git a/Core/Mesh/BaseKernel.cc b/Core/Mesh/BaseKernel.cc new file mode 100644 index 00000000..8671730b --- /dev/null +++ b/Core/Mesh/BaseKernel.cc @@ -0,0 +1,67 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +#include +namespace OpenMesh +{ + +void BaseKernel::property_stats(std::ostream& _ostr) const +{ + const PropertyContainer::Properties& vps = vprops_.properties(); + const PropertyContainer::Properties& hps = hprops_.properties(); + const PropertyContainer::Properties& eps = eprops_.properties(); + const PropertyContainer::Properties& fps = fprops_.properties(); + const PropertyContainer::Properties& mps = mprops_.properties(); + + PropertyContainer::Properties::const_iterator it; + + _ostr << vprops_.size() << " vprops:\n"; + for (it=vps.begin(); it!=vps.end(); ++it) + { + *it == NULL ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + } + _ostr << hprops_.size() << " hprops:\n"; + for (it=hps.begin(); it!=hps.end(); ++it) + { + *it == NULL ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + } + _ostr << eprops_.size() << " eprops:\n"; + for (it=eps.begin(); it!=eps.end(); ++it) + { + *it == NULL ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + } + _ostr << fprops_.size() << " fprops:\n"; + for (it=fps.begin(); it!=fps.end(); ++it) + { + *it == NULL ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + } + _ostr << mprops_.size() << " mprops:\n"; + for (it=mps.begin(); it!=mps.end(); ++it) + { + *it == NULL ? (void)(_ostr << "[deleted]" << "\n") : (*it)->stats(_ostr); + } +} + +} diff --git a/Core/Mesh/BaseKernel.hh b/Core/Mesh/BaseKernel.hh new file mode 100644 index 00000000..35bf87e5 --- /dev/null +++ b/Core/Mesh/BaseKernel.hh @@ -0,0 +1,568 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// CLASS BaseKernel +// +//============================================================================= + + +#ifndef OPENMESH_BASE_KERNEL_HH +#define OPENMESH_BASE_KERNEL_HH + + +//== INCLUDES ================================================================= + + +#include +// -------------------- +#include +#include +#include +// -------------------- +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + +/// This class provides the basic property management like adding/removing +/// properties and access to properties. +/// All operations provided by %BaseKernel need at least a property handle +/// (VPropHandleT, EPropHandleT, HPropHandleT, FPropHandleT, MPropHandleT). +/// which keeps the data type of the property, too. +/// +/// There are two types of properties: +/// -# Standard properties - mesh data (e.g. vertex normal or face color) +/// -# Custom properties - user defined data +/// +/// The differentiation is only semantically, technically both are +/// equally handled. Therefore the methods provided by the %BaseKernel +/// are applicable to both property types. +/// +/// \attention Since the class PolyMeshT derives from a kernel, hence all public +/// elements of %BaseKernel are usable. + +class BaseKernel +{ +public: //-------------------------------------------- constructor / destructor + + BaseKernel() {} + virtual ~BaseKernel() {} + + +public: //-------------------------------------------------- add new properties + + /// \name Add a property to a mesh item + + //@{ + + /** Adds a property + * + * Depending on the property handle type a vertex, (half-)edge, face or + * mesh property is added to the mesh. If the action fails the handle + * is invalid. + * On success the handle must be used to access the property data with + * property(). + * + * \param _ph A property handle defining the data type to bind to mesh. + * On success the handle is valid else invalid. + * \param _name Optional name of property. Following restrictions apply + * to the name: + * -# Maximum length of name is 256 characters + * -# The prefixes matching "^[vhefm]:" are reserved for + * internal usage. + * -# The expression "^<.*>$" is reserved for internal usage. + * \return \c true on success else \c false. + * + */ + + template + void add_property( VPropHandleT& _ph, const std::string& _name="") + { + _ph = VPropHandleT( vprops_.add(T(), _name) ); + vprops_.resize(n_vertices()); + } + + template + void add_property( HPropHandleT& _ph, const std::string& _name="") + { + _ph = HPropHandleT( hprops_.add(T(), _name) ); + hprops_.resize(n_halfedges()); + } + + template + void add_property( EPropHandleT& _ph, const std::string& _name="") + { + _ph = EPropHandleT( eprops_.add(T(), _name) ); + eprops_.resize(n_edges()); + } + + template + void add_property( FPropHandleT& _ph, const std::string& _name="") + { + _ph = FPropHandleT( fprops_.add(T(), _name) ); + fprops_.resize(n_faces()); + } + + template + void add_property( MPropHandleT& _ph, const std::string& _name="") + { + _ph = MPropHandleT( mprops_.add(T(), _name) ); + mprops_.resize(1); + } + + //@} + + +public: //--------------------------------------------------- remove properties + + /// \name Removing a property from a mesh tiem + //@{ + + /** Remove a property. + * + * Removes the property represented by the handle from the apropriate + * mesh item. + * \param _ph Property to be removed. The handle is invalid afterwords. + */ + + template + void remove_property(VPropHandleT& _ph) + { + if (_ph.is_valid()) + vprops_.remove(_ph); + _ph.reset(); + } + + template + void remove_property(HPropHandleT& _ph) + { + if (_ph.is_valid()) + hprops_.remove(_ph); + _ph.reset(); + } + + template + void remove_property(EPropHandleT& _ph) + { + if (_ph.is_valid()) + eprops_.remove(_ph); + _ph.reset(); + } + + template + void remove_property(FPropHandleT& _ph) + { + if (_ph.is_valid()) + fprops_.remove(_ph); + _ph.reset(); + } + + template + void remove_property(MPropHandleT& _ph) + { + if (_ph.is_valid()) + mprops_.remove(_ph); + _ph.reset(); + } + + //@} + +public: //------------------------------------------------ get handle from name + + /// \name Get property handle by name + //@{ + + /** Retrieves the handle to a named property by it's name. + * + * \param _ph A property handle. On success the handle is valid else + * invalid. + * \param _name Name of wanted property. + * \return \c true if such a named property is available, else \c false. + */ + + template + bool get_property_handle(VPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = VPropHandleT(vprops_.handle(T(), _name))).is_valid(); + } + + template + bool get_property_handle(HPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = HPropHandleT(hprops_.handle(T(), _name))).is_valid(); + } + + template + bool get_property_handle(EPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = EPropHandleT(eprops_.handle(T(), _name))).is_valid(); + } + + template + bool get_property_handle(FPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = FPropHandleT(fprops_.handle(T(), _name))).is_valid(); + } + + template + bool get_property_handle(MPropHandleT& _ph, + const std::string& _name) const + { + return (_ph = MPropHandleT(mprops_.handle(T(), _name))).is_valid(); + } + + //@} + +public: //--------------------------------------------------- access properties + + /// \name Access a property + //@{ + + /** Access a property + * + * This method returns a reference to property. The property handle + * must be valid! The result is unpredictable if the handle is invalid! + * + * \param _ph A \em valid (!) property handle. + * \return The wanted property if the handle is valid. + */ + + template + PropertyT& property(VPropHandleT _ph) { + return vprops_.property(_ph); + } + template + const PropertyT& property(VPropHandleT _ph) const { + return vprops_.property(_ph); + } + + template + PropertyT& property(HPropHandleT _ph) { + return hprops_.property(_ph); + } + template + const PropertyT& property(HPropHandleT _ph) const { + return hprops_.property(_ph); + } + + template + PropertyT& property(EPropHandleT _ph) { + return eprops_.property(_ph); + } + template + const PropertyT& property(EPropHandleT _ph) const { + return eprops_.property(_ph); + } + + template + PropertyT& property(FPropHandleT _ph) { + return fprops_.property(_ph); + } + template + const PropertyT& property(FPropHandleT _ph) const { + return fprops_.property(_ph); + } + + template + PropertyT& mproperty(MPropHandleT _ph) { + return mprops_.property(_ph); + } + template + const PropertyT& mproperty(MPropHandleT _ph) const { + return mprops_.property(_ph); + } + + //@} + +public: //-------------------------------------------- access property elements + + /// \name Access a property element using a handle to a mesh item + //@{ + + /** Return value of property for an item + */ + + template + typename VPropHandleT::reference + property(VPropHandleT _ph, VertexHandle _vh) { + return vprops_.property(_ph)[_vh.idx()]; + } + + template + typename VPropHandleT::const_reference + property(VPropHandleT _ph, VertexHandle _vh) const { + return vprops_.property(_ph)[_vh.idx()]; + } + + + template + typename HPropHandleT::reference + property(HPropHandleT _ph, HalfedgeHandle _hh) { + return hprops_.property(_ph)[_hh.idx()]; + } + + template + typename HPropHandleT::const_reference + property(HPropHandleT _ph, HalfedgeHandle _hh) const { + return hprops_.property(_ph)[_hh.idx()]; + } + + + template + typename EPropHandleT::reference + property(EPropHandleT _ph, EdgeHandle _eh) { + return eprops_.property(_ph)[_eh.idx()]; + } + + template + typename EPropHandleT::const_reference + property(EPropHandleT _ph, EdgeHandle _eh) const { + return eprops_.property(_ph)[_eh.idx()]; + } + + + template + typename FPropHandleT::reference + property(FPropHandleT _ph, FaceHandle _fh) { + return fprops_.property(_ph)[_fh.idx()]; + } + + template + typename FPropHandleT::const_reference + property(FPropHandleT _ph, FaceHandle _fh) const { + return fprops_.property(_ph)[_fh.idx()]; + } + + + template + typename MPropHandleT::reference + property(MPropHandleT _ph) { + return mprops_.property(_ph)[0]; + } + + template + typename MPropHandleT::const_reference + property(MPropHandleT _ph) const { + return mprops_.property(_ph)[0]; + } + + //@} + +protected: //------------------------------------------------- low-level access + +public: // used by non-native kernel and MeshIO, should be protected + + size_t n_vprops(void) const { return vprops_.size(); } + + size_t n_eprops(void) const { return eprops_.size(); } + + size_t n_hprops(void) const { return hprops_.size(); } + + size_t n_fprops(void) const { return fprops_.size(); } + + size_t n_mprops(void) const { return mprops_.size(); } + + BaseProperty* _get_vprop( const std::string& _name) + { return vprops_.property(_name); } + + BaseProperty* _get_eprop( const std::string& _name) + { return eprops_.property(_name); } + + BaseProperty* _get_hprop( const std::string& _name) + { return hprops_.property(_name); } + + BaseProperty* _get_fprop( const std::string& _name) + { return fprops_.property(_name); } + + BaseProperty* _get_mprop( const std::string& _name) + { return mprops_.property(_name); } + + const BaseProperty* _get_vprop( const std::string& _name) const + { return vprops_.property(_name); } + + const BaseProperty* _get_eprop( const std::string& _name) const + { return eprops_.property(_name); } + + const BaseProperty* _get_hprop( const std::string& _name) const + { return hprops_.property(_name); } + + const BaseProperty* _get_fprop( const std::string& _name) const + { return fprops_.property(_name); } + + const BaseProperty* _get_mprop( const std::string& _name) const + { return mprops_.property(_name); } + + BaseProperty& _vprop( size_t _idx ) { return vprops_._property( _idx ); } + BaseProperty& _eprop( size_t _idx ) { return eprops_._property( _idx ); } + BaseProperty& _hprop( size_t _idx ) { return hprops_._property( _idx ); } + BaseProperty& _fprop( size_t _idx ) { return fprops_._property( _idx ); } + BaseProperty& _mprop( size_t _idx ) { return mprops_._property( _idx ); } + + const BaseProperty& _vprop( size_t _idx ) const + { return vprops_._property( _idx ); } + const BaseProperty& _eprop( size_t _idx ) const + { return eprops_._property( _idx ); } + const BaseProperty& _hprop( size_t _idx ) const + { return hprops_._property( _idx ); } + const BaseProperty& _fprop( size_t _idx ) const + { return fprops_._property( _idx ); } + const BaseProperty& _mprop( size_t _idx ) const + { return mprops_._property( _idx ); } + + size_t _add_vprop( BaseProperty* _bp ) { return vprops_._add( _bp ); } + size_t _add_eprop( BaseProperty* _bp ) { return eprops_._add( _bp ); } + size_t _add_hprop( BaseProperty* _bp ) { return hprops_._add( _bp ); } + size_t _add_fprop( BaseProperty* _bp ) { return fprops_._add( _bp ); } + size_t _add_mprop( BaseProperty* _bp ) { return mprops_._add( _bp ); } + +protected: // low-level access non-public + + BaseProperty& _vprop( BaseHandle _h ) + { return vprops_._property( _h.idx() ); } + BaseProperty& _eprop( BaseHandle _h ) + { return eprops_._property( _h.idx() ); } + BaseProperty& _hprop( BaseHandle _h ) + { return hprops_._property( _h.idx() ); } + BaseProperty& _fprop( BaseHandle _h ) + { return fprops_._property( _h.idx() ); } + BaseProperty& _mprop( BaseHandle _h ) + { return mprops_._property( _h.idx() ); } + + const BaseProperty& _vprop( BaseHandle _h ) const + { return vprops_._property( _h.idx() ); } + const BaseProperty& _eprop( BaseHandle _h ) const + { return eprops_._property( _h.idx() ); } + const BaseProperty& _hprop( BaseHandle _h ) const + { return hprops_._property( _h.idx() ); } + const BaseProperty& _fprop( BaseHandle _h ) const + { return fprops_._property( _h.idx() ); } + const BaseProperty& _mprop( BaseHandle _h ) const + { return mprops_._property( _h.idx() ); } + + +public: //----------------------------------------------------- element numbers + + + virtual unsigned int n_vertices() const { return 0; } + virtual unsigned int n_halfedges() const { return 0; } + virtual unsigned int n_edges() const { return 0; } + virtual unsigned int n_faces() const { return 0; } + + +protected: //------------------------------------------- synchronize properties + + void vprops_reserve(unsigned int _n) const { vprops_.reserve(_n); } + void vprops_resize(unsigned int _n) const { vprops_.resize(_n); } + void vprops_swap(unsigned int _i0, unsigned int _i1) const { + vprops_.swap(_i0, _i1); + } + + void hprops_reserve(unsigned int _n) const { hprops_.reserve(_n); } + void hprops_resize(unsigned int _n) const { hprops_.resize(_n); } + void hprops_swap(unsigned int _i0, unsigned int _i1) const { + hprops_.swap(_i0, _i1); + } + + void eprops_reserve(unsigned int _n) const { eprops_.reserve(_n); } + void eprops_resize(unsigned int _n) const { eprops_.resize(_n); } + void eprops_swap(unsigned int _i0, unsigned int _i1) const { + eprops_.swap(_i0, _i1); + } + + void fprops_reserve(unsigned int _n) const { fprops_.reserve(_n); } + void fprops_resize(unsigned int _n) const { fprops_.resize(_n); } + void fprops_swap(unsigned int _i0, unsigned int _i1) const { + fprops_.swap(_i0, _i1); + } + + void mprops_resize(unsigned int _n) const { mprops_.resize(_n); } + +public: + + void property_stats(std::ostream& _ostr = std::clog) const; + +public: + + typedef PropertyContainer::iterator prop_iterator; + typedef PropertyContainer::const_iterator const_prop_iterator; + + prop_iterator vprops_begin() { return vprops_.begin(); } + prop_iterator vprops_end() { return vprops_.end(); } + const_prop_iterator vprops_begin() const { return vprops_.begin(); } + const_prop_iterator vprops_end() const { return vprops_.end(); } + + prop_iterator eprops_begin() { return eprops_.begin(); } + prop_iterator eprops_end() { return eprops_.end(); } + const_prop_iterator eprops_begin() const { return eprops_.begin(); } + const_prop_iterator eprops_end() const { return eprops_.end(); } + + prop_iterator hprops_begin() { return hprops_.begin(); } + prop_iterator hprops_end() { return hprops_.end(); } + const_prop_iterator hprops_begin() const { return hprops_.begin(); } + const_prop_iterator hprops_end() const { return hprops_.end(); } + + prop_iterator fprops_begin() { return fprops_.begin(); } + prop_iterator fprops_end() { return fprops_.end(); } + const_prop_iterator fprops_begin() const { return fprops_.begin(); } + const_prop_iterator fprops_end() const { return fprops_.end(); } + + prop_iterator mprops_begin() { return mprops_.begin(); } + prop_iterator mprops_end() { return mprops_.end(); } + const_prop_iterator mprops_begin() const { return mprops_.begin(); } + const_prop_iterator mprops_end() const { return mprops_.end(); } + +private: + + PropertyContainer vprops_; + PropertyContainer hprops_; + PropertyContainer eprops_; + PropertyContainer fprops_; + PropertyContainer mprops_; +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_BASE_KERNEL_HH defined +//============================================================================= diff --git a/Core/Mesh/BaseMesh.hh b/Core/Mesh/BaseMesh.hh new file mode 100644 index 00000000..9dc136fd --- /dev/null +++ b/Core/Mesh/BaseMesh.hh @@ -0,0 +1,79 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// CLASS BaseMesh +// +//============================================================================= + + +#ifndef OPENMESH_BASEMESH_HH +#define OPENMESH_BASEMESH_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** \class BaseMesh BaseMesh.hh + + Base class for all meshes. +*/ + +class BaseMesh { +public: + virtual ~BaseMesh(void) {;} +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + +//============================================================================= +#endif // OPENMESH_BASEMESH_HH defined +//============================================================================= diff --git a/Core/Mesh/Casts.hh b/Core/Mesh/Casts.hh new file mode 100644 index 00000000..8b54bdbf --- /dev/null +++ b/Core/Mesh/Casts.hh @@ -0,0 +1,54 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2004 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. * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_CASTS_HH +#define OPENMESH_CASTS_HH +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACES =============================================================== +namespace OpenMesh +{ + +template +inline TriMesh_ArrayKernelT& TRIMESH_CAST(PolyMesh_ArrayKernelT& _poly_mesh) +{ return reinterpret_cast< TriMesh_ArrayKernelT& >(_poly_mesh); } + +template +inline const TriMesh_ArrayKernelT& TRIMESH_CAST(const PolyMesh_ArrayKernelT& _poly_mesh) +{ return reinterpret_cast< const TriMesh_ArrayKernelT& >(_poly_mesh); } + +template +inline PolyMesh_ArrayKernelT& POLYMESH_CAST(TriMesh_ArrayKernelT& _tri_mesh) +{ return reinterpret_cast< PolyMesh_ArrayKernelT& >(_tri_mesh); } + +template +inline const PolyMesh_ArrayKernelT& POLYMESH_CAST(const TriMesh_ArrayKernelT& _tri_mesh) +{ return reinterpret_cast< const PolyMesh_ArrayKernelT& >(_tri_mesh); } + +}; +#endif//OPENMESH_CASTS_HH diff --git a/Core/Mesh/CirculatorsT.hh b/Core/Mesh/CirculatorsT.hh new file mode 100644 index 00000000..552eeda9 --- /dev/null +++ b/Core/Mesh/CirculatorsT.hh @@ -0,0 +1,3499 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ +#ifndef OPENMESH_CIRCULATORS_HH +#define OPENMESH_CIRCULATORS_HH +//============================================================================= +// +// Vertex and Face circulators for PolyMesh/TriMesh +// +//============================================================================= + + + +//== INCLUDES ================================================================= + +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Iterators { + + +//== FORWARD DECLARATIONS ===================================================== + + +template class VertexVertexIterT; +template class VertexIHalfedgeIterT; +template class VertexOHalfedgeIterT; +template class VertexEdgeIterT; +template class VertexFaceIterT; + +template class ConstVertexVertexIterT; +template class ConstVertexIHalfedgeIterT; +template class ConstVertexOHalfedgeIterT; +template class ConstVertexEdgeIterT; +template class ConstVertexFaceIterT; + +template class FaceVertexIterT; +template class FaceHalfedgeIterT; +template class FaceEdgeIterT; +template class FaceFaceIterT; + +template class ConstFaceVertexIterT; +template class ConstFaceHalfedgeIterT; +template class ConstFaceEdgeIterT; +template class ConstFaceFaceIterT; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class VertexVertexIterT CirculatorsT.hh + Circulator. +*/ + +template +class VertexVertexIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Vertex value_type; + typedef typename Mesh::VertexHandle value_handle; + +#if 0 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Vertex& reference; + typedef const typename Mesh::Vertex* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Vertex& reference; + typedef typename Mesh::Vertex* pointer; +#endif + + + + /// Default constructor + VertexVertexIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::VertexHandle + VertexVertexIterT(mesh_ref _mesh, typename Mesh::VertexHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { ; } + + + /// Construct with mesh and start halfedge + VertexVertexIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { ; } + + + /// Copy constructor + VertexVertexIterT(const VertexVertexIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// Assignment operator + VertexVertexIterT& operator=(const VertexVertexIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 0 + /// construct from non-const circulator type + VertexVertexIterT(const VertexVertexIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// assign from non-const circulator + VertexVertexIterT& operator=(const VertexVertexIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstVertexVertexIterT; +#endif + + + /// Equal ? + bool operator==(const VertexVertexIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const VertexVertexIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + VertexVertexIterT& operator++() { + assert(mesh_); + active_ = true; + heh_=mesh_->cw_rotated_halfedge_handle(heh_);; + return *this; + } + + + /// Pre-Decrement (next ccw target) + VertexVertexIterT& operator--() { + assert(mesh_); + active_ = true; + heh_=mesh_->ccw_rotated_halfedge_handle(heh_);; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::VertexHandle handle() const { + assert(mesh_); + return mesh_->to_vertex_handle(heh_);; + } + + + /// Cast to the handle of the current target. + operator typename Mesh::VertexHandle() const { + assert(mesh_); + return mesh_->to_vertex_handle(heh_);; + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class ConstVertexVertexIterT CirculatorsT.hh + Circulator. +*/ + +template +class ConstVertexVertexIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Vertex value_type; + typedef typename Mesh::VertexHandle value_handle; + +#if 1 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Vertex& reference; + typedef const typename Mesh::Vertex* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Vertex& reference; + typedef typename Mesh::Vertex* pointer; +#endif + + + + /// Default constructor + ConstVertexVertexIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::VertexHandle + ConstVertexVertexIterT(mesh_ref _mesh, typename Mesh::VertexHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { ; } + + + /// Construct with mesh and start halfedge + ConstVertexVertexIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { ; } + + + /// Copy constructor + ConstVertexVertexIterT(const ConstVertexVertexIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// Assignment operator + ConstVertexVertexIterT& operator=(const ConstVertexVertexIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 1 + /// construct from non-const circulator type + ConstVertexVertexIterT(const VertexVertexIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// assign from non-const circulator + ConstVertexVertexIterT& operator=(const VertexVertexIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstVertexVertexIterT; +#endif + + + /// Equal ? + bool operator==(const ConstVertexVertexIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const ConstVertexVertexIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + ConstVertexVertexIterT& operator++() { + assert(mesh_); + active_ = true; + heh_=mesh_->cw_rotated_halfedge_handle(heh_);; + return *this; + } + + + /// Pre-Decrement (next ccw target) + ConstVertexVertexIterT& operator--() { + assert(mesh_); + active_ = true; + heh_=mesh_->ccw_rotated_halfedge_handle(heh_);; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::VertexHandle handle() const { + assert(mesh_); + return mesh_->to_vertex_handle(heh_);; + } + + + /// Cast to the handle of the current target. + operator typename Mesh::VertexHandle() const { + assert(mesh_); + return mesh_->to_vertex_handle(heh_);; + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class VertexOHalfedgeIterT CirculatorsT.hh + Circulator. +*/ + +template +class VertexOHalfedgeIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Halfedge value_type; + typedef typename Mesh::HalfedgeHandle value_handle; + +#if 0 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Halfedge& reference; + typedef const typename Mesh::Halfedge* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Halfedge& reference; + typedef typename Mesh::Halfedge* pointer; +#endif + + + + /// Default constructor + VertexOHalfedgeIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::VertexHandle + VertexOHalfedgeIterT(mesh_ref _mesh, typename Mesh::VertexHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { ; } + + + /// Construct with mesh and start halfedge + VertexOHalfedgeIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { ; } + + + /// Copy constructor + VertexOHalfedgeIterT(const VertexOHalfedgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// Assignment operator + VertexOHalfedgeIterT& operator=(const VertexOHalfedgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 0 + /// construct from non-const circulator type + VertexOHalfedgeIterT(const VertexOHalfedgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// assign from non-const circulator + VertexOHalfedgeIterT& operator=(const VertexOHalfedgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstVertexOHalfedgeIterT; +#endif + + + /// Equal ? + bool operator==(const VertexOHalfedgeIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const VertexOHalfedgeIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + VertexOHalfedgeIterT& operator++() { + assert(mesh_); + active_ = true; + heh_=mesh_->cw_rotated_halfedge_handle(heh_);; + return *this; + } + + + /// Pre-Decrement (next ccw target) + VertexOHalfedgeIterT& operator--() { + assert(mesh_); + active_ = true; + heh_=mesh_->ccw_rotated_halfedge_handle(heh_);; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::HalfedgeHandle handle() const { + assert(mesh_); + return heh_; + } + + + /// Cast to the handle of the current target. + operator typename Mesh::HalfedgeHandle() const { + assert(mesh_); + return heh_; + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class ConstVertexOHalfedgeIterT CirculatorsT.hh + Circulator. +*/ + +template +class ConstVertexOHalfedgeIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Halfedge value_type; + typedef typename Mesh::HalfedgeHandle value_handle; + +#if 1 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Halfedge& reference; + typedef const typename Mesh::Halfedge* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Halfedge& reference; + typedef typename Mesh::Halfedge* pointer; +#endif + + + + /// Default constructor + ConstVertexOHalfedgeIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::VertexHandle + ConstVertexOHalfedgeIterT(mesh_ref _mesh, typename Mesh::VertexHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { ; } + + + /// Construct with mesh and start halfedge + ConstVertexOHalfedgeIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { ; } + + + /// Copy constructor + ConstVertexOHalfedgeIterT(const ConstVertexOHalfedgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// Assignment operator + ConstVertexOHalfedgeIterT& operator=(const ConstVertexOHalfedgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 1 + /// construct from non-const circulator type + ConstVertexOHalfedgeIterT(const VertexOHalfedgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// assign from non-const circulator + ConstVertexOHalfedgeIterT& operator=(const VertexOHalfedgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstVertexOHalfedgeIterT; +#endif + + + /// Equal ? + bool operator==(const ConstVertexOHalfedgeIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const ConstVertexOHalfedgeIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + ConstVertexOHalfedgeIterT& operator++() { + assert(mesh_); + active_ = true; + heh_=mesh_->cw_rotated_halfedge_handle(heh_);; + return *this; + } + + + /// Pre-Decrement (next ccw target) + ConstVertexOHalfedgeIterT& operator--() { + assert(mesh_); + active_ = true; + heh_=mesh_->ccw_rotated_halfedge_handle(heh_);; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::HalfedgeHandle handle() const { + assert(mesh_); + return heh_; + } + + + /// Cast to the handle of the current target. + operator typename Mesh::HalfedgeHandle() const { + assert(mesh_); + return heh_; + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class VertexIHalfedgeIterT CirculatorsT.hh + Circulator. +*/ + +template +class VertexIHalfedgeIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Halfedge value_type; + typedef typename Mesh::HalfedgeHandle value_handle; + +#if 0 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Halfedge& reference; + typedef const typename Mesh::Halfedge* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Halfedge& reference; + typedef typename Mesh::Halfedge* pointer; +#endif + + + + /// Default constructor + VertexIHalfedgeIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::VertexHandle + VertexIHalfedgeIterT(mesh_ref _mesh, typename Mesh::VertexHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { ; } + + + /// Construct with mesh and start halfedge + VertexIHalfedgeIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { ; } + + + /// Copy constructor + VertexIHalfedgeIterT(const VertexIHalfedgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// Assignment operator + VertexIHalfedgeIterT& operator=(const VertexIHalfedgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 0 + /// construct from non-const circulator type + VertexIHalfedgeIterT(const VertexIHalfedgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// assign from non-const circulator + VertexIHalfedgeIterT& operator=(const VertexIHalfedgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstVertexIHalfedgeIterT; +#endif + + + /// Equal ? + bool operator==(const VertexIHalfedgeIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const VertexIHalfedgeIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + VertexIHalfedgeIterT& operator++() { + assert(mesh_); + active_ = true; + heh_=mesh_->cw_rotated_halfedge_handle(heh_);; + return *this; + } + + + /// Pre-Decrement (next ccw target) + VertexIHalfedgeIterT& operator--() { + assert(mesh_); + active_ = true; + heh_=mesh_->ccw_rotated_halfedge_handle(heh_);; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::HalfedgeHandle handle() const { + assert(mesh_); + return mesh_->opposite_halfedge_handle(heh_); + } + + + /// Cast to the handle of the current target. + operator typename Mesh::HalfedgeHandle() const { + assert(mesh_); + return mesh_->opposite_halfedge_handle(heh_); + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class ConstVertexIHalfedgeIterT CirculatorsT.hh + Circulator. +*/ + +template +class ConstVertexIHalfedgeIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Halfedge value_type; + typedef typename Mesh::HalfedgeHandle value_handle; + +#if 1 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Halfedge& reference; + typedef const typename Mesh::Halfedge* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Halfedge& reference; + typedef typename Mesh::Halfedge* pointer; +#endif + + + + /// Default constructor + ConstVertexIHalfedgeIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::VertexHandle + ConstVertexIHalfedgeIterT(mesh_ref _mesh, typename Mesh::VertexHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { ; } + + + /// Construct with mesh and start halfedge + ConstVertexIHalfedgeIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { ; } + + + /// Copy constructor + ConstVertexIHalfedgeIterT(const ConstVertexIHalfedgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// Assignment operator + ConstVertexIHalfedgeIterT& operator=(const ConstVertexIHalfedgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 1 + /// construct from non-const circulator type + ConstVertexIHalfedgeIterT(const VertexIHalfedgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// assign from non-const circulator + ConstVertexIHalfedgeIterT& operator=(const VertexIHalfedgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstVertexIHalfedgeIterT; +#endif + + + /// Equal ? + bool operator==(const ConstVertexIHalfedgeIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const ConstVertexIHalfedgeIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + ConstVertexIHalfedgeIterT& operator++() { + assert(mesh_); + active_ = true; + heh_=mesh_->cw_rotated_halfedge_handle(heh_);; + return *this; + } + + + /// Pre-Decrement (next ccw target) + ConstVertexIHalfedgeIterT& operator--() { + assert(mesh_); + active_ = true; + heh_=mesh_->ccw_rotated_halfedge_handle(heh_);; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::HalfedgeHandle handle() const { + assert(mesh_); + return mesh_->opposite_halfedge_handle(heh_); + } + + + /// Cast to the handle of the current target. + operator typename Mesh::HalfedgeHandle() const { + assert(mesh_); + return mesh_->opposite_halfedge_handle(heh_); + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class VertexEdgeIterT CirculatorsT.hh + Circulator. +*/ + +template +class VertexEdgeIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Edge value_type; + typedef typename Mesh::EdgeHandle value_handle; + +#if 0 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Edge& reference; + typedef const typename Mesh::Edge* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Edge& reference; + typedef typename Mesh::Edge* pointer; +#endif + + + + /// Default constructor + VertexEdgeIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::VertexHandle + VertexEdgeIterT(mesh_ref _mesh, typename Mesh::VertexHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { ; } + + + /// Construct with mesh and start halfedge + VertexEdgeIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { ; } + + + /// Copy constructor + VertexEdgeIterT(const VertexEdgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// Assignment operator + VertexEdgeIterT& operator=(const VertexEdgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 0 + /// construct from non-const circulator type + VertexEdgeIterT(const VertexEdgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// assign from non-const circulator + VertexEdgeIterT& operator=(const VertexEdgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstVertexEdgeIterT; +#endif + + + /// Equal ? + bool operator==(const VertexEdgeIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const VertexEdgeIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + VertexEdgeIterT& operator++() { + assert(mesh_); + active_ = true; + heh_=mesh_->cw_rotated_halfedge_handle(heh_);; + return *this; + } + + + /// Pre-Decrement (next ccw target) + VertexEdgeIterT& operator--() { + assert(mesh_); + active_ = true; + heh_=mesh_->ccw_rotated_halfedge_handle(heh_);; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::EdgeHandle handle() const { + assert(mesh_); + return mesh_->edge_handle(heh_); + } + + + /// Cast to the handle of the current target. + operator typename Mesh::EdgeHandle() const { + assert(mesh_); + return mesh_->edge_handle(heh_); + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class ConstVertexEdgeIterT CirculatorsT.hh + Circulator. +*/ + +template +class ConstVertexEdgeIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Edge value_type; + typedef typename Mesh::EdgeHandle value_handle; + +#if 1 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Edge& reference; + typedef const typename Mesh::Edge* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Edge& reference; + typedef typename Mesh::Edge* pointer; +#endif + + + + /// Default constructor + ConstVertexEdgeIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::VertexHandle + ConstVertexEdgeIterT(mesh_ref _mesh, typename Mesh::VertexHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { ; } + + + /// Construct with mesh and start halfedge + ConstVertexEdgeIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { ; } + + + /// Copy constructor + ConstVertexEdgeIterT(const ConstVertexEdgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// Assignment operator + ConstVertexEdgeIterT& operator=(const ConstVertexEdgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 1 + /// construct from non-const circulator type + ConstVertexEdgeIterT(const VertexEdgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// assign from non-const circulator + ConstVertexEdgeIterT& operator=(const VertexEdgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstVertexEdgeIterT; +#endif + + + /// Equal ? + bool operator==(const ConstVertexEdgeIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const ConstVertexEdgeIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + ConstVertexEdgeIterT& operator++() { + assert(mesh_); + active_ = true; + heh_=mesh_->cw_rotated_halfedge_handle(heh_);; + return *this; + } + + + /// Pre-Decrement (next ccw target) + ConstVertexEdgeIterT& operator--() { + assert(mesh_); + active_ = true; + heh_=mesh_->ccw_rotated_halfedge_handle(heh_);; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::EdgeHandle handle() const { + assert(mesh_); + return mesh_->edge_handle(heh_); + } + + + /// Cast to the handle of the current target. + operator typename Mesh::EdgeHandle() const { + assert(mesh_); + return mesh_->edge_handle(heh_); + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class VertexFaceIterT CirculatorsT.hh + Circulator. +*/ + +template +class VertexFaceIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Face value_type; + typedef typename Mesh::FaceHandle value_handle; + +#if 0 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Face& reference; + typedef const typename Mesh::Face* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Face& reference; + typedef typename Mesh::Face* pointer; +#endif + + + + /// Default constructor + VertexFaceIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::VertexHandle + VertexFaceIterT(mesh_ref _mesh, typename Mesh::VertexHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { if (heh_.is_valid() && !handle().is_valid()) operator++();; } + + + /// Construct with mesh and start halfedge + VertexFaceIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { if (heh_.is_valid() && !handle().is_valid()) operator++();; } + + + /// Copy constructor + VertexFaceIterT(const VertexFaceIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { if (heh_.is_valid() && !handle().is_valid()) operator++();; } + + + /// Assignment operator + VertexFaceIterT& operator=(const VertexFaceIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 0 + /// construct from non-const circulator type + VertexFaceIterT(const VertexFaceIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { if (heh_.is_valid() && !handle().is_valid()) operator++();; } + + + /// assign from non-const circulator + VertexFaceIterT& operator=(const VertexFaceIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstVertexFaceIterT; +#endif + + + /// Equal ? + bool operator==(const VertexFaceIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const VertexFaceIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + VertexFaceIterT& operator++() { + assert(mesh_); + active_ = true; + do heh_=mesh_->cw_rotated_halfedge_handle(heh_); while ((*this) && (!handle().is_valid()));; + return *this; + } + + + /// Pre-Decrement (next ccw target) + VertexFaceIterT& operator--() { + assert(mesh_); + active_ = true; + do heh_=mesh_->ccw_rotated_halfedge_handle(heh_); while ((*this) && (!handle().is_valid()));; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::FaceHandle handle() const { + assert(mesh_); + return mesh_->face_handle(heh_); + } + + + /// Cast to the handle of the current target. + operator typename Mesh::FaceHandle() const { + assert(mesh_); + return mesh_->face_handle(heh_); + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class ConstVertexFaceIterT CirculatorsT.hh + Circulator. +*/ + +template +class ConstVertexFaceIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Face value_type; + typedef typename Mesh::FaceHandle value_handle; + +#if 1 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Face& reference; + typedef const typename Mesh::Face* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Face& reference; + typedef typename Mesh::Face* pointer; +#endif + + + + /// Default constructor + ConstVertexFaceIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::VertexHandle + ConstVertexFaceIterT(mesh_ref _mesh, typename Mesh::VertexHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { if (heh_.is_valid() && !handle().is_valid()) operator++();; } + + + /// Construct with mesh and start halfedge + ConstVertexFaceIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { if (heh_.is_valid() && !handle().is_valid()) operator++();; } + + + /// Copy constructor + ConstVertexFaceIterT(const ConstVertexFaceIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { if (heh_.is_valid() && !handle().is_valid()) operator++();; } + + + /// Assignment operator + ConstVertexFaceIterT& operator=(const ConstVertexFaceIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 1 + /// construct from non-const circulator type + ConstVertexFaceIterT(const VertexFaceIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { if (heh_.is_valid() && !handle().is_valid()) operator++();; } + + + /// assign from non-const circulator + ConstVertexFaceIterT& operator=(const VertexFaceIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstVertexFaceIterT; +#endif + + + /// Equal ? + bool operator==(const ConstVertexFaceIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const ConstVertexFaceIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + ConstVertexFaceIterT& operator++() { + assert(mesh_); + active_ = true; + do heh_=mesh_->cw_rotated_halfedge_handle(heh_); while ((*this) && (!handle().is_valid()));; + return *this; + } + + + /// Pre-Decrement (next ccw target) + ConstVertexFaceIterT& operator--() { + assert(mesh_); + active_ = true; + do heh_=mesh_->ccw_rotated_halfedge_handle(heh_); while ((*this) && (!handle().is_valid()));; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::FaceHandle handle() const { + assert(mesh_); + return mesh_->face_handle(heh_); + } + + + /// Cast to the handle of the current target. + operator typename Mesh::FaceHandle() const { + assert(mesh_); + return mesh_->face_handle(heh_); + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class FaceVertexIterT CirculatorsT.hh + Circulator. +*/ + +template +class FaceVertexIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Vertex value_type; + typedef typename Mesh::VertexHandle value_handle; + +#if 0 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Vertex& reference; + typedef const typename Mesh::Vertex* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Vertex& reference; + typedef typename Mesh::Vertex* pointer; +#endif + + + + /// Default constructor + FaceVertexIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::FaceHandle + FaceVertexIterT(mesh_ref _mesh, typename Mesh::FaceHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { ; } + + + /// Construct with mesh and start halfedge + FaceVertexIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { ; } + + + /// Copy constructor + FaceVertexIterT(const FaceVertexIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// Assignment operator + FaceVertexIterT& operator=(const FaceVertexIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 0 + /// construct from non-const circulator type + FaceVertexIterT(const FaceVertexIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// assign from non-const circulator + FaceVertexIterT& operator=(const FaceVertexIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstFaceVertexIterT; +#endif + + + /// Equal ? + bool operator==(const FaceVertexIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const FaceVertexIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + FaceVertexIterT& operator++() { + assert(mesh_); + active_ = true; + heh_=mesh_->next_halfedge_handle(heh_);; + return *this; + } + + + /// Pre-Decrement (next ccw target) + FaceVertexIterT& operator--() { + assert(mesh_); + active_ = true; + heh_=mesh_->prev_halfedge_handle(heh_);; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::VertexHandle handle() const { + assert(mesh_); + return mesh_->to_vertex_handle(heh_); + } + + + /// Cast to the handle of the current target. + operator typename Mesh::VertexHandle() const { + assert(mesh_); + return mesh_->to_vertex_handle(heh_); + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class ConstFaceVertexIterT CirculatorsT.hh + Circulator. +*/ + +template +class ConstFaceVertexIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Vertex value_type; + typedef typename Mesh::VertexHandle value_handle; + +#if 1 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Vertex& reference; + typedef const typename Mesh::Vertex* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Vertex& reference; + typedef typename Mesh::Vertex* pointer; +#endif + + + + /// Default constructor + ConstFaceVertexIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::FaceHandle + ConstFaceVertexIterT(mesh_ref _mesh, typename Mesh::FaceHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { ; } + + + /// Construct with mesh and start halfedge + ConstFaceVertexIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { ; } + + + /// Copy constructor + ConstFaceVertexIterT(const ConstFaceVertexIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// Assignment operator + ConstFaceVertexIterT& operator=(const ConstFaceVertexIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 1 + /// construct from non-const circulator type + ConstFaceVertexIterT(const FaceVertexIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// assign from non-const circulator + ConstFaceVertexIterT& operator=(const FaceVertexIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstFaceVertexIterT; +#endif + + + /// Equal ? + bool operator==(const ConstFaceVertexIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const ConstFaceVertexIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + ConstFaceVertexIterT& operator++() { + assert(mesh_); + active_ = true; + heh_=mesh_->next_halfedge_handle(heh_);; + return *this; + } + + + /// Pre-Decrement (next ccw target) + ConstFaceVertexIterT& operator--() { + assert(mesh_); + active_ = true; + heh_=mesh_->prev_halfedge_handle(heh_);; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::VertexHandle handle() const { + assert(mesh_); + return mesh_->to_vertex_handle(heh_); + } + + + /// Cast to the handle of the current target. + operator typename Mesh::VertexHandle() const { + assert(mesh_); + return mesh_->to_vertex_handle(heh_); + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class FaceHalfedgeIterT CirculatorsT.hh + Circulator. +*/ + +template +class FaceHalfedgeIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Halfedge value_type; + typedef typename Mesh::HalfedgeHandle value_handle; + +#if 0 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Halfedge& reference; + typedef const typename Mesh::Halfedge* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Halfedge& reference; + typedef typename Mesh::Halfedge* pointer; +#endif + + + + /// Default constructor + FaceHalfedgeIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::FaceHandle + FaceHalfedgeIterT(mesh_ref _mesh, typename Mesh::FaceHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { ; } + + + /// Construct with mesh and start halfedge + FaceHalfedgeIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { ; } + + + /// Copy constructor + FaceHalfedgeIterT(const FaceHalfedgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// Assignment operator + FaceHalfedgeIterT& operator=(const FaceHalfedgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 0 + /// construct from non-const circulator type + FaceHalfedgeIterT(const FaceHalfedgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// assign from non-const circulator + FaceHalfedgeIterT& operator=(const FaceHalfedgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstFaceHalfedgeIterT; +#endif + + + /// Equal ? + bool operator==(const FaceHalfedgeIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const FaceHalfedgeIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + FaceHalfedgeIterT& operator++() { + assert(mesh_); + active_ = true; + heh_=mesh_->next_halfedge_handle(heh_);; + return *this; + } + + + /// Pre-Decrement (next ccw target) + FaceHalfedgeIterT& operator--() { + assert(mesh_); + active_ = true; + heh_=mesh_->prev_halfedge_handle(heh_);; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::HalfedgeHandle handle() const { + assert(mesh_); + return heh_; + } + + + /// Cast to the handle of the current target. + operator typename Mesh::HalfedgeHandle() const { + assert(mesh_); + return heh_; + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class ConstFaceHalfedgeIterT CirculatorsT.hh + Circulator. +*/ + +template +class ConstFaceHalfedgeIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Halfedge value_type; + typedef typename Mesh::HalfedgeHandle value_handle; + +#if 1 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Halfedge& reference; + typedef const typename Mesh::Halfedge* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Halfedge& reference; + typedef typename Mesh::Halfedge* pointer; +#endif + + + + /// Default constructor + ConstFaceHalfedgeIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::FaceHandle + ConstFaceHalfedgeIterT(mesh_ref _mesh, typename Mesh::FaceHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { ; } + + + /// Construct with mesh and start halfedge + ConstFaceHalfedgeIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { ; } + + + /// Copy constructor + ConstFaceHalfedgeIterT(const ConstFaceHalfedgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// Assignment operator + ConstFaceHalfedgeIterT& operator=(const ConstFaceHalfedgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 1 + /// construct from non-const circulator type + ConstFaceHalfedgeIterT(const FaceHalfedgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// assign from non-const circulator + ConstFaceHalfedgeIterT& operator=(const FaceHalfedgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstFaceHalfedgeIterT; +#endif + + + /// Equal ? + bool operator==(const ConstFaceHalfedgeIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const ConstFaceHalfedgeIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + ConstFaceHalfedgeIterT& operator++() { + assert(mesh_); + active_ = true; + heh_=mesh_->next_halfedge_handle(heh_);; + return *this; + } + + + /// Pre-Decrement (next ccw target) + ConstFaceHalfedgeIterT& operator--() { + assert(mesh_); + active_ = true; + heh_=mesh_->prev_halfedge_handle(heh_);; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::HalfedgeHandle handle() const { + assert(mesh_); + return heh_; + } + + + /// Cast to the handle of the current target. + operator typename Mesh::HalfedgeHandle() const { + assert(mesh_); + return heh_; + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class FaceEdgeIterT CirculatorsT.hh + Circulator. +*/ + +template +class FaceEdgeIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Edge value_type; + typedef typename Mesh::EdgeHandle value_handle; + +#if 0 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Edge& reference; + typedef const typename Mesh::Edge* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Edge& reference; + typedef typename Mesh::Edge* pointer; +#endif + + + + /// Default constructor + FaceEdgeIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::FaceHandle + FaceEdgeIterT(mesh_ref _mesh, typename Mesh::FaceHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { ; } + + + /// Construct with mesh and start halfedge + FaceEdgeIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { ; } + + + /// Copy constructor + FaceEdgeIterT(const FaceEdgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// Assignment operator + FaceEdgeIterT& operator=(const FaceEdgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 0 + /// construct from non-const circulator type + FaceEdgeIterT(const FaceEdgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// assign from non-const circulator + FaceEdgeIterT& operator=(const FaceEdgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstFaceEdgeIterT; +#endif + + + /// Equal ? + bool operator==(const FaceEdgeIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const FaceEdgeIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + FaceEdgeIterT& operator++() { + assert(mesh_); + active_ = true; + heh_=mesh_->next_halfedge_handle(heh_);; + return *this; + } + + + /// Pre-Decrement (next ccw target) + FaceEdgeIterT& operator--() { + assert(mesh_); + active_ = true; + heh_=mesh_->prev_halfedge_handle(heh_);; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::EdgeHandle handle() const { + assert(mesh_); + return mesh_->edge_handle(heh_); + } + + + /// Cast to the handle of the current target. + operator typename Mesh::EdgeHandle() const { + assert(mesh_); + return mesh_->edge_handle(heh_); + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class ConstFaceEdgeIterT CirculatorsT.hh + Circulator. +*/ + +template +class ConstFaceEdgeIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Edge value_type; + typedef typename Mesh::EdgeHandle value_handle; + +#if 1 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Edge& reference; + typedef const typename Mesh::Edge* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Edge& reference; + typedef typename Mesh::Edge* pointer; +#endif + + + + /// Default constructor + ConstFaceEdgeIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::FaceHandle + ConstFaceEdgeIterT(mesh_ref _mesh, typename Mesh::FaceHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { ; } + + + /// Construct with mesh and start halfedge + ConstFaceEdgeIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { ; } + + + /// Copy constructor + ConstFaceEdgeIterT(const ConstFaceEdgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// Assignment operator + ConstFaceEdgeIterT& operator=(const ConstFaceEdgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 1 + /// construct from non-const circulator type + ConstFaceEdgeIterT(const FaceEdgeIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { ; } + + + /// assign from non-const circulator + ConstFaceEdgeIterT& operator=(const FaceEdgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstFaceEdgeIterT; +#endif + + + /// Equal ? + bool operator==(const ConstFaceEdgeIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const ConstFaceEdgeIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + ConstFaceEdgeIterT& operator++() { + assert(mesh_); + active_ = true; + heh_=mesh_->next_halfedge_handle(heh_);; + return *this; + } + + + /// Pre-Decrement (next ccw target) + ConstFaceEdgeIterT& operator--() { + assert(mesh_); + active_ = true; + heh_=mesh_->prev_halfedge_handle(heh_);; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::EdgeHandle handle() const { + assert(mesh_); + return mesh_->edge_handle(heh_); + } + + + /// Cast to the handle of the current target. + operator typename Mesh::EdgeHandle() const { + assert(mesh_); + return mesh_->edge_handle(heh_); + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class FaceFaceIterT CirculatorsT.hh + Circulator. +*/ + +template +class FaceFaceIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Face value_type; + typedef typename Mesh::FaceHandle value_handle; + +#if 0 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Face& reference; + typedef const typename Mesh::Face* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Face& reference; + typedef typename Mesh::Face* pointer; +#endif + + + + /// Default constructor + FaceFaceIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::FaceHandle + FaceFaceIterT(mesh_ref _mesh, typename Mesh::FaceHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { if (heh_.is_valid() && !handle().is_valid()) operator++();; } + + + /// Construct with mesh and start halfedge + FaceFaceIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { if (heh_.is_valid() && !handle().is_valid()) operator++();; } + + + /// Copy constructor + FaceFaceIterT(const FaceFaceIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { if (heh_.is_valid() && !handle().is_valid()) operator++();; } + + + /// Assignment operator + FaceFaceIterT& operator=(const FaceFaceIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 0 + /// construct from non-const circulator type + FaceFaceIterT(const FaceFaceIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { if (heh_.is_valid() && !handle().is_valid()) operator++();; } + + + /// assign from non-const circulator + FaceFaceIterT& operator=(const FaceFaceIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstFaceFaceIterT; +#endif + + + /// Equal ? + bool operator==(const FaceFaceIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const FaceFaceIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + FaceFaceIterT& operator++() { + assert(mesh_); + active_ = true; + do heh_=mesh_->next_halfedge_handle(heh_); while ((*this) && (!handle().is_valid()));; + return *this; + } + + + /// Pre-Decrement (next ccw target) + FaceFaceIterT& operator--() { + assert(mesh_); + active_ = true; + do heh_=mesh_->prev_halfedge_handle(heh_); while ((*this) && (!handle().is_valid()));; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::FaceHandle handle() const { + assert(mesh_); + return mesh_->face_handle(mesh_->opposite_halfedge_handle(heh_)); + } + + + /// Cast to the handle of the current target. + operator typename Mesh::FaceHandle() const { + assert(mesh_); + return mesh_->face_handle(mesh_->opposite_halfedge_handle(heh_)); + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +/** \class ConstFaceFaceIterT CirculatorsT.hh + Circulator. +*/ + +template +class ConstFaceFaceIterT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef typename Mesh::Face value_type; + typedef typename Mesh::FaceHandle value_handle; + +#if 1 + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const typename Mesh::Face& reference; + typedef const typename Mesh::Face* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef typename Mesh::Face& reference; + typedef typename Mesh::Face* pointer; +#endif + + + + /// Default constructor + ConstFaceFaceIterT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a typename Mesh::FaceHandle + ConstFaceFaceIterT(mesh_ref _mesh, typename Mesh::FaceHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { if (heh_.is_valid() && !handle().is_valid()) operator++();; } + + + /// Construct with mesh and start halfedge + ConstFaceFaceIterT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { if (heh_.is_valid() && !handle().is_valid()) operator++();; } + + + /// Copy constructor + ConstFaceFaceIterT(const ConstFaceFaceIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { if (heh_.is_valid() && !handle().is_valid()) operator++();; } + + + /// Assignment operator + ConstFaceFaceIterT& operator=(const ConstFaceFaceIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if 1 + /// construct from non-const circulator type + ConstFaceFaceIterT(const FaceFaceIterT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { if (heh_.is_valid() && !handle().is_valid()) operator++();; } + + + /// assign from non-const circulator + ConstFaceFaceIterT& operator=(const FaceFaceIterT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstFaceFaceIterT; +#endif + + + /// Equal ? + bool operator==(const ConstFaceFaceIterT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const ConstFaceFaceIterT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + ConstFaceFaceIterT& operator++() { + assert(mesh_); + active_ = true; + do heh_=mesh_->next_halfedge_handle(heh_); while ((*this) && (!handle().is_valid()));; + return *this; + } + + + /// Pre-Decrement (next ccw target) + ConstFaceFaceIterT& operator--() { + assert(mesh_); + active_ = true; + do heh_=mesh_->prev_halfedge_handle(heh_); while ((*this) && (!handle().is_valid()));; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + typename Mesh::FaceHandle handle() const { + assert(mesh_); + return mesh_->face_handle(mesh_->opposite_halfedge_handle(heh_)); + } + + + /// Cast to the handle of the current target. + operator typename Mesh::FaceHandle() const { + assert(mesh_); + return mesh_->face_handle(mesh_->opposite_halfedge_handle(heh_)); + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +protected: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + +//============================================================================= +} // namespace Iterators +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/Mesh/FinalMeshItemsT.hh b/Core/Mesh/FinalMeshItemsT.hh new file mode 100644 index 00000000..e1435b36 --- /dev/null +++ b/Core/Mesh/FinalMeshItemsT.hh @@ -0,0 +1,121 @@ +//============================================================================= +// +// 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: 3794 $ +// $Date: 2008-11-25 19:25:02 +0100 (Di, 25. Nov 2008) $ +// +//============================================================================= + +#ifndef OPENMESH_MESH_ITEMS_HH +#define OPENMESH_MESH_ITEMS_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + +/// Definition of the mesh entities (items). +template +struct FinalMeshItemsT +{ + //--- build Refs structure --- +#ifndef DOXY_IGNORE_THIS + struct Refs + { + typedef typename Traits::Point Point; + typedef typename vector_traits::value_type Scalar; + + typedef typename Traits::Normal Normal; + typedef typename Traits::Color Color; + typedef typename Traits::TexCoord1D TexCoord1D; + typedef typename Traits::TexCoord2D TexCoord2D; + typedef typename Traits::TexCoord3D TexCoord3D; + typedef typename Traits::TextureIndex TextureIndex; + typedef OpenMesh::VertexHandle VertexHandle; + typedef OpenMesh::FaceHandle FaceHandle; + typedef OpenMesh::EdgeHandle EdgeHandle; + typedef OpenMesh::HalfedgeHandle HalfedgeHandle; + }; +#endif + //--- export Refs types --- + typedef typename Refs::Point Point; + typedef typename Refs::Scalar Scalar; + typedef typename Refs::Normal Normal; + typedef typename Refs::Color Color; + typedef typename Refs::TexCoord1D TexCoord1D; + typedef typename Refs::TexCoord2D TexCoord2D; + typedef typename Refs::TexCoord3D TexCoord3D; + typedef typename Refs::TextureIndex TextureIndex; + + //--- get attribute bits from Traits --- + enum Attribs + { + VAttribs = Traits::VertexAttributes, + HAttribs = Traits::HalfedgeAttributes, + EAttribs = Traits::EdgeAttributes, + FAttribs = Traits::FaceAttributes + }; + //--- merge internal items with traits items --- + + +/* + typedef typename GenProg::IF< + (bool)(HAttribs & Attributes::PrevHalfedge), + typename InternalItems::Halfedge_with_prev, + typename InternalItems::Halfedge_without_prev + >::Result InternalHalfedge; +*/ + //typedef typename InternalItems::Vertex InternalVertex; + //typedef typename InternalItems::template Edge InternalEdge; + //typedef typename InternalItems::template Face InternalFace; + class ITraits + {}; + + typedef typename Traits::template VertexT VertexData; + typedef typename Traits::template HalfedgeT HalfedgeData; + typedef typename Traits::template EdgeT EdgeData; + typedef typename Traits::template FaceT FaceData; +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESH_ITEMS_HH defined +//============================================================================= + diff --git a/Core/Mesh/Handles.hh b/Core/Mesh/Handles.hh new file mode 100644 index 00000000..f8943692 --- /dev/null +++ b/Core/Mesh/Handles.hh @@ -0,0 +1,134 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + +#ifndef OPENMESH_HANDLES_HH +#define OPENMESH_HANDLES_HH + + +//== INCLUDES ================================================================= + +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + + +/// Base class for all handle types +class BaseHandle +{ +public: + + explicit BaseHandle(int _idx=-1) : idx_(_idx) {} + + /// Get the underlying index of this handle + int idx() const { return idx_; } + + /// The handle is valid iff the index is not equal to -1. + bool is_valid() const { return idx_ != -1; } + + /// reset handle to be invalid + void reset() { idx_=-1; } + /// reset handle to be invalid + void invalidate() { idx_ = -1; } + + bool operator==(const BaseHandle& _rhs) const { + return idx_ == _rhs.idx_; + } + + bool operator!=(const BaseHandle& _rhs) const { + return idx_ != _rhs.idx_; + } + + bool operator<(const BaseHandle& _rhs) const { + return idx_ < _rhs.idx_; + } + + + // this is to be used only by the iterators + void __increment() { ++idx_; } + void __decrement() { --idx_; } + + +private: + + int idx_; +}; + + +//----------------------------------------------------------------------------- + +/// Write handle \c _hnd to stream \c _os +inline std::ostream& operator<<(std::ostream& _os, const BaseHandle& _hnd) +{ + return (_os << _hnd.idx()); +} + + +//----------------------------------------------------------------------------- + + +/// Handle for a vertex entity +struct VertexHandle : public BaseHandle +{ + explicit VertexHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/// Handle for a halfedge entity +struct HalfedgeHandle : public BaseHandle +{ + explicit HalfedgeHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/// Handle for a edge entity +struct EdgeHandle : public BaseHandle +{ + explicit EdgeHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/// Handle for a face entity +struct FaceHandle : public BaseHandle +{ + explicit FaceHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_HANDLES_HH +//============================================================================= diff --git a/Core/Mesh/IteratorsT.hh b/Core/Mesh/IteratorsT.hh new file mode 100644 index 00000000..e2dd1add --- /dev/null +++ b/Core/Mesh/IteratorsT.hh @@ -0,0 +1,1364 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ +#ifndef OPENMESH_ITERATORS_HH +#define OPENMESH_ITERATORS_HH +//============================================================================= +// +// Iterators for PolyMesh/TriMesh +// +//============================================================================= + + + +//== INCLUDES ================================================================= + +#include +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Iterators { + + +//== FORWARD DECLARATIONS ===================================================== + + +template class VertexIterT; +template class ConstVertexIterT; +template class HalfedgeIterT; +template class ConstHalfedgeIterT; +template class EdgeIterT; +template class ConstEdgeIterT; +template class FaceIterT; +template class ConstFaceIterT; + + + + +//== CLASS DEFINITION ========================================================= + + +/** \class VertexIterT IteratorsT.hh + Linear iterator. +*/ + +template +class VertexIterT +{ +public: + + + //--- Typedefs --- + + typedef typename Mesh::Vertex value_type; + typedef typename Mesh::VertexHandle value_handle; + +#if 0 + typedef const value_type& reference; + typedef const value_type* pointer; + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; +#else + typedef value_type& reference; + typedef value_type* pointer; + typedef Mesh* mesh_ptr; + typedef Mesh& mesh_ref; +#endif + + + + + /// Default constructor. + VertexIterT() + : mesh_(0), skip_bits_(0) + {} + + + /// Construct with mesh and a target handle. + VertexIterT(mesh_ref _mesh, value_handle _hnd, bool _skip=false) + : mesh_(&_mesh), hnd_(_hnd), skip_bits_(0) + { + if (_skip) enable_skipping(); + } + + + /// Copy constructor + VertexIterT(const VertexIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment operator + VertexIterT& operator=(const VertexIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + + +#if 0 + + /// Construct from a non-const iterator + VertexIterT(const VertexIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment from non-const iterator + VertexIterT& operator=(const VertexIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + +#else + friend class ConstVertexIterT; +#endif + + + /// Standard dereferencing operator. + reference operator*() const { return mesh_->deref(hnd_); } + + /// Standard pointer operator. + pointer operator->() const { return &(mesh_->deref(hnd_)); } + + /// Get the handle of the item the iterator refers to. + value_handle handle() const { return hnd_; } + + /// Cast to the handle of the item the iterator refers to. + operator value_handle() const { return hnd_; } + + /// Are two iterators equal? Only valid if they refer to the same mesh! + bool operator==(const VertexIterT& _rhs) const + { return ((mesh_ == _rhs.mesh_) && (hnd_ == _rhs.hnd_)); } + + /// Not equal? + bool operator!=(const VertexIterT& _rhs) const + { return !operator==(_rhs); } + + /// Standard pre-increment operator + VertexIterT& operator++() + { hnd_.__increment(); if (skip_bits_) skip_fwd(); return *this; } + + /// Standard pre-decrement operator + VertexIterT& operator--() + { hnd_.__decrement(); if (skip_bits_) skip_bwd(); return *this; } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void enable_skipping() + { + if (mesh_ && mesh_->has_vertex_status()) + { + Attributes::StatusInfo status; + status.set_deleted(true); + status.set_hidden(true); + skip_bits_ = status.bits(); + skip_fwd(); + } + else skip_bits_ = 0; + } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void disable_skipping() { skip_bits_ = 0; } + + + +private: + + void skip_fwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() < (signed) mesh_->n_vertices()) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__increment(); + } + + + void skip_bwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() >= 0) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__decrement(); + } + + + +private: + mesh_ptr mesh_; + value_handle hnd_; + unsigned int skip_bits_; +}; + + +//== CLASS DEFINITION ========================================================= + + +/** \class ConstVertexIterT IteratorsT.hh + Linear iterator. +*/ + +template +class ConstVertexIterT +{ +public: + + + //--- Typedefs --- + + typedef typename Mesh::Vertex value_type; + typedef typename Mesh::VertexHandle value_handle; + +#if 1 + typedef const value_type& reference; + typedef const value_type* pointer; + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; +#else + typedef value_type& reference; + typedef value_type* pointer; + typedef Mesh* mesh_ptr; + typedef Mesh& mesh_ref; +#endif + + + + + /// Default constructor. + ConstVertexIterT() + : mesh_(0), skip_bits_(0) + {} + + + /// Construct with mesh and a target handle. + ConstVertexIterT(mesh_ref _mesh, value_handle _hnd, bool _skip=false) + : mesh_(&_mesh), hnd_(_hnd), skip_bits_(0) + { + if (_skip) enable_skipping(); + } + + + /// Copy constructor + ConstVertexIterT(const ConstVertexIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment operator + ConstVertexIterT& operator=(const ConstVertexIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + + +#if 1 + + /// Construct from a non-const iterator + ConstVertexIterT(const VertexIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment from non-const iterator + ConstVertexIterT& operator=(const VertexIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + +#else + friend class ConstVertexIterT; +#endif + + + /// Standard dereferencing operator. + reference operator*() const { return mesh_->deref(hnd_); } + + /// Standard pointer operator. + pointer operator->() const { return &(mesh_->deref(hnd_)); } + + /// Get the handle of the item the iterator refers to. + value_handle handle() const { return hnd_; } + + /// Cast to the handle of the item the iterator refers to. + operator value_handle() const { return hnd_; } + + /// Are two iterators equal? Only valid if they refer to the same mesh! + bool operator==(const ConstVertexIterT& _rhs) const + { return ((mesh_ == _rhs.mesh_) && (hnd_ == _rhs.hnd_)); } + + /// Not equal? + bool operator!=(const ConstVertexIterT& _rhs) const + { return !operator==(_rhs); } + + /// Standard pre-increment operator + ConstVertexIterT& operator++() + { hnd_.__increment(); if (skip_bits_) skip_fwd(); return *this; } + + /// Standard pre-decrement operator + ConstVertexIterT& operator--() + { hnd_.__decrement(); if (skip_bits_) skip_bwd(); return *this; } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void enable_skipping() + { + if (mesh_ && mesh_->has_vertex_status()) + { + Attributes::StatusInfo status; + status.set_deleted(true); + status.set_hidden(true); + skip_bits_ = status.bits(); + skip_fwd(); + } + else skip_bits_ = 0; + } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void disable_skipping() { skip_bits_ = 0; } + + + +private: + + void skip_fwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() < (signed) mesh_->n_vertices()) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__increment(); + } + + + void skip_bwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() >= 0) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__decrement(); + } + + + +private: + mesh_ptr mesh_; + value_handle hnd_; + unsigned int skip_bits_; +}; + + +//== CLASS DEFINITION ========================================================= + + +/** \class HalfedgeIterT IteratorsT.hh + Linear iterator. +*/ + +template +class HalfedgeIterT +{ +public: + + + //--- Typedefs --- + + typedef typename Mesh::Halfedge value_type; + typedef typename Mesh::HalfedgeHandle value_handle; + +#if 0 + typedef const value_type& reference; + typedef const value_type* pointer; + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; +#else + typedef value_type& reference; + typedef value_type* pointer; + typedef Mesh* mesh_ptr; + typedef Mesh& mesh_ref; +#endif + + + + + /// Default constructor. + HalfedgeIterT() + : mesh_(0), skip_bits_(0) + {} + + + /// Construct with mesh and a target handle. + HalfedgeIterT(mesh_ref _mesh, value_handle _hnd, bool _skip=false) + : mesh_(&_mesh), hnd_(_hnd), skip_bits_(0) + { + if (_skip) enable_skipping(); + } + + + /// Copy constructor + HalfedgeIterT(const HalfedgeIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment operator + HalfedgeIterT& operator=(const HalfedgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + + +#if 0 + + /// Construct from a non-const iterator + HalfedgeIterT(const HalfedgeIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment from non-const iterator + HalfedgeIterT& operator=(const HalfedgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + +#else + friend class ConstHalfedgeIterT; +#endif + + + /// Standard dereferencing operator. + reference operator*() const { return mesh_->deref(hnd_); } + + /// Standard pointer operator. + pointer operator->() const { return &(mesh_->deref(hnd_)); } + + /// Get the handle of the item the iterator refers to. + value_handle handle() const { return hnd_; } + + /// Cast to the handle of the item the iterator refers to. + operator value_handle() const { return hnd_; } + + /// Are two iterators equal? Only valid if they refer to the same mesh! + bool operator==(const HalfedgeIterT& _rhs) const + { return ((mesh_ == _rhs.mesh_) && (hnd_ == _rhs.hnd_)); } + + /// Not equal? + bool operator!=(const HalfedgeIterT& _rhs) const + { return !operator==(_rhs); } + + /// Standard pre-increment operator + HalfedgeIterT& operator++() + { hnd_.__increment(); if (skip_bits_) skip_fwd(); return *this; } + + /// Standard pre-decrement operator + HalfedgeIterT& operator--() + { hnd_.__decrement(); if (skip_bits_) skip_bwd(); return *this; } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void enable_skipping() + { + if (mesh_ && mesh_->has_halfedge_status()) + { + Attributes::StatusInfo status; + status.set_deleted(true); + status.set_hidden(true); + skip_bits_ = status.bits(); + skip_fwd(); + } + else skip_bits_ = 0; + } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void disable_skipping() { skip_bits_ = 0; } + + + +private: + + void skip_fwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() < (signed) mesh_->n_halfedges()) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__increment(); + } + + + void skip_bwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() >= 0) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__decrement(); + } + + + +private: + mesh_ptr mesh_; + value_handle hnd_; + unsigned int skip_bits_; +}; + + +//== CLASS DEFINITION ========================================================= + + +/** \class ConstHalfedgeIterT IteratorsT.hh + Linear iterator. +*/ + +template +class ConstHalfedgeIterT +{ +public: + + + //--- Typedefs --- + + typedef typename Mesh::Halfedge value_type; + typedef typename Mesh::HalfedgeHandle value_handle; + +#if 1 + typedef const value_type& reference; + typedef const value_type* pointer; + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; +#else + typedef value_type& reference; + typedef value_type* pointer; + typedef Mesh* mesh_ptr; + typedef Mesh& mesh_ref; +#endif + + + + + /// Default constructor. + ConstHalfedgeIterT() + : mesh_(0), skip_bits_(0) + {} + + + /// Construct with mesh and a target handle. + ConstHalfedgeIterT(mesh_ref _mesh, value_handle _hnd, bool _skip=false) + : mesh_(&_mesh), hnd_(_hnd), skip_bits_(0) + { + if (_skip) enable_skipping(); + } + + + /// Copy constructor + ConstHalfedgeIterT(const ConstHalfedgeIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment operator + ConstHalfedgeIterT& operator=(const ConstHalfedgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + + +#if 1 + + /// Construct from a non-const iterator + ConstHalfedgeIterT(const HalfedgeIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment from non-const iterator + ConstHalfedgeIterT& operator=(const HalfedgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + +#else + friend class ConstHalfedgeIterT; +#endif + + + /// Standard dereferencing operator. + reference operator*() const { return mesh_->deref(hnd_); } + + /// Standard pointer operator. + pointer operator->() const { return &(mesh_->deref(hnd_)); } + + /// Get the handle of the item the iterator refers to. + value_handle handle() const { return hnd_; } + + /// Cast to the handle of the item the iterator refers to. + operator value_handle() const { return hnd_; } + + /// Are two iterators equal? Only valid if they refer to the same mesh! + bool operator==(const ConstHalfedgeIterT& _rhs) const + { return ((mesh_ == _rhs.mesh_) && (hnd_ == _rhs.hnd_)); } + + /// Not equal? + bool operator!=(const ConstHalfedgeIterT& _rhs) const + { return !operator==(_rhs); } + + /// Standard pre-increment operator + ConstHalfedgeIterT& operator++() + { hnd_.__increment(); if (skip_bits_) skip_fwd(); return *this; } + + /// Standard pre-decrement operator + ConstHalfedgeIterT& operator--() + { hnd_.__decrement(); if (skip_bits_) skip_bwd(); return *this; } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void enable_skipping() + { + if (mesh_ && mesh_->has_halfedge_status()) + { + Attributes::StatusInfo status; + status.set_deleted(true); + status.set_hidden(true); + skip_bits_ = status.bits(); + skip_fwd(); + } + else skip_bits_ = 0; + } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void disable_skipping() { skip_bits_ = 0; } + + + +private: + + void skip_fwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() < (signed) mesh_->n_halfedges()) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__increment(); + } + + + void skip_bwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() >= 0) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__decrement(); + } + + + +private: + mesh_ptr mesh_; + value_handle hnd_; + unsigned int skip_bits_; +}; + + +//== CLASS DEFINITION ========================================================= + + +/** \class EdgeIterT IteratorsT.hh + Linear iterator. +*/ + +template +class EdgeIterT +{ +public: + + + //--- Typedefs --- + + typedef typename Mesh::Edge value_type; + typedef typename Mesh::EdgeHandle value_handle; + +#if 0 + typedef const value_type& reference; + typedef const value_type* pointer; + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; +#else + typedef value_type& reference; + typedef value_type* pointer; + typedef Mesh* mesh_ptr; + typedef Mesh& mesh_ref; +#endif + + + + + /// Default constructor. + EdgeIterT() + : mesh_(0), skip_bits_(0) + {} + + + /// Construct with mesh and a target handle. + EdgeIterT(mesh_ref _mesh, value_handle _hnd, bool _skip=false) + : mesh_(&_mesh), hnd_(_hnd), skip_bits_(0) + { + if (_skip) enable_skipping(); + } + + + /// Copy constructor + EdgeIterT(const EdgeIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment operator + EdgeIterT& operator=(const EdgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + + +#if 0 + + /// Construct from a non-const iterator + EdgeIterT(const EdgeIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment from non-const iterator + EdgeIterT& operator=(const EdgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + +#else + friend class ConstEdgeIterT; +#endif + + + /// Standard dereferencing operator. + reference operator*() const { return mesh_->deref(hnd_); } + + /// Standard pointer operator. + pointer operator->() const { return &(mesh_->deref(hnd_)); } + + /// Get the handle of the item the iterator refers to. + value_handle handle() const { return hnd_; } + + /// Cast to the handle of the item the iterator refers to. + operator value_handle() const { return hnd_; } + + /// Are two iterators equal? Only valid if they refer to the same mesh! + bool operator==(const EdgeIterT& _rhs) const + { return ((mesh_ == _rhs.mesh_) && (hnd_ == _rhs.hnd_)); } + + /// Not equal? + bool operator!=(const EdgeIterT& _rhs) const + { return !operator==(_rhs); } + + /// Standard pre-increment operator + EdgeIterT& operator++() + { hnd_.__increment(); if (skip_bits_) skip_fwd(); return *this; } + + /// Standard pre-decrement operator + EdgeIterT& operator--() + { hnd_.__decrement(); if (skip_bits_) skip_bwd(); return *this; } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void enable_skipping() + { + if (mesh_ && mesh_->has_edge_status()) + { + Attributes::StatusInfo status; + status.set_deleted(true); + status.set_hidden(true); + skip_bits_ = status.bits(); + skip_fwd(); + } + else skip_bits_ = 0; + } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void disable_skipping() { skip_bits_ = 0; } + + + +private: + + void skip_fwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() < (signed) mesh_->n_edges()) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__increment(); + } + + + void skip_bwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() >= 0) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__decrement(); + } + + + +private: + mesh_ptr mesh_; + value_handle hnd_; + unsigned int skip_bits_; +}; + + +//== CLASS DEFINITION ========================================================= + + +/** \class ConstEdgeIterT IteratorsT.hh + Linear iterator. +*/ + +template +class ConstEdgeIterT +{ +public: + + + //--- Typedefs --- + + typedef typename Mesh::Edge value_type; + typedef typename Mesh::EdgeHandle value_handle; + +#if 1 + typedef const value_type& reference; + typedef const value_type* pointer; + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; +#else + typedef value_type& reference; + typedef value_type* pointer; + typedef Mesh* mesh_ptr; + typedef Mesh& mesh_ref; +#endif + + + + + /// Default constructor. + ConstEdgeIterT() + : mesh_(0), skip_bits_(0) + {} + + + /// Construct with mesh and a target handle. + ConstEdgeIterT(mesh_ref _mesh, value_handle _hnd, bool _skip=false) + : mesh_(&_mesh), hnd_(_hnd), skip_bits_(0) + { + if (_skip) enable_skipping(); + } + + + /// Copy constructor + ConstEdgeIterT(const ConstEdgeIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment operator + ConstEdgeIterT& operator=(const ConstEdgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + + +#if 1 + + /// Construct from a non-const iterator + ConstEdgeIterT(const EdgeIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment from non-const iterator + ConstEdgeIterT& operator=(const EdgeIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + +#else + friend class ConstEdgeIterT; +#endif + + + /// Standard dereferencing operator. + reference operator*() const { return mesh_->deref(hnd_); } + + /// Standard pointer operator. + pointer operator->() const { return &(mesh_->deref(hnd_)); } + + /// Get the handle of the item the iterator refers to. + value_handle handle() const { return hnd_; } + + /// Cast to the handle of the item the iterator refers to. + operator value_handle() const { return hnd_; } + + /// Are two iterators equal? Only valid if they refer to the same mesh! + bool operator==(const ConstEdgeIterT& _rhs) const + { return ((mesh_ == _rhs.mesh_) && (hnd_ == _rhs.hnd_)); } + + /// Not equal? + bool operator!=(const ConstEdgeIterT& _rhs) const + { return !operator==(_rhs); } + + /// Standard pre-increment operator + ConstEdgeIterT& operator++() + { hnd_.__increment(); if (skip_bits_) skip_fwd(); return *this; } + + /// Standard pre-decrement operator + ConstEdgeIterT& operator--() + { hnd_.__decrement(); if (skip_bits_) skip_bwd(); return *this; } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void enable_skipping() + { + if (mesh_ && mesh_->has_edge_status()) + { + Attributes::StatusInfo status; + status.set_deleted(true); + status.set_hidden(true); + skip_bits_ = status.bits(); + skip_fwd(); + } + else skip_bits_ = 0; + } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void disable_skipping() { skip_bits_ = 0; } + + + +private: + + void skip_fwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() < (signed) mesh_->n_edges()) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__increment(); + } + + + void skip_bwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() >= 0) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__decrement(); + } + + + +private: + mesh_ptr mesh_; + value_handle hnd_; + unsigned int skip_bits_; +}; + + +//== CLASS DEFINITION ========================================================= + + +/** \class FaceIterT IteratorsT.hh + Linear iterator. +*/ + +template +class FaceIterT +{ +public: + + + //--- Typedefs --- + + typedef typename Mesh::Face value_type; + typedef typename Mesh::FaceHandle value_handle; + +#if 0 + typedef const value_type& reference; + typedef const value_type* pointer; + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; +#else + typedef value_type& reference; + typedef value_type* pointer; + typedef Mesh* mesh_ptr; + typedef Mesh& mesh_ref; +#endif + + + + + /// Default constructor. + FaceIterT() + : mesh_(0), skip_bits_(0) + {} + + + /// Construct with mesh and a target handle. + FaceIterT(mesh_ref _mesh, value_handle _hnd, bool _skip=false) + : mesh_(&_mesh), hnd_(_hnd), skip_bits_(0) + { + if (_skip) enable_skipping(); + } + + + /// Copy constructor + FaceIterT(const FaceIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment operator + FaceIterT& operator=(const FaceIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + + +#if 0 + + /// Construct from a non-const iterator + FaceIterT(const FaceIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment from non-const iterator + FaceIterT& operator=(const FaceIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + +#else + friend class ConstFaceIterT; +#endif + + + /// Standard dereferencing operator. + reference operator*() const { return mesh_->deref(hnd_); } + + /// Standard pointer operator. + pointer operator->() const { return &(mesh_->deref(hnd_)); } + + /// Get the handle of the item the iterator refers to. + value_handle handle() const { return hnd_; } + + /// Cast to the handle of the item the iterator refers to. + operator value_handle() const { return hnd_; } + + /// Are two iterators equal? Only valid if they refer to the same mesh! + bool operator==(const FaceIterT& _rhs) const + { return ((mesh_ == _rhs.mesh_) && (hnd_ == _rhs.hnd_)); } + + /// Not equal? + bool operator!=(const FaceIterT& _rhs) const + { return !operator==(_rhs); } + + /// Standard pre-increment operator + FaceIterT& operator++() + { hnd_.__increment(); if (skip_bits_) skip_fwd(); return *this; } + + /// Standard pre-decrement operator + FaceIterT& operator--() + { hnd_.__decrement(); if (skip_bits_) skip_bwd(); return *this; } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void enable_skipping() + { + if (mesh_ && mesh_->has_face_status()) + { + Attributes::StatusInfo status; + status.set_deleted(true); + status.set_hidden(true); + skip_bits_ = status.bits(); + skip_fwd(); + } + else skip_bits_ = 0; + } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void disable_skipping() { skip_bits_ = 0; } + + + +private: + + void skip_fwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() < (signed) mesh_->n_faces()) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__increment(); + } + + + void skip_bwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() >= 0) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__decrement(); + } + + + +private: + mesh_ptr mesh_; + value_handle hnd_; + unsigned int skip_bits_; +}; + + +//== CLASS DEFINITION ========================================================= + + +/** \class ConstFaceIterT IteratorsT.hh + Linear iterator. +*/ + +template +class ConstFaceIterT +{ +public: + + + //--- Typedefs --- + + typedef typename Mesh::Face value_type; + typedef typename Mesh::FaceHandle value_handle; + +#if 1 + typedef const value_type& reference; + typedef const value_type* pointer; + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; +#else + typedef value_type& reference; + typedef value_type* pointer; + typedef Mesh* mesh_ptr; + typedef Mesh& mesh_ref; +#endif + + + + + /// Default constructor. + ConstFaceIterT() + : mesh_(0), skip_bits_(0) + {} + + + /// Construct with mesh and a target handle. + ConstFaceIterT(mesh_ref _mesh, value_handle _hnd, bool _skip=false) + : mesh_(&_mesh), hnd_(_hnd), skip_bits_(0) + { + if (_skip) enable_skipping(); + } + + + /// Copy constructor + ConstFaceIterT(const ConstFaceIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment operator + ConstFaceIterT& operator=(const ConstFaceIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + + +#if 1 + + /// Construct from a non-const iterator + ConstFaceIterT(const FaceIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment from non-const iterator + ConstFaceIterT& operator=(const FaceIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + +#else + friend class ConstFaceIterT; +#endif + + + /// Standard dereferencing operator. + reference operator*() const { return mesh_->deref(hnd_); } + + /// Standard pointer operator. + pointer operator->() const { return &(mesh_->deref(hnd_)); } + + /// Get the handle of the item the iterator refers to. + value_handle handle() const { return hnd_; } + + /// Cast to the handle of the item the iterator refers to. + operator value_handle() const { return hnd_; } + + /// Are two iterators equal? Only valid if they refer to the same mesh! + bool operator==(const ConstFaceIterT& _rhs) const + { return ((mesh_ == _rhs.mesh_) && (hnd_ == _rhs.hnd_)); } + + /// Not equal? + bool operator!=(const ConstFaceIterT& _rhs) const + { return !operator==(_rhs); } + + /// Standard pre-increment operator + ConstFaceIterT& operator++() + { hnd_.__increment(); if (skip_bits_) skip_fwd(); return *this; } + + /// Standard pre-decrement operator + ConstFaceIterT& operator--() + { hnd_.__decrement(); if (skip_bits_) skip_bwd(); return *this; } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void enable_skipping() + { + if (mesh_ && mesh_->has_face_status()) + { + Attributes::StatusInfo status; + status.set_deleted(true); + status.set_hidden(true); + skip_bits_ = status.bits(); + skip_fwd(); + } + else skip_bits_ = 0; + } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void disable_skipping() { skip_bits_ = 0; } + + + +private: + + void skip_fwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() < (signed) mesh_->n_faces()) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__increment(); + } + + + void skip_bwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() >= 0) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__decrement(); + } + + + +private: + mesh_ptr mesh_; + value_handle hnd_; + unsigned int skip_bits_; +}; + + +//============================================================================= +} // namespace Iterators +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/Mesh/PolyConnectivity.cc b/Core/Mesh/PolyConnectivity.cc new file mode 100644 index 00000000..11bdacf0 --- /dev/null +++ b/Core/Mesh/PolyConnectivity.cc @@ -0,0 +1,838 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2004 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. * + * * +\*===========================================================================*/ + +//== IMPLEMENTATION ========================================================== +#include +#include + +namespace OpenMesh { + +const PolyConnectivity::VertexHandle PolyConnectivity::InvalidVertexHandle; +const PolyConnectivity::HalfedgeHandle PolyConnectivity::InvalidHalfedgeHandle; +const PolyConnectivity::EdgeHandle PolyConnectivity::InvalidEdgeHandle; +const PolyConnectivity::FaceHandle PolyConnectivity::InvalidFaceHandle; + +//----------------------------------------------------------------------------- +PolyConnectivity::HalfedgeHandle +PolyConnectivity::find_halfedge(VertexHandle _start_vh, VertexHandle _end_vh ) const +{ + assert(_start_vh.is_valid() && _end_vh.is_valid()); + + for (ConstVertexVertexIter vvIt=cvv_iter(_start_vh); vvIt; ++vvIt) + if (vvIt.handle() == _end_vh) + return vvIt.current_halfedge_handle(); + + return InvalidHalfedgeHandle; +} + + +bool PolyConnectivity::is_boundary(FaceHandle _fh, bool _check_vertex) const +{ + for (ConstFaceEdgeIter cfeit = cfe_iter( _fh ); cfeit; ++cfeit) + if (is_boundary( cfeit.handle() ) ) + return true; + + if (_check_vertex) + { + for (ConstFaceVertexIter cfvit = cfv_iter( _fh ); cfvit; ++cfvit) + if (is_boundary( cfvit.handle() ) ) + return true; + } + return false; +} + +bool PolyConnectivity::is_manifold(VertexHandle _vh) const +{ + /* The vertex is non-manifold if more than one gap exists, i.e. + more than one outgoing boundary halfedge. If (at least) one + boundary halfedge exists, the vertex' halfedge must be a + boundary halfedge. If iterating around the vertex finds another + boundary halfedge, the vertex is non-manifold. */ + + ConstVertexOHalfedgeIter vh_it(*this, _vh); + if (vh_it) + for (++vh_it; vh_it; ++vh_it) + if (is_boundary(vh_it.handle())) + return false; + return true; +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::adjust_outgoing_halfedge(VertexHandle _vh) +{ + for (ConstVertexOHalfedgeIter vh_it=cvoh_iter(_vh); vh_it; ++vh_it) + { + if (is_boundary(vh_it.handle())) + { + set_halfedge_handle(_vh, vh_it.handle()); + break; + } + } +} + +//----------------------------------------------------------------------------- +namespace +{ +template +struct NextCacheEntryT : public std::pair<_Handle, _Handle> +{ + typedef std::pair<_Handle, _Handle> Base; + + NextCacheEntryT(_Handle _heh0, _Handle _heh1) + : Base(_heh0, _heh1) + { + assert(_heh0.is_valid()); + assert(_heh1.is_valid()); + } +}; +} + +PolyConnectivity::FaceHandle +PolyConnectivity::add_face(const VertexHandle* _vertex_handles, uint _vhs_size) +{ + VertexHandle vh; + uint i, ii, n(_vhs_size), id; + std::vector halfedge_handles(n); + std::vector is_new(n), needs_adjust(n, false); + HalfedgeHandle inner_next, inner_prev, + outer_next, outer_prev, + boundary_next, boundary_prev, + patch_start, patch_end; + + // cache for set_next_halfedge and vertex' set_halfedge + typedef NextCacheEntryT NextCacheEntry; + typedef std::vector NextCache; + + NextCache next_cache; + next_cache.reserve(3*n); + // don't allow degenerated faces + assert (n > 2); + + // test for topological errors + for (i=0, ii=1; ifirst, ncIt->second); + + // adjust vertices' halfedge handle + for (i=0; i face_handles; + face_handles.reserve(8); + for (VFIter vf_it(vf_iter(_vh)); vf_it; ++vf_it) + face_handles.push_back(vf_it.handle()); + + + // delete collected faces + std::vector::iterator fh_it(face_handles.begin()), + fh_end(face_handles.end()); + + for (; fh_it!=fh_end; ++fh_it) + delete_face(*fh_it, _delete_isolated_vertices); + + status(_vh).set_deleted(true); +} + +//----------------------------------------------------------------------------- + +void PolyConnectivity::delete_edge(EdgeHandle _eh, bool _delete_isolated_vertices) +{ + FaceHandle fh0(face_handle(halfedge_handle(_eh, 0))); + FaceHandle fh1(face_handle(halfedge_handle(_eh, 1))); + + if (fh0.is_valid()) delete_face(fh0, _delete_isolated_vertices); + if (fh1.is_valid()) delete_face(fh1, _delete_isolated_vertices); +} + +//----------------------------------------------------------------------------- + +void PolyConnectivity::delete_face(FaceHandle _fh, bool _delete_isolated_vertices) +{ + assert(_fh.is_valid() && !status(_fh).deleted()); + + // mark face deleted + status(_fh).set_deleted(true); + + + // this vector will hold all boundary edges of face _fh + // these edges will be deleted + std::vector deleted_edges; + deleted_edges.reserve(3); + + + // this vector will hold all vertices of face _fh + // for updating their outgoing halfedge + std::vector vhandles; + vhandles.reserve(3); + + + // for all halfedges of face _fh do: + // 1) invalidate face handle. + // 2) collect all boundary halfedges, set them deleted + // 3) store vertex handles + HalfedgeHandle hh; + for (FaceHalfedgeIter fh_it(fh_iter(_fh)); fh_it; ++fh_it) + { + hh = fh_it.handle(); + + set_boundary(hh);//set_face_handle(hh, InvalidFaceHandle); + + if (is_boundary(opposite_halfedge_handle(hh))) + deleted_edges.push_back(edge_handle(hh)); + + vhandles.push_back(to_vertex_handle(hh)); + } + + + // delete all collected (half)edges + // delete isolated vertices (if _delete_isolated_vertices is true) + if (!deleted_edges.empty()) + { + std::vector::iterator del_it(deleted_edges.begin()), + del_end(deleted_edges.end()); + HalfedgeHandle h0, h1, next0, next1, prev0, prev1; + VertexHandle v0, v1; + + for (; del_it!=del_end; ++del_it) + { + h0 = halfedge_handle(*del_it, 0); + v0 = to_vertex_handle(h0); + next0 = next_halfedge_handle(h0); + prev0 = prev_halfedge_handle(h0); + + h1 = halfedge_handle(*del_it, 1); + v1 = to_vertex_handle(h1); + next1 = next_halfedge_handle(h1); + prev1 = prev_halfedge_handle(h1); + + // adjust next and prev handles + set_next_halfedge_handle(prev0, next1); + set_next_halfedge_handle(prev1, next0); + + // mark edge deleted + status(*del_it).set_deleted(true); + + // update v0 + if (halfedge_handle(v0) == h1) + { + // isolated ? + if (next0 == h1) + { + if (_delete_isolated_vertices) + status(v0).set_deleted(true); + set_isolated(v0); + } + else set_halfedge_handle(v0, next0); + } + + // update v1 + if (halfedge_handle(v1) == h0) + { + // isolated ? + if (next1 == h0) + { + if (_delete_isolated_vertices) + status(v1).set_deleted(true); + set_isolated(v1); + } + else set_halfedge_handle(v1, next1); + } + } + } + + // update outgoing halfedge handles of remaining vertices + std::vector::iterator v_it(vhandles.begin()), + v_end(vhandles.end()); + for (; v_it!=v_end; ++v_it) + adjust_outgoing_halfedge(*v_it); +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::collapse(HalfedgeHandle _hh) +{ + HalfedgeHandle h0 = _hh; + HalfedgeHandle h1 = next_halfedge_handle(h0); + HalfedgeHandle o0 = opposite_halfedge_handle(h0); + HalfedgeHandle o1 = next_halfedge_handle(o0); + + // remove edge + collapse_edge(h0); + + // remove loops + if (next_halfedge_handle(next_halfedge_handle(h1)) == h1) + collapse_loop(next_halfedge_handle(h1)); + if (next_halfedge_handle(next_halfedge_handle(o1)) == o1) + collapse_loop(o1); +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::collapse_edge(HalfedgeHandle _hh) +{ + HalfedgeHandle h = _hh; + HalfedgeHandle hn = next_halfedge_handle(h); + HalfedgeHandle hp = prev_halfedge_handle(h); + + HalfedgeHandle o = opposite_halfedge_handle(h); + HalfedgeHandle on = next_halfedge_handle(o); + HalfedgeHandle op = prev_halfedge_handle(o); + + FaceHandle fh = face_handle(h); + FaceHandle fo = face_handle(o); + + VertexHandle vh = to_vertex_handle(h); + VertexHandle vo = to_vertex_handle(o); + + + + // halfedge -> vertex + for (VertexIHalfedgeIter vih_it(vih_iter(vo)); vih_it; ++vih_it) + set_vertex_handle(vih_it.handle(), vh); + + + // halfedge -> halfedge + set_next_halfedge_handle(hp, hn); + set_next_halfedge_handle(op, on); + + + // face -> halfedge + if (fh.is_valid()) set_halfedge_handle(fh, hn); + if (fo.is_valid()) set_halfedge_handle(fo, on); + + + // vertex -> halfedge + if (halfedge_handle(vh) == o) set_halfedge_handle(vh, hn); + adjust_outgoing_halfedge(vh); + set_isolated(vo); + + // delete stuff + status(edge_handle(h)).set_deleted(true); + status(vo).set_deleted(true); +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::collapse_loop(HalfedgeHandle _hh) +{ + HalfedgeHandle h0 = _hh; + HalfedgeHandle h1 = next_halfedge_handle(h0); + + HalfedgeHandle o0 = opposite_halfedge_handle(h0); + HalfedgeHandle o1 = opposite_halfedge_handle(h1); + + VertexHandle v0 = to_vertex_handle(h0); + VertexHandle v1 = to_vertex_handle(h1); + + FaceHandle fh = face_handle(h0); + FaceHandle fo = face_handle(o0); + + + + // is it a loop ? + assert ((next_halfedge_handle(h1) == h0) && (h1 != o0)); + + + // halfedge -> halfedge + set_next_halfedge_handle(h1, next_halfedge_handle(o0)); + set_next_halfedge_handle(prev_halfedge_handle(o0), h1); + + + // halfedge -> face + set_face_handle(h1, fo); + + + // vertex -> halfedge + set_halfedge_handle(v0, h1); adjust_outgoing_halfedge(v0); + set_halfedge_handle(v1, o1); adjust_outgoing_halfedge(v1); + + + // face -> halfedge + if (fo.is_valid() && halfedge_handle(fo) == o0) + { + set_halfedge_handle(fo, h1); + } + + // delete stuff + if (fh.is_valid()) + { + set_halfedge_handle(fh, InvalidHalfedgeHandle); + status(fh).set_deleted(true); + } + status(edge_handle(h0)).set_deleted(true); +} + +//----------------------------------------------------------------------------- +bool PolyConnectivity::is_simple_link(EdgeHandle _eh) const +{ + HalfedgeHandle heh0 = halfedge_handle(_eh, 0); + HalfedgeHandle heh1 = halfedge_handle(_eh, 1); + + FaceHandle fh0 = face_handle(heh0);//fh0 or fh1 might be a invalid, + FaceHandle fh1 = face_handle(heh1);//i.e., representing the boundary + + HalfedgeHandle next_heh = next_halfedge_handle(heh0); + while (next_heh != heh0) + {//check if there are no other edges shared between fh0 & fh1 + if (opposite_face_handle(next_heh) == fh1) + { + return false; + } + next_heh = next_halfedge_handle(next_heh); + } + return true; +} + +//----------------------------------------------------------------------------- +bool PolyConnectivity::is_simply_connected(FaceHandle _fh) const +{ + std::set nb_fhs; + for (ConstFaceFaceIter cff_it = cff_iter(_fh); cff_it; ++cff_it) + { + if (nb_fhs.find(cff_it) == nb_fhs.end()) + { + nb_fhs.insert(cff_it); + } + else + {//there is more than one link + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +PolyConnectivity::FaceHandle +PolyConnectivity::remove_edge(EdgeHandle _eh) +{ + //don't allow "dangling" vertices and edges + assert(!status(_eh).deleted() && is_simple_link(_eh)); + + HalfedgeHandle heh0 = halfedge_handle(_eh, 0); + HalfedgeHandle heh1 = halfedge_handle(_eh, 1); + + //deal with the faces + FaceHandle rem_fh = face_handle(heh0), del_fh = face_handle(heh1); + if (!del_fh.is_valid()) + {//boundary case - we must delete the rem_fh + std::swap(del_fh, rem_fh); + } + assert(del_fh.is_valid()); +/* for (FaceHalfedgeIter fh_it = fh_iter(del_fh); fh_it; ++fh_it) + {//set the face handle of the halfedges of del_fh to point to rem_fh + set_face_handle(fh_it, rem_fh); + } */ + //fix the halfedge relations + HalfedgeHandle prev_heh0 = prev_halfedge_handle(heh0); + HalfedgeHandle prev_heh1 = prev_halfedge_handle(heh1); + + HalfedgeHandle next_heh0 = next_halfedge_handle(heh0); + HalfedgeHandle next_heh1 = next_halfedge_handle(heh1); + + set_next_halfedge_handle(prev_heh0, next_heh1); + set_next_halfedge_handle(prev_heh1, next_heh0); + //correct outgoing vertex handles for the _eh vertices (if needed) + VertexHandle vh0 = to_vertex_handle(heh0); + VertexHandle vh1 = to_vertex_handle(heh1); + + if (halfedge_handle(vh0) == heh1) + { + set_halfedge_handle(vh0, next_heh0); + } + if (halfedge_handle(vh1) == heh0) + { + set_halfedge_handle(vh1, next_heh1); + } + + //correct the hafledge handle of rem_fh if needed and preserve its first vertex + if (halfedge_handle(rem_fh) == heh0) + {//rem_fh is the face at heh0 + set_halfedge_handle(rem_fh, prev_heh1); + } + else if (halfedge_handle(rem_fh) == heh1) + {//rem_fh is the face at heh1 + set_halfedge_handle(rem_fh, prev_heh0); + } + for (FaceHalfedgeIter fh_it = fh_iter(rem_fh); fh_it; ++fh_it) + {//set the face handle of the halfedges of del_fh to point to rem_fh + set_face_handle(fh_it, rem_fh); + } + + status(_eh).set_deleted(true); + status(del_fh).set_deleted(true); + return rem_fh;//returns the remaining face handle +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::reinsert_edge(EdgeHandle _eh) +{ + //this does not work without prev_halfedge_handle + assert_compile(sizeof(Halfedge) == sizeof(Halfedge_with_prev)); + //shoudl be deleted + assert(status(_eh).deleted()); + status(_eh).set_deleted(false); + + HalfedgeHandle heh0 = halfedge_handle(_eh, 0); + HalfedgeHandle heh1 = halfedge_handle(_eh, 1); + FaceHandle rem_fh = face_handle(heh0), del_fh = face_handle(heh1); + if (!del_fh.is_valid()) + {//boundary case - we must delete the rem_fh + std::swap(del_fh, rem_fh); + } + assert(status(del_fh).deleted()); + status(del_fh).set_deleted(false); + + //restore halfedge relations + HalfedgeHandle prev_heh0 = prev_halfedge_handle(heh0); + HalfedgeHandle prev_heh1 = prev_halfedge_handle(heh1); + + HalfedgeHandle next_heh0 = next_halfedge_handle(heh0); + HalfedgeHandle next_heh1 = next_halfedge_handle(heh1); + + set_next_halfedge_handle(prev_heh0, heh0); + set_prev_halfedge_handle(next_heh0, heh0); + + set_next_halfedge_handle(prev_heh1, heh1); + set_prev_halfedge_handle(next_heh1, heh1); + + for (FaceHalfedgeIter fh_it = fh_iter(del_fh); fh_it; ++fh_it) + {//reassign halfedges to del_fh + set_face_handle(fh_it, del_fh); + } + + if (face_handle(halfedge_handle(rem_fh)) == del_fh) + {//correct the halfedge handle of rem_fh + if (halfedge_handle(rem_fh) == prev_heh0) + {//rem_fh is the face at heh1 + set_halfedge_handle(rem_fh, heh1); + } + else + {//rem_fh is the face at heh0 + assert(halfedge_handle(rem_fh) == prev_heh1); + set_halfedge_handle(rem_fh, heh0); + } + } +} + +//----------------------------------------------------------------------------- +PolyConnectivity::HalfedgeHandle +PolyConnectivity::insert_edge(HalfedgeHandle _prev_heh, HalfedgeHandle _next_heh) +{ + assert(face_handle(_prev_heh) == face_handle(_next_heh));//only the manifold case + assert(next_halfedge_handle(_prev_heh) != _next_heh);//this can not be done + VertexHandle vh0 = to_vertex_handle(_prev_heh); + VertexHandle vh1 = from_vertex_handle(_next_heh); + //create the link between vh0 and vh1 + HalfedgeHandle heh0 = new_edge(vh0, vh1); + HalfedgeHandle heh1 = opposite_halfedge_handle(heh0); + HalfedgeHandle next_prev_heh = next_halfedge_handle(_prev_heh); + HalfedgeHandle prev_next_heh = prev_halfedge_handle(_next_heh); + set_next_halfedge_handle(_prev_heh, heh0); + set_next_halfedge_handle(heh0, _next_heh); + set_next_halfedge_handle(prev_next_heh, heh1); + set_next_halfedge_handle(heh1, next_prev_heh); + + //now set the face handles - the new face is assigned to heh0 + FaceHandle new_fh = new_face(); + set_halfedge_handle(new_fh, heh0); + for (FaceHalfedgeIter fh_it = fh_iter(new_fh); fh_it; ++fh_it) + { + set_face_handle(fh_it, new_fh); + } + FaceHandle old_fh = face_handle(next_prev_heh); + set_face_handle(heh1, old_fh); + if (old_fh.is_valid() && face_handle(halfedge_handle(old_fh)) == new_fh) + {//fh pointed to one of the halfedges now assigned to new_fh + set_halfedge_handle(old_fh, heh1); + } + adjust_outgoing_halfedge(vh0); + adjust_outgoing_halfedge(vh1); + return heh0; +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::triangulate(FaceHandle _fh) +{ + /* + Split an arbitrary face into triangles by connecting + each vertex of fh after its second to vh. + + - fh will remain valid (it will become one of the + triangles) + - the halfedge handles of the new triangles will + point to the old halfedges + */ + + HalfedgeHandle base_heh(halfedge_handle(_fh)); + VertexHandle start_vh = from_vertex_handle(base_heh); + HalfedgeHandle next_heh(next_halfedge_handle(base_heh)); + + while (to_vertex_handle(next_halfedge_handle(next_heh)) != start_vh) + { + HalfedgeHandle next_next_heh(next_halfedge_handle(next_heh)); + + FaceHandle new_fh = new_face(); + set_halfedge_handle(new_fh, base_heh); + + HalfedgeHandle new_heh = new_edge(to_vertex_handle(next_heh), start_vh); + + set_next_halfedge_handle(base_heh, next_heh); + set_next_halfedge_handle(next_heh, new_heh); + set_next_halfedge_handle(new_heh, base_heh); + + set_face_handle(base_heh, new_fh); + set_face_handle(next_heh, new_fh); + set_face_handle(new_heh, new_fh); + + base_heh = opposite_halfedge_handle(new_heh); + next_heh = next_next_heh; + } + set_halfedge_handle(_fh, base_heh); //the last face takes the handle _fh + + set_next_halfedge_handle(base_heh, next_heh); + set_next_halfedge_handle(next_halfedge_handle(next_heh), base_heh); + + set_face_handle(base_heh, _fh); +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::triangulate() +{ + /* The iterators will stay valid, even though new faces are added, + because they are now implemented index-based instead of + pointer-based. + */ + FaceIter f_it(faces_begin()), f_end(faces_end()); + for (; f_it!=f_end; ++f_it) + triangulate(f_it); +} + +//----------------------------------------------------------------------------- +void PolyConnectivity::split(FaceHandle fh, VertexHandle vh) +{ + /* + Split an arbitrary face into triangles by connecting + each vertex of fh to vh. + + - fh will remain valid (it will become one of the + triangles) + - the halfedge handles of the new triangles will + point to the old halfeges + */ + + HalfedgeHandle hend = halfedge_handle(fh); + HalfedgeHandle hh = next_halfedge_handle(hend); + + HalfedgeHandle hold = new_edge(to_vertex_handle(hend), vh); + + set_next_halfedge_handle(hend, hold); + set_face_handle(hold, fh); + + hold = opposite_halfedge_handle(hold); + + while (hh != hend) { + + HalfedgeHandle hnext = next_halfedge_handle(hh); + + FaceHandle fnew = new_face(); + set_halfedge_handle(fnew, hh); + + HalfedgeHandle hnew = new_edge(to_vertex_handle(hh), vh); + + set_next_halfedge_handle(hnew, hold); + set_next_halfedge_handle(hold, hh); + set_next_halfedge_handle(hh, hnew); + + set_face_handle(hnew, fnew); + set_face_handle(hold, fnew); + set_face_handle(hh, fnew); + + hold = opposite_halfedge_handle(hnew); + + hh = hnext; + } + + set_next_halfedge_handle(hold, hend); + set_next_halfedge_handle(next_halfedge_handle(hend), hold); + + set_face_handle(hold, fh); + + set_halfedge_handle(vh, hold); +} + +//----------------------------------------------------------------------------- +uint PolyConnectivity::valence(VertexHandle _vh) const +{ + uint count(0); + for (ConstVertexVertexIter vv_it=cvv_iter(_vh); vv_it; ++vv_it) + ++count; + return count; +} + +//----------------------------------------------------------------------------- +uint PolyConnectivity::valence(FaceHandle _fh) const +{ + uint count(0); + for (ConstFaceVertexIter fv_it=cfv_iter(_fh); fv_it; ++fv_it) + ++count; + return count; +} + +}//namespace OpenMesh + diff --git a/Core/Mesh/PolyConnectivity.hh b/Core/Mesh/PolyConnectivity.hh new file mode 100644 index 00000000..e0a25627 --- /dev/null +++ b/Core/Mesh/PolyConnectivity.hh @@ -0,0 +1,513 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2004 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. * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_POLYCONNECTIVITY_HH +#define OPENMESH_POLYCONNECTIVITY_HH + +#include +#include +#include + +namespace OpenMesh +{ + +class PolyConnectivity : public ArrayKernel +{ +public: + /// \name Mesh Handles + //@{ + /// Invalid handle + static const VertexHandle InvalidVertexHandle; + /// Invalid handle + static const HalfedgeHandle InvalidHalfedgeHandle; + /// Invalid handle + static const EdgeHandle InvalidEdgeHandle; + /// Invalid handle + static const FaceHandle InvalidFaceHandle; + //@} + + typedef PolyConnectivity This; + + //--- iterators --- + + /** \name Mesh Iterators + Refer to OpenMesh::Mesh::Iterators or \ref mesh_iterators for + documentation. + */ + //@{ + /// Linear iterator + typedef Iterators::VertexIterT VertexIter; + typedef Iterators::HalfedgeIterT HalfedgeIter; + typedef Iterators::EdgeIterT EdgeIter; + typedef Iterators::FaceIterT FaceIter; + + typedef Iterators::ConstVertexIterT ConstVertexIter; + typedef Iterators::ConstHalfedgeIterT ConstHalfedgeIter; + typedef Iterators::ConstEdgeIterT ConstEdgeIter; + typedef Iterators::ConstFaceIterT ConstFaceIter; + //@} + + //--- circulators --- + + /** \name Mesh Circulators + Refer to OpenMesh::Mesh::Iterators or \ref mesh_iterators + for documentation. + */ + //@{ + /// Circulator + typedef Iterators::VertexVertexIterT VertexVertexIter; + typedef Iterators::VertexOHalfedgeIterT VertexOHalfedgeIter; + typedef Iterators::VertexIHalfedgeIterT VertexIHalfedgeIter; + typedef Iterators::VertexEdgeIterT VertexEdgeIter; + typedef Iterators::VertexFaceIterT VertexFaceIter; + typedef Iterators::FaceVertexIterT FaceVertexIter; + typedef Iterators::FaceHalfedgeIterT FaceHalfedgeIter; + typedef Iterators::FaceEdgeIterT FaceEdgeIter; + typedef Iterators::FaceFaceIterT FaceFaceIter; + + typedef Iterators::ConstVertexVertexIterT ConstVertexVertexIter; + typedef Iterators::ConstVertexOHalfedgeIterT ConstVertexOHalfedgeIter; + typedef Iterators::ConstVertexIHalfedgeIterT ConstVertexIHalfedgeIter; + typedef Iterators::ConstVertexEdgeIterT ConstVertexEdgeIter; + typedef Iterators::ConstVertexFaceIterT ConstVertexFaceIter; + typedef Iterators::ConstFaceVertexIterT ConstFaceVertexIter; + typedef Iterators::ConstFaceHalfedgeIterT ConstFaceHalfedgeIter; + typedef Iterators::ConstFaceEdgeIterT ConstFaceEdgeIter; + typedef Iterators::ConstFaceFaceIterT ConstFaceFaceIter; + //@} + + // --- shortcuts + + /** \name Typedef Shortcuts + Provided for convenience only + */ + //@{ + /// Alias typedef + typedef VertexHandle VHandle; + typedef HalfedgeHandle HHandle; + typedef EdgeHandle EHandle; + typedef FaceHandle FHandle; + + typedef VertexIter VIter; + typedef HalfedgeIter HIter; + typedef EdgeIter EIter; + typedef FaceIter FIter; + + typedef ConstVertexIter CVIter; + typedef ConstHalfedgeIter CHIter; + typedef ConstEdgeIter CEIter; + typedef ConstFaceIter CFIter; + + typedef VertexVertexIter VVIter; + typedef VertexOHalfedgeIter VOHIter; + typedef VertexIHalfedgeIter VIHIter; + typedef VertexEdgeIter VEIter; + typedef VertexFaceIter VFIter; + typedef FaceVertexIter FVIter; + typedef FaceHalfedgeIter FHIter; + typedef FaceEdgeIter FEIter; + typedef FaceFaceIter FFIter; + + typedef ConstVertexVertexIter CVVIter; + typedef ConstVertexOHalfedgeIter CVOHIter; + typedef ConstVertexIHalfedgeIter CVIHIter; + typedef ConstVertexEdgeIter CVEIter; + typedef ConstVertexFaceIter CVFIter; + typedef ConstFaceVertexIter CFVIter; + typedef ConstFaceHalfedgeIter CFHIter; + typedef ConstFaceEdgeIter CFEIter; + typedef ConstFaceFaceIter CFFIter; + //@} + +public: + + PolyConnectivity() {} + virtual ~PolyConnectivity() {} + + inline static bool is_triangles() + { return false; } + + /** assign_connectivity() method. See ArrayKernel::assign_connectivity() + for more details. */ + inline void assign_connectivity(const PolyConnectivity& _other) + { ArrayKernel::assign_connectivity(_other); } + + /** \name Adding items to a mesh + */ + //@{ + /// Add a new vertex + inline VertexHandle add_vertex() + { return new_vertex(); } + + /// Add and connect a new face + FaceHandle add_face(const std::vector& _vhandles) + { return add_face(&_vhandles.front(), _vhandles.size()); } + + FaceHandle add_face(VertexHandle _vh0, VertexHandle _vh1, VertexHandle _vh2) + { + VertexHandle vhs[3] = { _vh0, _vh1, _vh2 }; + return add_face(vhs, 3); + } + + FaceHandle add_face(VertexHandle _vh0, VertexHandle _vh1, VertexHandle _vh2, VertexHandle _vh3) + { + VertexHandle vhs[4] = { _vh0, _vh1, _vh2, _vh3 }; + return add_face(vhs, 4); + } + + FaceHandle add_face(const VertexHandle* _vhandles, uint _vhs_size); + //@} + + /// \name Deleting mesh items and other connectivity/topology modifications + //@{ + + /** Mark vertex and all incident edges and faces deleted. + Items marked deleted will be removed by garbageCollection(). + \attention Needs the Attributes::Status attribute for vertices, + edges and faces. + */ + void delete_vertex(VertexHandle _vh, bool _delete_isolated_vertices = true); + + /** Mark edge (two opposite halfedges) and incident faces deleted. + Resulting isolated vertices are marked deleted if + _delete_isolated_vertices is true. Items marked deleted will be + removed by garbageCollection(). + + \attention Needs the Attributes::Status attribute for vertices, + edges and faces. + */ + void delete_edge(EdgeHandle _eh, bool _delete_isolated_vertices=true); + + /** Delete face _fh and resulting degenerated empty halfedges as + well. Resultling isolated vertices will be deleted if + _delete_isolated_vertices is true. + + \attention All item will only be marked to be deleted. They will + actually be removed by calling garbage_collection(). + + \attention Needs the Attributes::Status attribute for vertices, + edges and faces. + */ + void delete_face(FaceHandle _fh, bool _delete_isolated_vertices=true); + + //@} + + /** \name Begin and end iterators + */ + //@{ + + /// Begin iterator for vertices + VertexIter vertices_begin() + { return VertexIter(*this, VertexHandle(0)); } + /// Const begin iterator for vertices + ConstVertexIter vertices_begin() const + { return ConstVertexIter(*this, VertexHandle(0)); } + /// End iterator for vertices + VertexIter vertices_end() + { return VertexIter(*this, VertexHandle(n_vertices())); } + /// Const end iterator for vertices + ConstVertexIter vertices_end() const + { return ConstVertexIter(*this, VertexHandle(n_vertices())); } + + /// Begin iterator for halfedges + HalfedgeIter halfedges_begin() + { return HalfedgeIter(*this, HalfedgeHandle(0)); } + /// Const begin iterator for halfedges + ConstHalfedgeIter halfedges_begin() const + { return ConstHalfedgeIter(*this, HalfedgeHandle(0)); } + /// End iterator for halfedges + HalfedgeIter halfedges_end() + { return HalfedgeIter(*this, HalfedgeHandle(n_halfedges())); } + /// Const end iterator for halfedges + ConstHalfedgeIter halfedges_end() const + { return ConstHalfedgeIter(*this, HalfedgeHandle(n_halfedges())); } + + /// Begin iterator for edges + EdgeIter edges_begin() + { return EdgeIter(*this, EdgeHandle(0)); } + /// Const begin iterator for edges + ConstEdgeIter edges_begin() const + { return ConstEdgeIter(*this, EdgeHandle(0)); } + /// End iterator for edges + EdgeIter edges_end() + { return EdgeIter(*this, EdgeHandle(n_edges())); } + /// Const end iterator for edges + ConstEdgeIter edges_end() const + { return ConstEdgeIter(*this, EdgeHandle(n_edges())); } + + /// Begin iterator for faces + FaceIter faces_begin() + { return FaceIter(*this, FaceHandle(0)); } + /// Const begin iterator for faces + ConstFaceIter faces_begin() const + { return ConstFaceIter(*this, FaceHandle(0)); } + /// End iterator for faces + FaceIter faces_end() + { return FaceIter(*this, FaceHandle(n_faces())); } + /// Const end iterator for faces + ConstFaceIter faces_end() const + { return ConstFaceIter(*this, FaceHandle(n_faces())); } + + //@} + + + + /** \name Begin for skipping iterators + */ + //@{ + + /// Begin iterator for vertices + VertexIter vertices_sbegin() + { return VertexIter(*this, VertexHandle(0), true); } + /// Const begin iterator for vertices + ConstVertexIter vertices_sbegin() const + { return ConstVertexIter(*this, VertexHandle(0), true); } + + /// Begin iterator for halfedges + HalfedgeIter halfedges_sbegin() + { return HalfedgeIter(*this, HalfedgeHandle(0), true); } + /// Const begin iterator for halfedges + ConstHalfedgeIter halfedges_sbegin() const + { return ConstHalfedgeIter(*this, HalfedgeHandle(0), true); } + + /// Begin iterator for edges + EdgeIter edges_sbegin() + { return EdgeIter(*this, EdgeHandle(0), true); } + /// Const begin iterator for edges + ConstEdgeIter edges_sbegin() const + { return ConstEdgeIter(*this, EdgeHandle(0), true); } + + /// Begin iterator for faces + FaceIter faces_sbegin() + { return FaceIter(*this, FaceHandle(0), true); } + /// Const begin iterator for faces + ConstFaceIter faces_sbegin() const + { return ConstFaceIter(*this, FaceHandle(0), true); } + + //@} + + //--- circulators --- + + /** \name Vertex and Face circulators + */ + //@{ + + /// vertex - vertex circulator + VertexVertexIter vv_iter(VertexHandle _vh) { + return VertexVertexIter(*this, _vh); } + /// vertex - incoming halfedge circulator + VertexIHalfedgeIter vih_iter(VertexHandle _vh) + { return VertexIHalfedgeIter(*this, _vh); } + /// vertex - outgoing halfedge circulator + VertexOHalfedgeIter voh_iter(VertexHandle _vh) + { return VertexOHalfedgeIter(*this, _vh); } + /// vertex - edge circulator + VertexEdgeIter ve_iter(VertexHandle _vh) + { return VertexEdgeIter(*this, _vh); } + /// vertex - face circulator + VertexFaceIter vf_iter(VertexHandle _vh) + { return VertexFaceIter(*this, _vh); } + + /// const vertex circulator + ConstVertexVertexIter cvv_iter(VertexHandle _vh) const + { return ConstVertexVertexIter(*this, _vh); } + /// const vertex - incoming halfedge circulator + ConstVertexIHalfedgeIter cvih_iter(VertexHandle _vh) const + { return ConstVertexIHalfedgeIter(*this, _vh); } + /// const vertex - outgoing halfedge circulator + ConstVertexOHalfedgeIter cvoh_iter(VertexHandle _vh) const + { return ConstVertexOHalfedgeIter(*this, _vh); } + /// const vertex - edge circulator + ConstVertexEdgeIter cve_iter(VertexHandle _vh) const + { return ConstVertexEdgeIter(*this, _vh); } + /// const vertex - face circulator + ConstVertexFaceIter cvf_iter(VertexHandle _vh) const + { return ConstVertexFaceIter(*this, _vh); } + + /// face - vertex circulator + FaceVertexIter fv_iter(FaceHandle _fh) + { return FaceVertexIter(*this, _fh); } + /// face - halfedge circulator + FaceHalfedgeIter fh_iter(FaceHandle _fh) + { return FaceHalfedgeIter(*this, _fh); } + /// face - edge circulator + FaceEdgeIter fe_iter(FaceHandle _fh) + { return FaceEdgeIter(*this, _fh); } + /// face - face circulator + FaceFaceIter ff_iter(FaceHandle _fh) + { return FaceFaceIter(*this, _fh); } + + /// const face - vertex circulator + ConstFaceVertexIter cfv_iter(FaceHandle _fh) const + { return ConstFaceVertexIter(*this, _fh); } + /// const face - halfedge circulator + ConstFaceHalfedgeIter cfh_iter(FaceHandle _fh) const + { return ConstFaceHalfedgeIter(*this, _fh); } + /// const face - edge circulator + ConstFaceEdgeIter cfe_iter(FaceHandle _fh) const + { return ConstFaceEdgeIter(*this, _fh); } + /// const face - face circulator + ConstFaceFaceIter cff_iter(FaceHandle _fh) const + { return ConstFaceFaceIter(*this, _fh); } + //@} + + /** \name Boundary and manifold tests + */ + //@{ + bool is_boundary(HalfedgeHandle _heh) const + { return ArrayKernel::is_boundary(_heh); } + + /** Is the edge _eh a boundary edge, i.e. is one of its halfedges + a boundary halfege ? */ + bool is_boundary(EdgeHandle _eh) const + { + return (is_boundary(halfedge_handle(_eh, 0)) || + is_boundary(halfedge_handle(_eh, 1))); + } + /// Is vertex _vh a boundary vertex ? + bool is_boundary(VertexHandle _vh) const + { + HalfedgeHandle heh(halfedge_handle(_vh)); + return (!(heh.is_valid() && face_handle(heh).is_valid())); + } + + /** Is face _fh at boundary, i.e. is one of its edges (or vertices) + * a boundary edge? + * \param _fh Check this face + * \param _check_vertex If \c true, check the corner vertices of + * the face, too. + */ + bool is_boundary(FaceHandle _fh, bool _check_vertex=false) const; + /// Is (the mesh at) vertex _vh two-manifold ? + bool is_manifold(VertexHandle _vh) const; + //@} + + // --- shortcuts --- + + /// returns the face handle of the opposite halfedge + inline FaceHandle opposite_face_handle(HalfedgeHandle _heh) const + { return face_handle(opposite_halfedge_handle(_heh)); } + + // --- misc --- + + /** Adjust outgoing halfedge handle for vertices, so that it is a + boundary halfedge whenever possible. + */ + void adjust_outgoing_halfedge(VertexHandle _vh); + /// Find halfedge from _vh0 to _vh1. Returns invalid handle if not found. + HalfedgeHandle find_halfedge(VertexHandle _start_vh, VertexHandle _end_vh) const; + /// Vertex valence + uint valence(VertexHandle _vh) const; + /// Face valence + uint valence(FaceHandle _fh) const; + + // --- connectivity operattions + + /** Halfedge collapse: collapse the from-vertex of halfedge _heh + into its to-vertex. + + \attention Needs vertex/edge/face status attribute in order to + delete the items that degenerate. + + \note This function does not perform a garbage collection. It + only marks degenerate items as deleted. + + \attention A halfedge collapse may lead to topological inconsistencies. + Therefore you should check this using is_collapse_ok(). + \TODO: implement is_collapse_ok() const for polygonal/triangle meshes + */ + void collapse(HalfedgeHandle _heh); + /** return true if the this the only link between the faces adjacent to _eh. + _eh is allowed to be boundary, in which case true is returned iff _eh is + the only boundary edge of its ajdacent face. + */ + bool is_simple_link(EdgeHandle _eh) const; + /** return true if _fh shares only one edge with all of its adjacent faces. + Boundary is treated as one face, i.e., the function false if _fh has more + than one boundary edge. + */ + bool is_simply_connected(FaceHandle _fh) const; + /** Removes the edge _eh. Its adjacent faces are merged. _eh and one of the + adjacent faces are set deleted. The handle of the remaining face is + returned (InvalidFaceHandle is returned if _eh is a boundary edge). + + \precondition is_simple_link(_eh). This ensures that there are no hole faces + or isolated vertices appearing in result of the operation. + + \attention Needs the Attributes::Status attribute for edges and faces. + + \note This function does not perform a garbage collection. It + only marks items as deleted. + */ + FaceHandle remove_edge(EdgeHandle _eh); + /** Inverse of remove_edge. _eh should be the handle of the edge and the + vertex and halfedge handles pointed by edge(_eh) should be valid. + */ + void reinsert_edge(EdgeHandle _eh); + /** Inserts an edge between to_vh(_prev_heh) and from_vh(_next_heh). + A new face is created started at heh0 of the inserted edge and + its halfedges loop includes both _prev_heh and _next_heh. If an + old face existed which includes the argument halfedges, it is + split at the new edge. heh0 is returned. + + \note assumes _prev_heh and _next_heh are either boundary or pointed + to the same face + */ + HalfedgeHandle insert_edge(HalfedgeHandle _prev_heh, HalfedgeHandle _next_heh); + + /// Face split (= 1-to-n split) + void split(FaceHandle _fh, VertexHandle _vh); + /// triangulate the face _fh + void triangulate(FaceHandle _fh); + /// triangulate the entire mesh + void triangulate(); + + + /** \name Generic handle derefertiation. + Calls the respective vertex(), halfedge(), edge(), face() + method of the mesh kernel. + */ + //@{ + /// Get item from handle + const Vertex& deref(VertexHandle _h) const { return vertex(_h); } + Vertex& deref(VertexHandle _h) { return vertex(_h); } + const Halfedge& deref(HalfedgeHandle _h) const { return halfedge(_h); } + Halfedge& deref(HalfedgeHandle _h) { return halfedge(_h); } + const Edge& deref(EdgeHandle _h) const { return edge(_h); } + Edge& deref(EdgeHandle _h) { return edge(_h); } + const Face& deref(FaceHandle _h) const { return face(_h); } + Face& deref(FaceHandle _h) { return face(_h); } + //@} + +protected: + /// Helper for halfedge collapse + void collapse_edge(HalfedgeHandle _hh); + /// Helper for halfedge collapse + void collapse_loop(HalfedgeHandle _hh); +}; + +}//namespace OpenMesh + +#endif//OPENMESH_POLYCONNECTIVITY_HH diff --git a/Core/Mesh/PolyMeshT.cc b/Core/Mesh/PolyMeshT.cc new file mode 100644 index 00000000..124a588c --- /dev/null +++ b/Core/Mesh/PolyMeshT.cc @@ -0,0 +1,265 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// CLASS PolyMeshT - IMPLEMENTATION +// +//============================================================================= + + +#define OPENMESH_POLYMESH_C + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + +//== IMPLEMENTATION ========================================================== + +template +uint PolyMeshT::find_feature_edges(Scalar _angle_tresh) +{ + assert(Kernel::has_edge_status());//this function needs edge status property + uint n_feature_edges = 0; + for (EdgeIter e_it = Kernel::edges_begin(); e_it != Kernel::edges_end(); ++e_it) + { + if (fabs(calc_dihedral_angle(e_it)) > _angle_tresh) + {//note: could be optimized by comparing cos(dih_angle) vs. cos(_angle_tresh) + status(e_it).set_feature(true); + n_feature_edges++; + } + else + { + status(e_it).set_feature(false); + } + } + return n_feature_edges; +} + +//----------------------------------------------------------------------------- + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_face_normal(FaceHandle _fh) const +{ + assert(halfedge_handle(_fh).is_valid()); + ConstFaceVertexIter fv_it(cfv_iter(_fh)); + + const Point& p0(point(fv_it)); ++fv_it; + const Point& p1(point(fv_it)); ++fv_it; + const Point& p2(point(fv_it)); + + return calc_face_normal(p0, p1, p2); +} + + +//----------------------------------------------------------------------------- + + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_face_normal(const Point& _p0, + const Point& _p1, + const Point& _p2) const +{ +#if 1 + // The OpenSG ::operator -= () does not support the type Point + // as rhs. Therefore use vector_cast at this point!!! + // Note! OpenSG distinguishes between Normal and Point!!! + Normal p1p0(_p0); p1p0 -= vector_cast(_p1); + Normal p1p2(_p2); p1p2 -= vector_cast(_p1); + + Normal n = cross(p1p2, p1p0); + Scalar norm = n.length(); + + // The expression ((n *= (1.0/norm)),n) is used because the OpenSG + // vector class does not return self after component-wise + // self-multiplication with a scalar!!! + return (norm != Scalar(0)) ? ((n *= (Scalar(1)/norm)),n) : Normal(0,0,0); +#else + Point p1p0 = _p0; p1p0 -= _p1; + Point p1p2 = _p2; p1p2 -= _p1; + + Normal n = vector_cast(cross(p1p2, p1p0)); + Scalar norm = n.length(); + + return (norm != 0.0) ? n *= (1.0/norm) : Normal(0,0,0); +#endif +} + +//----------------------------------------------------------------------------- + +template +void +PolyMeshT:: +calc_face_centroid(FaceHandle _fh, Point& _pt) const +{ + _pt.vectorize(0); + uint valence = 0; + for (ConstFaceVertexIter cfv_it = cfv_iter(_fh); cfv_it; ++cfv_it, ++valence) + { + _pt += point(cfv_it); + } + _pt /= valence; +} +//----------------------------------------------------------------------------- + + +template +void +PolyMeshT:: +update_normals() +{ + if (Kernel::has_face_normals()) update_face_normals(); + if (Kernel::has_vertex_normals()) update_vertex_normals(); +} + + +//----------------------------------------------------------------------------- + + +template +void +PolyMeshT:: +update_face_normals() +{ + FaceIter f_it(Kernel::faces_begin()), f_end(Kernel::faces_end()); + + for (; f_it != f_end; ++f_it) + set_normal(f_it.handle(), calc_face_normal(f_it.handle())); +} + + +//----------------------------------------------------------------------------- + + +template +typename PolyMeshT::Normal +PolyMeshT:: +calc_vertex_normal(VertexHandle _vh) const +{ + Normal n; + calc_vertex_normal_fast(_vh,n); + + Scalar norm = n.length(); + if (norm != 0.0) n *= (1.0/norm); + + return n; +} + +//----------------------------------------------------------------------------- +template +void PolyMeshT:: +calc_vertex_normal_fast(VertexHandle _vh, Normal& _n) const +{ + _n.vectorize(0.0); + for (ConstVertexFaceIter vf_it=cvf_iter(_vh); vf_it; ++vf_it) + _n += normal(vf_it.handle()); +} + +//----------------------------------------------------------------------------- +template +void PolyMeshT:: +calc_vertex_normal_correct(VertexHandle _vh, Normal& _n) const +{ + _n.vectorize(0.0); + ConstVertexIHalfedgeIter cvih_it = cvih_iter(_vh); + if (!cvih_it) + {//don't crash on isolated vertices + return; + } + Normal in_he_vec; + calc_edge_vector(cvih_it, in_he_vec); + for ( ; cvih_it; ++cvih_it) + {//calculates the sector normal defined by cvih_it and adds it to _n + if (is_boundary(cvih_it)) + { + continue; + } + HalfedgeHandle out_heh(next_halfedge_handle(cvih_it)); + Normal out_he_vec; + calc_edge_vector(out_heh, out_he_vec); + _n += cross(in_he_vec, out_he_vec);//sector area is taken into account + in_he_vec = out_he_vec; + in_he_vec *= -1;//change the orientation + } +} + +//----------------------------------------------------------------------------- +template +void PolyMeshT:: +calc_vertex_normal_loop(VertexHandle _vh, Normal& _n) const +{ + static const LoopSchemeMaskDouble& loop_scheme_mask__ = + LoopSchemeMaskDoubleSingleton::Instance(); + + Normal t_v(0.0,0.0,0.0), t_w(0.0,0.0,0.0); + unsigned int vh_val = valence(_vh); + unsigned int i = 0; + for (ConstVertexOHalfedgeIter cvoh_it = cvoh_iter(_vh); cvoh_it; ++cvoh_it, ++i) + { + VertexHandle r1_v(to_vertex_handle(cvoh_it)); + t_v += (typename Point::value_type)(loop_scheme_mask__.tang0_weight(vh_val, i))*point(r1_v); + t_w += (typename Point::value_type)(loop_scheme_mask__.tang1_weight(vh_val, i))*point(r1_v); + } + _n = cross(t_w, t_v);//hack: should be cross(t_v, t_w), but then the normals are reversed? +} + +//----------------------------------------------------------------------------- + + +template +void +PolyMeshT:: +update_vertex_normals() +{ + VertexIter v_it(Kernel::vertices_begin()), v_end(Kernel::vertices_end()); + + for (; v_it!=v_end; ++v_it) + set_normal(v_it.handle(), calc_vertex_normal(v_it.handle())); +} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Core/Mesh/PolyMeshT.hh b/Core/Mesh/PolyMeshT.hh new file mode 100644 index 00000000..ce8c5262 --- /dev/null +++ b/Core/Mesh/PolyMeshT.hh @@ -0,0 +1,434 @@ +//============================================================================= +// +// 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: 2983 $ +// $Date: 2008-09-22 17:13:19 +0200 (Mo, 22. Sep 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// CLASS PolyMeshT +// +//============================================================================= + + +#ifndef OPENMESH_POLYMESHT_HH +#define OPENMESH_POLYMESHT_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** \class PolyMeshT PolyMeshT.hh + + Base type for a polygonal mesh. + + This is the base class for a polygonal mesh. It is parameterized + by a mesh kernel that is given as a template argument. This class + inherits all methods from its mesh kernel. + + \param Kernel: template argument for the mesh kernel + \note You should use the predefined mesh-kernel combinations in + \ref mesh_types_group + \see \ref mesh_type +*/ + +template +class PolyMeshT : public Kernel +{ +public: + + /// Self type. Used to specify iterators/circulators. + typedef PolyMeshT This; + //--- item types --- + + //@{ + /// Determine whether this is a PolyMeshT or TriMeshT + enum { IsPolyMesh = 1 }; + enum { IsTriMesh = 0 }; + static bool is_polymesh() { return true; } + static bool is_trimesh() { return false; } + //@} + + /// \name Mesh Items + //@{ + /// Scalar type + typedef typename Kernel::Scalar Scalar; + /// Coordinate type + typedef typename Kernel::Point Point; + /// Normal type + typedef typename Kernel::Normal Normal; + /// Color type + typedef typename Kernel::Color Color; + /// TexCoord1D type + typedef typename Kernel::TexCoord1D TexCoord1D; + /// TexCoord2D type + typedef typename Kernel::TexCoord2D TexCoord2D; + /// TexCoord3D type + typedef typename Kernel::TexCoord3D TexCoord3D; + /// Vertex type + typedef typename Kernel::Vertex Vertex; + /// Halfedge type + typedef typename Kernel::Halfedge Halfedge; + /// Edge type + typedef typename Kernel::Edge Edge; + /// Face type + typedef typename Kernel::Face Face; + //@} + + //--- handle types --- + + /// Handle for referencing the corresponding item + typedef typename Kernel::VertexHandle VertexHandle; + typedef typename Kernel::HalfedgeHandle HalfedgeHandle; + typedef typename Kernel::EdgeHandle EdgeHandle; + typedef typename Kernel::FaceHandle FaceHandle; + + + + typedef typename Kernel::VertexIter VertexIter; + typedef typename Kernel::HalfedgeIter HalfedgeIter; + typedef typename Kernel::EdgeIter EdgeIter; + typedef typename Kernel::FaceIter FaceIter; + + typedef typename Kernel::ConstVertexIter ConstVertexIter; + typedef typename Kernel::ConstHalfedgeIter ConstHalfedgeIter; + typedef typename Kernel::ConstEdgeIter ConstEdgeIter; + typedef typename Kernel::ConstFaceIter ConstFaceIter; + //@} + + //--- circulators --- + + /** \name Mesh Circulators + Refer to OpenMesh::Mesh::Iterators or \ref mesh_iterators + for documentation. + */ + //@{ + /// Circulator + typedef typename Kernel::VertexVertexIter VertexVertexIter; + typedef typename Kernel::VertexOHalfedgeIter VertexOHalfedgeIter; + typedef typename Kernel::VertexIHalfedgeIter VertexIHalfedgeIter; + typedef typename Kernel::VertexEdgeIter VertexEdgeIter; + typedef typename Kernel::VertexFaceIter VertexFaceIter; + typedef typename Kernel::FaceVertexIter FaceVertexIter; + typedef typename Kernel::FaceHalfedgeIter FaceHalfedgeIter; + typedef typename Kernel::FaceEdgeIter FaceEdgeIter; + typedef typename Kernel::FaceFaceIter FaceFaceIter; + + typedef typename Kernel::ConstVertexVertexIter ConstVertexVertexIter; + typedef typename Kernel::ConstVertexOHalfedgeIter ConstVertexOHalfedgeIter; + typedef typename Kernel::ConstVertexIHalfedgeIter ConstVertexIHalfedgeIter; + typedef typename Kernel::ConstVertexEdgeIter ConstVertexEdgeIter; + typedef typename Kernel::ConstVertexFaceIter ConstVertexFaceIter; + typedef typename Kernel::ConstFaceVertexIter ConstFaceVertexIter; + typedef typename Kernel::ConstFaceHalfedgeIter ConstFaceHalfedgeIter; + typedef typename Kernel::ConstFaceEdgeIter ConstFaceEdgeIter; + typedef typename Kernel::ConstFaceFaceIter ConstFaceFaceIter; + //@} + + + // --- constructor/destructor + PolyMeshT() {} + virtual ~PolyMeshT() {} + + /** Uses default copy and assignment operator. + Use them to assign two meshes of \b equal type. + If the mesh types vary, use PolyMeshT::assign() instead. */ + + // --- creation --- + inline VertexHandle new_vertex() + { return Kernel::new_vertex(); } + + inline VertexHandle new_vertex(const Point& _p) + { + VertexHandle vh(Kernel::new_vertex()); + set_point(vh, _p); + return vh; + } + + inline VertexHandle add_vertex(const Point& _p) + { return new_vertex(_p); } + + // --- normal vectors --- + + /** \name Normal vector computation + */ + //@{ + + /** Calls update_face_normals() and update_vertex_normals() if + these normals (i.e. the properties) exist */ + void update_normals(); + + /// Update normal for face _fh + void update_normal(FaceHandle _fh) + { set_normal(_fh, calc_face_normal(_fh)); } + + /** Update normal vectors for all faces. + \attention Needs the Attributes::Normal attribute for faces. */ + void update_face_normals(); + + /** Calculate normal vector for face _fh. */ + Normal calc_face_normal(FaceHandle _fh) const; + + /** Calculate normal vector for face (_p0, _p1, _p2). */ + Normal calc_face_normal(const Point& _p0, const Point& _p1, + const Point& _p2) const; + // calculates the average of the vertices defining _fh + void calc_face_centroid(FaceHandle _fh, Point& _pt) const; + /// Update normal for vertex _vh + void update_normal(VertexHandle _vh) + { set_normal(_vh, calc_vertex_normal(_vh)); } + + /** Update normal vectors for all vertices. \attention Needs the + Attributes::Normal attribute for faces and vertices. */ + void update_vertex_normals(); + + /** Calculate normal vector for vertex _vh by averaging normals + of adjacent faces. Face normals have to be computed first. + \attention Needs the Attributes::Normal attribute for faces. */ + Normal calc_vertex_normal(VertexHandle _vh) const; + + /** Different methods for calculation of the normal at _vh: + - -"-_fast - the default one - the same as calc vertex_normal() + - needs the Attributes::Normal attribute for faces + - -"-_correct - works properly for non-triangular meshes + - does not need any attributes + - -"-_loop - calculates loop surface normals + - does not need any attributes */ + void calc_vertex_normal_fast(VertexHandle _vh, Normal& _n) const; + void calc_vertex_normal_correct(VertexHandle _vh, Normal& _n) const; + void calc_vertex_normal_loop(VertexHandle _vh, Normal& _n) const; + + + //@} + + // --- Geometry API - still in development --- + + /** Calculates the edge vector as the vector defined by + the halfedge with id #0 (see below) */ + void calc_edge_vector(EdgeHandle _eh, Normal& _edge_vec) const + { calc_edge_vector(halfedge_handle(_eh,0), _edge_vec); } + + /** Calculates the edge vector as the difference of the + the points defined by to_vertex_handle() and from_vertex_handle() */ + void calc_edge_vector(HalfedgeHandle _heh, Normal& _edge_vec) const + { + _edge_vec = point(to_vertex_handle(_heh)); + _edge_vec -= point(from_vertex_handle(_heh)); + } + + // Calculates the length of the edge _eh + Scalar calc_edge_length(EdgeHandle _eh) const + { return calc_edge_length(halfedge_handle(_eh,0)); } + + /** Calculates the length of the edge _heh + */ + Scalar calc_edge_length(HalfedgeHandle _heh) const + { return (Scalar)sqrt(calc_edge_sqr_length(_heh)); } + + Scalar calc_edge_sqr_length(EdgeHandle _eh) const + { return calc_edge_sqr_length(halfedge_handle(_eh,0)); } + + Scalar calc_edge_sqr_length(HalfedgeHandle _heh) const + { + Normal edge_vec; + calc_edge_vector(_heh, edge_vec); + return edge_vec.sqrnorm(); + } + + /** defines a consistent representation of a sector geometry: + the halfedge _in_heh defines the sector orientation + the vertex pointed by _in_heh defines the sector center + _vec0 and _vec1 are resp. the first and the second vectors defining the sector */ + void calc_sector_vectors(HalfedgeHandle _in_heh, Normal& _vec0, Normal& _vec1) const + { + calc_edge_vector(next_halfedge_handle(_in_heh), _vec0);//p2 - p1 + calc_edge_vector(opposite_halfedge_handle(_in_heh), _vec1);//p0 - p1 + } + + /** calculates the sector angle.\n + * The vertex pointed by _in_heh defines the sector center + * The angle will be calculated between the given halfedge and the next halfedge.\n + * Seen from the center vertex this will be the next halfedge in clockwise direction.\n + NOTE: only boundary concave sectors are treated correctly */ + Scalar calc_sector_angle(HalfedgeHandle _in_heh) const + { + Normal v0, v1; + calc_sector_vectors(_in_heh, v0, v1); + Scalar denom = v0.norm()*v1.norm(); + if (is_zero(denom)) + { + return 0; + } + Scalar cos_a = (v0 | v1) / denom; + if (is_boundary(_in_heh)) + {//determine if the boundary sector is concave or convex + FaceHandle fh(face_handle(opposite_halfedge_handle(_in_heh))); + Normal f_n(calc_face_normal(fh));//this normal is (for convex fh) OK + Scalar sign_a = dot(cross(v0, v1), f_n); + return angle(cos_a, sign_a); + } + else + { + return acos(sane_aarg(cos_a)); + } + } + + // calculate the cos and the sin of angle <(_in_heh,next_halfedge(_in_heh)) + /* + void calc_sector_angle_cos_sin(HalfedgeHandle _in_heh, Scalar& _cos_a, Scalar& _sin_a) const + { + Normal in_vec, out_vec; + calc_edge_vector(_in_heh, in_vec); + calc_edge_vector(next_halfedge_handle(_in_heh), out_vec); + Scalar denom = in_vec.norm()*out_vec.norm(); + if (is_zero(denom)) + { + _cos_a = 1; + _sin_a = 0; + } + else + { + _cos_a = dot(in_vec, out_vec)/denom; + _sin_a = cross(in_vec, out_vec).norm()/denom; + } + } + */ + /** calculates the normal (non-normalized) of the face sector defined by + the angle <(_in_heh,next_halfedge(_in_heh)) */ + void calc_sector_normal(HalfedgeHandle _in_heh, Normal& _sector_normal) const + { + Normal vec0, vec1; + calc_sector_vectors(_in_heh, vec0, vec1); + _sector_normal = cross(vec0, vec1);//(p2-p1)^(p0-p1) + } + + /** calculates the area of the face sector defined by + the angle <(_in_heh,next_halfedge(_in_heh)) + NOTE: special cases (e.g. concave sectors) are not handled correctly */ + Scalar calc_sector_area(HalfedgeHandle _in_heh) const + { + Normal sector_normal; + calc_sector_normal(_in_heh, sector_normal); + return sector_normal.norm()/2; + } + + /** calculates the dihedral angle on the halfedge _heh + \attention Needs the Attributes::Normal attribute for faces */ + Scalar calc_dihedral_angle_fast(HalfedgeHandle _heh) const + { + CHECK(Kernel::has_face_normals()); + if (is_boundary(edge_handle(_heh))) + {//the dihedral angle at a boundary edge is 0 + return 0; + } + const Normal& n0 = normal(face_handle(_heh)); + const Normal& n1 = normal(face_handle(opposite_halfedge_handle(_heh))); + Normal he; + calc_edge_vector(_heh, he); + Scalar da_cos = dot(n0, n1); + //should be normalized, but we need only the sign + Scalar da_sin_sign = dot(cross(n0, n1), he); + return angle(da_cos, da_sin_sign); + } + + /** calculates the dihedral angle on the edge _eh + \attention Needs the Attributes::Normal attribute for faces */ + Scalar calc_dihedral_angle_fast(EdgeHandle _eh) const + { return calc_dihedral_angle_fast(halfedge_handle(_eh,0)); } + + // calculates the dihedral angle on the halfedge _heh + Scalar calc_dihedral_angle(HalfedgeHandle _heh) const + { + if (is_boundary(edge_handle(_heh))) + {//the dihedral angle at a boundary edge is 0 + return 0; + } + Normal n0, n1, he; + calc_sector_normal(_heh, n0); + calc_sector_normal(opposite_halfedge_handle(_heh), n1); + calc_edge_vector(_heh, he); + Scalar denom = n0.norm()*n1.norm(); + if (denom == Scalar(0)) + { + return 0; + } + Scalar da_cos = dot(n0, n1)/denom; + //should be normalized, but we need only the sign + Scalar da_sin_sign = dot(cross(n0, n1), he); + return angle(da_cos, da_sin_sign); + } + + // calculates the dihedral angle on the edge _eh + Scalar calc_dihedral_angle(EdgeHandle _eh) const + { return calc_dihedral_angle(halfedge_handle(_eh,0)); } + + /** tags an edge as a feature if its dihedral angle is larger than _angle_tresh + returns the number of the found feature edges, requires edge_status property*/ + uint find_feature_edges(Scalar _angle_tresh = OpenMesh::deg_to_rad(44.0)); + // --- misc --- + + /// Face split (= 1-to-n split) + inline void split(FaceHandle _fh, const Point& _p) + { Kernel::split(_fh, add_vertex(_p)); } + + inline void split(FaceHandle _fh, VertexHandle _vh) + { Kernel::split(_fh, _vh); } + + inline void split(EdgeHandle _eh, const Point& _p) + { Kernel::split(_eh, add_vertex(_p)); } + + inline void split(EdgeHandle _eh, VertexHandle _vh) + { Kernel::split(_eh, _vh); } +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_POLYMESH_C) +# define OPENMESH_POLYMESH_TEMPLATES +# include "PolyMeshT.cc" +#endif +//============================================================================= +#endif // OPENMESH_POLYMESHT_HH defined +//============================================================================= diff --git a/Core/Mesh/PolyMesh_ArrayKernelT.hh b/Core/Mesh/PolyMesh_ArrayKernelT.hh new file mode 100644 index 00000000..8aa85796 --- /dev/null +++ b/Core/Mesh/PolyMesh_ArrayKernelT.hh @@ -0,0 +1,89 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// CLASS PolyMesh_ArrayKernelT +// +//============================================================================= + + +#ifndef OPENMESH_POLY_MESH_ARRAY_KERNEL_HH +#define OPENMESH_POLY_MESH_ARRAY_KERNEL_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + +/// Helper class to build a PolyMesh-type +template +struct PolyMesh_ArrayKernel_GeneratorT +{ + typedef FinalMeshItemsT MeshItems; + typedef AttribKernelT AttribKernel; + typedef PolyMeshT Mesh; +}; + + +/** \class PolyMesh_ArrayKernelT PolyMesh_ArrayKernelT.hh + + \ingroup mesh_types_group + Polygonal mesh based on the ArrayKernel. + \see OpenMesh::PolyMeshT + \see OpenMesh::ArrayKernel +*/ +template +class PolyMesh_ArrayKernelT + : public PolyMesh_ArrayKernel_GeneratorT::Mesh +{}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_POLY_MESH_ARRAY_KERNEL_HH +//============================================================================= diff --git a/Core/Mesh/Status.hh b/Core/Mesh/Status.hh new file mode 100644 index 00000000..4ea1f418 --- /dev/null +++ b/Core/Mesh/Status.hh @@ -0,0 +1,158 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// CLASS Status +// +//============================================================================= + + +#ifndef OPENMESH_ATTRIBUTE_STATUS_HH +#define OPENMESH_ATTRIBUTE_STATUS_HH + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Attributes { + + +//== CLASS DEFINITION ======================================================== + + +/** Status bits used by the Status class. + * \see OpenMesh::Attributes::StatusInfo + */ +enum StatusBits { + + DELETED = 1, ///< Item has been deleted + LOCKED = 2, ///< Item is locked. + SELECTED = 4, ///< Item is selected. + HIDDEN = 8, ///< Item is hidden. + FEATURE = 16, ///< Item is a feature or belongs to a feature. + TAGGED = 32, ///< Item is tagged. + TAGGED2 = 64, ///< Alternate bit for tagging an item. + UNUSED = 128 ///< +}; + + +/** \class StatusInfo Status.hh + * + * Add status information to a base class. + * + * \see StatusBits + */ +class StatusInfo +{ +public: + + typedef unsigned int value_type; + + StatusInfo() : status_(0) {} + + /// is deleted ? + bool deleted() const { return is_bit_set(DELETED); } + /// set deleted + void set_deleted(bool _b) { change_bit(DELETED, _b); } + + + /// is locked ? + bool locked() const { return is_bit_set(LOCKED); } + /// set locked + void set_locked(bool _b) { change_bit(LOCKED, _b); } + + + /// is selected ? + bool selected() const { return is_bit_set(SELECTED); } + /// set selected + void set_selected(bool _b) { change_bit(SELECTED, _b); } + + + /// is hidden ? + bool hidden() const { return is_bit_set(HIDDEN); } + /// set hidden + void set_hidden(bool _b) { change_bit(HIDDEN, _b); } + + + /// is feature ? + bool feature() const { return is_bit_set(FEATURE); } + /// set feature + void set_feature(bool _b) { change_bit(FEATURE, _b); } + + + /// is tagged ? + bool tagged() const { return is_bit_set(TAGGED); } + /// set tagged + void set_tagged(bool _b) { change_bit(TAGGED, _b); } + + + /// is tagged2 ? This is just one more tag info. + bool tagged2() const { return is_bit_set(TAGGED2); } + /// set tagged + void set_tagged2(bool _b) { change_bit(TAGGED2, _b); } + + + /// return whole status + unsigned int bits() const { return status_; } + /// set whole status at once + void set_bits(unsigned int _bits) { status_ = _bits; } + + + /// is a certain bit set ? + bool is_bit_set(unsigned int _s) const { return (status_ & _s) > 0; } + /// set a certain bit + void set_bit(unsigned int _s) { status_ |= _s; } + /// unset a certain bit + void unset_bit(unsigned int _s) { status_ &= ~_s; } + /// set or unset a certain bit + void change_bit(unsigned int _s, bool _b) { + if (_b) status_ |= _s; else status_ &= ~_s; } + + +private: + + value_type status_; +}; + + +//============================================================================= +} // namespace Attributes +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ATTRIBUTE_STATUS_HH defined +//============================================================================= diff --git a/Core/Mesh/Traits.hh b/Core/Mesh/Traits.hh new file mode 100644 index 00000000..50b56c3e --- /dev/null +++ b/Core/Mesh/Traits.hh @@ -0,0 +1,227 @@ +//============================================================================= +// +// 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: 3794 $ +// $Date: 2008-11-25 19:25:02 +0100 (Di, 25. Nov 2008) $ +// +//============================================================================= + + +/** \file Core/Mesh/Traits.hh + This file defines the default traits and some convenience macros. +*/ + + +//============================================================================= +// +// CLASS Traits +// +//============================================================================= + +#ifndef OPENMESH_TRAITS_HH +#define OPENMESH_TRAITS_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/// Macro for defining the vertex attributes. See \ref mesh_type. +#define VertexAttributes(_i) enum { VertexAttributes = _i } + +/// Macro for defining the halfedge attributes. See \ref mesh_type. +#define HalfedgeAttributes(_i) enum { HalfedgeAttributes = _i } + +/// Macro for defining the edge attributes. See \ref mesh_type. +#define EdgeAttributes(_i) enum { EdgeAttributes = _i } + +/// Macro for defining the face attributes. See \ref mesh_type. +#define FaceAttributes(_i) enum { FaceAttributes = _i } + +/// Macro for defining the vertex traits. See \ref mesh_type. +#define VertexTraits \ + template struct VertexT : public Base + +/// Macro for defining the halfedge traits. See \ref mesh_type. +#define HalfedgeTraits \ + template struct HalfedgeT : public Base + +/// Macro for defining the edge traits. See \ref mesh_type. +#define EdgeTraits \ + template struct EdgeT : public Base + +/// Macro for defining the face traits. See \ref mesh_type. +#define FaceTraits \ + template struct FaceT : public Base + + + +//== CLASS DEFINITION ========================================================= + + +/** \class DefaultTraits Traits.hh + + Base class for all traits. All user traits should be derived from + this class. You may enrich all basic items by additional + properties or define one or more of the types \c Point, \c Normal, + \c TexCoord, or \c Color. + + \see The Mesh docu section on \ref mesh_type. + \see Traits.hh for a list of macros for traits classes. +*/ +struct DefaultTraits +{ + /// The default coordinate type is OpenMesh::Vec3f. + typedef Vec3f Point; + + /// The default normal type is OpenMesh::Vec3f. + typedef Vec3f Normal; + + /// The default 1D texture coordinate type is float. + typedef float TexCoord1D; + /// The default 2D texture coordinate type is OpenMesh::Vec2f. + typedef Vec2f TexCoord2D; + /// The default 3D texture coordinate type is OpenMesh::Vec3f. + typedef Vec3f TexCoord3D; + + /// The default texture index type + typedef int TextureIndex; + + /// The default color type is OpenMesh::Vec3uc. + typedef Vec3uc Color; + +#ifndef DOXY_IGNORE_THIS + VertexTraits {}; + HalfedgeTraits {}; + EdgeTraits {}; + FaceTraits {}; +#endif + + VertexAttributes(0); + HalfedgeAttributes(Attributes::PrevHalfedge); + EdgeAttributes(0); + FaceAttributes(0); +}; + + +//== CLASS DEFINITION ========================================================= + + +/** Helper class to merge two mesh traits. + * \internal + * + * With the help of this class it's possible to merge two mesh traits. + * Whereby \c _Traits1 overrides equally named symbols of \c _Traits2. + * + * For your convenience use the provided defines \c OM_Merge_Traits + * and \c OM_Merge_Traits_In_Template instead. + * + * \see OM_Merge_Traits, OM_Merge_Traits_In_Template + */ +template struct MergeTraits +{ +#ifndef DOXY_IGNORE_THIS + struct Result + { + // Mipspro needs this (strange) typedef + typedef _Traits1 T1; + typedef _Traits2 T2; + + + VertexAttributes ( T1::VertexAttributes | T2::VertexAttributes ); + HalfedgeAttributes ( T1::HalfedgeAttributes | T2::HalfedgeAttributes ); + EdgeAttributes ( T1::EdgeAttributes | T2::EdgeAttributes ); + FaceAttributes ( T1::FaceAttributes | T2::FaceAttributes ); + + + typedef typename T1::Point Point; + typedef typename T1::Normal Normal; + typedef typename T1::Color Color; + typedef typename T1::TexCoord TexCoord; + + template class VertexT : + public T1::template VertexT< + typename T2::template VertexT, Refs> + {}; + + template class HalfedgeT : + public T1::template HalfedgeT< + typename T2::template HalfedgeT, Refs> + {}; + + + template class EdgeT : + public T1::template EdgeT< + typename T2::template EdgeT, Refs> + {}; + + + template class FaceT : + public T1::template FaceT< + typename T2::template FaceT, Refs> + {}; + }; +#endif +}; + + +/** + Macro for merging two traits classes _S1 and _S2 into one traits class _D. + Note that in case of ambiguities class _S1 overrides _S2, especially + the point/normal/color/texcoord type to be used is taken from _S1::Point/ + _S1::Normal/_S1::Color/_S1::TexCoord. +*/ +#define OM_Merge_Traits(_S1, _S2, _D) \ + typedef OpenMesh::MergeTraits<_S1, _S2>::Result _D; + + +/** + Macro for merging two traits classes _S1 and _S2 into one traits class _D. + Same as OM_Merge_Traits, but this can be used inside template classes. +*/ +#define OM_Merge_Traits_In_Template(_S1, _S2, _D) \ + typedef typename OpenMesh::MergeTraits<_S1, _S2>::Result _D; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_TRAITS_HH defined +//============================================================================= + diff --git a/Core/Mesh/TriConnectivity.cc b/Core/Mesh/TriConnectivity.cc new file mode 100644 index 00000000..1e3e919a --- /dev/null +++ b/Core/Mesh/TriConnectivity.cc @@ -0,0 +1,448 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= +// CLASS TriMeshT - IMPLEMENTATION + +#include +#include + +namespace OpenMesh +{ + +TriConnectivity::FaceHandle +TriConnectivity::add_face(const VertexHandle* _vertex_handles, uint _vhs_size) +{ + // need at least 3 vertices + if (_vhs_size < 3) return InvalidFaceHandle; + + /// face is triangle -> ok + if (_vhs_size == 3) + return PolyConnectivity::add_face(_vertex_handles, _vhs_size); + + /// face is not a triangle -> triangulate + else + { + //omlog() << "triangulating " << _vhs_size << "_gon\n"; + + VertexHandle vhandles[3]; + vhandles[0] = _vertex_handles[0]; + + FaceHandle fh; + unsigned int i(1); + --_vhs_size; + + while (i < _vhs_size) + { + vhandles[1] = _vertex_handles[i]; + vhandles[2] = _vertex_handles[++i]; + fh = PolyConnectivity::add_face(vhandles, 3); + } + + return fh; + } +} + +//----------------------------------------------------------------------------- +bool TriConnectivity::is_collapse_ok(HalfedgeHandle v0v1) +{ + HalfedgeHandle v1v0(opposite_halfedge_handle(v0v1)); + VertexHandle v0(to_vertex_handle(v1v0)); + VertexHandle v1(to_vertex_handle(v0v1)); + + // are vertices already deleted ? + if (status(v0).deleted() || status(v1).deleted()) + return false; + + + VertexHandle vl, vr; + HalfedgeHandle h1, h2; + + + // the edges v1-vl and vl-v0 must not be both boundary edges + if (!is_boundary(v0v1)) + { + vl = to_vertex_handle(next_halfedge_handle(v0v1)); + + h1 = next_halfedge_handle(v0v1); + h2 = next_halfedge_handle(h1); + if (is_boundary(opposite_halfedge_handle(h1)) && + is_boundary(opposite_halfedge_handle(h2))) + { + return false; + } + } + + + // the edges v0-vr and vr-v1 must not be both boundary edges + if (!is_boundary(v1v0)) + { + vr = to_vertex_handle(next_halfedge_handle(v1v0)); + + h1 = next_halfedge_handle(v1v0); + h2 = next_halfedge_handle(h1); + if (is_boundary(opposite_halfedge_handle(h1)) && + is_boundary(opposite_halfedge_handle(h2))) + return false; + } + + + // if vl and vr are equal or both invalid -> fail + if (vl == vr) return false; + + + VertexVertexIter vv_it; + + + // test intersection of the one-rings of v0 and v1 + for (vv_it = vv_iter(v0); vv_it; ++vv_it) + status(vv_it).set_tagged(false); + + for (vv_it = vv_iter(v1); vv_it; ++vv_it) + status(vv_it).set_tagged(true); + + for (vv_it = vv_iter(v0); vv_it; ++vv_it) + if (status(vv_it).tagged() && vv_it.handle() != vl && vv_it.handle() != vr) + return false; + + + + // edge between two boundary vertices should be a boundary edge + if ( is_boundary(v0) && is_boundary(v1) && + !is_boundary(v0v1) && !is_boundary(v1v0)) + return false; + + // passed all tests + return true; +} + +//----------------------------------------------------------------------------- +TriConnectivity::HalfedgeHandle +TriConnectivity::vertex_split(VertexHandle v0, VertexHandle v1, + VertexHandle vl, VertexHandle vr) +{ + HalfedgeHandle v1vl, vlv1, vrv1, v0v1; + + // build loop from halfedge v1->vl + if (vl.is_valid()) + { + v1vl = find_halfedge(v1, vl); + assert(v1vl.is_valid()); + vlv1 = insert_loop(v1vl); + } + + // build loop from halfedge vr->v1 + if (vr.is_valid()) + { + vrv1 = find_halfedge(vr, v1); + assert(vrv1.is_valid()); + insert_loop(vrv1); + } + + // handle boundary cases + if (!vl.is_valid()) + vlv1 = prev_halfedge_handle(halfedge_handle(v1)); + if (!vr.is_valid()) + vrv1 = prev_halfedge_handle(halfedge_handle(v1)); + + + // split vertex v1 into edge v0v1 + v0v1 = insert_edge(v0, vlv1, vrv1); + + + return v0v1; +} + +//----------------------------------------------------------------------------- +TriConnectivity::HalfedgeHandle +TriConnectivity::insert_loop(HalfedgeHandle _hh) +{ + HalfedgeHandle h0(_hh); + HalfedgeHandle o0(opposite_halfedge_handle(h0)); + + VertexHandle v0(to_vertex_handle(o0)); + VertexHandle v1(to_vertex_handle(h0)); + + HalfedgeHandle h1 = new_edge(v1, v0); + HalfedgeHandle o1 = opposite_halfedge_handle(h1); + + FaceHandle f0 = face_handle(h0); + FaceHandle f1 = new_face(); + + // halfedge -> halfedge + set_next_halfedge_handle(prev_halfedge_handle(h0), o1); + set_next_halfedge_handle(o1, next_halfedge_handle(h0)); + set_next_halfedge_handle(h1, h0); + set_next_halfedge_handle(h0, h1); + + // halfedge -> face + set_face_handle(o1, f0); + set_face_handle(h0, f1); + set_face_handle(h1, f1); + + // face -> halfedge + set_halfedge_handle(f1, h0); + if (f0.is_valid()) + set_halfedge_handle(f0, o1); + + + // vertex -> halfedge + adjust_outgoing_halfedge(v0); + adjust_outgoing_halfedge(v1); + + return h1; +} + +//----------------------------------------------------------------------------- +TriConnectivity::HalfedgeHandle +TriConnectivity::insert_edge(VertexHandle _vh, HalfedgeHandle _h0, HalfedgeHandle _h1) +{ + assert(_h0.is_valid() && _h1.is_valid()); + + VertexHandle v0 = _vh; + VertexHandle v1 = to_vertex_handle(_h0); + + assert( v1 == to_vertex_handle(_h1)); + + HalfedgeHandle v0v1 = new_edge(v0, v1); + HalfedgeHandle v1v0 = opposite_halfedge_handle(v0v1); + + + + // vertex -> halfedge + set_halfedge_handle(v0, v0v1); + set_halfedge_handle(v1, v1v0); + + + // halfedge -> halfedge + set_next_halfedge_handle(v0v1, next_halfedge_handle(_h0)); + set_next_halfedge_handle(_h0, v0v1); + set_next_halfedge_handle(v1v0, next_halfedge_handle(_h1)); + set_next_halfedge_handle(_h1, v1v0); + + + // halfedge -> vertex + for (VertexIHalfedgeIter vih_it(vih_iter(v0)); vih_it; ++vih_it) + set_vertex_handle(vih_it.handle(), v0); + + + // halfedge -> face + set_face_handle(v0v1, face_handle(_h0)); + set_face_handle(v1v0, face_handle(_h1)); + + + // face -> halfedge + if (face_handle(v0v1).is_valid()) + set_halfedge_handle(face_handle(v0v1), v0v1); + if (face_handle(v1v0).is_valid()) + set_halfedge_handle(face_handle(v1v0), v1v0); + + + // vertex -> halfedge + adjust_outgoing_halfedge(v0); + adjust_outgoing_halfedge(v1); + + + return v0v1; +} + +//----------------------------------------------------------------------------- +bool TriConnectivity::is_flip_ok(EdgeHandle _eh) const +{ + // boundary edges cannot be flipped + if (is_boundary(_eh)) return false; + + + HalfedgeHandle hh = halfedge_handle(_eh, 0); + HalfedgeHandle oh = halfedge_handle(_eh, 1); + + + // check if the flipped edge is already present + // in the mesh + + VertexHandle ah = to_vertex_handle(next_halfedge_handle(hh)); + VertexHandle bh = to_vertex_handle(next_halfedge_handle(oh)); + + if (ah == bh) // this is generally a bad sign !!! + return false; + + for (ConstVertexVertexIter vvi(*this, ah); vvi; ++vvi) + if (vvi.handle() == bh) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +void TriConnectivity::flip(EdgeHandle _eh) +{ + // CAUTION : Flipping a halfedge may result in + // a non-manifold mesh, hence check for yourself + // whether this operation is allowed or not! + assert(is_flip_ok(_eh));//let's make it sure it is actually checked + assert(!is_boundary(_eh)); + + HalfedgeHandle a0 = halfedge_handle(_eh, 0); + HalfedgeHandle b0 = halfedge_handle(_eh, 1); + + HalfedgeHandle a1 = next_halfedge_handle(a0); + HalfedgeHandle a2 = next_halfedge_handle(a1); + + HalfedgeHandle b1 = next_halfedge_handle(b0); + HalfedgeHandle b2 = next_halfedge_handle(b1); + + VertexHandle va0 = to_vertex_handle(a0); + VertexHandle va1 = to_vertex_handle(a1); + + VertexHandle vb0 = to_vertex_handle(b0); + VertexHandle vb1 = to_vertex_handle(b1); + + FaceHandle fa = face_handle(a0); + FaceHandle fb = face_handle(b0); + + set_vertex_handle(a0, va1); + set_vertex_handle(b0, vb1); + + set_next_halfedge_handle(a0, a2); + set_next_halfedge_handle(a2, b1); + set_next_halfedge_handle(b1, a0); + + set_next_halfedge_handle(b0, b2); + set_next_halfedge_handle(b2, a1); + set_next_halfedge_handle(a1, b0); + + set_face_handle(a1, fb); + set_face_handle(b1, fa); + + set_halfedge_handle(fa, a0); + set_halfedge_handle(fb, b0); + + if (halfedge_handle(va0) == b0) + set_halfedge_handle(va0, a1); + if (halfedge_handle(vb0) == a0) + set_halfedge_handle(vb0, b1); +} + + +//----------------------------------------------------------------------------- +void TriConnectivity::split(EdgeHandle _eh, VertexHandle _vh) +{ + HalfedgeHandle h0 = halfedge_handle(_eh, 0); + HalfedgeHandle o0 = halfedge_handle(_eh, 1); + + VertexHandle v2 = to_vertex_handle(o0); + + HalfedgeHandle e1 = new_edge(_vh, v2); + HalfedgeHandle t1 = opposite_halfedge_handle(e1); + + FaceHandle f0 = face_handle(h0); + FaceHandle f3 = face_handle(o0); + + set_halfedge_handle(_vh, h0); + set_vertex_handle(o0, _vh); + + if (!is_boundary(h0)) + { + HalfedgeHandle h1 = next_halfedge_handle(h0); + HalfedgeHandle h2 = next_halfedge_handle(h1); + + VertexHandle v1 = to_vertex_handle(h1); + + HalfedgeHandle e0 = new_edge(_vh, v1); + HalfedgeHandle t0 = opposite_halfedge_handle(e0); + + FaceHandle f1 = new_face(); + set_halfedge_handle(f0, h0); + set_halfedge_handle(f1, h2); + + set_face_handle(h1, f0); + set_face_handle(t0, f0); + set_face_handle(h0, f0); + + set_face_handle(h2, f1); + set_face_handle(t1, f1); + set_face_handle(e0, f1); + + set_next_halfedge_handle(h0, h1); + set_next_halfedge_handle(h1, t0); + set_next_halfedge_handle(t0, h0); + + set_next_halfedge_handle(e0, h2); + set_next_halfedge_handle(h2, t1); + set_next_halfedge_handle(t1, e0); + } + else + { + set_next_halfedge_handle(prev_halfedge_handle(h0), t1); + set_next_halfedge_handle(t1, h0); + // halfedge handle of _vh already is h0 + } + + + if (!is_boundary(o0)) + { + HalfedgeHandle o1 = next_halfedge_handle(o0); + HalfedgeHandle o2 = next_halfedge_handle(o1); + + VertexHandle v3 = to_vertex_handle(o1); + + HalfedgeHandle e2 = new_edge(_vh, v3); + HalfedgeHandle t2 = opposite_halfedge_handle(e2); + + FaceHandle f2 = new_face(); + set_halfedge_handle(f2, o1); + set_halfedge_handle(f3, o0); + + set_face_handle(o1, f2); + set_face_handle(t2, f2); + set_face_handle(e1, f2); + + set_face_handle(o2, f3); + set_face_handle(o0, f3); + set_face_handle(e2, f3); + + set_next_halfedge_handle(e1, o1); + set_next_halfedge_handle(o1, t2); + set_next_halfedge_handle(t2, e1); + + set_next_halfedge_handle(o0, e2); + set_next_halfedge_handle(e2, o2); + set_next_halfedge_handle(o2, o0); + } + else + { + set_next_halfedge_handle(e1, next_halfedge_handle(o0)); + set_next_halfedge_handle(o0, e1); + set_halfedge_handle(_vh, e1); + } + + if (halfedge_handle(v2) == h0) + set_halfedge_handle(v2, t1); +} + +}// namespace OpenMesh diff --git a/Core/Mesh/TriConnectivity.hh b/Core/Mesh/TriConnectivity.hh new file mode 100644 index 00000000..e52951bc --- /dev/null +++ b/Core/Mesh/TriConnectivity.hh @@ -0,0 +1,130 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2004 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. * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_TRICONNECTIVITY_HH +#define OPENMESH_TRICONNECTIVITY_HH + +#include + +namespace OpenMesh { + +class TriConnectivity : public PolyConnectivity +{ +public: + + TriConnectivity() {} + virtual ~TriConnectivity() {} + + inline static bool is_triangles() + { return true; } + + /** assign_connectivity() methods. See ArrayKernel::assign_connectivity() + for more details. When the source connectivity is not triangles, in + addition "fan" connectivity triangulation is performed*/ + inline void assign_connectivity(const TriConnectivity& _other) + { PolyConnectivity::assign_connectivity(_other); } + + inline void assign_connectivity(const PolyConnectivity& _other) + { + PolyConnectivity::assign_connectivity(_other); + triangulate(); + } + + /** \name Addding items to a mesh + */ + //@{ + /** Override OpenMesh::Mesh::PolyMeshT::add_face(). Faces that aren't + triangles will be triangulated and added. In this case an + invalid face handle will be returned. */ + FaceHandle add_face(const std::vector& _vhandles) + { return add_face(&_vhandles.front(), _vhandles.size()); } + + FaceHandle add_face(const VertexHandle* _vhandles, uint _vhs_size); + + FaceHandle add_face(VertexHandle _vh0, VertexHandle _vh1, VertexHandle _vh2) + { + VertexHandle vhs[3] = { _vh0, _vh1, _vh2 }; + return PolyConnectivity::add_face(vhs, 3); + } + + //@} + + /** Returns the opposite vertex to the halfedge _heh in the face + referenced by _heh returns InvalidVertexHandle if the _heh is + boundary */ + inline VertexHandle opposite_vh(HalfedgeHandle _heh) const + { + return is_boundary(_heh) ? InvalidVertexHandle : + to_vertex_handle(next_halfedge_handle(_heh)); + } + + /** Returns the opposite vertex to the opposite halfedge of _heh in + the face referenced by it returns InvalidVertexHandle if the + opposite halfedge is boundary */ + VertexHandle opposite_he_opposite_vh(HalfedgeHandle _heh) const + { return opposite_vh(opposite_halfedge_handle(_heh)); } + + /** \name Topology modifying operators + */ + //@{ + + + /** Returns whether collapsing halfedge _heh is ok or would lead to + topological inconsistencies. + \attention This method need the Attributes::Status attribute and + changes the \em tagged bit. */ + bool is_collapse_ok(HalfedgeHandle _heh); + + /// Vertex Split: inverse operation to collapse(). + HalfedgeHandle vertex_split(VertexHandle v0, VertexHandle v1, + VertexHandle vl, VertexHandle vr); + + /// Check whether flipping _eh is topologically correct. + bool is_flip_ok(EdgeHandle _eh) const; + + /** Flip edge _eh. + Check for topological correctness first using is_flip_ok(). */ + void flip(EdgeHandle _eh); + + /// Edge split (= 2-to-4 split) + void split(EdgeHandle _eh, VertexHandle _vh); + + /// Face split (= 1-to-3 split, calls corresponding PolyMeshT function). + inline void split(FaceHandle _fh, VertexHandle _vh) + { PolyConnectivity::split(_fh, _vh); } + + //@} + +private: + /// Helper for vertex split + HalfedgeHandle insert_loop(HalfedgeHandle _hh); + /// Helper for vertex split + HalfedgeHandle insert_edge(VertexHandle _vh, + HalfedgeHandle _h0, HalfedgeHandle _h1); +}; + +} + +#endif//OPENMESH_TRICONNECTIVITY_HH diff --git a/Core/Mesh/TriMeshT.cc b/Core/Mesh/TriMeshT.cc new file mode 100644 index 00000000..14a87724 --- /dev/null +++ b/Core/Mesh/TriMeshT.cc @@ -0,0 +1,60 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// CLASS TriMeshT - IMPLEMENTATION +// +//============================================================================= + + +#define OPENMESH_TRIMESH_C + + +//== INCLUDES ================================================================= + + +#include +#include +#include + + +//== NAMESPACES ============================================================== + + +namespace OpenMesh { + + +//== IMPLEMENTATION ========================================================== + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Core/Mesh/TriMeshT.hh b/Core/Mesh/TriMeshT.hh new file mode 100644 index 00000000..952cd56c --- /dev/null +++ b/Core/Mesh/TriMeshT.hh @@ -0,0 +1,195 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// CLASS TriMeshT +// +//============================================================================= + + +#ifndef OPENMESH_TRIMESH_HH +#define OPENMESH_TRIMESH_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** \class TriMeshT TriMeshT.hh + + Base type for a triangle mesh. + + Base type for a triangle mesh, parameterized by a mesh kernel. The + mesh inherits all methods from the kernel class and the + more general polygonal mesh PolyMeshT. Therefore it provides + the same types for items, handles, iterators and so on. + + \param Kernel: template argument for the mesh kernel + \note You should use the predefined mesh-kernel combinations in + \ref mesh_types_group + \see \ref mesh_type + \see OpenMesh::PolyMeshT +*/ + +template +class TriMeshT : public PolyMeshT +{ + +public: + + + // self + typedef TriMeshT This; + typedef PolyMeshT PolyMesh; + + //@{ + /// Determine whether this is a PolyMeshT or TriMeshT + enum { IsPolyMesh = 0 }; + enum { IsTriMesh = 1 }; + static bool is_polymesh() { return false; } + static bool is_trimesh() { return true; } + //@} + + //--- items --- + + typedef typename PolyMesh::Scalar Scalar; + typedef typename PolyMesh::Point Point; + typedef typename PolyMesh::Normal Normal; + typedef typename PolyMesh::Color Color; + typedef typename PolyMesh::TexCoord1D TexCoord1D; + typedef typename PolyMesh::TexCoord2D TexCoord2D; + typedef typename PolyMesh::TexCoord3D TexCoord3D; + typedef typename PolyMesh::Vertex Vertex; + typedef typename PolyMesh::Halfedge Halfedge; + typedef typename PolyMesh::Edge Edge; + typedef typename PolyMesh::Face Face; + + + //--- handles --- + + typedef typename PolyMesh::VertexHandle VertexHandle; + typedef typename PolyMesh::HalfedgeHandle HalfedgeHandle; + typedef typename PolyMesh::EdgeHandle EdgeHandle; + typedef typename PolyMesh::FaceHandle FaceHandle; + + + //--- iterators --- + + typedef typename PolyMesh::VertexIter VertexIter; + typedef typename PolyMesh::ConstVertexIter ConstVertexIter; + typedef typename PolyMesh::EdgeIter EdgeIter; + typedef typename PolyMesh::ConstEdgeIter ConstEdgeIter; + typedef typename PolyMesh::FaceIter FaceIter; + typedef typename PolyMesh::ConstFaceIter ConstFaceIter; + + + + //--- circulators --- + + typedef typename PolyMesh::VertexVertexIter VertexVertexIter; + typedef typename PolyMesh::VertexOHalfedgeIter VertexOHalfedgeIter; + typedef typename PolyMesh::VertexIHalfedgeIter VertexIHalfedgeIter; + typedef typename PolyMesh::VertexEdgeIter VertexEdgeIter; + typedef typename PolyMesh::VertexFaceIter VertexFaceIter; + typedef typename PolyMesh::FaceVertexIter FaceVertexIter; + typedef typename PolyMesh::FaceHalfedgeIter FaceHalfedgeIter; + typedef typename PolyMesh::FaceEdgeIter FaceEdgeIter; + typedef typename PolyMesh::FaceFaceIter FaceFaceIter; + typedef typename PolyMesh::ConstVertexVertexIter ConstVertexVertexIter; + typedef typename PolyMesh::ConstVertexOHalfedgeIter ConstVertexOHalfedgeIter; + typedef typename PolyMesh::ConstVertexIHalfedgeIter ConstVertexIHalfedgeIter; + typedef typename PolyMesh::ConstVertexEdgeIter ConstVertexEdgeIter; + typedef typename PolyMesh::ConstVertexFaceIter ConstVertexFaceIter; + typedef typename PolyMesh::ConstFaceVertexIter ConstFaceVertexIter; + typedef typename PolyMesh::ConstFaceHalfedgeIter ConstFaceHalfedgeIter; + typedef typename PolyMesh::ConstFaceEdgeIter ConstFaceEdgeIter; + typedef typename PolyMesh::ConstFaceFaceIter ConstFaceFaceIter; + + // --- constructor/destructor + + /// Default constructor + TriMeshT() : PolyMesh() {} + /// Destructor + virtual ~TriMeshT() {} + + //--- halfedge collapse / vertex split --- + + /// Vertex Split: inverse operation to collapse(). + inline HalfedgeHandle vertex_split(Point _v0_point, VertexHandle _v1, + VertexHandle _vl, VertexHandle _vr) + { return PolyMesh::vertex_split(add_vertex(_v0_point), _v1, _vl, _vr); } + + inline HalfedgeHandle vertex_split(VertexHandle _v0, VertexHandle _v1, + VertexHandle _vl, VertexHandle _vr) + { return PolyMesh::vertex_split(_v0, _v1, _vl, _vr); } + + /// Edge split (= 2-to-4 split) + inline void split(EdgeHandle _eh, const Point& _p) + { PolyMesh::split(_eh, add_vertex(_p)); } + + inline void split(EdgeHandle _eh, VertexHandle _vh) + { PolyMesh::split(_eh, _vh); } + + /// Face split (= 1-to-3 split, calls corresponding PolyMeshT function). + + /// Face split (= 1-to-3 split, calls corresponding PolyMeshT function). + inline void split(FaceHandle _fh, const Point& _p) + { PolyMesh::split(_fh, _p); } + + inline void split(FaceHandle _fh, VertexHandle _vh) + { PolyMesh::split(_fh, _vh); } +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_TRIMESH_C) +#define OPENMESH_TRIMESH_TEMPLATES +#include "TriMeshT.cc" +#endif +//============================================================================= +#endif // OPENMESH_TRIMESH_HH defined +//============================================================================= diff --git a/Core/Mesh/TriMesh_ArrayKernelT.hh b/Core/Mesh/TriMesh_ArrayKernelT.hh new file mode 100644 index 00000000..be1f27d6 --- /dev/null +++ b/Core/Mesh/TriMesh_ArrayKernelT.hh @@ -0,0 +1,89 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// CLASS TriMesh_ArrayKernelT +// +//============================================================================= + + +#ifndef OPENMESH_TRIMESH_ARRAY_KERNEL_HH +#define OPENMESH_TRIMESH_ARRAY_KERNEL_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/// Helper class to create a TriMesh-type based on ArrayKernelT +template +struct TriMesh_ArrayKernel_GeneratorT +{ + typedef FinalMeshItemsT MeshItems; + typedef AttribKernelT AttribKernel; + typedef TriMeshT Mesh; +}; + + + +/** \ingroup mesh_types_group + Triangle mesh based on the ArrayKernel. + \see OpenMesh::TriMeshT + \see OpenMesh::ArrayKernelT +*/ +template +class TriMesh_ArrayKernelT + : public TriMesh_ArrayKernel_GeneratorT::Mesh +{}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_TRIMESH_ARRAY_KERNEL_HH +//============================================================================= diff --git a/Core/Mesh/gen/circulators_header.hh b/Core/Mesh/gen/circulators_header.hh new file mode 100644 index 00000000..48e731a7 --- /dev/null +++ b/Core/Mesh/gen/circulators_header.hh @@ -0,0 +1,73 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ +#ifndef OPENMESH_CIRCULATORS_HH +#define OPENMESH_CIRCULATORS_HH +//============================================================================= +// +// Vertex and Face circulators for PolyMesh/TriMesh +// +//============================================================================= + + + +//== INCLUDES ================================================================= + +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Iterators { + + +//== FORWARD DECLARATIONS ===================================================== + + +template class VertexVertexIterT; +template class VertexIHalfedgeIterT; +template class VertexOHalfedgeIterT; +template class VertexEdgeIterT; +template class VertexFaceIterT; + +template class ConstVertexVertexIterT; +template class ConstVertexIHalfedgeIterT; +template class ConstVertexOHalfedgeIterT; +template class ConstVertexEdgeIterT; +template class ConstVertexFaceIterT; + +template class FaceVertexIterT; +template class FaceHalfedgeIterT; +template class FaceEdgeIterT; +template class FaceFaceIterT; + +template class ConstFaceVertexIterT; +template class ConstFaceHalfedgeIterT; +template class ConstFaceEdgeIterT; +template class ConstFaceFaceIterT; + + + diff --git a/Core/Mesh/gen/circulators_template.hh b/Core/Mesh/gen/circulators_template.hh new file mode 100644 index 00000000..97a21715 --- /dev/null +++ b/Core/Mesh/gen/circulators_template.hh @@ -0,0 +1,190 @@ +//== CLASS DEFINITION ========================================================= + + +/** \class CirculatorT CirculatorsT.hh + Circulator. +*/ + +template +class CirculatorT +{ + public: + + + //--- Typedefs --- + + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + typedef TargetType value_type; + typedef TargetHandle value_handle; + +#if IsConst + typedef const Mesh& mesh_ref; + typedef const Mesh* mesh_ptr; + typedef const TargetType& reference; + typedef const TargetType* pointer; +#else + typedef Mesh& mesh_ref; + typedef Mesh* mesh_ptr; + typedef TargetType& reference; + typedef TargetType* pointer; +#endif + + + + /// Default constructor + CirculatorT() : mesh_(0), active_(false) {} + + + /// Construct with mesh and a SourceHandle + CirculatorT(mesh_ref _mesh, SourceHandle _start) : + mesh_(&_mesh), + start_(_mesh.halfedge_handle(_start)), + heh_(start_), + active_(false) + { post_init; } + + + /// Construct with mesh and start halfedge + CirculatorT(mesh_ref _mesh, HalfedgeHandle _heh) : + mesh_(&_mesh), + start_(_heh), + heh_(_heh), + active_(false) + { post_init; } + + + /// Copy constructor + CirculatorT(const CirculatorT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { post_init; } + + + /// Assignment operator + CirculatorT& operator=(const CirculatorT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } + + +#if IsConst + /// construct from non-const circulator type + CirculatorT(const NonConstCircT& _rhs) : + mesh_(_rhs.mesh_), + start_(_rhs.start_), + heh_(_rhs.heh_), + active_(_rhs.active_) + { post_init; } + + + /// assign from non-const circulator + CirculatorT& operator=(const NonConstCircT& _rhs) + { + mesh_ = _rhs.mesh_; + start_ = _rhs.start_; + heh_ = _rhs.heh_; + active_ = _rhs.active_; + return *this; + } +#else + friend class ConstCircT; +#endif + + + /// Equal ? + bool operator==(const CirculatorT& _rhs) const { + return ((mesh_ == _rhs.mesh_) && + (start_ == _rhs.start_) && + (heh_ == _rhs.heh_) && + (active_ == _rhs.active_)); + } + + + /// Not equal ? + bool operator!=(const CirculatorT& _rhs) const { + return !operator==(_rhs); + } + + + /// Pre-Increment (next cw target) + CirculatorT& operator++() { + assert(mesh_); + active_ = true; + increment; + return *this; + } + + + /// Pre-Decrement (next ccw target) + CirculatorT& operator--() { + assert(mesh_); + active_ = true; + decrement; + return *this; + } + + + /** Get the current halfedge. There are \c Vertex*Iters and \c + Face*Iters. For both the current state is defined by the + current halfedge. This is what this method returns. + */ + HalfedgeHandle current_halfedge_handle() const { + return heh_; + } + + + /// Return the handle of the current target. + TargetHandle handle() const { + assert(mesh_); + return get_handle; + } + + + /// Cast to the handle of the current target. + operator TargetHandle() const { + assert(mesh_); + return get_handle; + } + + + /// Return a reference to the current target. + reference operator*() const { + assert(mesh_); + return mesh_->deref(handle()); + } + + + /// Return a pointer to the current target. + pointer operator->() const { + assert(mesh_); + return &mesh_->deref(handle()); + } + + + /** Returns whether the circulator is still valid. + After one complete round around a vertex/face the circulator becomes + invalid, i.e. this function will return \c false. Nevertheless you + can continue circulating. This method just tells you whether you + have completed the first round. + */ + operator bool() const { + return heh_.is_valid() && ((start_ != heh_) || (!active_)); + } + + +private: + + mesh_ptr mesh_; + HalfedgeHandle start_, heh_; + bool active_; +}; + + + diff --git a/Core/Mesh/gen/footer.hh b/Core/Mesh/gen/footer.hh new file mode 100644 index 00000000..8e2a9c12 --- /dev/null +++ b/Core/Mesh/gen/footer.hh @@ -0,0 +1,6 @@ +//============================================================================= +} // namespace Iterators +} // namespace OpenMesh +//============================================================================= +#endif +//============================================================================= diff --git a/Core/Mesh/gen/generate.sh b/Core/Mesh/gen/generate.sh new file mode 100644 index 00000000..3bcaffdc --- /dev/null +++ b/Core/Mesh/gen/generate.sh @@ -0,0 +1,175 @@ +#!/bin/bash + +#------------------------------------------------------------------------------ + + +# generate_iterator( TargetType, n_elements, has_element_status ) +function generate_iterator +{ + NonConstIter=$1"IterT" + ConstIter="Const"$NonConstIter + TargetType="typename Mesh::"$1 + TargetHandle="typename Mesh::"$1"Handle" + + + cat iterators_template.hh \ + | sed -e "s/IteratorT/$NonConstIter/; s/IteratorT/$NonConstIter/; + s/NonConstIterT/$NonConstIter/; + s/ConstIterT/$ConstIter/; + s/TargetType/$TargetType/; + s/TargetHandle/$TargetHandle/; + s/IsConst/0/; + s/n_elements/$2/; + s/has_element_status/$3/;" + + + cat iterators_template.hh \ + | sed -e "s/IteratorT/$ConstIter/; s/IteratorT/$ConstIter/; + s/NonConstIterT/$NonConstIter/; + s/ConstIterT/$ConstIter/; + s/TargetType/$TargetType/; + s/TargetHandle/$TargetHandle/; + s/IsConst/1/; + s/n_elements/$2/; + s/has_element_status/$3/;" +} + + +#------------------------------------------------------------------------------ + + +# generate_circulator( NonConstName, SourceType, TargetType, +# post_init, +# increment, decrement, +# get_handle, +# [Name] ) +function generate_circulator +{ + NonConstCirc=$1 + ConstCirc="Const"$NonConstCirc + SourceHandle="typename Mesh::"$2"Handle" + TargetHandle="typename Mesh::"$3"Handle" + TargetType="typename Mesh::"$3 + + + cat circulators_template.hh \ + | sed -e "s/CirculatorT/$NonConstCirc/; s/CirculatorT/$NonConstCirc/; + s/NonConstCircT/$NonConstCirc/; + s/ConstCircT/$ConstCirc/; + s/SourceHandle/$SourceHandle/; + s/TargetHandle/$TargetHandle/; + s/TargetType/$TargetType/; + s/IsConst/0/; + s/post_init/$4/; + s/increment/$5/; + s/decrement/$6/; + s/get_handle/$7/;" + + + cat circulators_template.hh \ + | sed -e "s/CirculatorT/$ConstCirc/; s/CirculatorT/$ConstCirc/; + s/NonConstCircT/$NonConstCirc/; + s/ConstCircT/$ConstCirc/; + s/SourceHandle/$SourceHandle/; + s/TargetHandle/$TargetHandle/; + s/TargetType/$TargetType/; + s/IsConst/1/; + s/post_init/$4/; + s/increment/$5/; + s/decrement/$6/; + s/get_handle/$7/;" +} + + +#------------------------------------------------------------------------------ + + +### Generate IteratorsT.hh + +cat iterators_header.hh > IteratorsT.hh + +generate_iterator Vertex n_vertices has_vertex_status >> IteratorsT.hh +generate_iterator Halfedge n_halfedges has_halfedge_status >> IteratorsT.hh +generate_iterator Edge n_edges has_edge_status >> IteratorsT.hh +generate_iterator Face n_faces has_face_status >> IteratorsT.hh + +cat footer.hh >> IteratorsT.hh + + +#------------------------------------------------------------------------------ + + +### Generate CirculatorsT.hh + +cat circulators_header.hh > CirculatorsT.hh + + +generate_circulator VertexVertexIterT Vertex Vertex \ + " " \ + "heh_=mesh_->cw_rotated_halfedge_handle(heh_);" \ + "heh_=mesh_->ccw_rotated_halfedge_handle(heh_);" \ + "mesh_->to_vertex_handle(heh_);" \ + >> CirculatorsT.hh + +generate_circulator VertexOHalfedgeIterT Vertex Halfedge \ + " " \ + "heh_=mesh_->cw_rotated_halfedge_handle(heh_);" \ + "heh_=mesh_->ccw_rotated_halfedge_handle(heh_);" \ + "heh_" \ + >> CirculatorsT.hh + +generate_circulator VertexIHalfedgeIterT Vertex Halfedge \ + " " \ + "heh_=mesh_->cw_rotated_halfedge_handle(heh_);" \ + "heh_=mesh_->ccw_rotated_halfedge_handle(heh_);" \ + "mesh_->opposite_halfedge_handle(heh_)" \ + >> CirculatorsT.hh + +generate_circulator VertexEdgeIterT Vertex Edge \ + " " \ + "heh_=mesh_->cw_rotated_halfedge_handle(heh_);" \ + "heh_=mesh_->ccw_rotated_halfedge_handle(heh_);" \ + "mesh_->edge_handle(heh_)" \ + >> CirculatorsT.hh + +generate_circulator VertexFaceIterT Vertex Face \ + "if (heh_.is_valid() \&\& !handle().is_valid()) operator++();" \ + "do heh_=mesh_->cw_rotated_halfedge_handle(heh_); while ((*this) \&\& (!handle().is_valid()));" \ + "do heh_=mesh_->ccw_rotated_halfedge_handle(heh_); while ((*this) \&\& (!handle().is_valid()));" \ + "mesh_->face_handle(heh_)" \ + >> CirculatorsT.hh + + +generate_circulator FaceVertexIterT Face Vertex \ + " " \ + "heh_=mesh_->next_halfedge_handle(heh_);" \ + "heh_=mesh_->prev_halfedge_handle(heh_);" \ + "mesh_->to_vertex_handle(heh_)" \ + >> CirculatorsT.hh + +generate_circulator FaceHalfedgeIterT Face Halfedge \ + " " \ + "heh_=mesh_->next_halfedge_handle(heh_);" \ + "heh_=mesh_->prev_halfedge_handle(heh_);" \ + "heh_" \ + >> CirculatorsT.hh + +generate_circulator FaceEdgeIterT Face Edge \ + " " \ + "heh_=mesh_->next_halfedge_handle(heh_);" \ + "heh_=mesh_->prev_halfedge_handle(heh_);" \ + "mesh_->edge_handle(heh_)" \ + >> CirculatorsT.hh + +generate_circulator FaceFaceIterT Face Face \ + "if (heh_.is_valid() \&\& !handle().is_valid()) operator++();" \ + "do heh_=mesh_->next_halfedge_handle(heh_); while ((*this) \&\& (!handle().is_valid()));" \ + "do heh_=mesh_->prev_halfedge_handle(heh_); while ((*this) \&\& (!handle().is_valid()));" \ + "mesh_->face_handle(mesh_->opposite_halfedge_handle(heh_))" \ + >> CirculatorsT.hh + + +cat footer.hh >> CirculatorsT.hh + + +#------------------------------------------------------------------------------ diff --git a/Core/Mesh/gen/iterators_header.hh b/Core/Mesh/gen/iterators_header.hh new file mode 100644 index 00000000..19bb58fb --- /dev/null +++ b/Core/Mesh/gen/iterators_header.hh @@ -0,0 +1,62 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ +#ifndef OPENMESH_ITERATORS_HH +#define OPENMESH_ITERATORS_HH +//============================================================================= +// +// Iterators for PolyMesh/TriMesh +// +//============================================================================= + + + +//== INCLUDES ================================================================= + +#include +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Iterators { + + +//== FORWARD DECLARATIONS ===================================================== + + +template class VertexIterT; +template class ConstVertexIterT; +template class HalfedgeIterT; +template class ConstHalfedgeIterT; +template class EdgeIterT; +template class ConstEdgeIterT; +template class FaceIterT; +template class ConstFaceIterT; + + + + diff --git a/Core/Mesh/gen/iterators_template.hh b/Core/Mesh/gen/iterators_template.hh new file mode 100644 index 00000000..99f54e06 --- /dev/null +++ b/Core/Mesh/gen/iterators_template.hh @@ -0,0 +1,162 @@ +//== CLASS DEFINITION ========================================================= + + +/** \class IteratorT IteratorsT.hh + Linear iterator. +*/ + +template +class IteratorT +{ +public: + + + //--- Typedefs --- + + typedef TargetType value_type; + typedef TargetHandle value_handle; + +#if IsConst + typedef const value_type& reference; + typedef const value_type* pointer; + typedef const Mesh* mesh_ptr; + typedef const Mesh& mesh_ref; +#else + typedef value_type& reference; + typedef value_type* pointer; + typedef Mesh* mesh_ptr; + typedef Mesh& mesh_ref; +#endif + + + + + /// Default constructor. + IteratorT() + : mesh_(0), skip_bits_(0) + {} + + + /// Construct with mesh and a target handle. + IteratorT(mesh_ref _mesh, value_handle _hnd, bool _skip=false) + : mesh_(&_mesh), hnd_(_hnd), skip_bits_(0) + { + if (_skip) enable_skipping(); + } + + + /// Copy constructor + IteratorT(const IteratorT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment operator + IteratorT& operator=(const IteratorT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + + +#if IsConst + + /// Construct from a non-const iterator + IteratorT(const NonConstIterT& _rhs) + : mesh_(_rhs.mesh_), hnd_(_rhs.hnd_), skip_bits_(_rhs.skip_bits_) + {} + + + /// Assignment from non-const iterator + IteratorT& operator=(const NonConstIterT& _rhs) + { + mesh_ = _rhs.mesh_; + hnd_ = _rhs.hnd_; + skip_bits_ = _rhs.skip_bits_; + return *this; + } + +#else + friend class ConstIterT; +#endif + + + /// Standard dereferencing operator. + reference operator*() const { return mesh_->deref(hnd_); } + + /// Standard pointer operator. + pointer operator->() const { return &(mesh_->deref(hnd_)); } + + /// Get the handle of the item the iterator refers to. + value_handle handle() const { return hnd_; } + + /// Cast to the handle of the item the iterator refers to. + operator value_handle() const { return hnd_; } + + /// Are two iterators equal? Only valid if they refer to the same mesh! + bool operator==(const IteratorT& _rhs) const + { return ((mesh_ == _rhs.mesh_) && (hnd_ == _rhs.hnd_)); } + + /// Not equal? + bool operator!=(const IteratorT& _rhs) const + { return !operator==(_rhs); } + + /// Standard pre-increment operator + IteratorT& operator++() + { hnd_.__increment(); if (skip_bits_) skip_fwd(); return *this; } + + /// Standard pre-decrement operator + IteratorT& operator--() + { hnd_.__decrement(); if (skip_bits_) skip_bwd(); return *this; } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void enable_skipping() + { + if (mesh_ && mesh_->has_element_status()) + { + Attributes::StatusInfo status; + status.set_deleted(true); + status.set_hidden(true); + skip_bits_ = status.bits(); + skip_fwd(); + } + else skip_bits_ = 0; + } + + + /// Turn on skipping: automatically skip deleted/hidden elements + void disable_skipping() { skip_bits_ = 0; } + + + +private: + + void skip_fwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() < (signed) mesh_->n_elements()) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__increment(); + } + + + void skip_bwd() + { + assert(mesh_ && skip_bits_); + while ((hnd_.idx() >= 0) && + (mesh_->status(hnd_).bits() & skip_bits_)) + hnd_.__decrement(); + } + + + +private: + mesh_ptr mesh_; + value_handle hnd_; + unsigned int skip_bits_; +}; + + diff --git a/Core/OpenMesh_Core.vcproj b/Core/OpenMesh_Core.vcproj new file mode 100755 index 00000000..20b5bc2f --- /dev/null +++ b/Core/OpenMesh_Core.vcproj @@ -0,0 +1,578 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/System/ACGMakefile b/Core/System/ACGMakefile new file mode 100644 index 00000000..6d85b985 --- /dev/null +++ b/Core/System/ACGMakefile @@ -0,0 +1,17 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = $(call find-subdirs) + +PACKAGES := + +PROJ_LIBS := + +MODULES := cxxlib + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Core/System/compiler.hh b/Core/System/compiler.hh new file mode 100644 index 00000000..11161405 --- /dev/null +++ b/Core/System/compiler.hh @@ -0,0 +1,161 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +#ifndef OPENMESH_COMPILER_H +#define OPENMESH_COMPILER_H + +//============================================================================= + +#if defined(ACGMAKE_STATIC_BUILD) +# define OM_STATIC_BUILD 1 +#endif + +//============================================================================= + +#if defined(_DEBUG) || defined(DEBUG) +# define OM_DEBUG +#endif + +//============================================================================= + +// Workaround for Intel Compiler with MS VC++ 6 +#if defined(_MSC_VER) && \ + ( defined(__ICL) || defined(__INTEL_COMPILER) || defined(__ICC) ) +# if !defined(__INTEL_COMPILER) +# define __INTEL_COMPILER __ICL +# endif +# define OM_USE_INTEL_COMPILER 1 +#endif + +// --------------------------------------------------------- MS Visual C++ ---- +// Compiler _MSC_VER +// .NET 2002 1300 +// .NET 2003 1310 +// .NET 2005 1400 +#if defined(_MSC_VER) && !defined(OM_USE_INTEL_COMPILER) +# if (_MSC_VER == 1300) +# define OM_CC_MSVC +# define OM_TYPENAME +# define OM_OUT_OF_CLASS_TEMPLATE 0 +# define OM_PARTIAL_SPECIALIZATION 0 +# define OM_INCLUDE_TEMPLATES 1 +# elif (_MSC_VER == 1310) +# define OM_CC_MSVC +# define OM_TYPENAME +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 1 +# elif (_MSC_VER >= 1400) // settings for .NET 2005 (NOTE: not fully tested) +# pragma warning(disable : 4996) +# define OM_TYPENAME +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 1 +# else +# error "Version 7 (.NET 2002) or higher of the MS VC++ is required!" +# endif +// currently no windows dll supported +# define OM_STATIC_BUILD 1 +# if defined(_MT) +# define OM_REENTRANT 1 +# endif +# define OM_CC "MSVC++" +# define OM_CC_VERSION _MSC_VER +// Does not work stable because the define _CPPRTTI sometimes does not exist, +// though the option /GR is set!? +# if defined(__cplusplus) && !defined(_CPPRTTI) +# error "Enable Runtime Type Information (Compiler Option /GR)!" +# endif +# if !defined(_USE_MATH_DEFINES) +# error "You have to define _USE_MATH_DEFINES in the compiler settings!" +# endif +// ------------------------------------------------------------- Borland C ---- +#elif defined(__BORLANDC__) +# error "Borland Compiler are not supported yet!" +// ------------------------------------------------------------- GNU C/C++ ---- +#elif defined(__GNUC__) && !defined(__ICC) +# define OM_CC_GCC +# define OM_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 ) +# define OM_GCC_MAJOR __GNUC__ +# define OM_GCC_MINOR __GNUC_MINOR__ +# if (OM_GCC_VERSION >= 30200) +# define OM_TYPENAME typename +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 1 +# else +# error "Version 3.2.0 or better of the GNU Compiler is required!" +# endif +# if defined(_REENTRANT) +# define OM_REENTRANT 1 +# endif +# define OM_CC "GCC" +# define OM_CC_VERSION OM_GCC_VERSION +// ------------------------------------------------------------- Intel icc ---- +#elif defined(__ICC) || defined(__INTEL_COMPILER) +# define OM_CC_ICC +# define OM_TYPENAME typename +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 1 +# if defined(_REENTRANT) || defined(_MT) +# define OM_REENTRANT 1 +# endif +# define OM_CC "ICC" +# define OM_CC_VERSION __INTEL_COMPILER +// currently no windows dll supported +# if defined(_MSC_VER) || defined(WIN32) +# define OM_STATIC_BUILD 1 +# endif +// ------------------------------------------------------ MIPSpro Compiler ---- +#elif defined(__MIPS_ISA) || defined(__mips) +// _MIPS_ISA +// _COMPILER_VERSION e.g. 730, 7 major, 3 minor +// _MIPS_FPSET 32|64 +// _MIPS_SZINT 32|64 +// _MIPS_SZLONG 32|64 +// _MIPS_SZPTR 32|64 +# define OM_CC_MIPS +# define OM_TYPENAME typename +# define OM_OUT_OF_CLASS_TEMPLATE 1 +# define OM_PARTIAL_SPECIALIZATION 1 +# define OM_INCLUDE_TEMPLATES 0 +# define OM_CC "MIPS" +# define OM_CC_VERSION _COMPILER_VERSION +// ------------------------------------------------------------------ ???? ---- +#else +# error "You're using an unsupported compiler!" +#endif + +//============================================================================= +#endif // OPENMESH_COMPILER_H defined +//============================================================================= + diff --git a/Core/System/config.h b/Core/System/config.h new file mode 100644 index 00000000..bae30346 --- /dev/null +++ b/Core/System/config.h @@ -0,0 +1,60 @@ +//============================================================================= +// +// 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: 1.2 $ +// $Date: 2007-05-18 15:17:48 $ +// +//============================================================================= + +/** \file config.h + * \todo Move content to config.hh and include it to be compatible with old + * source. + */ + +//============================================================================= + +#ifndef OPENMESH_CONFIG_H +#define OPENMESH_CONFIG_H + +//============================================================================= + +#include +#include + +// ---------------------------------------------------------------------------- + +#define OM_VERSION 0x10000 + +// only defined, if it is a beta version +#define OM_VERSION_BETA 4 + +#define OM_GET_VER ((OM_VERSION && 0xf0000) >> 16) +#define OM_GET_MAJ ((OM_VERSION && 0x0ff00) >> 8) +#define OM_GET_MIN (OM_VERSION && 0x000ff) + +typedef unsigned int uint; +//============================================================================= +#endif // OPENMESH_CONFIG_H defined +//============================================================================= diff --git a/Core/System/config.hh b/Core/System/config.hh new file mode 100644 index 00000000..c056a8bc --- /dev/null +++ b/Core/System/config.hh @@ -0,0 +1 @@ +#include diff --git a/Core/System/mostream.hh b/Core/System/mostream.hh new file mode 100644 index 00000000..49616c3d --- /dev/null +++ b/Core/System/mostream.hh @@ -0,0 +1,282 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// multiplex streams & ultilities +// +//============================================================================= + +#ifndef OPENMESH_MOSTREAM_HH +#define OPENMESH_MOSTREAM_HH + + +//== INCLUDES ================================================================= + +#include +#include +#if defined( OM_CC_GCC ) && OM_CC_VERSION < 30000 +# include +#else +# include +#endif +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +#ifndef DOXY_IGNORE_THIS + + +//== CLASS DEFINITION ========================================================= + + +class basic_multiplex_target +{ +public: + virtual ~basic_multiplex_target() {} + virtual void operator<<(const std::string& _s) = 0; +}; + + +template +class multiplex_target : public basic_multiplex_target +{ +public: + multiplex_target(T& _t) : target_(_t) {} + virtual void operator<<(const std::string& _s) { target_ << _s; } +private: + T& target_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +#if defined( OM_CC_GCC ) && OM_CC_VERSION < 30000 +# define STREAMBUF streambuf +# define INT_TYPE int +# define TRAITS_TYPE +#else +# define STREAMBUF std::basic_streambuf +#endif + +class multiplex_streambuf : public STREAMBUF +{ +public: + + typedef STREAMBUF base_type; +#if defined( OM_CC_GCC ) && OM_CC_VERSION < 30000 + typedef int int_type; + struct traits_type + { + static int_type eof() { return -1; } + static char to_char_type(int_type c) { return char(c); } + }; +#else + typedef base_type::int_type int_type; + typedef base_type::traits_type traits_type; +#endif + + // Constructor + multiplex_streambuf() : enabled_(true) { buffer_.reserve(100); } + + // Destructor + ~multiplex_streambuf() + { + tmap_iter t_it(target_map_.begin()), t_end(target_map_.end()); + for (; t_it!=t_end; ++t_it) + delete t_it->second; + } + + + // buffer enable/disable + bool is_enabled() const { return enabled_; } + void enable() { enabled_ = true; } + void disable() { enabled_ = false; } + + + // construct multiplex_target and add it to targets + template bool connect(T& _target) + { + void* key = (void*) &_target; + + if (target_map_.find(key) != target_map_.end()) + return false; + + target_type* mtarget = new multiplex_target(_target); + target_map_[key] = mtarget; + + __connect(mtarget); + return true; + } + + + // disconnect target from multiplexer + template bool disconnect(T& _target) + { + void* key = (void*) &_target; + tmap_iter t_it = target_map_.find(key); + + if (t_it != target_map_.end()) + { + __disconnect(t_it->second); + target_map_.erase(t_it); + return true; + } + + return false; + } + + +protected: + + // output what's in buffer_ + virtual int sync() + { + if (!buffer_.empty()) + { + if (enabled_) multiplex(); +#if defined(OM_CC_GCC) || OM_CC_VERSION < 30000 + buffer_ = ""; // member clear() not available! +#else + buffer_.clear(); +#endif + } + return base_type::sync(); + } + + + // take on char and add it to buffer_ + // if '\n' is encountered, trigger a sync() + virtual + int_type overflow(int_type _c = multiplex_streambuf::traits_type::eof()) + { + char c = traits_type::to_char_type(_c); + buffer_.push_back(c); + if (c == '\n') sync(); + return 0; + } + + +private: + + typedef basic_multiplex_target target_type; + typedef std::vector target_list; + typedef target_list::iterator tlist_iter; + typedef std::map target_map; + typedef target_map::iterator tmap_iter; + + + // add _target to list of multiplex targets + void __connect(target_type* _target) { targets_.push_back(_target); } + + + // remove _target from list of multiplex targets + void __disconnect(target_type* _target) { + targets_.erase(std::find(targets_.begin(), targets_.end(), _target)); + } + + + // multiplex output of buffer_ to all targets + void multiplex() + { + tlist_iter t_it(targets_.begin()), t_end(targets_.end()); + for (; t_it!=t_end; ++t_it) + **t_it << buffer_; + } + + +private: + + target_list targets_; + target_map target_map_; + std::string buffer_; + bool enabled_; +}; + +#undef STREAMBUF + + +//== CLASS DEFINITION ========================================================= + + +/** \class mostream mostream.hh + + This class provides streams that can easily be multiplexed (using + the connect() method) and toggled on/off (using enable() / + disable()). + + \see omlog, omout, omerr +*/ + +class mostream : public std::ostream +{ +public: + + /// Explicit constructor + explicit mostream() : std::ostream(NULL) { init(&streambuffer_); } + + + /// Connect target to multiplexer + template bool connect(T& _target) + { + return streambuffer_.connect(_target); + } + + + /// Disconnect target from multiplexer + template bool disconnect(T& _target) + { + return streambuffer_.disconnect(_target); + } + + + /// is buffer enabled + bool is_enabled() const { return streambuffer_.is_enabled(); } + + /// enable this buffer + void enable() { streambuffer_.enable(); } + + /// disable this buffer + void disable() { streambuffer_.disable(); } + + +private: + multiplex_streambuf streambuffer_; +}; + + +//============================================================================= +#endif +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MOSTREAM_HH defined +//============================================================================= diff --git a/Core/System/omstream.cc b/Core/System/omstream.cc new file mode 100644 index 00000000..9e408dd0 --- /dev/null +++ b/Core/System/omstream.cc @@ -0,0 +1,74 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS mostream - IMPLEMENTATION +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#include + + +//== IMPLEMENTATION ========================================================== + + +OpenMesh::mostream& omlog() +{ + static bool initialized = false; + static OpenMesh::mostream mystream; + if (!initialized) + { + mystream.connect(std::clog); +#ifdef NDEBUG + mystream.disable(); +#endif + } + return mystream; +} + + +OpenMesh::mostream& omout() +{ + static bool initialized = false; + static OpenMesh::mostream mystream; + if (!initialized) mystream.connect(std::cout); + return mystream; +} + + +OpenMesh::mostream& omerr() +{ + static bool initialized = false; + static OpenMesh::mostream mystream; + if (!initialized) mystream.connect(std::cerr); + return mystream; +} + + +//============================================================================= diff --git a/Core/System/omstream.hh b/Core/System/omstream.hh new file mode 100644 index 00000000..92489ace --- /dev/null +++ b/Core/System/omstream.hh @@ -0,0 +1,61 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// OpenMesh streams: omlog, omout, omerr +// +//============================================================================= + +#ifndef OPENMESH_OMSTREAMS_HH +#define OPENMESH_OMSTREAMS_HH + + +//== INCLUDES ================================================================= + +#include + + +//== CLASS DEFINITION ========================================================= + +/** \file omstream.hh + This file provides the streams omlog, omout, and omerr. +*/ + +//@{ +/** These stream provide replacements for clog, cout, and cerr. They have + the advantage that they can easily be multiplexed. + \see OpenMesh::mostream +*/ + +OpenMesh::mostream& omlog(); +OpenMesh::mostream& omout(); +OpenMesh::mostream& omerr(); + +//@} + +//============================================================================= +#endif // OPENMESH_OMSTREAMS_HH defined +//============================================================================= diff --git a/Core/Templates/newClass.cc b/Core/Templates/newClass.cc new file mode 100644 index 00000000..c712efa0 --- /dev/null +++ b/Core/Templates/newClass.cc @@ -0,0 +1,53 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass - IMPLEMENTATION +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== IMPLEMENTATION ========================================================== + + + +//----------------------------------------------------------------------------- + + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Core/Templates/newClass.hh b/Core/Templates/newClass.hh new file mode 100644 index 00000000..7a75b9e4 --- /dev/null +++ b/Core/Templates/newClass.hh @@ -0,0 +1,85 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= +#ifndef DOXY_IGNORE_THIS +#ifndef OPENMESH_NEWCLASS_HH +#define OPENMESH_NEWCLASS_HH + + +//== INCLUDES ================================================================= + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + +/** \class newClass newClass.hh + + Brief Description. + + A more elaborate description follows. +*/ + +class newClass +{ +public: + + /// Default constructor + newClass() {} + + /// Destructor + ~newClass() {} + + +private: + + /// Copy constructor (not used) + newClass(const newClass& _rhs); + + /// Assignment operator (not used) + newClass& operator=(const newClass& _rhs); + +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_NEWCLASS_HH defined +#endif // DOXY_IGNORE_THIS +//============================================================================= + diff --git a/Core/Templates/newClass.sh b/Core/Templates/newClass.sh new file mode 100644 index 00000000..7ea19a72 --- /dev/null +++ b/Core/Templates/newClass.sh @@ -0,0 +1,9 @@ +#! /bin/sh + +A=`echo $1_ | tr '[:lower:]' '[:upper:]'` + +sed -e s/newClass/$1/g -e s/NEWCLASS_/$A/g < newClass.cc > tmp_newClass.cc +sed -e s/newClass/$1/g -e s/NEWCLASS_/$A/g < newClass.hh > tmp_newClass.hh + +mv -i tmp_newClass.cc $1.cc && echo $1.cc - ok +mv -i tmp_newClass.hh $1.hh && echo $1.hh - ok diff --git a/Core/Templates/newClassT.cc b/Core/Templates/newClassT.cc new file mode 100644 index 00000000..8dd41de6 --- /dev/null +++ b/Core/Templates/newClassT.cc @@ -0,0 +1,54 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_NEWCLASS_C + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== IMPLEMENTATION ========================================================== + + + +//----------------------------------------------------------------------------- + + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Core/Templates/newClassT.hh b/Core/Templates/newClassT.hh new file mode 100644 index 00000000..5ec744df --- /dev/null +++ b/Core/Templates/newClassT.hh @@ -0,0 +1,92 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= +#ifndef DOXY_IGNORE_THIS +#ifndef OPENMESH_NEWCLASST_HH +#define OPENMESH_NEWCLASST_HH + + +//== INCLUDES ================================================================= + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + + + +/** \class newClassT newClassT.hh + + Brief Description. + + A more elaborate description follows. +*/ + +template <> +class newClassT +{ +public: + + /// Default constructor + newClassT() {} + + /// Destructor + ~newClassT() {} + + +private: + + /// Copy constructor (not used) + newClassT(const newClassT& _rhs); + + /// Assignment operator (not used) + newClassT& operator=(const newClassT& _rhs); + +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_NEWCLASS_C) +#define OPENMESH_NEWCLASS_TEMPLATES +#include "newClass.cc" +#endif +//============================================================================= +#endif // OPENMESH_NEWCLASST_HH defined +#endif // DOXY_IGNORE_THIS +//============================================================================= diff --git a/Core/Templates/newClassT.sh b/Core/Templates/newClassT.sh new file mode 100644 index 00000000..70232447 --- /dev/null +++ b/Core/Templates/newClassT.sh @@ -0,0 +1,9 @@ +#! /bin/sh + +A=`echo $1_ | tr '[:lower:]' '[:upper:]'` + +sed -e s/newClass/$1/g -e s/NEWCLASS_/$A/g < newClassT.cc > tmp_newClass.cc +sed -e s/newClass/$1/g -e s/NEWCLASS_/$A/g < newClassT.hh > tmp_newClass.hh + +mv -i tmp_newClass.cc $1.cc && echo $1.cc - ok +mv -i tmp_newClass.hh $1.hh && echo $1.hh - ok diff --git a/Core/Utils/ACGMakefile b/Core/Utils/ACGMakefile new file mode 100644 index 00000000..6d85b985 --- /dev/null +++ b/Core/Utils/ACGMakefile @@ -0,0 +1,17 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = $(call find-subdirs) + +PACKAGES := + +PROJ_LIBS := + +MODULES := cxxlib + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Core/Utils/AutoPropertyHandleT.hh b/Core/Utils/AutoPropertyHandleT.hh new file mode 100644 index 00000000..5341103e --- /dev/null +++ b/Core/Utils/AutoPropertyHandleT.hh @@ -0,0 +1,115 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-2004 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. * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_AutoPropertyHandleT_HH +#define OPENMESH_AutoPropertyHandleT_HH + +//== INCLUDES ================================================================= +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + +template +class AutoPropertyHandleT : public PropertyHandle_ +{ +public: + typedef Mesh_ Mesh; + typedef PropertyHandle_ PropertyHandle; + typedef PropertyHandle Base; + typedef typename PropertyHandle::Value Value; + typedef AutoPropertyHandleT + Self; +protected: + Mesh* m_; + bool own_property_;//ref counting? + +public: + AutoPropertyHandleT() + : m_(NULL), own_property_(false) + {} + + AutoPropertyHandleT(const Self& _other) + : Base(_other.idx()), m_(_other.m_), own_property_(false) + {} + + explicit AutoPropertyHandleT(Mesh& _m, const std::string& _pp_name = std::string()) + { add_property(_m, _pp_name); } + + AutoPropertyHandleT(Mesh& _m, PropertyHandle _pph) + : Base(_pph.idx()), m_(&_m), own_property_(false) + {} + + ~AutoPropertyHandleT() + { + if (own_property_) + { + m_->remove_property(*this); + } + } + + inline void add_property(Mesh& _m, const std::string& _pp_name = std::string()) + { + assert(!is_valid()); + m_ = &_m; + own_property_ = _pp_name.empty() || !m_->get_property_handle(*this, _pp_name); + if (own_property_) + { + m_->add_property(*this, _pp_name); + } + } + + inline void remove_property() + { + assert(own_property_);//only the owner can delete the property + m_->remove_property(*this); + own_property_ = false; + invalidate(); + } + + template + inline Value& operator [] (_Handle _hnd) + { return m_->property(*this, _hnd); } + + template + inline const Value& operator [] (_Handle _hnd) const + { return m_->property(*this, _hnd); } + + inline bool own_property() const + { return own_property_; } + + inline void free_property() + { own_property_ = false; } +}; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_AutoPropertyHandleT_HH defined +//============================================================================= diff --git a/Core/Utils/BaseProperty.cc b/Core/Utils/BaseProperty.cc new file mode 100644 index 00000000..2d1bd220 --- /dev/null +++ b/Core/Utils/BaseProperty.cc @@ -0,0 +1,37 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +#include +#include + +namespace OpenMesh +{ + +void BaseProperty::stats(std::ostream& _ostr) const +{ + _ostr << " " << name() << (persistent() ? ", persistent " : "") << "\n"; +} + +} diff --git a/Core/Utils/BaseProperty.hh b/Core/Utils/BaseProperty.hh new file mode 100644 index 00000000..54fd9f0b --- /dev/null +++ b/Core/Utils/BaseProperty.hh @@ -0,0 +1,159 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2004 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. * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_BASEPROPERTY_HH +#define OPENMESH_BASEPROPERTY_HH + +#include +#include +#include + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + +/** \class BaseProperty Property.hh + + Abstract class defining the basic interface of a dynamic property. +**/ + +class BaseProperty +{ +public: + + /// Indicates an error when a size is returned by a member. + static const size_t UnknownSize = size_t(-1); + +public: + + /// \brief Default constructor. + /// + /// In %OpenMesh all mesh data is stored in so-called properties. + /// We distinuish between standard properties, which can be defined at + /// compile time using the Attributes in the traits definition and + /// at runtime using the request property functions defined in one of + /// the kernels. + /// + /// If the property should be stored along with the default properties + /// in the OM-format one must name the property and enable the persistant + /// flag with set_persistent(). + /// + /// \param _name Optional textual name for the property. + /// + BaseProperty(const std::string& _name = "") + : name_(_name), persistent_(false) + {} + + /// \brief Copy constructor + BaseProperty(const BaseProperty & _rhs) + : name_( _rhs.name_ ), persistent_( _rhs.persistent_ ) {} + + /// Destructor. + virtual ~BaseProperty() {} + +public: // synchronized array interface + + /// Reserve memory for n elements. + virtual void reserve(size_t _n) = 0; + + /// Resize storage to hold n elements. + virtual void resize(size_t _n) = 0; + + /// Extend the number of elements by one. + virtual void push_back() = 0; + + /// Let two elements swap their storage place. + virtual void swap(size_t _i0, size_t _i1) = 0; + + /// Return a deep copy of self. + virtual BaseProperty* clone () const = 0; + +public: // named property interface + + /// Return the name of the property + const std::string& name() const { return name_; } + + virtual void stats(std::ostream& _ostr) const; + +public: // I/O support + + /// Returns true if the persistent flag is enabled else false. + bool persistent(void) const { return persistent_; } + + /// Enable or disable persistency. Self must be a named property to enable + /// persistency. + virtual void set_persistent( bool _yn ) = 0; + + /// Number of elements in property + virtual size_t n_elements() const = 0; + + /// Size of one element in bytes or UnknownSize if not known. + virtual size_t element_size() const = 0; + + /// Return size of property in bytes + virtual size_t size_of() const + { + return size_of( n_elements() ); + } + + /// Estimated size of property if it has _n_elem elements. + /// The member returns UnknownSize if the size cannot be estimated. + virtual size_t size_of(size_t _n_elem) const + { + return (element_size()!=UnknownSize) + ? (_n_elem*element_size()) + : UnknownSize; + } + + /// Store self as one binary block + virtual size_t store( std::ostream& _ostr, bool _swap ) const = 0; + + /** Restore self from a binary block. Uses reserve() to set the + size of self before restoring. + **/ + virtual size_t restore( std::istream& _istr, bool _swap ) = 0; + +protected: + + // To be used in a derived class, when overloading set_persistent() + template < typename T > + void check_and_set_persistent( bool _yn ) + { + if ( _yn && !IO::is_streamable() ) + omerr() << "Warning! Type of property value is not binary storable!\n"; + persistent_ = IO::is_streamable() && _yn; + } + +private: + + std::string name_; + bool persistent_; +}; + +}//namespace OpenMesh + +#endif //OPENMESH_BASEPROPERTY_HH + + diff --git a/Core/Utils/Endian.cc b/Core/Utils/Endian.cc new file mode 100644 index 00000000..902d2180 --- /dev/null +++ b/Core/Utils/Endian.cc @@ -0,0 +1,70 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +//== INCLUDES ================================================================= + + +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== IMPLEMENTATION =========================================================== + +//----------------------------------------------------------------------------- + +int Endian::one_ = 1; + +const Endian::Type Endian::local_ = *((unsigned char*)&Endian::one_) + ? Endian::LSB + : Endian::MSB; + +const char * Endian::as_string(Type _t) +{ + return _t == LSB ? "LSB" : "MSB"; +} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Core/Utils/Endian.hh b/Core/Utils/Endian.hh new file mode 100644 index 00000000..1c800533 --- /dev/null +++ b/Core/Utils/Endian.hh @@ -0,0 +1,86 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#ifndef OPENMESH_UTILS_ENDIAN_HH +#define OPENMESH_UTILS_ENDIAN_HH + + +//== INCLUDES ================================================================= + + +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** Determine byte order of host system. + */ +class Endian +{ +public: + + enum Type { + LSB = 1, ///< Little endian (Intel family and clones) + MSB ///< big endian (Motorola's 68x family, DEC Alpha, MIPS) + }; + + /// Return endian type of host system. + static Type local() { return local_; } + + /// Return type _t as string. + static const char * as_string(Type _t); + +private: + static int one_; + static const Type local_; +}; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= + diff --git a/Core/Utils/GenProg.hh b/Core/Utils/GenProg.hh new file mode 100644 index 00000000..abf191eb --- /dev/null +++ b/Core/Utils/GenProg.hh @@ -0,0 +1,147 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// Utils for generic/generative programming +// +//============================================================================= + +#ifndef OPENMESH_GENPROG_HH +#define OPENMESH_GENPROG_HH + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +namespace GenProg { +#ifndef DOXY_IGNORE_THIS + +//== IMPLEMENTATION =========================================================== + + +/// This type maps \c true or \c false to different types. +template struct Bool2Type { enum { my_bool = b }; }; + +/// This class generates different types from different \c int 's. +template struct Int2Type { enum { my_int = i }; }; + +/// Handy typedef for Bool2Type classes +typedef Bool2Type True; + +/// Handy typedef for Bool2Type classes +typedef Bool2Type False; + +//----------------------------------------------------------------------------- +/// compile time assertions +template struct AssertCompile; +template <> struct AssertCompile {}; + + + +//--- Template "if" w/ partial specialization --------------------------------- +#if OM_PARTIAL_SPECIALIZATION + + +template +struct IF { typedef Then Result; }; + +/** Template \c IF w/ partial specialization +\code +typedef IF::Result ResultType; +\endcode +*/ +template +struct IF { typedef Else Result; }; + + + + + +//--- Template "if" w/o partial specialization -------------------------------- +#else + + +struct SelectThen +{ + template struct Select { + typedef Then Result; + }; +}; + +struct SelectElse +{ + template struct Select { + typedef Else Result; + }; +}; + +template struct ChooseSelector { + typedef SelectThen Result; +}; + +template <> struct ChooseSelector { + typedef SelectElse Result; +}; + + +/** Template \c IF w/o partial specialization. Use it like +\code +typedef IF::Result ResultType; +\endcode +*/ + +template +class IF +{ + typedef typename ChooseSelector::Result Selector; +public: + typedef typename Selector::template Select::Result Result; +}; + +#endif + +//============================================================================= +#endif +} // namespace GenProg +} // namespace OpenMesh + +#define assert_compile(EXPR) GenProg::AssertCompile<(EXPR)>(); + +//============================================================================= +#endif // OPENMESH_GENPROG_HH defined +//============================================================================= diff --git a/Core/Utils/Noncopyable.hh b/Core/Utils/Noncopyable.hh new file mode 100644 index 00000000..fcbd3c55 --- /dev/null +++ b/Core/Utils/Noncopyable.hh @@ -0,0 +1,76 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// Implements the Non-Copyable metapher +// +//============================================================================= + +#ifndef OPENMESH_NONCOPYABLE_HH +#define OPENMESH_NONCOPYABLE_HH + + +//----------------------------------------------------------------------------- + +#include + +//----------------------------------------------------------------------------- + +namespace OpenMesh { +namespace Utils { + +//----------------------------------------------------------------------------- + +/** This class demonstrates the non copyable idiom. In some cases it is + important an object can't be copied. Deriving from Noncopyable makes sure + all relevant constructor and operators are made inaccessable, for public + AND derived classes. +**/ +class Noncopyable +{ +public: + Noncopyable() { } + +private: + /// Prevent access to copy constructor + Noncopyable( const Noncopyable& ); + + /// Prevent access to assignment operator + const Noncopyable& operator=( const Noncopyable& ); +}; + +//============================================================================= +} // namespace Utils +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_NONCOPYABLE_HH +//============================================================================= diff --git a/Core/Utils/Property.hh b/Core/Utils/Property.hh new file mode 100644 index 00000000..6e580f64 --- /dev/null +++ b/Core/Utils/Property.hh @@ -0,0 +1,512 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_PROPERTY_HH +#define OPENMESH_PROPERTY_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + +/** \class PropertyT Property.hh + * + * \brief Default property class for any type T. + * + * The default property class for any type T. + * + * The property supports persistency if T is a "fundamental" type: + * - integer fundamental types except bool: + * char, short, int, long, long long (__int64 for MS VC++) and + * their unsigned companions. + * - float fundamentals except long double: + * float, double + * - %OpenMesh vector types + * + * Persistency of non-fundamental types is supported if and only if a + * specialization of struct IO::binary<> exists for the wanted type. + */ + +// TODO: it might be possible to define Property using kind of a runtime info +// structure holding the size of T. Then reserve, swap, resize, etc can be written +// in pure malloc() style w/o virtual overhead. Template member function proved per +// element access to the properties, asserting dynamic_casts in debug + +template +class PropertyT : public BaseProperty +{ +public: + + typedef T Value; + typedef std::vector vector_type; + typedef T value_type; + typedef typename vector_type::reference reference; + typedef typename vector_type::const_reference const_reference; + +public: + + /// Default constructor + PropertyT(const std::string& _name = "") + : BaseProperty(_name) + {} + + /// Copy constructor + PropertyT(const PropertyT & _rhs) + : BaseProperty( _rhs ), data_( _rhs.data_ ) {} + +public: // inherited from BaseProperty + + virtual void reserve(size_t _n) { data_.reserve(_n); } + virtual void resize(size_t _n) { data_.resize(_n); } + virtual void push_back() { data_.push_back(T()); } + virtual void swap(size_t _i0, size_t _i1) + { std::swap(data_[_i0], data_[_i1]); } + +public: + + virtual void set_persistent( bool _yn ) + { check_and_set_persistent( _yn ); } + + virtual size_t n_elements() const { return data_.size(); } + virtual size_t element_size() const { return IO::size_of(); } + +#ifndef DOXY_IGNORE_THIS + struct plus { + size_t operator () ( size_t _b, const T& _v ) + { return _b + IO::size_of(_v); } + }; +#endif + + virtual size_t size_of(void) const + { + if (element_size() != IO::UnknownSize) + return this->BaseProperty::size_of(n_elements()); + return std::accumulate(data_.begin(), data_.end(), 0, plus()); + } + + virtual size_t size_of(size_t _n_elem) const + { return this->BaseProperty::size_of(_n_elem); } + + virtual size_t store( std::ostream& _ostr, bool _swap ) const + { + if ( IO::is_streamable() ) + return IO::store(_ostr, data_, _swap ); + size_t bytes = 0; + for (size_t i=0; i() ) + return IO::restore(_istr, data_, _swap ); + size_t bytes = 0; + for (size_t i=0; i* clone() const + { + PropertyT* p = new PropertyT( *this ); + return p; + } + + +private: + + vector_type data_; +}; + +//----------------------------------------------------------------------------- + + +/** \class PropertyT Property.hh + + Property specialization for bool type. The data will be stored as + a bitset. + */ +template <> +class PropertyT : public BaseProperty +{ +public: + + typedef std::vector vector_type; + typedef bool value_type; + typedef vector_type::reference reference; + typedef vector_type::const_reference const_reference; + +public: + + PropertyT(const std::string& _name = "") + : BaseProperty(_name) + { } + +public: // inherited from BaseProperty + + virtual void reserve(size_t _n) { data_.reserve(_n); } + virtual void resize(size_t _n) { data_.resize(_n); } + virtual void push_back() { data_.push_back(bool()); } + virtual void swap(size_t _i0, size_t _i1) + { bool t(data_[_i0]); data_[_i0]=data_[_i1]; data_[_i1]=t; } + +public: + + virtual void set_persistent( bool _yn ) + { + check_and_set_persistent( _yn ); + } + + virtual size_t n_elements() const { return data_.size(); } + virtual size_t element_size() const { return UnknownSize; } + virtual size_t size_of() const { return size_of( n_elements() ); } + virtual size_t size_of(size_t _n_elem) const + { + return _n_elem / 8 + ((_n_elem % 8)!=0); + } + + size_t store( std::ostream& _ostr, bool /* _swap */ ) const + { + size_t bytes = 0; + + size_t N = data_.size() / 8; + size_t R = data_.size() % 8; + + size_t idx; // element index + size_t bidx; + unsigned char bits; // bitset + + for (bidx=idx=0; idx < N; ++idx, bidx+=8) + { + bits = !!data_[bidx] + | (!!data_[bidx+1] << 1) + | (!!data_[bidx+2] << 2) + | (!!data_[bidx+3] << 3) + | (!!data_[bidx+4] << 4) + | (!!data_[bidx+5] << 5) + | (!!data_[bidx+6] << 6) + | (!!data_[bidx+7] << 7); + _ostr << bits; + } + bytes = N; + + if (R) + { + bits = 0; + for (idx=0; idx < R; ++idx) + bits |= !!data_[bidx+idx] << idx; + _ostr << bits; + ++bytes; + } + + std::cout << std::endl; + + assert( bytes == size_of() ); + + return bytes; + } + + size_t restore( std::istream& _istr, bool /* _swap */ ) + { + size_t bytes = 0; + + size_t N = data_.size() / 8; + size_t R = data_.size() % 8; + + size_t idx; // element index + size_t bidx; // + unsigned char bits; // bitset + + for (bidx=idx=0; idx < N; ++idx, bidx+=8) + { + _istr >> bits; + data_[bidx+0] = !!(bits & 0x01); + data_[bidx+1] = !!(bits & 0x02); + data_[bidx+2] = !!(bits & 0x04); + data_[bidx+3] = !!(bits & 0x08); + data_[bidx+4] = !!(bits & 0x10); + data_[bidx+5] = !!(bits & 0x20); + data_[bidx+6] = !!(bits & 0x40); + data_[bidx+7] = !!(bits & 0x80); + } + bytes = N; + + if (R) + { + _istr >> bits; + for (idx=0; idx < R; ++idx) + data_[bidx+idx] = !!(bits & (1<* clone() const + { + PropertyT* p = new PropertyT( *this ); + return p; + } + + +private: + + vector_type data_; +}; + + +//----------------------------------------------------------------------------- + + +/** \class PropertyT Property.hh + + Property specialization for std::string type. +*/ +template <> +class PropertyT : public BaseProperty +{ +public: + + typedef std::string Value; + typedef std::vector vector_type; + typedef std::string value_type; + typedef vector_type::reference reference; + typedef vector_type::const_reference const_reference; + +public: + + PropertyT(const std::string& _name = "") + : BaseProperty(_name) + { } + +public: // inherited from BaseProperty + + virtual void reserve(size_t _n) { data_.reserve(_n); } + virtual void resize(size_t _n) { data_.resize(_n); } + virtual void push_back() { data_.push_back(std::string()); } + virtual void swap(size_t _i0, size_t _i1) { + std::swap(data_[_i0], data_[_i1]); + } + +public: + + virtual void set_persistent( bool _yn ) + { check_and_set_persistent( _yn ); } + + virtual size_t n_elements() const { return data_.size(); } + virtual size_t element_size() const { return UnknownSize; } + virtual size_t size_of() const + { return IO::size_of( data_ ); } + + virtual size_t size_of(size_t /* _n_elem */) const + { return UnknownSize; } + + /// Store self as one binary block. Max. length of a string is 65535 bytes. + size_t store( std::ostream& _ostr, bool _swap ) const + { return IO::store( _ostr, data_, _swap ); } + + size_t restore( std::istream& _istr, bool _swap ) + { return IO::restore( _istr, data_, _swap ); } + +public: + + const value_type* data() const { + if( data_.empty() ) + return 0; + + return (value_type*) &data_[0]; + } + + /// Access the i'th element. No range check is performed! + reference operator[](int _idx) { + assert( size_t(_idx) < data_.size()); + return ((value_type*) &data_[0])[_idx]; + } + + /// Const access the i'th element. No range check is performed! + const_reference operator[](int _idx) const { + assert( size_t(_idx) < data_.size()); + return ((value_type*) &data_[0])[_idx]; + } + + PropertyT* clone() const { + PropertyT* p = new PropertyT( *this ); + return p; + } + + +private: + + vector_type data_; + +}; + +/// Base property handle. +template +struct BasePropHandleT : public BaseHandle +{ + typedef T Value; + typedef std::vector vector_type; + typedef T value_type; + typedef typename vector_type::reference reference; + typedef typename vector_type::const_reference const_reference; + + explicit BasePropHandleT(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing a vertex property + */ +template +struct VPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + + explicit VPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit VPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing a halfedge property + */ +template +struct HPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + + explicit HPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit HPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing an edge property + */ +template +struct EPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + + explicit EPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit EPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing a face property + */ +template +struct FPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + + explicit FPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit FPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + + +/** \ingroup mesh_property_handle_group + * Handle representing a mesh property + */ +template +struct MPropHandleT : public BasePropHandleT +{ + typedef T Value; + typedef T value_type; + + explicit MPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} + explicit MPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} +}; + +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_PROPERTY_HH defined +//============================================================================= diff --git a/Core/Utils/PropertyContainer.hh b/Core/Utils/PropertyContainer.hh new file mode 100644 index 00000000..3b78c365 --- /dev/null +++ b/Core/Utils/PropertyContainer.hh @@ -0,0 +1,263 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2004 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. * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_PROPERTYCONTAINER +#define OPENMESH_PROPERTYCONTAINER + +// Use static casts when not debugging +#ifdef NDEBUG +#define OM_FORCE_STATIC_CAST +#endif + +#include + +//----------------------------------------------------------------------------- +namespace OpenMesh +{ +//== FORWARDDECLARATIONS ====================================================== + class BaseKernel; + +//== CLASS DEFINITION ========================================================= +/// A a container for properties. +class PropertyContainer +{ +public: + + //-------------------------------------------------- constructor / destructor + + PropertyContainer() {} + virtual ~PropertyContainer() { clear(); } + + + //------------------------------------------------------------- info / access + + typedef std::vector Properties; + const Properties& properties() const { return properties_; } + size_t size() const { return properties_.size(); } + + + + //--------------------------------------------------------- copy / assignment + + PropertyContainer(const PropertyContainer& _rhs) { operator=(_rhs); } + + PropertyContainer& operator=(const PropertyContainer& _rhs) + { + clear(); + properties_ = _rhs.properties_; + Properties::iterator p_it=properties_.begin(), p_end=properties_.end(); + for (; p_it!=p_end; ++p_it) + if (*p_it) + *p_it = (*p_it)->clone(); + return *this; + } + + + + //--------------------------------------------------------- manage properties + + template + BasePropHandleT add(const T&, const std::string& _name="") + { + Properties::iterator p_it=properties_.begin(), p_end=properties_.end(); + int idx=0; + for ( ; p_it!=p_end && *p_it!=NULL; ++p_it, ++idx ) {}; + if (p_it==p_end) properties_.push_back(NULL); + properties_[idx] = new PropertyT(_name); + return BasePropHandleT(idx); + } + + + template + BasePropHandleT handle(const T&, const std::string& _name) const + { + Properties::const_iterator p_it = properties_.begin(); + for (int idx=0; p_it != properties_.end(); ++p_it, ++idx) + { + if (*p_it != NULL && + (*p_it)->name() == _name //skip deleted properties +// Skip type check +#ifndef OM_FORCE_STATIC_CAST + && dynamic_cast*>(properties_[idx]) != NULL //check type +#endif + ) + { + return BasePropHandleT(idx); + } + } + return BasePropHandleT(); + } + + BaseProperty* property( const std::string& _name ) const + { + Properties::const_iterator p_it = properties_.begin(); + for (int idx=0; p_it != properties_.end(); ++p_it, ++idx) + { + if (*p_it != NULL && (*p_it)->name() == _name) //skip deleted properties + { + return *p_it; + } + } + return NULL; + } + + template PropertyT& property(BasePropHandleT _h) + { + assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size()); + assert(properties_[_h.idx()] != NULL); +#ifdef OM_FORCE_STATIC_CAST + return *static_cast *> (properties_[_h.idx()]); +#else + PropertyT* p = dynamic_cast*>(properties_[_h.idx()]); + assert(p != NULL); + return *p; +#endif + } + + + template const PropertyT& property(BasePropHandleT _h) const + { + assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size()); + assert(properties_[_h.idx()] != NULL); +#ifdef OM_FORCE_STATIC_CAST + return *static_cast*>(properties_[_h.idx()]); +#else + PropertyT* p = dynamic_cast*>(properties_[_h.idx()]); + assert(p != NULL); + return *p; +#endif + } + + + template void remove(BasePropHandleT _h) + { + assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size()); + delete properties_[_h.idx()]; + properties_[_h.idx()] = NULL; + } + + + void clear() + { + std::for_each(properties_.begin(), properties_.end(), Delete()); + } + + + //---------------------------------------------------- synchronize properties + + void reserve(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), Reserve(_n)); + } + + void resize(size_t _n) const { + std::for_each(properties_.begin(), properties_.end(), Resize(_n)); + } + + void swap(size_t _i0, size_t _i1) const { + std::for_each(properties_.begin(), properties_.end(), Swap(_i0, _i1)); + } + + + +protected: // generic add/get + + size_t _add( BaseProperty* _bp ) + { + Properties::iterator p_it=properties_.begin(), p_end=properties_.end(); + size_t idx=0; + for (; p_it!=p_end && *p_it!=NULL; ++p_it, ++idx) {}; + if (p_it==p_end) properties_.push_back(NULL); + properties_[idx] = _bp; + return idx; + } + + BaseProperty& _property( size_t _idx ) + { + assert( _idx < properties_.size()); + assert( properties_[_idx] != NULL); + BaseProperty *p = properties_[_idx]; + assert( p != NULL ); + return *p; + } + + const BaseProperty& _property( size_t _idx ) const + { + assert( _idx < properties_.size()); + assert( properties_[_idx] != NULL); + BaseProperty *p = properties_[_idx]; + assert( p != NULL ); + return *p; + } + + + typedef Properties::iterator iterator; + typedef Properties::const_iterator const_iterator; + iterator begin() { return properties_.begin(); } + iterator end() { return properties_.end(); } + const_iterator begin() const { return properties_.begin(); } + const_iterator end() const { return properties_.end(); } + + friend class BaseKernel; + +private: + + //-------------------------------------------------- synchronization functors + +#ifndef DOXY_IGNORE_THIS + struct Reserve + { + Reserve(size_t _n) : n_(_n) {} + void operator()(BaseProperty* _p) const { if (_p) _p->reserve(n_); } + size_t n_; + }; + + struct Resize + { + Resize(size_t _n) : n_(_n) {} + void operator()(BaseProperty* _p) const { if (_p) _p->resize(n_); } + size_t n_; + }; + + struct Swap + { + Swap(size_t _i0, size_t _i1) : i0_(_i0), i1_(_i1) {} + void operator()(BaseProperty* _p) const { if (_p) _p->swap(i0_, i1_); } + size_t i0_, i1_; + }; + + struct Delete + { + Delete() {} + void operator()(BaseProperty* _p) const { if (_p) delete _p; _p=NULL; } + }; +#endif + + Properties properties_; +}; + +}//namespace OpenMesh + +#endif//OPENMESH_PROPERTYCONTAINER + diff --git a/Core/Utils/SingletonT.cc b/Core/Utils/SingletonT.cc new file mode 100644 index 00000000..e53f89bf --- /dev/null +++ b/Core/Utils/SingletonT.cc @@ -0,0 +1,62 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements a simple singleton template +// +//============================================================================= + + +#define OPENMESH_SINGLETON_C + + +//== INCLUDES ================================================================= + + +// header +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//== SINGLETON'S DATA ========================================================= + + +template +T* SingletonT::pInstance__ = 0; + +template +bool SingletonT::destroyed__ = false; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= diff --git a/Core/Utils/SingletonT.hh b/Core/Utils/SingletonT.hh new file mode 100644 index 00000000..62ca6373 --- /dev/null +++ b/Core/Utils/SingletonT.hh @@ -0,0 +1,132 @@ +/*===========================================================================*\ + * * + * 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. * + * * +\*===========================================================================*/ + + +//============================================================================= +// +// Implements a simple singleton template +// +//============================================================================= + + +#ifndef __SINGLETON_HH__ +#define __SINGLETON_HH__ + + +//=== INCLUDES ================================================================ + +// OpenMesh +#include + +// STL +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//=== IMPLEMENTATION ========================================================== + + +/** A simple singleton template. + Encapsulates an arbitrary class and enforces its uniqueness. +*/ + +template +class SingletonT +{ +public: + + /** Singleton access function. + Use this function to obtain a reference to the instance of the + encapsulated class. Note that this instance is unique and created + on the first call to Instance(). + */ + + static T& Instance() + { + if (!pInstance__) + { + // check if singleton alive + if (destroyed__) + { + OnDeadReference(); + } + // first time request -> initialize + else + { + Create(); + } + } + return *pInstance__; + } + + +private: + + // Disable constructors/assignment to enforce uniqueness + SingletonT(); + SingletonT(const SingletonT&); + SingletonT& operator=(const SingletonT&); + + // Create a new singleton and store its pointer + static void Create() + { + static T theInstance; + pInstance__ = &theInstance; + } + + // Will be called if instance is accessed after its lifetime has expired + static void OnDeadReference() + { + throw std::runtime_error("[Singelton error] - Dead reference detected!\n"); + } + + virtual ~SingletonT() + { + pInstance__ = 0; + destroyed__ = true; + } + + static T* pInstance__; + static bool destroyed__; +}; + + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_SINGLETON_C) +# define OPENMESH_SINGLETON_TEMPLATES +# include "SingletonT.cc" +#endif +//============================================================================= +#endif // __SINGLETON_HH__ +//============================================================================= diff --git a/Core/Utils/color_cast.hh b/Core/Utils/color_cast.hh new file mode 100644 index 00000000..04474363 --- /dev/null +++ b/Core/Utils/color_cast.hh @@ -0,0 +1,235 @@ +//============================================================================= +// +// 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: 4118 $ +// $Date: 2009-01-05 07:45:18 +0100 (Mo, 05. Jan 2009) $ +// +//============================================================================= + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#ifndef OPENMESH_COLOR_CAST_HH +#define OPENMESH_COLOR_CAST_HH + + +//== INCLUDES ================================================================= + + +#include +#include + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** \name Cast vector type to another vector type. +*/ +//@{ + +//----------------------------------------------------------------------------- +#ifndef DOXY_IGNORE_THIS + +/// Cast one color vector to another. +template +struct color_caster +{ + typedef dst_t return_type; + + inline static return_type cast(const src_t& _src) + { + dst_t dst; + vector_copy(_src, dst, GenProg::Int2Type::size_>()); + return dst; + } +}; + + +template <> +struct color_caster +{ + typedef Vec3uc return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec3uc( (unsigned char)(_src[0]* 255.0f + 0.5f), + (unsigned char)(_src[1]* 255.0f + 0.5f), + (unsigned char)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3uc return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec3uc( (unsigned char)(_src[0]* 255.0f + 0.5f), + (unsigned char)(_src[1]* 255.0f + 0.5f), + (unsigned char)(_src[2]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4uc return_type; + + inline static return_type cast(const Vec3f& _src) + { + return Vec4uc( (unsigned char)(_src[0]* 255.0f + 0.5f), + (unsigned char)(_src[1]* 255.0f + 0.5f), + (unsigned char)(_src[2]* 255.0f + 0.5f), + (unsigned char)(255) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4uc return_type; + + inline static return_type cast(const Vec4f& _src) + { + return Vec4uc( (unsigned char)(_src[0]* 255.0f + 0.5f), + (unsigned char)(_src[1]* 255.0f + 0.5f), + (unsigned char)(_src[2]* 255.0f + 0.5f), + (unsigned char)(_src[3]* 255.0f + 0.5f) ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4uc return_type; + + inline static return_type cast(const Vec3uc& _src) + { + return Vec4uc( _src[0], _src[1], _src[2], 255 ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3f return_type; + + inline static return_type cast(const Vec3uc& _src) + { + const float f = 1.0f / 255.0f; + return Vec3f(_src[0] * f, _src[1] * f, _src[2] * f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec3f return_type; + + inline static return_type cast(const Vec4uc& _src) + { + const float f = 1.0f / 255.0f; + return Vec3f(_src[0] * f, _src[1] * f, _src[2] * f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4f return_type; + + inline static return_type cast(const Vec3uc& _src) + { + const float f = 1.0f / 255.0f; + return Vec4f(_src[0] * f, _src[1] * f, _src[2] * f, 1.0f ); + } +}; + +template <> +struct color_caster +{ + typedef Vec4f return_type; + + inline static return_type cast(const Vec4uc& _src) + { + const float f = 1.0f / 255.0f; + return Vec4f(_src[0] * f, _src[1] * f, _src[2] * f, _src[3] * f ); + } +}; + +// ---------------------------------------------------------------------------- + + +#ifndef DOXY_IGNORE_THIS + +#if !defined(OM_CC_MSVC) +template +struct color_caster +{ + typedef const dst_t& return_type; + + inline static return_type cast(const dst_t& _src) + { + return _src; + } +}; +#endif + +#endif + +//----------------------------------------------------------------------------- + + +template +inline +typename color_caster::return_type +color_cast(const src_t& _src ) +{ + return color_caster::cast(_src); +} + +#endif +//----------------------------------------------------------------------------- + +//@} + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_COLOR_CAST_HH defined +//============================================================================= + diff --git a/Core/Utils/vector_cast.hh b/Core/Utils/vector_cast.hh new file mode 100644 index 00000000..1c19f36f --- /dev/null +++ b/Core/Utils/vector_cast.hh @@ -0,0 +1,172 @@ +//============================================================================= +// +// 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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#ifndef OPENMESH_VECTORCAST_HH +#define OPENMESH_VECTORCAST_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** \name Cast vector type to another vector type. +*/ +//@{ + +//----------------------------------------------------------------------------- + + +template +inline void vector_copy( const src_t &_src, dst_t &_dst, GenProg::Int2Type<1> ) +{ + _dst[0] = _src[0]; +} + +template +inline void vector_copy( const src_t &_src, dst_t &_dst, GenProg::Int2Type<2> ) +{ + _dst[0] = _src[0]; + _dst[1] = _src[1]; +} + +template +inline void vector_copy( const src_t &_src, dst_t &_dst, GenProg::Int2Type<3> ) +{ + _dst[0] = _src[0]; + _dst[1] = _src[1]; + _dst[2] = _src[2]; +} + +template +inline void vector_copy( const src_t &_src, dst_t &_dst, GenProg::Int2Type<4> ) +{ + _dst[0] = _src[0]; + _dst[1] = _src[1]; + _dst[2] = _src[2]; + _dst[3] = _src[3]; +} + +template +inline void vector_copy( const src_t &_src, dst_t &_dst, GenProg::Int2Type<5> ) +{ + _dst[0] = _src[0]; + _dst[1] = _src[1]; + _dst[2] = _src[2]; + _dst[3] = _src[3]; + _dst[4] = _src[4]; +} + +template +inline void vector_copy( const src_t &_src, dst_t &_dst, GenProg::Int2Type<6> ) +{ + _dst[0] = _src[0]; + _dst[1] = _src[1]; + _dst[2] = _src[2]; + _dst[3] = _src[3]; + _dst[4] = _src[4]; + _dst[5] = _src[5]; +} + + +//----------------------------------------------------------------------------- +#ifndef DOXY_IGNORE_THIS + +template +struct vector_caster +{ + typedef dst_t return_type; + + inline static return_type cast(const src_t& _src) + { + dst_t dst; + vector_copy(_src, dst, GenProg::Int2Type::size_>()); + return dst; + } +}; + +#if !defined(OM_CC_MSVC) +template +struct vector_caster +{ + typedef const dst_t& return_type; + + inline static return_type cast(const dst_t& _src) + { + return _src; + } +}; +#endif + +#endif +//----------------------------------------------------------------------------- + + +/// Cast vector type to another vector type by copying the vector elements +template +inline +typename vector_caster::return_type +vector_cast(const src_t& _src ) +{ + return vector_caster::cast(_src); +} + + +//@} + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= diff --git a/Core/Utils/vector_traits.hh b/Core/Utils/vector_traits.hh new file mode 100644 index 00000000..beaa5e7f --- /dev/null +++ b/Core/Utils/vector_traits.hh @@ -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: 1801 $ +// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + + +//============================================================================= +// +// Helper Functions for binary reading / writing +// +//============================================================================= + + +#ifndef OPENMESH_VECTOR_TRAITS_HH +#define OPENMESH_VECTOR_TRAITS_HH + + +//== INCLUDES ================================================================= + +#include +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { + + +//============================================================================= + + +/** \name Provide a standardized access to relevant information about a + vector type. +*/ +//@{ + +//----------------------------------------------------------------------------- + +/** Helper class providing information about a vector type. + * + * If want to use a different vector type than the one provided %OpenMesh + * you need to supply a specialization of this class for the new vector type. + */ +template +struct vector_traits +{ + /// Type of the vector class + typedef typename T::vector_type vector_type; + + /// Type of the scalar value + typedef typename T::value_type value_type; + + /// size/dimension of the vector + static const size_t size_ = T::size_; + + /// size/dimension of the vector + static size_t size() { return size_; } +}; + +//@} + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_MESHREADER_HH defined +//============================================================================= diff --git a/Doc/ACGMakefile b/Doc/ACGMakefile new file mode 100644 index 00000000..51c316cd --- /dev/null +++ b/Doc/ACGMakefile @@ -0,0 +1,28 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +MODULES := doxygen + +DOXY_PROJECT_NAME = OpenMesh + +DOXY_FILE_PATTERNS = *.cc *.hh *.docu +DOXY_EXCLUDE_DIRS = $(cur-dir)/Examples $(proj-dir)/Tools/Test $(proj-dir)/Apps +DOXY_EXCLUDE_PATTERNS = CVS $(build-dir) *.moc.cc footer.hh +DOXY_EXAMPLE_PATH = $(cur-dir)/Examples $(cur-dir)/Tutorial +DOXY_EXAMPLE_PATTERNS = *.cc *.hh +DOXY_MACROS = OM_Attribute=class + +DOXY_GENERATE_HTML = YES +DOXY_GENERATE_LATEX = NO +DOXY_GENERATE_RTF = NO +DOXY_GENERATE_MAN = NO +DOXY_USE_PDFLATEX = YES +DOXY_ACG_STYLE = YES +DOXY_HAVE_DOT = NO +DOXY_COLLABORATION_GRAPH = NO + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Doc/Concepts/MeshItems.hh b/Doc/Concepts/MeshItems.hh new file mode 100644 index 00000000..e1a0c603 --- /dev/null +++ b/Doc/Concepts/MeshItems.hh @@ -0,0 +1,188 @@ +//============================================================================= +// +// OpenMesh +// Copyright (C) 2001-2005 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 Library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +//----------------------------------------------------------------------------- +// +// $Revision: 1.2 $ +// $Date: 2005-12-21 14:05:27 $ +// +//============================================================================= + + +//============================================================================= +// +// Mesh Items Concept +// +//============================================================================= + + +#error this file is for documentation purposes only + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Concepts { + + +//== CLASS DEFINITION ========================================================= + + +/** \ingroup mesh_concepts_group + The mesh items class encapsulates the types VertexT, HalfedgeT, + EdgeT, and FaceT. + \see VertexT, HalfedgeT, EdgeT, FaceT +*/ +struct MeshItems { + + +/** Interface for the internal vertex type. This minimal interface + must be provided by every vertex. It's up to the mesh kernel (or + the items used by the mesh kernel) to implement it. + + All methods marked as internal should only be used by the mesh + kernel. +*/ +template class VertexT +{ +public: + + /// Re-export the template argument Refs. This \b must be done! + typedef Refs_ Refs; + + /// Default constructor + VertexT(); + + /// Get an outgoing halfedge + HalfedgeHandle halfedge_handle() const; + /// Set the outgoing halfedge link + void set_halfedge_handle(HalfedgeHandle _eh); +}; + + + + +/** Interface for the internal halfedge type. This minimal interface + must be provided by every halfedge. It's up to the mesh kernel (or + the items used by the mesh kernel) to implement it. + + All methods marked as internal should only be used by the mesh + kernel. +*/ +template class HalfedgeT +{ +public: + + /// Re-export the template argument Refs. This \b must be done! + typedef Refs_ Refs; + + /** Get the vertex the halfedge point to. + \internal */ + VertexHandle vertex_handle() const; + + /** Set the vertex the halfedge point to. + \internal */ + void set_vertex_handle(VertexHandle _vh); + + /** Get the face this halfedge belongs to. + \internal */ + FaceHandle face_handle() const; + + /** Set the face this halfedge belongs to. + \internal */ + void set_face_handle(FaceHandle _fh); + + /** Get the next halfedge inside this face. + \internal */ + HalfedgeHandle next_halfedge_handle() const; + + /** Set the next halfedge inside this face. + \internal */ + void set_next_halfedge_handle(HalfedgeHandle _eh); +}; + + + + +/** Interface for the internal edge type. This minimal interface must + be provided by every edge. It's up to the mesh kernel (or the + items used by the mesh kernel) to implement it. + + All methods marked as internal should only be used by the mesh + kernel. +*/ +template class EdgeT +{ +public: + + /// Re-export the template argument Refs. This \b must be done! + typedef Refs_ Refs; + + /** Store two halfedges. + \internal */ + Halfedge halfedges[2]; +}; + + + + +/** Interface for the internal face type. This minimal interface must + be provided by every face. It's up to the mesh kernel (or the + items used by the mesh kernel) to implement it. + + All methods marked as internal should only be used by the mesh + kernel. +*/ +template class FaceT +{ +public: + + /// Re-export the template argument Refs. This \b must be done! + typedef Refs_ Refs; + + /** Compile-time-tag: is this face a triangle? Should be typedef'ed + to either GenProg::TagTrue or GenProg::TagFalse */ + typedef GenProg::TagTrue IsTriangle; + /// Run-time test: is this face a triangle? + static bool is_triangle(); + + /// Get the number of vertices of this face. + unsigned char n_vertices() const; + /** Set the number of vertices of this face. + \internal */ + void set_n_vertices(unsigned char _n); + + /// Get a halfedge that belongs to this face. + HalfedgeHandle halfedge_handle() const; + /** Set a halfedge that belongs this face. + \internal */ + void set_halfedge_handle(HalfedgeHandle _eh); +}; + +}; + +//============================================================================= +} // namespace Concepts +} // namespace OpenMesh +//============================================================================= diff --git a/Doc/Concepts/MeshKernel.hh b/Doc/Concepts/MeshKernel.hh new file mode 100644 index 00000000..aa9630f9 --- /dev/null +++ b/Doc/Concepts/MeshKernel.hh @@ -0,0 +1,510 @@ +//============================================================================= +// +// OpenMesh +// Copyright (C) 2001-2005 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 Library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +//----------------------------------------------------------------------------- +// +// $Revision: 1.2 $ +// $Date: 2005-12-21 14:05:27 $ +// +//============================================================================= + + +//============================================================================= +// +// Kernel Concept +// +//============================================================================= + + +#error this file is for documentation purposes only + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Concepts { + + +//== CLASS DEFINITION ========================================================= + + +/** \ingroup mesh_concepts_group + This class describes the minimum interface a mesh kernel + has to implement (because the resulting mesh will rely on + this interface). + + This is the template class the actually holds the mesh kernel + implementation. All functions marked as internal should only be used + by the mesh class (that inherits the kernel). The mesh may then + provide wrapper functions that provide the same functionality. + + \todo Check, if the member list is complete. +*/ +template class KernelT +{ +public: + + /// \name Mesh Items + //@{ + + /// Derive this type from the FinalMeshItems + typedef typename FinalMeshItems::Vertex Vertex; + typedef typename FinalMeshItems::Halfedge Halfedge; + typedef typename FinalMeshItems::Edge Edge; + typedef typename FinalMeshItems::Face Face; + typedef typename FinalMeshItems::Point Point; + typedef typename FinalMeshItems::Scalar Scalar; + typedef typename FinalMeshItems::Normal Normal; + typedef typename FinalMeshItems::Color Color; + typedef typename FinalMeshItems::TexCoord TexCoord; + typedef typename FinalMeshItems::VertexHandle VertexHandle; + typedef typename FinalMeshItems::HalfedgeHandle HalfedgeHandle; + typedef typename FinalMeshItems::EdgeHandle EdgeHandle; + typedef typename FinalMeshItems::FaceHandle FaceHandle; + + //@} + + + /// \name Kernel Iterators + //@{ + /// This type depends on the container type in use. + typedef SomeIterator KernelVertexIter; + typedef SomeIterator KernelConstVertexIter; + typedef SomeIterator KernelEdgeIter; + typedef SomeIterator KernelConstEdgeIter; + typedef SomeIterator KernelFaceIter; + typedef SomeIterator KernelConstFaceIter; + //@} + + /// \name Constructor/Destructor + //@{ + /// Default constructor + KernelT() {} + + /// Destructor + ~KernelT(); + //@} + + /// Assignment operator + KernelT& operator=(const KernelT& _rhs); + + + /** Reserve memory for vertices, edges, faces. + * + * Reserve memory for the mesh items vertices, edges, faces. Use + * this method if you can estimate the memory consumption, for + * instance in algorithm expanding the mesh. Depending on the + * underlying array type you might be better of using this method, + * then letting the array type decide when to increase the + * capacity. For instance the STL vector class \c std::vector (used + * in the supplied ArrayKernelT) doubles the capacity if it is + * exhausted. This might lead to an memory allocation exception, + * though an smaller increment would be enough. + */ + void reserve( unsigned int _n_vertices, + unsigned int _n_edges, + unsigned int _n_faces ); + + + /// \name Handle -> Item. + //@{ + /// Translate handle to item (see also OpenMesh::PolyMeshT::deref()) + const Vertex& vertex(VertexHandle _h) const { return deref(_h); } + Vertex& vertex(VertexHandle _h) { return deref(_h); } + const Halfedge& halfedge(HalfedgeHandle _h) const { return deref(_h); } + Halfedge& halfedge(HalfedgeHandle _h) { return deref(_h); } + const Edge& edge(EdgeHandle _h) const { return deref(_h); } + Edge& edge(EdgeHandle _h) { return deref(_h); } + const Face& face(FaceHandle _h) const { return deref(_h); } + Face& face(FaceHandle _h) { return deref(_h); } + //@} + + + /// \name Item -> Handle + //@{ + /// Translate item to handle + VertexHandle handle(const Vertex& _v) const; + HalfedgeHandle handle(const Halfedge& _he) const; + EdgeHandle handle(const Edge& _e) const; + FaceHandle handle(const Face& _f) const; + //@} + + + /// \name Get the i'th item + //@{ + /// Get the i'th item + VertexHandle vertex_handle(unsigned int _i) const; + HalfedgeHandle halfedge_handle(unsigned int _i) const; + EdgeHandle edge_handle(unsigned int _i) const; + FaceHandle face_handle(unsigned int _i) const; + //@} + + + /// \name Delete items + //@{ + /// Delete all items, i.e. clear all item containers. + void clear(); + /** Remove all items that are marked as deleted from the + corresponding containers. + \note Needs the Attributes::Status attribute + \note This function may not be implemented for all kernels. + */ + void garbage_collection(); + + /** Remove the last vertex imidiately, i.e. call pop_back() for the + VertexContainer. + */ + void remove_last_vertex() { vertices_.pop_back(); } + /** Remove the last edge imidiately, i.e. call pop_back() for the + EdgeContainer. Used e.g. by the add_face() method of PolyMeshT + */ + void remove_last_edge() { edges_.pop_back(); } + /** Remove the last face imidiately, i.e. call pop_back() for the + FaceContainer. Used e.g. by the add_face() method of PolyMeshT + */ + void remove_last_face() { faces_.pop_back(); } + + //@} + + + + + /// \name Number of elements + //@{ + /// Returns number of vertices + unsigned int n_vertices() const; + /// Returns number of halfedges (should be 2*n_edges()) + unsigned int n_halfedges() const; + /// Returns number of edges + unsigned int n_edges() const; + /// Returns number of faces + unsigned int n_faces() const; + /// Is the vertex container empty? + bool vertices_empty() const; + /// Is the halfedge container empty (should be the same as edges_empty()). + bool halfedges_empty() const; + /// Is the edge container empty? + bool edges_empty() const; + /// Is the face container empty? + bool faces_empty() const; + //@} + + + + /// \name Vertex connectivity + //@{ + /// Get an outgoing halfedge of a given vertex + HalfedgeHandle halfedge_handle(VertexHandle _vh) const; + /// Set the outgoing halfedge handle of a given vertex + void set_halfedge_handle(VertexHandle _vh, HalfedgeHandle _heh); + /// Get the coordinate of a vertex + const Point& point(VertexHandle _vh) const; + /// Get the coordinate of a vertex + const Point& point(const Vertex& _v) const; + /// Set the coordinate of a vertex + void set_point(VertexHandle _vh, const Point& _p); + /// Set the coordinate of a vertex + void set_point(Vertex& _v, const Point& _p); + //@} + + + + + /// \name Halfedge connectivity + //@{ + /// Get the vertex the halfedge points to + VertexHandle to_vertex_handle(HalfedgeHandle _heh) const; + /** Get the vertex the halfedge starts from (implemented as to-handle + of the opposite halfedge, provided for convenience) */ + VertexHandle from_vertex_handle(HalfedgeHandle _heh) const; + /// Set the to-vertex-handle of the halfedge + void set_vertex_handle(HalfedgeHandle _heh, VertexHandle _vh); + /** Get the face the halfedge belongs to. + \note The handle is invalid if the halfedge is a boundary halfedge */ + FaceHandle face_handle(HalfedgeHandle _heh) const; + /// Set the face the halfedge belongs to + void set_face_handle(HalfedgeHandle _heh, FaceHandle _fh); + /// Get the next halfedge handle + HalfedgeHandle next_halfedge_handle(HalfedgeHandle _heh) const; + /** Set the next halfedge handle. \note If the previous halfedge is + also stored (see OpenMesh::Attributes::PrevHalfedge) then this + method also has to set this link) */ + void set_next_halfedge_handle(HalfedgeHandle _heh, HalfedgeHandle _nheh); + /** Get the previous halfedge of the given halfedge. The + implementation should take care of an existing + OpenMesh::Attributes::PrevHalfedge attribute. */ + HalfedgeHandle prev_halfedge_handle(HalfedgeHandle _heh) const; + /// Get the opposite halfedge + HalfedgeHandle opposite_halfedge_handle(HalfedgeHandle _heh) const; + /// Counter-clockwise rotate the given halfedge around its from vertex + HalfedgeHandle ccw_rotated_halfedge_handle(HalfedgeHandle _heh) const; + /// Clockwise rotate the given halfedge around its from vertex + HalfedgeHandle cw_rotated_halfedge_handle(HalfedgeHandle _heh) const; + /// Get the edge the current halfedge it contained in + EdgeHandle edge_handle(HalfedgeHandle _heh) const; + //@} + + + + /// \name Edge connectivity + //@{ + /// Get the first or second halfedge of the given edge + HalfedgeHandle halfedge_handle(EdgeHandle _eh, unsigned int _i) const; + //@} + + + + /// \name Face connectivity + //@{ + /// Get a halfedge belonging to the face + HalfedgeHandle halfedge_handle(FaceHandle _fh) const; + /// Set one halfedge of the face + void set_halfedge_handle(FaceHandle _fh, HalfedgeHandle _heh); + //@} + + +public: // Standard Property Management + + /// \name set/get value of a standard property + //@{ + + // vertex + const Point& point(VertexHandle _vh) const; ///< Get position + void set_point(VertexHandle _vh, const Point& _p); ///< Set position + Point& point(VertexHandle _vh); ///< Convenience function + + const Normal& normal(VertexHandle _vh) const; ///< Get normal + void set_normal(VertexHandle _vh, const Normal& _n); ///< Set normal + + const Color& color(VertexHandle _vh) const; ///< Get color + void set_color(VertexHandle _vh, const Color& _c) ///< Set color + + const TexCoord& texcoord(VertexHandle _vh) const; ///< Get texture coordinate. + void set_texcoord(VertexHandle _vh, const TexCoord& _t); ///< Set texture coordinate. + + const StatusInfo& status(VertexHandle _vh) const; ///< Get status + StatusInfo& status(VertexHandle _vh); ///< Get status + + // halfedge + const StatusInfo& status(HalfedgeHandle _vh) const; ///< Get status + StatusInfo& status(HalfedgeHandle _vh); ///< Get status + + // edge + const StatusInfo& status(EdgeHandle _vh) const; ///< Get status + StatusInfo& status(EdgeHandle _vh); ///< Get status + + // face + const Normal& normal(FaceHandle _fh) const; ///< Get normal + void set_normal(FaceHandle _fh, const Normal& _n); ///< Set normal + + const Color& color(FaceHandle _fh) const; ///< Get color + void set_color(FaceHandle _fh, const Color& _c); ///< Set color + + const StatusInfo& status(FaceHandle _vh) const; ///< Get status + StatusInfo& status(FaceHandle _vh); ///< Get status + + //@} + + /// \name Dynamically add standard properties + //@{ + /// Request property + void request_vertex_normals(); + void request_vertex_colors(); + void request_vertex_texcoords(); + void request_vertex_status(); + + void request_halfedge_status(); + + void request_edge_status(); + + void request_face_normals(); + void request_face_colors(); + void request_face_status(); + //@} + + /// \name Remove standard properties + //@{ + /// Remove property + void release_vertex_normals(); + void release_vertex_colors(); + void release_vertex_texcoords(); + void release_vertex_status(); + + void release_halfedge_status(); + + void release_edge_status(); + + void release_face_normals(); + void release_face_colors(); + void release_face_status(); + //@} + + /// \name Check availability of standard properties + //@{ + /// Is property available? + bool has_vertex_normals() const; + bool has_vertex_colors() const; + bool has_vertex_texcoords() const; + bool has_vertex_status() const; + bool has_edge_status() const; + bool has_halfedge_status() const; + bool has_face_normals() const; + bool has_face_colors() const; + bool has_face_status() const; + //@} + +public: // Property Management + + /// \anchor concepts_kernelt_property_management + + /// \name Property management - add property + //@{ + /// Add property. + /// @copydoc OpenMesh::BaseKernel::add_property() + template bool add_property( [VEHFM]PropHandleT& _ph, + const std::string& _name = "" ); + //@} + + /// \name Property management - remove property + //@{ + /// Remove property + template void remove_property( [VEHFM]PropHandleT& ); + //@} + + /// \name Property management - get property by name + //@{ + /// Get property handle by name + template + bool get_property_handle( [VEHFM]PropHandleT& ph, const std::string& _n ) const; + //@} + + /// \name Property management - get property + //@{ + /// Get property + template PropertyT& property( [VEHF]PropHandleT _ph ); + template const PropertyT& property( [VEHF]PropHandleT _ph ) const; + template PropertyT& mproperty( MPropHandleT _ph ); + template const PropertyT& mproperty( MPropHandleT _ph ) const; + //@} + + /// \name Property management - get property value for an item + //@{ + + /// Get value for item represented by the handle. + template + T& property( VPropHandleT _ph, VertexHandle _vh ); + template + const T& property( VPropHandleT _ph, VertexHandle _vh ) const; + + template + T& property( EPropHandleT _ph, EdgeHandle _vh ); + template + const T& property( EPropHandleT _ph, EdgeHandle _vh ) const; + + template + T& property( HPropHandleT _ph, HalfedgeHandle _vh ); + template + const T& property( HPropHandleT _ph, HalfedgeHandle _vh ) const; + + template + T& property( FPropHandleT _ph, FaceHandle _vh ); + template + const T& property( FPropHandleT _ph, FaceHandle _vh ) const; + + template + T& property( MPropHandleT _ph ); + template + const T& property( MPropHandleT _ph ) const; + + //@} + +public: + + + /// \name Low-level adding new items + //@{ + /** Add a new (default) vertex. + \internal */ + VertexHandle new_vertex(); + /** Add a new vertex with a given point coordinate. + \internal */ + VertexHandle new_vertex(const Point& _p); + /** Add a new vertex (copied from the given one). + \internal */ + VertexHandle new_vertex(const Vertex& _v); + /** Add a new edge from \c _start_vertex_handle to \c _end_vertex_handle. + This method should add an edge (i.e. two opposite halfedges) and set + the corresponding vertex handles of these halfedges. + \internal + */ + HalfedgeHandle new_edge(VertexHandle _start_vertex_handle, + VertexHandle _end_vertex_handle); + + /** Adding a new face + \internal + */ + FaceHandle new_face(); + /** Adding a new face (copied from a \c _f). + \internal */ + FaceHandle new_face(const Face& _f); + //@} + + + // --- iterators --- + + /// \name Kernel item iterators + //@{ + /** Kernel item iterator + \internal */ + KernelVertexIter vertices_begin(); + KernelConstVertexIter vertices_begin() const; + KernelVertexIter vertices_end(); + KernelConstVertexIter vertices_end() const; + KernelEdgeIter edges_begin(); + KernelConstEdgeIter edges_begin() const; + KernelEdgeIter edges_end(); + KernelConstEdgeIter edges_end() const; + KernelFaceIter faces_begin(); + KernelConstFaceIter faces_begin() const; + KernelFaceIter faces_end(); + KernelConstFaceIter faces_end() const; + //@} + + + +private: + + + // --- private functions --- + + /// copy constructor: not used + KernelT(const KernelT& _rhs); +}; +}; + + +//============================================================================= +} // namespace Concepts +} // namespace OpenMesh +//============================================================================= diff --git a/Doc/Doxyfile b/Doc/Doxyfile new file mode 100644 index 00000000..ad385566 --- /dev/null +++ b/Doc/Doxyfile @@ -0,0 +1,1417 @@ +# Doxyfile 1.5.6 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = OpenMesh + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, +# and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = ../ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = YES + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = YES + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.cc *.hh *.docu + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = Examples ../Tools/Test ../Apps + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = .svn CVS Debian64 *.moc.cc footer.hh + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = Examples Tutorial + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = *.cc *.hh + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = images + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = html/acg_header.html + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = html/acg_footer.html + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hiererachy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. + +GENERATE_TREEVIEW = NONE + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = DOXYGEN OM_Attribute=class + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is enabled by default, which results in a transparent +# background. Warning: Depending on the platform used, enabling this option +# may lead to badly anti-aliased labels on the edges of a graph (i.e. they +# become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/Doc/Examples/BaseExporter.hh b/Doc/Examples/BaseExporter.hh new file mode 100644 index 00000000..3e7483a8 --- /dev/null +++ b/Doc/Examples/BaseExporter.hh @@ -0,0 +1,22 @@ +class BaseExporter +{ +public: + + virtual void update() = 0; + + virtual PVertexIter const_vertices_begin() = 0; + virtual PVertexIter const_vertices_end() = 0; + + virtual PTexCoordIter const_texcoords_begin() = 0; + virtual PTexCoordIter const_texcoords_end() = 0; + + virtual PIdxFaceIter const_idx_faces_begin() = 0; + virtual PIdxFaceIter const_idx_faces_end() = 0; + + virtual PFaceIter const_set_faces_begin() = 0; + virtual PFaceIter const_set_faces_end() = 0; + + virtual unsigned int n_faces() = 0; + virtual unsigned int n_vertices() = 0; + virtual unsigned int n_texcoords() = 0; +}; diff --git a/Doc/Examples/BaseImporter.hh b/Doc/Examples/BaseImporter.hh new file mode 100644 index 00000000..14946936 --- /dev/null +++ b/Doc/Examples/BaseImporter.hh @@ -0,0 +1,9 @@ +class BaseImporter +{ +public: + + virtual void add_vertex (const OpenMesh::Vec3f&) {}; + virtual void add_normal (const OpenMesh::Vec3f&) {}; + virtual void add_texture (const OpenMesh::Vec2f&) {}; + virtual void add_face (const FaceType&) {}; +}; diff --git a/Doc/Examples/BaseReader.hh b/Doc/Examples/BaseReader.hh new file mode 100644 index 00000000..62c718e9 --- /dev/null +++ b/Doc/Examples/BaseReader.hh @@ -0,0 +1,13 @@ +class BaseReader +{ +public: + + virtual std::string get_description() const = 0; + virtual std::string get_extensions() const = 0; + virtual std::string get_magic() const { return std::string(""); } + + virtual bool read(std::istream& _is, BaseImporter& _bi) const = 0; + virtual bool read(const std::string& _filename, BaseImporter& _bi) const = 0; + + ... +}; diff --git a/Doc/Examples/adasub.cc b/Doc/Examples/adasub.cc new file mode 100644 index 00000000..de2f4c71 --- /dev/null +++ b/Doc/Examples/adasub.cc @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include + +// ---------------------------------------- + +using OpenMesh::Subdivider::Adaptive; + +// ---------------------------------------- necessary types + +OpenMesh::TriMesh_ArrayKernelT< CompositeTraits > MyMesh; +CompositeT< MyMesh > Subdivider; + +// ---------------------------------------- setup a subdivider + +int main(int argc, char **argv) +{ + MyMesh mesh; // create mesh and fill it + + if (!OpenMesh::IO::read_mesh(mesh, argv[1])) + return 1; // error reading mesh + + Subdivider subdivider(mesh); // bind subdivider to mesh + + // -------------------- add some rules + + // anonymous registration + subdivider.add< Tvv3::Handle >(); + subdivider.add< VF::Handle >(); + subdivider.add< FF::Handle >(); + + // 'named' registration + FVc::Handle hFVc; + subdivider.add( hFVc ); + + // print pre-computed coefficients to std::cout... + std::copy(subdivider.rule( hFVc ).coeffs().begin(), + subdivider.rule( hFVc ).coeffs().end(), + std::ostream_iterator(std::cout, ", ")); + + // prepare subdivider and the traits + if (!subdivider.initialize()) + return 1; // error initializing subdivider + + MyMesh::FaceHandle fh; // select a face + subdivider.refine(fh); +} diff --git a/Doc/Examples/build-trimesh.cc b/Doc/Examples/build-trimesh.cc new file mode 100644 index 00000000..49d97d9a --- /dev/null +++ b/Doc/Examples/build-trimesh.cc @@ -0,0 +1,8 @@ +template +struct TriMesh_ArrayKernel_GeneratorT +{ + typedef FinalMeshItemsT MeshItems; + typedef AttribKernelT AttribKernel; + typedef ArrayKernelT MeshKernel; + typedef TriMeshT Mesh; +}; diff --git a/Doc/Examples/circulators.cc b/Doc/Examples/circulators.cc new file mode 100644 index 00000000..2d94ae3b --- /dev/null +++ b/Doc/Examples/circulators.cc @@ -0,0 +1,11 @@ +MyMesh mesh; + +// (linearly) iterate over all vertices +for (MyMesh::VertexIter v_it=mesh.vertices_begin(); v_it!=mesh.vertices_end(); ++v_it) +{ + // circulate around the current vertex + for (MyMesh::VertexVertexIter vv_it=mesh.vv_iter(v_it.handle()); vv_it; ++vv_it) + { + // do something with e.g. mesh.point(*vv_it) + } +} diff --git a/Doc/Examples/decimater.cc b/Doc/Examples/decimater.cc new file mode 100644 index 00000000..10785acd --- /dev/null +++ b/Doc/Examples/decimater.cc @@ -0,0 +1,30 @@ +// +using namespace OpenMesh + +// ---------------------------------------- necessary types + +// Mesh type +typedef TriMesh_ArrayKernelT<> Mesh; + +// Decimater type +typedef Decimater::DecimaterT< Mesh > Decimater; + +// Decimation Module Handle type +typedef Decimater::ModQuadricT< decimater >::Handle HModQuadric; + +// ---------------------------------------- decimater setup + +Mesh mesh; // a mesh object +Decimater decimater(mesh); // a decimater object, connected to a mesh +HModQuadric hModQuadric; // use a quadric module + +decimater.add( hModQuadric ); // register module at the decimater + +std::cout << decimater.module( hModQuadric ).name() << std::endl; + // the way to access the module + +decimater.initialize(); // let the decimater initialize the mesh and the + // modules + +decimater.decimate(); // do decimation + diff --git a/Doc/Examples/draw_normals.cc b/Doc/Examples/draw_normals.cc new file mode 100644 index 00000000..43a8bfb8 --- /dev/null +++ b/Doc/Examples/draw_normals.cc @@ -0,0 +1,14 @@ +#include + +// draw a face normal if we have one +void drawFaceNormal(const MyMesh::Face& _f) { + drawFaceNormal(_f, GenProg::Bool2Type()); +} + +// normal exists -> use it +void drawFaceNormal(const MyMesh::Face& _f, GenProg::Bool2Type) { + glNormal3fv(_f.normal()); +} + +// empty dummy (no normals) +void drawFaceNormal(const MyMesh::Face& _f, GenProg::Bool2Type){} diff --git a/Doc/Examples/iterators.cc b/Doc/Examples/iterators.cc new file mode 100644 index 00000000..957df892 --- /dev/null +++ b/Doc/Examples/iterators.cc @@ -0,0 +1,18 @@ +MyMesh mesh; + +// iterate over all vertices +for (MyMesh::VertexIter v_it=mesh.vertices_begin(); v_it!=mesh.vertices_end(); ++v_it) + ...; // do something with *v_it, v_it->, or v_it.handle() + +// iterate over all halfedges +for (MyMesh::HalfedgeIter h_it=mesh.halfedges_begin(); v_it!=mesh.halfedges_end(); ++v_it) + ...; // do something with *h_it, h_it->, or h_it.handle() + +// iterate over all edges +for (MyMesh::EdgeIter e_it=mesh.edges_begin(); v_it!=mesh.edges_end(); ++v_it) + ...; // do something with *e_it, e_it->, or e_it.handle() + +// iterator over all faces +for (MyMesh::FaceIter f_it=mesh.faces_begin(); v_it!=mesh.faces_end(); ++v_it) + ...; // do something with *f_it, f_it->, or f_it.handle() + diff --git a/Doc/Examples/mesh_io.cc b/Doc/Examples/mesh_io.cc new file mode 100644 index 00000000..7a75728d --- /dev/null +++ b/Doc/Examples/mesh_io.cc @@ -0,0 +1,17 @@ +#include + +MyMesh mesh; + +if (!OpenMesh::IO::read_mesh(mesh, "some input file")) +{ + std::cerr << "read error\n"; + exit(1); +} + +// do something with your mesh ... + +if (!OpenMesh::IO::write_mesh(mesh, "some output file")) +{ + std::cerr << "write error\n"; + exit(1); +} diff --git a/Doc/Examples/mymesh.cc b/Doc/Examples/mymesh.cc new file mode 100644 index 00000000..3bdbf219 --- /dev/null +++ b/Doc/Examples/mymesh.cc @@ -0,0 +1,51 @@ +#include + + +// define traits +struct MyTraits : public OpenMesh::DefaultTraits +{ + // use double valued coordinates + typedef OpenMesh::Vec3d Point; + + // use vertex normals and vertex colors + VertexAttributes( OpenMesh::DefaultAttributer::Normal | + OpenMesh::DefaultAttributer::Color ); + + // store the previous halfedge + HalfedgeAttributes( OpenMesh::DefaultAttributer::PrevHalfedge ); + + // use face normals + FaceAttributes( OpenMesh::DefaultAttributer::Normal ); + + // store a face handle for each vertex + VertexTraits + { + typename Base::Refs::FaceHandle my_face_handle; + }; + +}; + + +// Select mesh type (TriMesh) and kernel (ArrayKernel) +// and define my personal mesh type (MyMesh) +typedef OpenMesh::TriMesh_ArrayKernelT MyMesh; + +int main(int argc, char **argv) +{ + MyMesh mesh; + + // -------------------- Add dynamic data + + // for each vertex an extra double value + OpenMesh::VPropHandleT< double > vprop_double; + mesh.add_property( vprop_double ); + + // for the mesh an extra string + OpenMesh::MPropHandleT< string > mprop_string; + mesh.add_property( mprop_string ); + + // -------------------- do something + + ...; + +} diff --git a/Doc/Examples/traits0.cc b/Doc/Examples/traits0.cc new file mode 100644 index 00000000..23b19216 --- /dev/null +++ b/Doc/Examples/traits0.cc @@ -0,0 +1,17 @@ +struct DefaultTraits +{ + typedef Vec3f Point; + typedef Vec3f Normal; + typedef Vec2f TexCoord; + typedef Vec3uc Color; + + VertexTraits {}; + HalfedgeTraits {}; + EdgeTraits {}; + FaceTraits {}; + + VertexAttributes(0); + HalfedgeAttributes(Attributes::PrevHalfedge); + EdgeAttributes(0); + FaceAttributes(0); +}; diff --git a/Doc/Examples/traits1.cc b/Doc/Examples/traits1.cc new file mode 100644 index 00000000..9579e3c2 --- /dev/null +++ b/Doc/Examples/traits1.cc @@ -0,0 +1,4 @@ +struct MyTraits : public OpenMesh::DefaultTraits +{ + typedef OpenMesh::Vec3d Point; // use double-values points +}; diff --git a/Doc/Examples/traits2.cc b/Doc/Examples/traits2.cc new file mode 100644 index 00000000..d0d770ac --- /dev/null +++ b/Doc/Examples/traits2.cc @@ -0,0 +1,7 @@ +struct MyTraits : public OpenMesh::DefaultTraits +{ + VertexTraits + { + int some_additional_index; + }; +}; diff --git a/Doc/Examples/traits3.cc b/Doc/Examples/traits3.cc new file mode 100644 index 00000000..5590ef13 --- /dev/null +++ b/Doc/Examples/traits3.cc @@ -0,0 +1,7 @@ +struct MyTraits : public OpenMesh::DefaultTraits +{ + template struct VertexT : public Base + { + int some_additional_index; + }; +}; diff --git a/Doc/Examples/traits4.cc b/Doc/Examples/traits4.cc new file mode 100644 index 00000000..ba37aa36 --- /dev/null +++ b/Doc/Examples/traits4.cc @@ -0,0 +1,8 @@ +struct MyTraits : public OpenMesh::DefaultTraits +{ + VertexTraits + { + int some_additional_index; + typename Base::Refs::FaceHandle my_face_handle; + }; +}; diff --git a/Doc/Examples/traits5.cc b/Doc/Examples/traits5.cc new file mode 100644 index 00000000..c980f0cd --- /dev/null +++ b/Doc/Examples/traits5.cc @@ -0,0 +1,7 @@ +struct MyTraits : public OpenMesh::DefaultTraits +{ + VertexAttributes( OpenMesh::Attributes::Normal | + OpenMesh::Attributes::Color ); + + FaceAttributes( OpenMesh::Attributes::Normal ); +}; diff --git a/Doc/Tutorial/01-build_cube/ACGMakefile b/Doc/Tutorial/01-build_cube/ACGMakefile new file mode 100644 index 00000000..d1ff6370 --- /dev/null +++ b/Doc/Tutorial/01-build_cube/ACGMakefile @@ -0,0 +1,24 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +# subdirs to process +SUBDIRS = $(call find-subdirs) + +# programms (files containing main(), w/o suffix) +EXECS = $(call cxx-find-execs) + +# packages (qt, opengl, ...) +PACKAGES := + +# project DSOs +PROJ_LIBS := OpenMesh/Core + +# modules to use (cxx, c, moc, uic, yacc) ! order-dependent ! +MODULES := cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Doc/Tutorial/01-build_cube/build_cube.cc b/Doc/Tutorial/01-build_cube/build_cube.cc new file mode 100644 index 00000000..c1178007 --- /dev/null +++ b/Doc/Tutorial/01-build_cube/build_cube.cc @@ -0,0 +1,127 @@ +//============================================================================= +// +// OpenMesh +// Copyright (C) 2001-2005 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 Library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +//----------------------------------------------------------------------------- +// +// $Revision: 1.2 $ +// $Date: 2005-12-21 14:05:30 $ +// +//============================================================================= + + +#include +// -------------------- OpenMesh +#include +#include + + +// ---------------------------------------------------------------------------- + +typedef OpenMesh::PolyMesh_ArrayKernelT<> MyMesh; + + +// ---------------------------------------------------------------------------- +// Build a simple cube and write it to std::cout + +int main() +{ + MyMesh mesh; + + // generate vertices + + MyMesh::VertexHandle vhandle[8]; + + vhandle[0] = mesh.add_vertex(MyMesh::Point(-1, -1, 1)); + vhandle[1] = mesh.add_vertex(MyMesh::Point( 1, -1, 1)); + vhandle[2] = mesh.add_vertex(MyMesh::Point( 1, 1, 1)); + vhandle[3] = mesh.add_vertex(MyMesh::Point(-1, 1, 1)); + vhandle[4] = mesh.add_vertex(MyMesh::Point(-1, -1, -1)); + vhandle[5] = mesh.add_vertex(MyMesh::Point( 1, -1, -1)); + vhandle[6] = mesh.add_vertex(MyMesh::Point( 1, 1, -1)); + vhandle[7] = mesh.add_vertex(MyMesh::Point(-1, 1, -1)); + + + // generate (quadrilateral) faces + + std::vector face_vhandles; + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[0]); + face_vhandles.push_back(vhandle[1]); + face_vhandles.push_back(vhandle[2]); + face_vhandles.push_back(vhandle[3]); + mesh.add_face(face_vhandles); + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[7]); + face_vhandles.push_back(vhandle[6]); + face_vhandles.push_back(vhandle[5]); + face_vhandles.push_back(vhandle[4]); + mesh.add_face(face_vhandles); + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[1]); + face_vhandles.push_back(vhandle[0]); + face_vhandles.push_back(vhandle[4]); + face_vhandles.push_back(vhandle[5]); + mesh.add_face(face_vhandles); + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[2]); + face_vhandles.push_back(vhandle[1]); + face_vhandles.push_back(vhandle[5]); + face_vhandles.push_back(vhandle[6]); + mesh.add_face(face_vhandles); + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[3]); + face_vhandles.push_back(vhandle[2]); + face_vhandles.push_back(vhandle[6]); + face_vhandles.push_back(vhandle[7]); + mesh.add_face(face_vhandles); + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[0]); + face_vhandles.push_back(vhandle[3]); + face_vhandles.push_back(vhandle[7]); + face_vhandles.push_back(vhandle[4]); + mesh.add_face(face_vhandles); + + + // write mesh to output.obj + try + { + if ( !OpenMesh::IO::write_mesh(mesh, "output.off") ) + { + std::cerr << "Cannot write mesh to file 'output.off'" << std::endl; + return 1; + } + } + catch( std::exception& x ) + { + std::cerr << x.what() << std::endl; + return 1; + } + + return 0; +} diff --git a/Doc/Tutorial/02-iterators/ACGMakefile b/Doc/Tutorial/02-iterators/ACGMakefile new file mode 100644 index 00000000..d1ff6370 --- /dev/null +++ b/Doc/Tutorial/02-iterators/ACGMakefile @@ -0,0 +1,24 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +# subdirs to process +SUBDIRS = $(call find-subdirs) + +# programms (files containing main(), w/o suffix) +EXECS = $(call cxx-find-execs) + +# packages (qt, opengl, ...) +PACKAGES := + +# project DSOs +PROJ_LIBS := OpenMesh/Core + +# modules to use (cxx, c, moc, uic, yacc) ! order-dependent ! +MODULES := cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Doc/Tutorial/02-iterators/smooth.cc b/Doc/Tutorial/02-iterators/smooth.cc new file mode 100644 index 00000000..ad8273b3 --- /dev/null +++ b/Doc/Tutorial/02-iterators/smooth.cc @@ -0,0 +1,76 @@ +#include +#include +// -------------------- OpenMesh +#include +#include + +typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh; + + +int main(int argc, char **argv) +{ + MyMesh mesh; + + + // check command line options + if (argc != 4) + { + std::cerr << "Usage: " << argv[0] << " #iterations infile outfile\n"; + return 1; + } + + + // read mesh from stdin + if ( ! OpenMesh::IO::read_mesh(mesh, argv[2]) ) + { + std::cerr << "Error: Cannot read mesh from " << argv[2] << std::endl; + return 1; + } + + + // this vector stores the computed centers of gravity + std::vector cogs; + std::vector::iterator cog_it; + cogs.reserve(mesh.n_vertices()); + + + // smoothing mesh argv[1] times + MyMesh::VertexIter v_it, v_end(mesh.vertices_end()); + MyMesh::VertexVertexIter vv_it; + MyMesh::Point cog; + MyMesh::Scalar valence; + unsigned int i, N(atoi(argv[1])); + + + for (i=0; i < N; ++i) + { + cogs.clear(); + for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it) + { + cog[0] = cog[1] = cog[2] = valence = 0.0; + + for (vv_it=mesh.vv_iter( v_it ); vv_it; ++vv_it) + { + cog += mesh.point( vv_it ); + ++valence; + } + + cogs.push_back(cog / valence); + } + + for (v_it=mesh.vertices_begin(), cog_it=cogs.begin(); + v_it!=v_end; ++v_it, ++cog_it) + if ( !mesh.is_boundary( v_it ) ) + mesh.set_point( v_it, *cog_it ); + } + + + // write mesh to stdout + if ( ! OpenMesh::IO::write_mesh(mesh, argv[3]) ) + { + std::cerr << "Error: cannot write mesh to " << argv[3] << std::endl; + return 1; + } + + return 0; +} diff --git a/Doc/Tutorial/03-properties/ACGMakefile b/Doc/Tutorial/03-properties/ACGMakefile new file mode 100644 index 00000000..d1ff6370 --- /dev/null +++ b/Doc/Tutorial/03-properties/ACGMakefile @@ -0,0 +1,24 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +# subdirs to process +SUBDIRS = $(call find-subdirs) + +# programms (files containing main(), w/o suffix) +EXECS = $(call cxx-find-execs) + +# packages (qt, opengl, ...) +PACKAGES := + +# project DSOs +PROJ_LIBS := OpenMesh/Core + +# modules to use (cxx, c, moc, uic, yacc) ! order-dependent ! +MODULES := cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Doc/Tutorial/03-properties/smooth.cc b/Doc/Tutorial/03-properties/smooth.cc new file mode 100644 index 00000000..207a619b --- /dev/null +++ b/Doc/Tutorial/03-properties/smooth.cc @@ -0,0 +1,74 @@ +#include +#include +// -------------------- +#include +#include + +typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh; + + +int main(int argc, char **argv) +{ + MyMesh mesh; + + + // check command line options + if (argc != 4) + { + std::cerr << "Usage: " << argv[0] << " #iterations infile outfile\n"; + return 1; + } + + + + // read mesh from stdin + if ( ! OpenMesh::IO::read_mesh(mesh, argv[2]) ) + { + std::cerr << "Error: Cannot read mesh from " << argv[2] << std::endl; + return 1; + } + + + + // this vertex property stores the computed centers of gravity + OpenMesh::VPropHandleT cogs; + mesh.add_property(cogs); + + // smoothing mesh argv[1] times + MyMesh::VertexIter v_it, v_end(mesh.vertices_end()); + MyMesh::VertexVertexIter vv_it; + MyMesh::Point cog; + MyMesh::Scalar valence; + unsigned int i, N(atoi(argv[1])); + + + for (i=0; i < N; ++i) + { + for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it) + { + mesh.property(cogs,v_it).vectorize(0.0f); + valence = 0; + + for (vv_it=mesh.vv_iter( v_it ); vv_it; ++vv_it) + { + mesh.property(cogs,v_it) += mesh.point( vv_it ); + ++valence; + } + mesh.property(cogs,v_it) /= valence; + } + + for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it) + if ( !mesh.is_boundary( v_it ) ) + mesh.set_point( v_it, mesh.property(cogs,v_it) ); + } + + + // write mesh to stdout + if ( ! OpenMesh::IO::write_mesh(mesh, argv[3]) ) + { + std::cerr << "Error: cannot write mesh to " << argv[3] << std::endl; + return 1; + } + + return 0; +} diff --git a/Doc/Tutorial/04-stl_algorithms/ACGMakefile b/Doc/Tutorial/04-stl_algorithms/ACGMakefile new file mode 100644 index 00000000..d1ff6370 --- /dev/null +++ b/Doc/Tutorial/04-stl_algorithms/ACGMakefile @@ -0,0 +1,24 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +# subdirs to process +SUBDIRS = $(call find-subdirs) + +# programms (files containing main(), w/o suffix) +EXECS = $(call cxx-find-execs) + +# packages (qt, opengl, ...) +PACKAGES := + +# project DSOs +PROJ_LIBS := OpenMesh/Core + +# modules to use (cxx, c, moc, uic, yacc) ! order-dependent ! +MODULES := cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Doc/Tutorial/04-stl_algorithms/smooth.cc b/Doc/Tutorial/04-stl_algorithms/smooth.cc new file mode 100644 index 00000000..3bb7f5aa --- /dev/null +++ b/Doc/Tutorial/04-stl_algorithms/smooth.cc @@ -0,0 +1,59 @@ +#include +#include +// -------------------- OpenMesh +#include +#include +// -------------------- +#include "smooth_algo.hh" + + +// ---------------------------------------------------------------------------- + +#ifndef DOXY_IGNORE_THIS + +struct MyTraits : public OpenMesh::DefaultTraits +{ + HalfedgeAttributes(OpenMesh::Attributes::PrevHalfedge); +}; + +#endif + +typedef OpenMesh::TriMesh_ArrayKernelT MyMesh; + + +// ---------------------------------------------------------------------------- + +int main(int argc, char **argv) +{ + MyMesh mesh; + + + // check command line options + if (argc != 4) + { + std::cerr << "Usage: " << argv[0] << " #iterations infile outfile\n"; + return 1; + } + + + // read mesh from stdin + if ( ! OpenMesh::IO::read_mesh(mesh, argv[2]) ) + { + std::cerr << "Error: Cannot read mesh from " << argv[2] << std::endl; + return 1; + } + + + // smoothing mesh argv[1] times + SmootherT smoother(mesh); + smoother.smooth(atoi(argv[1])); + + + // write mesh to stdout + if ( ! OpenMesh::IO::write_mesh(mesh, argv[3]) ) + { + std::cerr << "Error: cannot write mesh to " << argv[3] << std::endl; + return 1; + } + return 0; +} diff --git a/Doc/Tutorial/04-stl_algorithms/smooth_algo.hh b/Doc/Tutorial/04-stl_algorithms/smooth_algo.hh new file mode 100644 index 00000000..9c564427 --- /dev/null +++ b/Doc/Tutorial/04-stl_algorithms/smooth_algo.hh @@ -0,0 +1,106 @@ +#include +#include + +#ifndef DOXY_IGNORE_THIS + +template class SmootherT +{ +public: + + typedef typename Mesh::Point cog_t; + typedef OpenMesh::VPropHandleT< cog_t > Property_cog; + +public: + + // construct with a given mesh + SmootherT(Mesh& _mesh) + : mesh_(_mesh) + { + mesh_.add_property( cog_ ); + } + + ~SmootherT() + { + mesh_.remove_property( cog_ ); + } + + // smooth mesh _iterations times + void smooth(unsigned int _iterations) + { + for (unsigned int i=0; i < _iterations; ++i) + { + std::for_each(mesh_.vertices_begin(), + mesh_.vertices_end(), + ComputeCOG(mesh_, cog_)); + + std::for_each(mesh_.vertices_begin(), + mesh_.vertices_end(), + SetCOG(mesh_, cog_)); + } + } + + +private: + + + //--- private classes --- + + class ComputeCOG + { + public: + ComputeCOG(Mesh& _mesh, Property_cog& _cog) + : mesh_(_mesh), cog_(_cog) + {} + + void operator()(typename Mesh::Vertex& _v) + { + typename Mesh::VertexHandle vh( mesh_.handle(_v) ); + typename Mesh::VertexVertexIter vv_it; + typename Mesh::Scalar valence(0.0); + + mesh_.property(cog_, vh) = typename Mesh::Point(0.0, 0.0, 0.0); + + for (vv_it=mesh_.vv_iter(vh); vv_it; ++vv_it) + { + mesh_.property(cog_, vh) += mesh_.point( vv_it ); + ++valence; + } + + mesh_.property(cog_, mesh_.handle(_v) ) /= valence; + } + + private: + Mesh& mesh_; + Property_cog& cog_; + }; + + + class SetCOG + { + public: + SetCOG(Mesh& _mesh, Property_cog& _cog) + : mesh_(_mesh), cog_(_cog) + {} + + void operator()(typename Mesh::Vertex& _v) + { + typename Mesh::VertexHandle vh(mesh_.handle(_v)); + + if (!mesh_.is_boundary(vh)) + mesh_.set_point( vh, mesh_.property(cog_, vh) ); + } + + private: + + Mesh& mesh_; + Property_cog& cog_; + }; + + + //--- private elements --- + + Mesh& mesh_; + Property_cog cog_; +}; + +#endif diff --git a/Doc/Tutorial/05-std_properties/ACGMakefile b/Doc/Tutorial/05-std_properties/ACGMakefile new file mode 100644 index 00000000..d1ff6370 --- /dev/null +++ b/Doc/Tutorial/05-std_properties/ACGMakefile @@ -0,0 +1,24 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +# subdirs to process +SUBDIRS = $(call find-subdirs) + +# programms (files containing main(), w/o suffix) +EXECS = $(call cxx-find-execs) + +# packages (qt, opengl, ...) +PACKAGES := + +# project DSOs +PROJ_LIBS := OpenMesh/Core + +# modules to use (cxx, c, moc, uic, yacc) ! order-dependent ! +MODULES := cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Doc/Tutorial/05-std_properties/properties.cc b/Doc/Tutorial/05-std_properties/properties.cc new file mode 100644 index 00000000..7fc05288 --- /dev/null +++ b/Doc/Tutorial/05-std_properties/properties.cc @@ -0,0 +1,71 @@ +#include +// -------------------- +#include +#include + + +typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh; + + +int main(int argc, char **argv) +{ + MyMesh mesh; + + if (argc!=2) + { + std::cerr << "Usage: " << argv[0] << " \n"; + return 1; + } + + // request vertex normals, so the mesh reader can use normal information + // if available + mesh.request_vertex_normals(); + + // assure we have vertex normals + if (!mesh.has_vertex_normals()) + { + std::cerr << "ERROR: Standard vertex property 'Normals' not available!\n"; + return 1; + } + + OpenMesh::IO::Options opt; + if ( ! OpenMesh::IO::read_mesh(mesh,argv[1], opt)) + { + std::cerr << "Error loading mesh from file " << argv[1] << std::endl; + return 1; + } + + // If the file did not provide vertex normals, then calculate them + if ( !opt.check( OpenMesh::IO::Options::VertexNormal ) ) + { + // we need face normals to update the vertex normals + mesh.request_face_normals(); + + // let the mesh update the normals + mesh.update_normals(); + + // dispose the face normals, as we don't need them anymore + mesh.release_face_normals(); + } + + // move all vertices one unit length along it's normal direction + for (MyMesh::VertexIter v_it = mesh.vertices_begin(); + v_it != mesh.vertices_end(); ++v_it) + { + std::cout << "Vertex #" << v_it << ": " << mesh.point( v_it ); + mesh.set_point( v_it, mesh.point(v_it)+mesh.normal(v_it) ); + std::cout << " moved to " << mesh.point( v_it ) << std::endl; + } + + // don't need the normals anymore? Remove them! + mesh.release_vertex_normals(); + + // just check if it really works + if (mesh.has_vertex_normals()) + { + std::cerr << "Ouch! ERROR! Shouldn't have any vertex normals anymore!\n"; + return 1; + } + + return 0; +} diff --git a/Doc/Tutorial/06-attributes/ACGMakefile b/Doc/Tutorial/06-attributes/ACGMakefile new file mode 100644 index 00000000..d1ff6370 --- /dev/null +++ b/Doc/Tutorial/06-attributes/ACGMakefile @@ -0,0 +1,24 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +# subdirs to process +SUBDIRS = $(call find-subdirs) + +# programms (files containing main(), w/o suffix) +EXECS = $(call cxx-find-execs) + +# packages (qt, opengl, ...) +PACKAGES := + +# project DSOs +PROJ_LIBS := OpenMesh/Core + +# modules to use (cxx, c, moc, uic, yacc) ! order-dependent ! +MODULES := cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Doc/Tutorial/06-attributes/attributes.cc b/Doc/Tutorial/06-attributes/attributes.cc new file mode 100644 index 00000000..8d446f72 --- /dev/null +++ b/Doc/Tutorial/06-attributes/attributes.cc @@ -0,0 +1,94 @@ +#include +#include +// -------------------- +#include + +#include +#include + +#ifndef DOXY_IGNORE_THIS + +// Define my personal traits +struct MyTraits : OpenMesh::DefaultTraits +{ + // Let Point and Normal be a vector of doubles + typedef OpenMesh::Vec3d Point; + typedef OpenMesh::Vec3d Normal; + + // Already defined in OpenMesh::DefaultTraits + // HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge ); + + // Uncomment next line to disable attribute PrevHalfedge + // HalfedgeAttributes( OpenMesh::Attributes::None ); + // + // or + // + // HalfedgeAttributes( 0 ); +}; + +#endif + +// Define my mesh with the new traits! +typedef OpenMesh::TriMesh_ArrayKernelT MyMesh; + +// ------------------------------------------------------------------ main ---- + +int main(int argc, char **argv) +{ + MyMesh mesh; + + if (argc!=2) + { + std::cerr << "Usage: " << argv[0] << " \n"; + return 1; + } + + // Just make sure that point element type is double + if ( typeid( OpenMesh::vector_traits::value_type ) + != typeid(double) ) + { + std::cerr << "Ouch! ERROR! Data type is wrong!\n"; + return 1; + } + + // Make sure that normal element type is double + if ( typeid( OpenMesh::vector_traits::value_type ) + != typeid(double) ) + { + std::cerr << "Ouch! ERROR! Data type is wrong!\n"; + return 1; + } + + // Add vertex normals as default property (ref. previous tutorial) + mesh.request_vertex_normals(); + + // Add face normals as default property + mesh.request_face_normals(); + + // load a mesh + OpenMesh::IO::Options opt; + if ( ! OpenMesh::IO::read_mesh(mesh,argv[1], opt)) + { + std::cerr << "Error loading mesh from file " << argv[1] << std::endl; + return 1; + } + + // If the file did not provide vertex normals, then calculate them + if ( !opt.check( OpenMesh::IO::Options::VertexNormal ) && + mesh.has_face_normals() && mesh.has_vertex_normals() ) + { + // let the mesh update the normals + mesh.update_normals(); + } + + // move all vertices one unit length along it's normal direction + for (MyMesh::VertexIter v_it = mesh.vertices_begin(); + v_it != mesh.vertices_end(); ++v_it) + { + std::cout << "Vertex #" << v_it << ": " << mesh.point( v_it ); + mesh.set_point( v_it, mesh.point(v_it)+mesh.normal(v_it) ); + std::cout << " moved to " << mesh.point( v_it ) << std::endl; + } + + return 0; +} diff --git a/Doc/Tutorial/07-traits/ACGMakefile b/Doc/Tutorial/07-traits/ACGMakefile new file mode 100644 index 00000000..d1ff6370 --- /dev/null +++ b/Doc/Tutorial/07-traits/ACGMakefile @@ -0,0 +1,24 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +# subdirs to process +SUBDIRS = $(call find-subdirs) + +# programms (files containing main(), w/o suffix) +EXECS = $(call cxx-find-execs) + +# packages (qt, opengl, ...) +PACKAGES := + +# project DSOs +PROJ_LIBS := OpenMesh/Core + +# modules to use (cxx, c, moc, uic, yacc) ! order-dependent ! +MODULES := cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Doc/Tutorial/07-traits/smooth.cc b/Doc/Tutorial/07-traits/smooth.cc new file mode 100644 index 00000000..4385b58c --- /dev/null +++ b/Doc/Tutorial/07-traits/smooth.cc @@ -0,0 +1,132 @@ +#include +#include +// -------------------- OpenMesh +#include +#include + + +#ifndef DOXY_IGNORE_THIS + +struct MyTraits : public OpenMesh::DefaultTraits +{ + // store barycenter of neighbors in this member + VertexTraits + { + private: + Point cog_; + public: + + VertexT() : cog_( Point(0.0f, 0.0f, 0.0f ) ) { } + + const Point& cog() const { return cog_; } + void set_cog(const Point& _p) { cog_ = _p; } + }; +}; + +#endif + +typedef OpenMesh::TriMesh_ArrayKernelT MyMesh; +typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh2; + +// --------------------------------------------------------------------------- +#define SIZEOF( entity,b ) \ + std::cout << _prefix << "size of " << #entity << ": " \ + << sizeof( entity ) << std::endl; \ + b += sizeof( entity ) + +template +void print_size(const std::string& _prefix = "") +{ + size_t total=0; + SIZEOF(Mesh::Vertex, total); + SIZEOF(Mesh::Halfedge, total); + SIZEOF(Mesh::Edge, total); + SIZEOF(Mesh::Face, total); + std::cout << _prefix << "total: " << total << std::endl; +} + +#undef SIZEOF +// --------------------------------------------------------------------------- + + +int main(int argc, char **argv) +{ + MyMesh mesh; + + // check command line options + if (argc < 4 || argc > 5) + { + std::cerr << "Usage: " << argv[0] << " [-s] #iterations infile outfile\n"; + exit(1); + } + + int idx=2; + + // display size of entities of the enhanced and the default mesh type + // when commandline option '-s' has been used. + if (argc == 5) + { + if (std::string("-s")==argv[idx-1]) + { + std::cout << "Enhanced mesh size statistics\n"; + print_size(" "); + + std::cout << "Default mesh size statistics\n"; + print_size(" "); + } + // else ignore! + ++idx; + } + + + // read mesh from stdin + std::cout<< " Input mesh: " << argv[idx] << std::endl; + if ( ! OpenMesh::IO::read_mesh(mesh, argv[idx]) ) + { + std::cerr << "Error: Cannot read mesh from " << argv[idx] << std::endl; + return 0; + } + + + + // smoothing mesh argv[1] times + MyMesh::VertexIter v_it, v_end(mesh.vertices_end()); + MyMesh::VertexVertexIter vv_it; + MyMesh::Point cog; + MyMesh::Scalar valence; + unsigned int i, N(atoi(argv[idx-1])); + + std::cout<< "Smooth mesh " << N << " times\n"; + + for (i=0; i < N; ++i) + { + for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it) + { + cog[0] = cog[1] = cog[2] = valence = 0.0; + + for (vv_it=mesh.vv_iter(v_it.handle()); vv_it; ++vv_it) + { + cog += mesh.point( vv_it.handle() ); + ++valence; + } + + v_it->set_cog(cog / valence); + } + + for (v_it=mesh.vertices_begin(); v_it!=v_end; ++v_it) + if (!mesh.is_boundary(v_it.handle())) + mesh.set_point( v_it.handle(), v_it->cog()); + } + + + // write mesh to stdout + std::cout<< "Output mesh: " << argv[idx+1] << std::endl; + + if ( ! OpenMesh::IO::write_mesh(mesh, argv[idx+1]) ) + { + std::cerr << "Error: cannot write mesh to " << argv[idx+1] << std::endl; + return 0; + } + return 1; +} + diff --git a/Doc/Tutorial/08-io_options/ACGMakefile b/Doc/Tutorial/08-io_options/ACGMakefile new file mode 100644 index 00000000..d1ff6370 --- /dev/null +++ b/Doc/Tutorial/08-io_options/ACGMakefile @@ -0,0 +1,24 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +# subdirs to process +SUBDIRS = $(call find-subdirs) + +# programms (files containing main(), w/o suffix) +EXECS = $(call cxx-find-execs) + +# packages (qt, opengl, ...) +PACKAGES := + +# project DSOs +PROJ_LIBS := OpenMesh/Core + +# modules to use (cxx, c, moc, uic, yacc) ! order-dependent ! +MODULES := cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Doc/Tutorial/08-io_options/io_options.cc b/Doc/Tutorial/08-io_options/io_options.cc new file mode 100644 index 00000000..b57b1725 --- /dev/null +++ b/Doc/Tutorial/08-io_options/io_options.cc @@ -0,0 +1,297 @@ +#include +#include +// -------------------- OpenMesh +#include +#include +#include + +// ---------------------------------------------------------------------------- + +using namespace OpenMesh; + +// ---------------------------------------------------------------------------- + +typedef TriMesh_ArrayKernelT<> MyMesh; + +// ---------------------------------------------------------------------------- + +#define CHKROPT( Option ) \ + std::cout << " provides " << #Option \ + << (ropt.check(IO::Options:: Option)?": yes\n":": no\n") + +#define CHKWOPT( Option ) \ + std::cout << " write " << #Option \ + << (wopt.check(IO::Options:: Option)?": yes\n":": no\n") + +#define MESHOPT( msg, tf ) \ + std::cout << " " << msg << ": " << ((tf)?"yes\n":"no\n") + +// ---------------------------------------------------------------------------- + +void parse_commandline( int _argc, char **_argv, MyMesh& _mesh, + IO::Options &ropt, IO::Options &wopt ); + +void usage_and_exit(int xcode); + +// ---------------------------------------------------------------------------- + +int main(int argc, char **argv) +{ + MyMesh mesh; + IO::Options ropt, wopt; + + // -------------------- evaluate commandline + + parse_commandline( argc, argv, mesh, ropt, wopt ); + + // -------------------- read mesh + + if ( ! IO::read_mesh(mesh,argv[optind], ropt)) + { + std::cerr << "Error loading mesh from file " << argv[optind] << std::endl; + return 1; + } + + // -------------------- show options + + std::cout << "File " << argv[optind] << std::endl; + + std::cout << " is binary: " + << (ropt.check(IO::Options::Binary) ? " yes\n" : " no\n"); + + std::cout << " byte order: "; + if (ropt.check(IO::Options::Swap)) + std::cout << "swapped\n"; + else if (ropt.check(IO::Options::LSB)) + std::cout << "little endian\n"; + else if (ropt.check(IO::Options::MSB)) + std::cout << "big endian\n"; + else + std::cout << "don't care\n"; + + std::cout << " provides VertexNormal" + << ( // strange layout for doxygen + ropt.check(IO::Options::VertexNormal) + ? ": yes\n":": no\n"); + CHKROPT( VertexColor ); + CHKROPT( VertexTexCoord ); + CHKROPT( FaceNormal ); + CHKROPT( FaceColor ); + + + // -------------------- mesh stats + + std::cout << "# Vertices: " << mesh.n_vertices() << std::endl; + std::cout << "# Edges : " << mesh.n_faces() << std::endl; + std::cout << "# Faces : " << mesh.n_faces() << std::endl; + + + // -------------------- show write options + + std::cout << "Selected write options:\n"; + std::cout << " use binary: " + << (wopt.check(IO::Options::Binary) ? " yes\n" : " no\n"); + + std::cout << " byte order: "; + if (wopt.check(IO::Options::Swap)) + std::cout << "swapped\n"; + else if (wopt.check(IO::Options::LSB)) + std::cout << "little endian\n"; + else if (wopt.check(IO::Options::MSB)) + std::cout << "big endian\n"; + else + std::cout << "don't care\n"; + + std::cout << " write VertexNormal" + << (wopt.check(IO::Options::VertexNormal) ? ": yes\n":": no\n"); + CHKWOPT( VertexColor ); + CHKWOPT( VertexTexCoord ); + CHKWOPT( FaceNormal ); + CHKWOPT( FaceColor ); + + // -------------------- show mesh capabilities + + std::cout << "Mesh supports\n"; + MESHOPT("vertex normals", mesh.has_vertex_normals()); + MESHOPT("vertex colors", mesh.has_vertex_colors()); + MESHOPT("texcoords", mesh.has_vertex_texcoords2D()); + MESHOPT("face normals", mesh.has_face_normals()); + MESHOPT("face colors", mesh.has_face_colors()); + + // -------------------- write mesh + + std::cout << "Write mesh to " << argv[optind+1] << ".."; + if ( !IO::write_mesh( mesh, argv[optind+1], wopt ) ) + { + std::cerr << "Error" << std::endl; + std::cerr << "Possible reasons:\n"; + std::cerr << "1. Chosen format cannot handle an option!\n"; + std::cerr << "2. Mesh does not provide necessary information!\n"; + std::cerr << "3. Or simply cannot open file for writing!\n"; + return 1; + } + else + std::cout << "Ok.\n"; + + return 0; +} + +// ---------------------------------------------------------------------------- + +void parse_commandline( int _argc, char **_argv, MyMesh& _mesh, + IO::Options &ropt, IO::Options &wopt ) +{ + int c; + while ((c=getopt(_argc, _argv, "bhsBF:LMSV:X:"))!=-1) + { + switch(c) + { + // -------------------- read options + + // force binary input + case 'b': + ropt += IO::Options::Binary; + break; + + // force swapping the byte order, when reading a binary file + case 's': + ropt += IO::Options::Swap; + break; + + // -------------------- write options + + // Write binary variant of format if possible + case 'B': + wopt += IO::Options::Binary; + break; + + // + case 'F': + for(size_t i=0; optarg[i]; ++i) + switch(optarg[i]) { + case 'n' : wopt += IO::Options::FaceNormal; break; + case 'c' : wopt += IO::Options::FaceColor; break; + } + break; + + // Use little endian when writing binary data + case 'L': + wopt += IO::Options::LSB; + break; + + // Use big endian when writing binary data + case 'M': + wopt += IO::Options::MSB; + break; + + // Swap byte order when writing binary data + case 'S': + wopt += IO::Options::Swap; + break; + + // + case 'V': + { + for(size_t i=0; optarg[i]; ++i) + switch(optarg[i]) { + case 'n' : // dont't change layout!! + wopt += IO::Options::VertexNormal; + break; + case 't' : wopt += IO::Options::VertexTexCoord; break; + case 'c' : wopt += IO::Options::VertexColor; break; + } + break; + } + + // -------------------- request mesh' standard properties + case 'X': + { + char entity='\0'; + for(size_t i=0; optarg[i]; ++i) + switch(optarg[i]) { + case 'v': + case 'f': entity = optarg[i]; break; + case 'n': + switch(entity) { + case 'v': _mesh.request_vertex_normals(); break; + case 'f': _mesh.request_face_normals(); break; + } + break; + case 'c': + switch(entity) { + case 'v': _mesh.request_vertex_colors(); break; + case 'f': _mesh.request_face_colors(); break; + } + break; + case 't': + switch(entity) { + case 'v': _mesh.request_vertex_texcoords2D(); break; + } + break; + } + break; + } + + // -------------------- help + case 'h': + usage_and_exit(0); + default: + usage_and_exit(1); + } + } + + if ( _argc-optind != 2) + usage_and_exit(1); +} + + +// ---------------------------------------------------------------------------- + +void usage_and_exit(int xcode) +{ + std::ostream &os = xcode ? std::cerr : std::cout; + + os << "Usage: io_options [Options] \n" + << std::endl; + os << " Read and write a mesh, using OpenMesh::IO::Options\n" + << std::endl; + os << "Options:\n" + << std::endl; + os << "a) read options\n" + << std::endl + << " -b\n" + << "\tAssume input file is a binary file\n" + << std::endl + << " -s\n" + << "\tSwap byte order when reading a binary file!\n" + << std::endl; + os << "b) write options\n" + << std::endl + << " -B\n" + << "\tWrite binary data\n" + << std::endl + << " -S\n" + << "\tSwap byte order, when writing binary data\n" + << std::endl + << " -M/-L\n" + << "\tUse MSB/LSB byte ordering, when writing binary data\n" + << std::endl + << " -V{n|t|c}\n" + << "\tWrite vertex normals, texcoords, and/or colors\n" + << std::endl + << " -F{n|c}\n" + << "\tWrite face normals, and/or colors\n" + << std::endl; + os << "c) Mesh properties\n" + << std::endl + << " -Xv{n|c|t}\n" + << "\tRequest vertex property normals|colors|texcoords\n" + << std::endl + << " -Xf{n|c}\n" + << "\tRequest face property normals|colors\n" + << std::endl; + exit(xcode); +} + +// end of file +// ============================================================================ diff --git a/Doc/Tutorial/09-persistence/ACGMakefile b/Doc/Tutorial/09-persistence/ACGMakefile new file mode 100644 index 00000000..d1ff6370 --- /dev/null +++ b/Doc/Tutorial/09-persistence/ACGMakefile @@ -0,0 +1,24 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +# subdirs to process +SUBDIRS = $(call find-subdirs) + +# programms (files containing main(), w/o suffix) +EXECS = $(call cxx-find-execs) + +# packages (qt, opengl, ...) +PACKAGES := + +# project DSOs +PROJ_LIBS := OpenMesh/Core + +# modules to use (cxx, c, moc, uic, yacc) ! order-dependent ! +MODULES := cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Doc/Tutorial/09-persistence/fill_props.hh b/Doc/Tutorial/09-persistence/fill_props.hh new file mode 100644 index 00000000..22c7bc5c --- /dev/null +++ b/Doc/Tutorial/09-persistence/fill_props.hh @@ -0,0 +1,123 @@ +#ifndef FILL_PROPS_HH +#define FILL_PROPS_HH + +#include +#include "int2roman.hh" + + +template +bool +fill_props( Mesh& _m, OpenMesh::VPropHandleT _ph, bool _check=false) +{ + float v; + static float a[9] = { 1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f, 7.7f, 8.8f, 9.9f }; + + for(typename Mesh::VertexIter it=_m.vertices_begin(); + it != _m.vertices_end(); ++it) + { + v = a[it.handle().idx()%9]; + if ( _check && !(_m.property( _ph, it ) == v) ) + return false; + else + _m.property( _ph, it ) = v; + } + return true; +} + + +template +bool +fill_props( Mesh& _m, OpenMesh::EPropHandleT _ph, bool _check=false ) +{ + size_t n; + bool v; + for( typename Mesh::EdgeIter it=_m.edges_begin(); + it != _m.edges_end(); ++it) + { + n = it.handle().idx(); + v = ((n&(n-1))==0); // true for 0,1,2,4,8,.. + + if (_check && _m.property( _ph, it ) != v) + { + std::cout << " eprop_bool: " << n << " -> " + << _m.property(_ph, it ) << " != " << v << std::endl; + return false; + } + else + { + _m.property( _ph, it ) = v; + std::cout << " eprop_bool: " << n << " -> " << v << std::endl; + } + } + return true; +} + + + +template +bool +fill_props(Mesh& _m, OpenMesh::FPropHandleT _ph, bool _check=false) +{ + int n; + for( typename Mesh::FaceIter it=_m.faces_begin(); + it != _m.faces_end(); ++it) + { + n = it.handle().idx(); + _m.property( _ph, it ) = int2roman(++n); + } + return true; +} + + +template +bool +fill_props( Mesh& _m, OpenMesh::HPropHandleT _ph, bool _check=false) +{ + int n; + T v; + static float a[9] = { 1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f, 7.7f, 8.8f, 9.9f }; + static float b[9] = { 2.2f, 3.3f, 4.4f, 5.5f, 6.6f, 7.7f, 8.8f, 9.9f, 1.1f }; + static float c[9] = { 3.3f, 4.4f, 5.5f, 6.6f, 7.7f, 8.8f, 9.9f, 1.1f, 2.2f }; + static float d[9] = { 4.4f, 5.5f, 6.6f, 7.7f, 8.8f, 9.9f, 1.1f, 2.2f, 3.3f }; + static double values[9] = { 0.1, 0.02, 0.003, 0.0004, 0.00005, 0.000006, + 0.0000007, 0.00000008, 0.000000009 }; + + for( typename Mesh::HalfedgeIter it=_m.halfedges_begin(); + it != _m.halfedges_end(); ++it) + { + n = it.handle().idx(); + + v = it.handle().idx()+1; // ival + v = values[n%9]; // dval + v = ((n&(n-1))==0); // bval + v.vec4fval[0] = a[n%9]; + v.vec4fval[1] = b[n%9]; + v.vec4fval[2] = c[n%9]; + v.vec4fval[3] = d[n%9]; + + if ( _check && _m.property( _ph, it ) != v ) + return false; + else + _m.property( _ph, it ) = v; + } + return true; +} + +template +bool +fill_props( Mesh& _m, OpenMesh::MPropHandleT _ph, bool _check=false) +{ + size_t idx; + for( typename Mesh::FaceIter it=_m.faces_begin(); it != _m.faces_end(); ++it) + { + idx = it.handle().idx(); + if ( _check && _m.property( _ph )[int2roman(idx+1)] != idx ) + return false; + else + _m.property( _ph )[int2roman(idx+1)] = idx; + } + return true; +} + + +#endif diff --git a/Doc/Tutorial/09-persistence/generate_cube.hh b/Doc/Tutorial/09-persistence/generate_cube.hh new file mode 100644 index 00000000..99f68ebb --- /dev/null +++ b/Doc/Tutorial/09-persistence/generate_cube.hh @@ -0,0 +1,70 @@ +#ifndef GENERATE_CUBE_HH +#define GENERATE_CUBE_HH + +template +size_t generate_cube( MeshType& mesh ) +{ + typedef typename MeshType::VertexHandle VertexHandle; + typedef typename MeshType::Point Point; + + typename MeshType::VertexHandle vhandle[8]; + + vhandle[0] = mesh.add_vertex(Point(-1, -1, 1)); + vhandle[1] = mesh.add_vertex(Point( 1, -1, 1)); + vhandle[2] = mesh.add_vertex(Point( 1, 1, 1)); + vhandle[3] = mesh.add_vertex(Point(-1, 1, 1)); + vhandle[4] = mesh.add_vertex(Point(-1, -1, -1)); + vhandle[5] = mesh.add_vertex(Point( 1, -1, -1)); + vhandle[6] = mesh.add_vertex(Point( 1, 1, -1)); + vhandle[7] = mesh.add_vertex(Point(-1, 1, -1)); + + // generate (quadrilateral) faces + + std::vector< VertexHandle > face_vhandles; + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[0]); + face_vhandles.push_back(vhandle[1]); + face_vhandles.push_back(vhandle[2]); + face_vhandles.push_back(vhandle[3]); + mesh.add_face(face_vhandles); + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[7]); + face_vhandles.push_back(vhandle[6]); + face_vhandles.push_back(vhandle[5]); + face_vhandles.push_back(vhandle[4]); + mesh.add_face(face_vhandles); + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[1]); + face_vhandles.push_back(vhandle[0]); + face_vhandles.push_back(vhandle[4]); + face_vhandles.push_back(vhandle[5]); + mesh.add_face(face_vhandles); + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[2]); + face_vhandles.push_back(vhandle[1]); + face_vhandles.push_back(vhandle[5]); + face_vhandles.push_back(vhandle[6]); + mesh.add_face(face_vhandles); + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[3]); + face_vhandles.push_back(vhandle[2]); + face_vhandles.push_back(vhandle[6]); + face_vhandles.push_back(vhandle[7]); + mesh.add_face(face_vhandles); + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[0]); + face_vhandles.push_back(vhandle[3]); + face_vhandles.push_back(vhandle[7]); + face_vhandles.push_back(vhandle[4]); + mesh.add_face(face_vhandles); + + return mesh.n_vertices(); +}; + +#endif diff --git a/Doc/Tutorial/09-persistence/int2roman.cc b/Doc/Tutorial/09-persistence/int2roman.cc new file mode 100644 index 00000000..b0cb5a19 --- /dev/null +++ b/Doc/Tutorial/09-persistence/int2roman.cc @@ -0,0 +1,45 @@ +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif +#include "int2roman.hh" + + +std::string int2roman( size_t decimal, size_t length ) +{ + assert( decimal > 0 && decimal < 1000 ); + + const size_t nrows = 4; + const size_t ncols = 4; + + static size_t table_arabs[ nrows ][ ncols ] = { { 1000, 1000, 1000, 1000 }, + { 900, 500, 400, 100 }, + { 90, 50, 40, 10 }, + { 9, 5, 4, 1 } }; + + static char *table_romans[ nrows ][ ncols ] = { { "M", "M", "M", "M" }, + { "CM", "D", "CD", "C" }, + { "XC", "L", "XL", "X" }, + { "IX", "V", "IV", "I" } }; + + size_t power; // power of ten + size_t index; // Indexes thru values to subtract + + std::string roman; + + roman.reserve(length); + + roman[ 0 ] = '\0'; + + for ( power = 0; power < nrows; power++ ) + for ( index = 0; index < ncols; index++ ) + while ( decimal >= table_arabs[ power ][ index ] ) + { + roman += table_romans[ power ][ index ]; + decimal -= table_arabs[ power ][ index ]; + } + + return roman; +} diff --git a/Doc/Tutorial/09-persistence/int2roman.hh b/Doc/Tutorial/09-persistence/int2roman.hh new file mode 100644 index 00000000..4d14a265 --- /dev/null +++ b/Doc/Tutorial/09-persistence/int2roman.hh @@ -0,0 +1,8 @@ +#ifndef INT2ROMAN_HH +#define INT2ROMAN_HH + +#include + +std::string int2roman( size_t decimal, size_t length=30 ); + +#endif diff --git a/Doc/Tutorial/09-persistence/persistence.cc b/Doc/Tutorial/09-persistence/persistence.cc new file mode 100644 index 00000000..54b25ff1 --- /dev/null +++ b/Doc/Tutorial/09-persistence/persistence.cc @@ -0,0 +1,347 @@ +#include +#include +#include +// -------------------- OpenMesh +#include +#include +#include +// -------------------- little helper +#include "generate_cube.hh" +#include "stats.hh" +#include "fill_props.hh" + +// ---------------------------------------------------------------------------- + +// Set to 1 to use an PolyMesh type. +#define UsePolyMesh 1 + +// ---------------------------------------------------------------------------- + +using namespace OpenMesh; + +// ---------------------------------------------------------------------------- + +typedef TriMesh_ArrayKernelT<> TriMesh; +typedef PolyMesh_ArrayKernelT<> PolyMesh; + +#if UsePolyMesh +typedef PolyMesh Mesh; +#else +typedef TriMesh Mesh; +#endif + +// ---------------------------------------------------------------------------- + +#ifndef DOXY_IGNORE_THIS + +struct MyData +{ + int ival; + double dval; + bool bval; + OpenMesh::Vec4f vec4fval; + + MyData() + : ival(0), dval(0.0), bval(false) + { } + + MyData( const MyData& _cpy ) + : ival(_cpy.ival), dval(_cpy.dval), bval(_cpy.bval), + vec4fval(_cpy.vec4fval) + { } + + + // ---------- assignment + + MyData& operator = (const MyData& _rhs) + { + ival = _rhs.ival; + dval = _rhs.dval; + bval = _rhs.bval; + vec4fval = _rhs.vec4fval; + return *this; + } + + MyData& operator = (int _rhs) { ival = _rhs; return *this; } + MyData& operator = (double _rhs) { dval = _rhs; return *this; } + MyData& operator = (bool _rhs) { bval = _rhs; return *this; } + MyData& operator = (const OpenMesh::Vec4f& _rhs) + { vec4fval = _rhs; return *this; } + + + // ---------- comparison + + bool operator == (const MyData& _rhs) const + { + return ival == _rhs.ival + && dval == _rhs.dval + && bval == _rhs.bval + && vec4fval == _rhs.vec4fval; + } + + bool operator != (const MyData& _rhs) const { return !(*this == _rhs); } + +}; + +#endif + + +// ---------------------------------------------------------------------------- + +typedef std::map< std::string, unsigned int > MyMap; + + +// ---------------------------------------------------------------------------- + +#ifndef DOXY_IGNORE_THIS + +namespace OpenMesh { + namespace IO { + + // support persistence for struct MyData + + template <> struct binary + { + typedef MyData value_type; + + static const bool is_streamable = true; + + // return binary size of the value + + static size_t size_of(void) + { + return sizeof(int)+sizeof(double)+sizeof(bool)+sizeof(OpenMesh::Vec4f); + } + + static size_t size_of(const value_type&) + { + return size_of(); + } + + static size_t store(std::ostream& _os, const value_type& _v, bool _swap=false) + { + size_t bytes; + bytes = IO::store( _os, _v.ival, _swap ); + bytes += IO::store( _os, _v.dval, _swap ); + bytes += IO::store( _os, _v.bval, _swap ); + bytes += IO::store( _os, _v.vec4fval, _swap ); + return _os.good() ? bytes : 0; + } + + static size_t restore( std::istream& _is, value_type& _v, bool _swap=false) + { + size_t bytes; + bytes = IO::restore( _is, _v.ival, _swap ); + bytes += IO::restore( _is, _v.dval, _swap ); + bytes += IO::restore( _is, _v.bval, _swap ); + bytes += IO::restore( _is, _v.vec4fval, _swap ); + return _is.good() ? bytes : 0; + } + }; + + + template <> struct binary< MyMap > + { + typedef MyMap value_type; + + static const bool is_streamable = true; + + // return generic binary size of self, if known + static size_t size_of(void) { return UnknownSize; } + + // return binary size of the value + static size_t size_of(const value_type& _v) + { + if (_v.empty()) + return sizeof(unsigned int); + + value_type::const_iterator it = _v.begin(); + unsigned int N = _v.size(); + size_t bytes = IO::size_of(N); + + for(;it!=_v.end(); ++it) + { + bytes += IO::size_of( it->first ); + bytes += IO::size_of( it->second ); + } + return bytes; + } + + static + size_t store(std::ostream& _os, const value_type& _v, bool _swap=false) + { + size_t bytes = 0; + unsigned int N = _v.size(); + + value_type::const_iterator it = _v.begin(); + + bytes += IO::store( _os, N, _swap ); + + for (; it != _v.end() && _os.good(); ++it) + { + bytes += IO::store( _os, it->first, _swap ); + bytes += IO::store( _os, it->second, _swap ); + } + return _os.good() ? bytes : 0; + } + + static + size_t restore( std::istream& _is, value_type& _v, bool _swap=false) + { + size_t bytes = 0; + unsigned int N = 0; + + _v.clear(); + + bytes += IO::restore( _is, N, _swap ); + + value_type::iterator it = _v.begin(); + std::string key; + size_t val; + + for (size_t i=0; i(mesh); + + + // should display 8 vertices, 18/12 edges, 12/6 faces (Tri/Poly) + mesh_stats(mesh); + + + // print out information about properties + mesh_property_stats(mesh); + + + std::cout << "Define some custom properties..\n"; + + OpenMesh::VPropHandleT vprop_float; + OpenMesh::EPropHandleT eprop_bool; + OpenMesh::FPropHandleT fprop_string; + OpenMesh::HPropHandleT hprop_mydata; + OpenMesh::MPropHandleT mprop_map; + + std::cout << ".. and registrate them at the mesh object.\n"; + + mesh.add_property(vprop_float, "vprop_float"); + mesh.add_property(eprop_bool, "eprop_bool"); + mesh.add_property(fprop_string, "fprop_string"); + mesh.add_property(hprop_mydata, "hprop_mydata"); + mesh.add_property(mprop_map, "mprop_map"); + + + mesh_property_stats(mesh); + + + std::cout << "Now let's fill the props..\n"; + + fill_props(mesh, vprop_float); + fill_props(mesh, eprop_bool); + fill_props(mesh, fprop_string); + fill_props(mesh, hprop_mydata); + fill_props(mesh, mprop_map); + + + std::cout << "Check props..\n"; +#define CHK_PROP( PH ) \ + std::cout << " " << #PH << " " \ + << (fill_props(mesh, PH, true)?"ok\n":"error\n") + + CHK_PROP(vprop_float); + CHK_PROP(eprop_bool); + CHK_PROP(fprop_string); + CHK_PROP(hprop_mydata); + CHK_PROP(mprop_map); +#undef CHK_PROP + + + std::cout << "Set persistent flag..\n"; +#define SET_PERS( PH ) \ + mesh.property(PH).set_persistent(true); \ + std::cout << " " << #PH << " " \ + << (mesh.property(PH).persistent()?"ok\n":"failed!\n") + + mesh.property(vprop_float).set_persistent(true); + std::cout << " vprop_float " + << (mesh.property(vprop_float).persistent()?"ok\n":"failed!\n"); + + SET_PERS( eprop_bool ); + SET_PERS( fprop_string ); + SET_PERS( hprop_mydata ); + mesh.mproperty(mprop_map).set_persistent(true); + std::cout << " mprop_map " + << (mesh.mproperty(mprop_map).persistent()?"ok\n":"failed!\n"); + + + std::cout << "Write mesh.."; + if (IO::write_mesh( mesh, "persistence-check.om" )) + std::cout << " ok\n"; + else + { + std::cout << " failed\n"; + return 1; + } + + + std::cout << "Clear mesh\n"; + mesh.clear(); + mesh_stats(mesh, " "); + + + std::cout << "Read back mesh.."; + try + { + if (IO::read_mesh( mesh, "persistence-check.om" )) + std::cout << " ok\n"; + else + { + std::cout << " failed!\n"; + return 1; + } + mesh_stats(mesh, " "); + } + catch( std::exception &x ) + { + std::cerr << x.what() << std::endl; + return 1; + } + + + std::cout << "Check props..\n"; +#define CHK_PROP( PH ) \ + std::cout << " " << #PH << " " \ + << (fill_props(mesh, PH, true)?"ok\n":"error\n") + CHK_PROP(vprop_float); + CHK_PROP(eprop_bool); + CHK_PROP(fprop_string); + CHK_PROP(hprop_mydata); + CHK_PROP(mprop_map); +#undef CHK_PROP + + return 0; +} + +// end of file +// ============================================================================ diff --git a/Doc/Tutorial/09-persistence/stats.hh b/Doc/Tutorial/09-persistence/stats.hh new file mode 100644 index 00000000..4ba082d2 --- /dev/null +++ b/Doc/Tutorial/09-persistence/stats.hh @@ -0,0 +1,20 @@ +#ifndef STATS_HH +#define STATS_HH + +template +void mesh_stats( Mesh& _m, const std::string& prefix = "" ) +{ + std::cout << prefix + << _m.n_vertices() << " vertices, " + << _m.n_edges() << " edges, " + << _m.n_faces() << " faces\n"; +} + +template +void mesh_property_stats(Mesh& _m) +{ + std::cout << "Current set of properties:\n"; + _m.property_stats(std::cout); +} + +#endif diff --git a/Doc/Tutorial/ACGMakefile b/Doc/Tutorial/ACGMakefile new file mode 100644 index 00000000..fa3f9465 --- /dev/null +++ b/Doc/Tutorial/ACGMakefile @@ -0,0 +1,17 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = $(call find-subdirs) + +PACKAGES := + +PROJ_LIBS := + +MODULES := cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Doc/decimater.docu b/Doc/decimater.docu new file mode 100644 index 00000000..52fc21a8 --- /dev/null +++ b/Doc/decimater.docu @@ -0,0 +1,89 @@ +//----------------------------------------------------------------------------- + +/** \page decimater_docu Mesh Decimation Framework + + The mesh decimation framework has 3 building blocks. + + -# \ref DecimaterAlg + -# \ref DecimaterMod + -# \ref DecimaterHnd + +\section DecimaterAlg The decimation algorithm + + The decimater (OpenMesh::Decimater::DecimaterT) provides the + decimation algorithm, while the decimation modules provide the + computational part. The modules compute a priority value due to some + error metric, which is used by the decimater to feed a priority + queue. The lower the error value, the more a potential collapse + moves to the front of the queue. The one with the lowest error will + always be the candidate for the next collapse. + + This implementation does a halfedge collapse, hence simply + collapsing one vertex into another connected by a halfedge. + + \note The decimater ignores all 'locked' and 'deleted' vertices (see + OpenMesh::Attributes::StatusBits) + + \attention The decimater sets temporarily the status bit 'tagged' and + clears it after usage regardless of a previous state. + +\section DecimaterMod Decimating Modules + + The vertex to be removed is determined by a decimation module, which has + to be derived from OpenMesh::Decimater::ModBaseT. The framework + supplies already a few decimation modules. But it's very easy to build + your own (\ref OpenMesh::Decimater::ModBaseT). The most important + function of a decimation module is + OpenMesh::Decimater::ModBaseT::collapse_priority(). It takes an + OpenMesh::Decimater::CollapseInfoT describing a potential halfedge + collapse, and returns a value due to some error metric. The error + value is used by the decimater to feed a priority queue. Collapses + with low error will be executed first, and those with large error + later. Of course a module computing the error quadric is provided + (OpenMesh::Decimater::ModQuadricT). + + This framework allows to use more than one decimation module with + some restrictions. Since the error value is always normalized and + sometimes very difficult to compare to other metrics, the framework + allows only one non-binary module, i.e. a module computing a float + value. Every further module must be a binary module, + i.e. collapse_prioerity() returns + OpenMesh::Decimater::ModBaseT::LEGAL_COLLAPSE or + OpenMesh::Decimater::ModBaseT::ILLEGAL_COLLAPSE. In the algorithm + the binary modules are evaluated first. If the evaluated collapse + passes the test, then the non-binary module contributes to the + decision step. + + In some cases the module does not contribute anything to the + decision engine of the decimater, but instead, e.g. simply collects + information, while the decimater does it's work. For instance the + module OpenMesh::Decimater::ModProgMeshT collects information from + all collapses that have been done. This information can be used to + generate progressive meshes as described in "Progressive meshes", + Hoppe, 1996. + + Provided decimation modules: + + - OpenMesh::Decimater::ModQuadricT + - OpenMesh::Decimater::ModRoundnessT + - OpenMesh::Decimater::ModNormalFlippingT + - OpenMesh::Decimater::ModIndependentSetsT + - OpenMesh::Decimater::ModProgMeshT + +\section DecimaterHnd Module Handles + + Similar to properties the modules are represented outside the + decimater by module handles. Before using the decimater a + non-binary module must be registrated with the decimater. + + See \ref DecimaterExa. + +\section DecimaterExa Basic Setup + + The following small example show the basic steps to setup up a + decimater: + +\include decimater.cc + +*/ + diff --git a/Doc/history.docu b/Doc/history.docu new file mode 100644 index 00000000..b1a5e3fd --- /dev/null +++ b/Doc/history.docu @@ -0,0 +1,509 @@ +/** \page history Version history + +\htmlonly + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
2.0 (2009/01/28) +
    +
  • Reader / writer have been updated
  • +
  • Some general bugfixes
  • +
  • Improved Documentation
  • +
  • Dropped support for acgmake which has been entirely replaced by qmake
  • +
+
1.9.7 (2008/10/13) +
    +
  • Ported applications to qt4
  • +
  • Bugfixes in Decimater
  • +
  • Improved Documentation
  • +
  • Dropped support for gcc 3.x compilers (This does not mean that it does not work anymore)
  • +
  • Dropped support for Versions of Visual Studio older than 2008
  • +
+
1.1.0 (2007/02/26) +
    +
  • Fixed a VS 2005 compilation issue regarding the Sqrt3 subdivision class.
  • +
  • Fixed GCC-4.1 compilation problems.
  • +
  • The STL writer routine now correctly closes the "solid" block with "endsolid".
  • +
  • The API of the vector class has been changed slightly due to problems with some versions of GCC:
    +The cast operator to the scalar type has been removed and replaced by +the function data(). Hence, existing code like +
    +Vec3f vertex;
    +...
    +glVertex3fv( vertex ); +
    +has to be changed to +
    +Vec3f vertex;
    +...
    +glVertex3fv( vertex.data() ); +
    +
  • +
+
1.0.0 (2005/09/20) +
    +
  • Mainly fixed the bugs collected in beta4.
  • +
  • Slightly changed module handling in the Decimater.
  • +
  • Removed some parts to keep the project maintainable.
  • +
  • Fixed MacOS compilation problems.
  • +
  • Compatibility for latest gcc4 compilers.
  • +
+
1.0.0-beta4 (2004/01/20) +
    +
  • Bugs fixed: 1.0.0-beta3:001
  • +
  • Documentation of module Core completed.
  • +
  • Documentation of module Tools::Decimater and + Tools::Subdivider completed.
  • +
  • Revised class structure for uniform subdivision.
  • +
  • Revised rule handling for composite adaptive subdivision.
  • +
+
1.0.0-beta3 (2003/12/04) +The beta3 fixes only the known bugs in beta2. +
    +
  • Bugs fixed: 1.0.0-beta2:{001, 002, 003, 004}
  • +
  • Known Bugs: +
      +
    • 001: OFFReader: Option bit not cleared before analyzing .off header. +
      Symptoms: If a previously read .off file had normals/texcoords, + a second read of another file w/o normals or texcoords, will return + with option bits normals/texcoords enabled. +
    • +
    +
  • +
+
1.0.0-beta2 (2003/11/05) + +
    + +
  • Change of directory structure +
    ++- %OpenMesh/
    +   +- Core/     # previously %OpenMesh
    +   +- Tools/    # previously OpenMeshTools
    +   +- Apps/     # previously OpenMeshApps
    +   +- Win/      # contains all solutions files and projects for MS VC++
    +   +- Doc/      # contains all documentation
    +    
    + Note! The supplied script \c %OpenMesh/migrate.sh can be used to + adjust include paths and ACGMakefiles. (It's not guarantied the + script handles every case, but so far it did not missed a file to + adjust.) +
  • + +
  • Porting issues: Due to a number of major changes in the + structure of %OpenMesh a few incompatibilities have been + introduced. Have look in \c %OpenMesh/porting.txt for hints how to + treat your source when updating from 0.11.x to + 1.0.0.
    Hint! The supplied script \c %OpenMesh/migrate.sh does a + few of the necessary modifications. +
  • + +
  • The list kernel has been removed +
  • + +
  • Improved IO support: +
      +
    • Read/write ascii and binary STL
    • +
    • Read/write ascii and binary OFF
    • +
    • Support for vertex normals and vertex texcoords in OFF and OBJ
    • +
    • Support importing diffuse material into face color property from + OBJ files. +
    • +
    • Properietary binary format OM, supporting read/write of custom properties +
    • +
    +
  • + +
  • Improved coordinate class OpenMesh::VectorT: +
      +
    • VectorT::vectorize(Scalar) is no longer static, now + it changes the vector. Use it e.g. to clear vector values. +
    • +
    • Casts between two vector classes of the same dimension are now + explicit. This avoids unwanted and expensive casts. +
    • +
    • Optimized performance by manual loop-unrolling. These optimizations + are partial specializations for vectors of dimension 2, 3 and 4. + Since Microsoft's VC++ still does not support partial specialization + and also provides rather poor loop-unrolling, users of this compiler + are stuck to lower performance. +
    • +
    +
  • + +
  • OpenSG Support: +
      +
    • New kernel type \c class TriMesh_OSGArrayKernelT<>. +
        +
      • Uses OpenSG geometry types!
      • +
      • PolyMesh not supported, yet!
      • +
      +
    • Use \c OpenMesh::Kernel_OSG::bind<> to link a mesh obj with an + \c osg::Geometry and vice versa.
      Please note that both objects + share the same data! +
        +
      • Binding a mesh to an \c osg::Geometry changes the content + of the \c osg::Geometry! +
      • Triangulates non-triangular faces!
      • +
      • Multi-indexed geometry not supported!
      • +
      • Transfer of vertex normals
      • +
      • Limited capability to transfer colors: + So far, only \c osg::Color3f <-> \c OpenMesh::Vec3ub +
      +
    • +
    +
  • + +
  • Microsoft VC++ 7.0 projects files +
      +
    • Tutorial solution file +
    +
  • + +
  • New tools/applications: +
      +
    • \c Tools/VDPM (View Dependent Progressive Mesh Library) +
        +
      • \c Apps/VDProgMesh/mkbalancedpm - Create a balanced + progressive mesh. +
      • +
      • \c Apps/VDProgMesh/Analyzer - Create a view dependent + progressive mesh file. +
      • +
      • \c Apps/VDProgMesh/Synthesizer - A viewer for the VDPM file.
      • +
      +
    • +
    • Apps/mconvert
    • +
    • Apps/IvViewer - added support for Coin
    • +
    +
  • + +
  • Known Bugs: + The following bugs are related to the TriMesh_OSGArrayKernelT<>: +
      +
    • 001: Cannot request/release the default attribute + halfedge_status. +
    • +
    • 002: Cannot release the default attribute vertex_texcoords +
    • +
    • 003: Assignment operator = () does not work properly.
    • +
    • 004: No copy-constructor available!
    • +
    +
  • + +
+
0.11.1 (2002/12/02) +
    + +
  • Bugs fixed: 0.11.0:{001, 002, 003, 004, 006}

    + 006: Use acgmake version 1.1.1. +
  • + +
  • Preprocessor warnings of gcc >= 3 fixed. +
  • + +
  • Added some more dynamic ways to append properties to items: + OpenMesh::Any and OpenMesh::PropertyT . +
  • + +
  • VectorT: standard operator less added, Vec4f is now + 16-bit aligned using gcc compiler (for later SIMD usage). +
  • + +
  • Use OM_STATIC_BUILD=1 when creating a static library. + The static version of the library needs to included IOInstances.hh, + which is done in that case. + When compiling with MS VC7, the define is set automatically, as + the DLL-Version is not supported yet. + acgmake (Version >= 1.1) set the define automatically when + using the flag for static compiling. +
  • + +
  • The read_mesh() methods now clears the mesh before reading a new one. +
  • + +
  • Added can_read() and can_write() methods to the IOManager. +
  • + + +
+
0.11.0 (2002/09/07) + +
    + +
  • Bugs fixed: 0.10.2:{001, 002, 003, 004, 005} +
  • + +
  • Added MS VC++ 7.0 project files for the tutorial programms. + (Have a look in /Win32/MSVC/) +
  • + +
  • New Input/Output management, see \ref mesh_io. The new interface + is as backwards-compatible as possible. Only the read_[off,obj] + and write_[off,obj] methods do no longer exist. You should now + include OpenMesh/IO/MeshIO.hh instead of MeshReader.hh and + MeshWriter.hh. The old include files may be removed in a future + release. +
  • + +
  • Added: Generic algorithms may now define their own traits, these traits can + be merged with other user-defined traits by the OM_Merge_Traits macro. + See tutorial \ref tutorial_06. +
  • + +
  • Added generic handle <-> item conversions, see +
      +
    • OpenMesh::Concepts::KernelT::handle() and +
    • OpenMesh::PolyMeshT::deref(). +
    + The kernel methods vertex_handle(), halfedge_handle(), edge_handle(), + face_handle() should no longer be used, but are still existent for + compatibility reasons. You can hide them by uncommenting the define + OM_HIDE_DEPRECATED in OpenMesh/System/config.h. +
  • + +
  • Internal methods, like Vertex::halfedge_handle() or Vertex::point() are + now hidden, since the respective kernel methods (like + MeshKernel::halfedge_handle(VertexHandle) or + MeshKernel::point(VertexHandle)) should be used instead. +
  • + +
  • Added convenience methods for the mesh kernels: +
      +
    • OpenMesh::Concepts::KernelT::n_halfedges() +
    • OpenMesh::Concepts::KernelT::halfedges_empty() +
    • OpenMesh::Concepts::KernelT::halfedge_handle(unsigned int _i) +
    +
  • + +
  • Known Bugs: +
      +
    • 001: Ambigous auto_ptr<> cast in ExporterT.hh.
    • +
    • 002: BaseImporter and BaseExporter have no virtual destructor.
    • +
    • 003: Reader does not work correctly, when reading from a istream.
    • +
    • 004: cross(VectorT, VectorT) returns Scalar instead of VectorT.
    • +
    • 005: PolyMeshT::calc_face_normal() may give wrong results if the + first 3 points of the polygon are colinear or concave.
    • +
    • 006: Reading/writing (MeshIO) of files does not work when using acgmake + with SuSE 8.1.
    • +
    +
  • + +
+
0.10.2 (2002/06/25) +
    +
  • Bugs fixed: 0.10.1:{001, 002} +
  • + +
  • The edge collapse checking method TriMeshT::is_collapse_ok() is now more + restrictive. It prohibits cases that could be handled by the + halfedge data structure, but would probably not be regarded as a + legal mesh. +
  • + +
  • The vertex split operation creates up to 3 new edges and 2 new + faces. Up to now it was possible to pass handles to edges/faces + that should be used instead of creating new ones. This option has + been removed in order to get a cleaner interface. +
  • + +
  • The MeshCheckerT has been changed slightly: it omits deleted elements, so + one does not have to perform a garbage collection before checking the mesh. + It also checks for the halfedges building cycles around faces or + boundaries. +
  • + +
  • Known Bugs: +
      +
    • 001: OpenMesh::PolyMeshT::operator=() does not return \c *this. +
    • 002: OpenMesh::DefaultAttributer added unnecessary 20 bits to the + elementary mesh types. +
    +
  • +
+
0.10.1 (2002/04/22) +
    +
  • Bugs fixed: 0.10.0:{001, 002, 003, 004, 005} +
  • + +
  • Added: Predefined attribute \c TexCoord. +
  • + +
  • Added: Support for MS VC++ 6.0 IDE with Intel Compiler. +
  • + +
  • Added: Tutorial 6 on generic algorithms. +
  • + +
  • SharedCoordArrayKernelT is now derived from ArrayKernelT. +
  • + +
  • Added: Assignment operator operator=() for PolyMeshT and TriMeshT. +
  • + +
  • Added: Method TriMeshT::is_collapse_ok(), checking topological conditions + for a given halfedge collapse. +
  • + +
  • Known Bugs: +
      +
    • 001: PolyMeshT::delete_face(): Outgoing halfedge handle of + a vertex can incorrectly be invalidated. Influences + vertex circulators, find_halfedge() and therefore + add_face().
      + Workaround: Replace v0 by v1 in line 585 of + PolyMeshT.cc +
    • +
    • 002: TriMeshT::collapse(): Some special cases are incorrectly + handled when collapsing boundary halfedges. The same + cases are also incorrect for the inverse operation + TriMeshT::vertex_split() operation. +
    • +
    +
  • +
+
0.10.0 (2002/03/19) +
    +
  • Interface for specifying the traits classes simplified (see + Traits.hh). +
  • + +
  • Changed attribute handling; the attributer class (the class that + adds and registers attributes to mesh items) can be provided by + the user. +
  • + +
  • Removed MyMesh::Face::n_vertices() and + MyMesh::Face::set_n_vertices(). +
  • + +
  • MeshWriter::write_* changed accordingly. +
  • + +
  • Bug fix: PolyMeshT::delete_[face,edge,vertex] now work correctly. +
  • + +
  • Removed cyclic dependency between items and kernel, because MS + VC++ cannot handle the resulting template forward declaration + :-(. Therefore the Base::Refs class, given for the traits + classes, no longer provides the types \c Vertex, \c Halfedge, \c + Edge, and \c Face. It now only provides all handle types, the + point and the scalar type. +
  • + +
  • Finally: MS VC++ 7.0 supported. +
  • + +
  • Known Bugs: +
      +
    • 001: TriMeshT.cc::vertex_split(): call to undefined + method Face::set_n_vertices().
      + Workaround: Comment out the two occurences of the call. +
    • +
    • 002: Missing \#include + + in OpenMesh/Mesh/Types/PolyMesh_ListKernelT.hh. +
    • +
    • 003: Special case in TriMeshT::edge_collapse(): when collapsing a + boundary vertex into an interior one, the outgoing halfedge of + the resulting vertex my not be a boundary one. +
    • +
    • 004: PolyMeshT::delete_edge did not pass its argument + _delete_isolated_vertices to PolyMeshT::delete_face. +
    • +
    • 005: PolyMeshT::assign() was not linked because of an \#if error. +
    +
  • +
+
0.9.2 (-) +
    +
  • PolyMeshT::add_face() now detects more topological errors. +
  • + +
  • Added mesh kernel methods: remove_last_[vertex,edge,face](). +
  • + +
+
0.9.1 (2002/02/07) +
    +
  • Changed the main namespace from ACG to OpenMesh. +
  • + +
  • Added invalid handle constants, e.g. PolyMeshT::InvalidVertexHandle. +
  • + +
  • Mesh provides circulators: PolyMeshT::vv_iter(VertexHandle). +
  • +
+
0.9 (2002/01/25) +
    +
  • initial release
  • +
+
+ +\endhtmlonly + +**/ diff --git a/Doc/html/acg_footer.html b/Doc/html/acg_footer.html new file mode 100644 index 00000000..b6cd7001 --- /dev/null +++ b/Doc/html/acg_footer.html @@ -0,0 +1,16 @@ +
+
+ + +acg pic + +Project $projectname, +©  Computer Graphics Group, RWTH Aachen. +Documentation generated using + +doxygen +. + +
+ + diff --git a/Doc/html/acg_header.html b/Doc/html/acg_header.html new file mode 100644 index 00000000..751e8ae5 --- /dev/null +++ b/Doc/html/acg_header.html @@ -0,0 +1,7 @@ + + + $title + + + + diff --git a/Doc/html/acg_icon.gif b/Doc/html/acg_icon.gif new file mode 100644 index 00000000..292610be Binary files /dev/null and b/Doc/html/acg_icon.gif differ diff --git a/Doc/html/acg_style.css b/Doc/html/acg_style.css new file mode 100644 index 00000000..c0706400 --- /dev/null +++ b/Doc/html/acg_style.css @@ -0,0 +1,367 @@ +BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { + font-family: Geneva, Arial, Helvetica, sans-serif; +} +BODY,TD { + font-size: 90%; +} +H1 { + text-align: center; + font-size: 160%; +} +H2 { + font-size: 120%; +} +H3 { + font-size: 100%; +} +CAPTION { font-weight: bold } +DIV.qindex { + width: 100%; + background-color: #375b3f; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +DIV.nav { + width: 100%; + background-color: #375b3f; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +DIV.navtab { + background-color: #375b3f; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +TD.navtab { + font-size: 70%; +} +A.qindex { + text-decoration: none; + font-weight: bold; + color: #f07030; +} +A.qindex:visited { + text-decoration: none; + font-weight: bold; + color: #f07030 +} +A.qindex:hover { + text-decoration: none; + background-color: #ddddff; +} +A.qindexHL { + text-decoration: none; + font-weight: bold; + background-color: #6666cc; + color: #ffffff; + border: 1px double #9295C2; +} +A.qindexHL:hover { + text-decoration: none; + background-color: #6666cc; + color: #ffffff; +} +A.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff } +A.el { text-decoration: none; font-weight: bold } +A.elRef { font-weight: bold } +A.code:link { text-decoration: none; font-weight: normal; color: #0000FF} +A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF} +A.codeRef:link { font-weight: normal; color: #0000FF} +A.codeRef:visited { font-weight: normal; color: #0000FF} +A.el:hover { text-decoration: none; color: #e0e0d0} +DL.el { margin-left: -1cm } +.fragment { + font-family: monospace, fixed; + font-size: 95%; +} +PRE.fragment { + color: black; + border: 1px solid #29442F; + background-color: #f5f5f5; + margin-top: 4px; + margin-bottom: 4px; + margin-left: 2px; + margin-right: 8px; + padding-left: 6px; + padding-right: 6px; + padding-top: 4px; + padding-bottom: 4px; +} +DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } + +DIV.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold; +} +DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% } +BODY { + background: #003010; + color: #e0e0d0; + margin-right: 20px; + margin-left: 20px; +} +TD.indexkey { + background-color: #375b3f; + font-weight: bold; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #29442F; +} +TD.indexvalue { + background-color: #375b3f; + font-style: italic; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #29442F; +} +TR.memlist { + background-color: #f0f0f0; +} +P.formulaDsp { text-align: center; } +IMG.formulaDsp { } +IMG.formulaInl { vertical-align: middle; } +/*SPAN.keyword { color: #008000 } +SPAN.keywordtype { color: #604020 } +SPAN.keywordflow { color: #e08000 } +SPAN.comment { color: #800000 } +SPAN.preprocessor { color: #806020 } +SPAN.stringliteral { color: #002080 } +SPAN.charliteral { color: #008080 }*/ +SPAN.keyword { color: #008000 } +SPAN.keywordtype { color: #604020 } +SPAN.keywordflow { color: #e08000 } +SPAN.comment { color: #800000 } +SPAN.preprocessor { color: #806020 } +SPAN.stringliteral { color: #002080 } +SPAN.charliteral { color: #008080 } + +.mdescLeft { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #375B3F; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.mdescRight { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #375B3F; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.memItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #375B3F; + font-size: 80%; +} +.memItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #375B3F; + font-size: 80%; +} +.memTemplItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #375B3F; + font-size: 80%; +} +.memTemplItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #375B3F; + font-size: 80%; +} +.memTemplParams { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + color: #606060; + background-color: #375B3F; + font-size: 80%; +} +.search { color: #003399; + font-weight: bold; +} +FORM.search { + margin-bottom: 0px; + margin-top: 0px; +} +INPUT.search { font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #375b3f; +} +TD.tiny { font-size: 75%; +} +a { + color: #f07030; +} +a:visited { + color: #f07030; +} +.dirtab { padding: 4px; + border-collapse: collapse; + border: 1px solid #84b0c7; +} +TH.dirtab { background: #375b3f; + font-weight: bold; +} +HR { height: 1px; + border: none; + border-top: 1px solid #e0e0d0; +} + +/* Style for detailed member documentation */ +.memtemplate { + font-size: 80%; + color: #e0e0d0; + font-weight: normal; +} +.memnav { + background-color: #375b3f; /*375b3f;*/ + border: 1px solid #29442f; /*84b0c7;*/ + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +.memitem { + padding: 4px; + background-color: #003010; /*eef3f5;*/ +/* border-width: 1px; */ +/* border-style: solid; */ +/* border-color: #dedeee;*/ + -moz-border-radius: 8px 8px 8px 8px; +} +.memname { + white-space: nowrap; + font-weight: bold; +} +.memdoc{ + padding-left: 10px; +} +.memproto { + background-color: #375b3f; /*#d5e1e8;*/ + width: 100%; + border-width: 1px; + border-style: solid; + border-color: #29442f; /*#84b0c7;*/ + font-weight: bold; + -moz-border-radius: 8px 8px 8px 8px; +} +.paramkey { + text-align: right; +} +.paramtype { + white-space: nowrap; +} +.paramname { + color: #db4949; /*602020;*/ + font-style: italic; + white-space: nowrap; +} +/* End Styling for detailed member documentation */ + +/* for the tree view */ +.ftvtree { + font-family: sans-serif; + margin:0.5em; +} +.directory { font-size: 9pt; font-weight: bold; } +.directory h3 { margin: 0px; margin-top: 1em; font-size: 11pt; } +.directory > h3 { margin-top: 0; } +.directory p { margin: 0px; white-space: nowrap; } +.directory div { display: none; margin: 0px; } +.directory img { vertical-align: -30%; } diff --git a/Doc/html/acg_tab_b.gif b/Doc/html/acg_tab_b.gif new file mode 100644 index 00000000..ffb44ea1 Binary files /dev/null and b/Doc/html/acg_tab_b.gif differ diff --git a/Doc/html/acg_tab_l.gif b/Doc/html/acg_tab_l.gif new file mode 100644 index 00000000..494a6b89 Binary files /dev/null and b/Doc/html/acg_tab_l.gif differ diff --git a/Doc/html/acg_tab_r.gif b/Doc/html/acg_tab_r.gif new file mode 100644 index 00000000..43770ac3 Binary files /dev/null and b/Doc/html/acg_tab_r.gif differ diff --git a/Doc/html/acg_tabs.css b/Doc/html/acg_tabs.css new file mode 100644 index 00000000..643d7c8e --- /dev/null +++ b/Doc/html/acg_tabs.css @@ -0,0 +1,107 @@ +/* tabs styles, based on http://www.alistapart.com/articles/slidingdoors */ + +DIV.tabs +{ + float : left; + width : 100%; + background : url("acg_tab_b.gif") repeat-x bottom; + margin-bottom : 4px; +} + +DIV.tabs UL +{ + margin : 0px; + padding-left : 10px; + list-style : none; +} + +DIV.tabs LI, DIV.tabs FORM +{ + display : inline; + margin : 0px; + padding : 0px; +} + +DIV.tabs FORM +{ + float : right; +} + +DIV.tabs A +{ + float : left; + background : url("acg_tab_r.gif") no-repeat right top; + border-bottom : 1px solid #e0e0d0; + font-size : x-small; + font-weight : bold; + text-decoration : none; +} + +DIV.tabs A:hover +{ + background-position: 100% -150px; +} + +DIV.tabs A:link, DIV.tabs A:visited +{ + color: #f07030; +} + +DIV.tabs A:hover, +DIV.tabs A:active +{ + color: #e0e0d0 +} + +DIV.tabs SPAN +{ + float : left; + display : block; + background : url("acg_tab_l.gif") no-repeat left top; + padding : 5px 9px; + white-space : nowrap; +} + +DIV.tabs INPUT +{ + float : right; + display : inline; + font-size : 1em; +} + +DIV.tabs TD +{ + font-size : x-small; + font-weight : bold; + text-decoration : none; +} + + + +/* Commented Backslash Hack hides rule from IE5-Mac \*/ +DIV.tabs SPAN {float : none;} +/* End IE5-Mac hack */ + +DIV.tabs A:hover SPAN +{ + background-position: 0% -150px; +} + +DIV.tabs LI#current A +{ + background-position: 100% -150px; + border-width : 0px; +} + +DIV.tabs LI#current SPAN +{ + background-position: 0% -150px; + padding-bottom : 6px; +} + +DIV.nav +{ + background : none; + border : none; + border-bottom : 1px solid #e0e0d0; +} diff --git a/Doc/images/class-hierarchy.png b/Doc/images/class-hierarchy.png new file mode 100644 index 00000000..f128fa69 Binary files /dev/null and b/Doc/images/class-hierarchy.png differ diff --git a/Doc/images/class-hierarchy2.png b/Doc/images/class-hierarchy2.png new file mode 100644 index 00000000..d0841118 Binary files /dev/null and b/Doc/images/class-hierarchy2.png differ diff --git a/Doc/images/collapse_info.png b/Doc/images/collapse_info.png new file mode 100644 index 00000000..8963f6f9 Binary files /dev/null and b/Doc/images/collapse_info.png differ diff --git a/Doc/images/diagrams.sxi b/Doc/images/diagrams.sxi new file mode 100644 index 00000000..e37e675f Binary files /dev/null and b/Doc/images/diagrams.sxi differ diff --git a/Doc/images/halfedge_structure.gif b/Doc/images/halfedge_structure.gif new file mode 100644 index 00000000..a53f39e5 Binary files /dev/null and b/Doc/images/halfedge_structure.gif differ diff --git a/Doc/images/halfedge_structure2.png b/Doc/images/halfedge_structure2.png new file mode 100644 index 00000000..a91e7278 Binary files /dev/null and b/Doc/images/halfedge_structure2.png differ diff --git a/Doc/images/halfedge_structure3.png b/Doc/images/halfedge_structure3.png new file mode 100644 index 00000000..c4d6299d Binary files /dev/null and b/Doc/images/halfedge_structure3.png differ diff --git a/Doc/images/inheritance-simple.png b/Doc/images/inheritance-simple.png new file mode 100644 index 00000000..1bf62963 Binary files /dev/null and b/Doc/images/inheritance-simple.png differ diff --git a/Doc/images/inheritance-simple.scaled.png b/Doc/images/inheritance-simple.scaled.png new file mode 100644 index 00000000..741177b6 Binary files /dev/null and b/Doc/images/inheritance-simple.scaled.png differ diff --git a/Doc/images/inheritance.fig b/Doc/images/inheritance.fig new file mode 100644 index 00000000..ccbfe7ec --- /dev/null +++ b/Doc/images/inheritance.fig @@ -0,0 +1,24 @@ +#FIG 3.2 +Landscape +Center +Inches +Letter +100.00 +Single +-2 +1200 2 +2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 2.00 120.00 240.00 + 2550 3900 2550 3300 +2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 2.00 120.00 240.00 + 2550 2700 2550 2100 +2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 1500 1500 3600 1500 3600 2100 1500 2100 1500 1500 +2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 1500 2700 3600 2700 3600 3300 1500 3300 1500 2700 +2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 1500 3900 3600 3900 3600 4500 1500 4500 1500 3900 +4 1 0 50 0 0 25 0.0000 4 255 990 2475 1950 Kernel\001 +4 1 0 50 0 0 25 0.0000 4 345 1500 2550 3150 PolyMesh\001 +4 1 0 50 0 0 25 0.0000 4 255 1290 2550 4350 TriMesh\001 diff --git a/Doc/images/inheritance.gif b/Doc/images/inheritance.gif new file mode 100644 index 00000000..de184c49 Binary files /dev/null and b/Doc/images/inheritance.gif differ diff --git a/Doc/images/iomanager.gif b/Doc/images/iomanager.gif new file mode 100644 index 00000000..2512a84b Binary files /dev/null and b/Doc/images/iomanager.gif differ diff --git a/Doc/images/om-format.png b/Doc/images/om-format.png new file mode 100644 index 00000000..b813f253 Binary files /dev/null and b/Doc/images/om-format.png differ diff --git a/Doc/mainpage.docu b/Doc/mainpage.docu new file mode 100644 index 00000000..e72e7870 --- /dev/null +++ b/Doc/mainpage.docu @@ -0,0 +1,10 @@ +/** \mainpage OpenMesh Documentation + +\li \ref compiling +\li \ref naming_conventions +\li \ref tutorial +\li \ref history +\li \ref mesh_docu +\li \ref tools_docu + +**/ diff --git a/Doc/mesh.docu b/Doc/mesh.docu new file mode 100644 index 00000000..dee0391f --- /dev/null +++ b/Doc/mesh.docu @@ -0,0 +1,877 @@ +//----------------------------------------------------------------------------- + + +/** \page mesh_docu OpenMesh Documentation + +We provided a short overview over the functionality of the %OpenMesh +library and some additional concepts in \ref tutorial, and +will now explain the most important topics of %OpenMesh in more +detail. + +-# \ref mesh_first_to_read +-# \ref mesh_features +-# \ref mesh_cpp +-# \ref mesh_hds +-# \ref mesh_type +-# \ref mesh_hierarchy +-# \ref mesh_members +-# \ref mesh_io +-# \ref mesh_iterators + +*/ + + +//----------------------------------------------------------------------------- + + +/** \page mesh_first_to_read Read me first!!! + +Please note, that %OpenMesh makes heavily use of C++ templates, +generic programming and all that stuff (see \ref mesh_cpp). Therefore +read this section carefully (else you get lost in the reference +manual): + +

There is no such thing like the %OpenMesh class

+ +The library provides a set of classes ( 99% templates ;-) ), where the +inheritance relationship is given by template parameterization. You +might ask: "What the heck is that?" It means, a parent class is passed +as a template argument to another class: + +\code + +class P1 { } +class P2 { } +template class B : public Parent {} + +typedef B fooB1; +typedef B fooB2; + +\endcode + +Voila, we have created two different types of B. Depending on the +interface, the public member elements, provided by \c P1 or \c P2, \c +fooB1 and \c fooB2 might have different behaviours or even different +interfaces! But if \c P1 and \c P2 have the some interface or at least +a common interface, then from programming point of view there is no +difference using \c fooB1 or \c fooB2. And this is all +about. %OpenMesh defines an interface concept for the kernel which is +documented in \ref OpenMesh::Concepts::KernelT. As long as the kernel +provides this the class handling polygonal meshes \c +OpenMesh::PolyMeshT can use any kernel. + +

Therefore documentation resides in two spaces

+ +-# Associated with the class/struct (as usual) +-# In a concept class in cases like the example code above. Hence, if you want + to know what a mesh type has to offer refer to OpenMesh::Concepts::KernelT, + OpenMesh::PolyMeshT, OpenMesh::TriMeshT. + + */ + +//----------------------------------------------------------------------------- + + +/** \page mesh_features Features and Goals + +The main features of the underlying data structure are: + +\li No restriction to triangles meshes, handle general polygonal meshes. +\li Explicit representation of vertices, halfedges, edges, and faces. +\li Efficient access to the one-ring neighborhood of a vertex. +\li Ability to handle non-manifold vertices (like two faces meeting in only + one vertex). + + +The goals/features of the C++ implementation are: + +
    +
  • Flexibility: +
      +
    • Choose suitable types for scalars and coordinates (e.g. float, + double, exact arithmetic and two-, three-, or n-dimensional + points). +
    • Enhance each item type by your own attributes/properties, like + e.g. adding a normal vector or a \c FaceHandle to class \c + Vertex. +
    +
  • Efficiency: +
      +
    • Avoid the overhead of virtual inheritance and virtual function calls. +
    • Resolve as many type/attribute dependencies as possible at + compile-time instead of testing for attributes at run-time + (e.g. normal vectors for faces). +
    +
  • Type-safety for handles, no type-casting (*): Vertices, + (Half-)Edges, Faces know each other and their corresponding + handles. + + (*) Since version 0.10.0 the Microsoft VisualC++ compiler is + supported. Due to the compilers inaptitude to process forwards on template + functions correctly, the type-safety had to be given up to some extend. + Though under the hood void pointers are used, the casting is done + within the mesh, and the user transparently uses his handles as before.
    + As soon as the compiler adheres to the C++ standard the type-safe version + will be restored. +
+*/ + + +//----------------------------------------------------------------------------- + + +/** \page mesh_cpp Some words on the C++ implementation + +If one takes a look at the goals and features section it soon becomes +obvious that these goals cannot be achieved using trivial C++ features +only. We make heavy use of templates, (partial) template specialization, +generative and generic programming, and the STL. This may be a challenge +for you as well as for your compiler, as these are quite late features +of the C++ language. + +While knowledge of generative programming is only necessary if you +want to create your own mesh kernels or extend iterators or similar +types, you will \b NOT need it for simply using these things. +Nevertheless working knowledge of C++ and basic knowlege of templates +is required. To get into this stuff we recommend the following +books: + +\li Bjarne Stroustrup, The C++ Programming Language , + +\li Matthew H. Austern, Generic Programming and the STL: Using + and Extending the C++ Standard Template Library , + +\li Andrei Alexandrescu, Modern C++ Design: Generic Programming + and Design Patterns Applied , + +\li Krzysztof Czarnecki, Ulrich Eisenecker, Generative Programming: + Methods, Tools, and Applications . + +*/ + + +//----------------------------------------------------------------------------- + + +/** \page mesh_hds The Halfedge Data Structure + +This section describes the underlying data structure that is used to +store the mesh entities (items) vertices, edges, faces, and their +connectivity information. There are many popular data structures used +to represent polygonal meshes. For a detailed comparison of them refer +to the papers at the end of this section. + +The data structure used in this project is the so called halfedge +data structure . While face-based structures store +their connectivity in faces referencing their vertices and neighbors, + edge-based structures put the connectivity information into +the edges. Each edge references its two vertices, the faces it belongs +to and the two next edges in these faces. If one now splits the edges +(i.e. an edge connecting vertex \c A and vertex \c B becomes two +directed halfeges from \c A to \c B and vice versa) one gets a + halfedge-based data structure. The following figure +illustrates the way connectivity is stored in this structure: + + + + + +
\image html halfedge_structure3.png + +
    +
  • Each \b vertex references one outgoing halfedge, i.e. a halfedge that + starts at this vertex (1). +
  • Each \b face references one of the halfedges bounding it (2). +
  • Each \b halfedge provides a handle to +
      +
    • the vertex it points to (3), +
    • the face it belongs to (4) +
    • the next halfedge inside the face (ordered counter-clockwise) (5), +
    • the opposite halfedge (6), +
    • (optionally: the previous halfedge in the face (7)). +
    +
+
+ +Having these links between the items, it is now possible to circulate +around a face in order to enumerate all its vertices, halgedges, or +neighboring faces. When starting at a vertex' halfedge and iterating +to the opposite of its previous one, one can easily circulate around +this vertex and get all its one-ring neighbors, the incoming/outgoing +halfedges, or the adjacent faces. All this functionality is +encapsulated into the so-called circulators , described in +\ref mesh_iterators. + +\attention In order to efficiently classify a boundary +vertex, the outgoing halfedge of these vertices must be a boundary +halfedge (see OpenMesh::PolyMeshT::is_boundary()). +\attention Whenever you modify the +topology using low-level topology changing functions, be sure to +guarantee this behaviour (see +OpenMesh::PolyMeshT::adjust_outgoing_halfedge()) + +While one does not need to store the previous halfedge (7) explicitly, +because it can be derived from the links to the next halfedges, one +may do so for the sake of performance. In fact, the previous halfedge +is stored by default (OpenMesh::DefaultTraits). Using traits and +attributes the previous halfedge can removed, to gain memory. This +kind of mesh customization is explained in \ref mesh_type. + +While the halfedge-based structures usually consume more memory than +their face-based counter-parts they have the following important +advantages: + +\li It is easy to mix faces of arbitrary vertex count in one mesh. + +\li We now have an explicit representation of vertices, faces, \em and + edges/halfedges. This becomes extremely useful if one has to store data + per edge/halfedge since this can easily be modelled by member + variables of these types (see \ref mesh_type). + +\li Circulating around a vertex in order to get its one-ring neighbors is an + important operation for many kinds of algorithms on polygonal meshes. + For face-based structures this leads to many if-then branchings, + the halfedge structure provides this funcionality without + conditional branching in constant time. + + +References + +S. Campagna, L. Kobbelt, H.-P. Seidel, Directed Edges - A +Scalable Representation For Triangle Meshes , ACM Journal of +Graphics Tools 3 (4), 1998. + +Lutz Kettner, Using Generic Programming for Designing a Data +Structure for Polyhedral Surfaces, in Proc. 14th Annual ACM +Symp. on Computational Geometry, 1998. + +*/ + + + +//----------------------------------------------------------------------------- + + +/** \page mesh_hierarchy Conceptual Class Hierarchy + +Since there is no such thing as a %OpenMesh class and the library +makes heavy use of C++ template, we show the inheritance graph of +OpenMesh::TriMesh_ArrayKernelT as proxy for all possible mesh types. + +Please note! Most of the inheritence relationships are realized by +template parameterization! Therefore some of the inheritance links are +not documented in a inheritance graph in the reference. This picture +shows the overall concept. + +\image html class-hierarchy2.png + +\subsection ch_kernel Building the kernel + +-# The BaseKernel defines the basic operations on properties like +add/remove/access. +-# Next the AttribKernelT adds the standard properties all associated +methods. +-# Finally the ArrayKernelT provides the methods to add/remove/access +the mesh items vertices, (half-)edges, and faces. The base class is passed +as a template parameter, since depending on the underlying storage type the +AttribKernel might change. + +\subsection ch_complete Building the mesh + +-# The PolyMeshT inherits from the kernel and provide all necessary methods +to work with polygonal meshes. +-# Finally we derive TriMeshT from PolyMeshT to have an specialization for +triangle meshes. + +Looks simple, but it isn't - it's a bit more complicated: + +\include build-trimesh.cc + +To generate the actual mesh type the helper template class \c +TriMesh_ArrayKernel_GeneratorT is used. It takes the traits in a +template argument and passes it to \c FinalMeshItemsT to get the final +type of the mesh items (MeshItems). The \c MeshItems defines the +types for Point, Normal, Color, TexCoord, Vertex, and for all mesh +items. With the help of \c MeshItems create the type of the \c +AttribKernel, which defines the apropriate standard properties for the +items. Finally use \c AttribKernel and \c MeshItems to create the +mesh kernel type \c MeshKernel. It's quite a way to get a kernel . As +long as the created kernel follows the kernel concept (\ref +mesh_kernels_group), we can easily create now the mesh. Here we +use now \c TriMeshT to create the final mesh type \c Mesh. + + */ + +//----------------------------------------------------------------------------- + + +/** \page mesh_type Specifying your MyMesh + +This section will show how to build your own custom tailored type \c +MyMesh. As we have seen in the section on goals and features there are +some parameters to be specified for a mesh. This is done in the +following four steps: + +
    + +
  1. Choose between triangle mesh and general polygonal mesh. + +
  2. Select the mesh kernel + +
  3. Parameterize the mesh by a so-called \em Traits class. You can +add arbitrary classes to the mesh items, specify the types \c Scalar, +\c Point, \c Normal and \c Color, and use predefined attributes like +\c Attributes::Normal and \c Attributes::Color. + +
  4. Dynamically bind data to the mesh or the mesh entities (vertex, +(half-)edge, face) using \em custom \em properties. + +
+ +We will explain these four parameterization steps and give a code +example at the end of this page. + +

+ +\section sec_select_face_type Polygonal or Triangle Mesh? + +This decision is quite simple: Whenever possible choose the triangle +mesh. The restriction to triangular faces usually leads to more +efficient algorithms (e.g. rendering triangles is much faster than +rendering arbitrary polygons). Additionally some algorithms are only +implemented for triangle meshes while triangle meshes inherit the full +functionality of polygonal meshes. For a list of them refer to the +following links. + +\see OpenMesh::PolyMeshT +\see OpenMesh::TriMeshT + + + +

+ +\section sec_select_kernel Choosing the right kernel + +The mesh kernel specifies how the mesh entities (vertices, +(half-)edges, faces) are internally stored. In fact the entities are kept in +so-called properties. A property itself provides an array like interface. +The kernel defines the corresponding handle types, +i.e. the way items reference each other. Since the properties have an +array like interface the handles are represented internally as indices. + +The default kernel is \c ArrayKernelT. Which is good for most +situations. But depending on the application a different kernel would +be better. E.g. the OpenSG integration has been realized be replacing +the kernel by a custom kernel, since OpenSG provides already array like +properties, which could be reused for the intergration. In case of a an OpenSG +environment one might be better off using \c OSG_Kernel::ArrayKernelT. + +\see \ref mesh_kernels_group + +

+ +\section sec_select_traits Mesh Traits + +While the last two sections only have chosen from a list of predefined +meshes or kernels, respectively, we now come to the user-defined +customization. + +The resulting mesh \c MyMesh will provide the following types: + +
    +
  • The point and scalar type: \c MyMesh::Point and \c + MyMesh::Scalar. +
  • The mesh items: \c MyMesh::Vertex, \c MyMesh::Halfedge, \c + MyMesh::Edge, \c MyMesh::Face. +
  • The handle types: \c MyMesh::VertexHandle, \c + MyMesh::HalfedgeHandle, \c MyMesh::EdgeHandle, \c + MyMesh::FaceHandle. +
+ +While the handle types are fixed, the other types can be customized. +Each mesh type (see \ref mesh_types_group) can be parameterized +by a so-called \em traits class. Using this mechanism one can + +
    +
  1. change the coordinate type \c MyMesh::Point and the resulting + scalar type \c MyMesh::Scalar == \c MyMesh::Point::value_type, +
  2. change the normal type \c MyMesh::Normal +
  3. change the color type \c MyMesh::Color +
  4. use predefined attributes like normal vector, color, texture + coordinates, ... for the + mesh items. +
  5. add arbitrary classes to the mesh items. +
+ +All these customizations are encapsulated in one class \c MyTraits, +that is used as template argument to the mesh, e.g. +\code +struct MyTraits { + // your customization +}; +typedef PolyMesh_ArrayKernelT MyMesh; +\endcode + +The rest of this section explains the construction of this traits +class, its application to the mesh will be the topic of the next section. + +For each mesh entity one can control the predefined attributes to be +attached by a traits class using some convenience macros, e.g. \c +OpenMesh::VertexAttributes and \c OpenMesh::VertexTraits for +vertices. The default traits class looks like this: + +\include traits0.cc + +Please note that for example \c VertexTraits is a define concealing a +template declaration. The actual template class name is \c VertexT, +which is further simplified to a specific type \c Vertex at a later +stage during the construction of the mesh kernel. + +Because the traits classes always have to provide the template classes +\c VertexT, \c HalfedgeT, \c EdgeT, \c FaceT, and the types \c Point, +\c Normal, \c Color, and \c TexCoord one should derive this class from +the default implementation \c DefaultTraits. In this case you will +only have to define the classes or types you want to override or substitute. + + +
+\subsection sec_change_point Changing the Point type + +Changing the type that is used to store the point coordinates as well +as the normal vectors can simply be done by defining this type in the +traits class. The following code changes the coordinate type in order +to use \c double instead of \c float. + +\include traits1.cc + +Using the OpenMesh::VectorT class you can easily plug in any scalar +type for the use in point coordinates, e.g. some exact arithmetic. You +can also exchange the whole class representing points as long as it +provides the same interface as the OpenMesh::VectorT class. + + +
+\subsection sec_add_attributes Adding Predefined Attributes + +There are some pre-defined attributes that can be appended to the mesh +items. These global attributes are defined in the namespace +OpenMesh::Attributes. The advantage of these attributes is that +they are registered at the items they are added to. Therefore +algorithms can check for these attributes at run-time as well as at +compile-time. This is important if you want to implement algorithms +acting on different meshes, that may or may not have e.g. normal +vectors per vertex/face. + +Adding these predefined attributes is quite simple. You provide an +unsigned int in the traits class, whose bits control whether +or not a certain attribute should be attached or not. + +If you want to add a normal vector to your vertices and faces, and also +want to have color information for vertices, the code would look like this: + +\include traits5.cc + +Internally each mesh item contains an \c enum defining the integer \c +Attributes (containing the bits of used attributes OR'ed +together). From its set/unset bits you can see whether a certain +attribute is used. OpenMesh provides the macro OM_Check_Attrib for +doing this: + +\code +if (OM_Check_Attrib(MyMesh::Vertex, Normal) + do_something_with_normals(); +\endcode + +These run-time checks may not be sufficient in some cases. You can also check +for attributes at compile-time and instantiate the correct functions +by using function overloading. The class \c GenProg::Bool2Type maps +true/false information to two different types, \c Bool2Type and +\c Bool2Type. An example that draws OpenGL normals if they are +available would look like this: + +\include draw_normals.cc + +Especially the compile-time checking for attributes is extremely +useful because it does not generate any unnecessary code and does not +perform expensive tests at run-time. + +\see OpenMesh::DefaultTraits +\see OpenMesh::Attributes +\see OpenMesh::GenProg + +
+\subsection sec_add_traits Adding User-Defined Elements + +You can also add arbitrary types/elements/methods to the mesh items by +providing a corresponding traits class for these items. Adding some +index to the \c Vertex class is easily done by + +\include traits2.cc + +The macro \c VertexTraits hides some ugly template stuff. In fact, it +is defined as + +\code +#define VertexTraits template struct VertexT : public Base +\endcode + +hence the traits class actually looks like this: + +\include traits3.cc + +You have to keep this in mind when you want to define constructors for +your vertex type or when you want to derive the vertex type from other +classes. + +The template argument \c Base provides access to the mesh handles and +to the \c Point and \c Scalar type by its member class \c Refs. Adding +a \c MyMesh::FaceHandle to the vertex class can therefore be +implemented like this: + +\include traits4.cc + +Adding elements to other mesh items works in the same manner. + + +
+\subsection sec_algo_traits Using traits defined by algorithms + +From version 0.10.3 on algorithms can define traits/attributes they +require and the user can merge these traits into his own traits. A more elegant +way is to use dynamic properites, which can be added/removed during runtime +by the algorithm. This is the preferred way to attach custom data to the mesh. + +An example for an algorithm as well as the application using traits +is given in \ref tutorial_06. + +

+ +\section sec_properties Dynamic Properties + +From version 1.0 on %OpenMesh provides dynamic properties. Instead of +using traits to bind data at compile time algorithms or the +application can use dynamic properties. Similar to entities the properties +are accessed and manipulated via handles. + +An example for an algorithm as well as the application using +properties is given in \ref tutorial_03 and \ref tutorial_04. + +

+ +\section sec_traits_example Final Implementation Example + +Consider an application where we just want to render triangle meshes. +This means we will select the triangle mesh and the \c +ArrayKernelT. Faces that are not triangles will automatically be +tesselated into triangles. Because we only display meshes and do not +dynamically add or remove items, we can just use the \c ArrayKernelT. + +All mesh-kernel combinations are predefined in the directory +%OpenMesh/Mesh/Types. Refer to \ref mesh_types_group for a +complete list of them. For our example we use the \c +TriMesh_ArrayKernelT and parameterize it by our \c MyTraits class. + +We will need face and vertex normals and e.g. for color coding vertex +curvature, i.e. vertex color. + +\include mymesh.cc + +That's it. + +*/ + + +//----------------------------------------------------------------------------- + + +/** \page mesh_members Where do I find a list of all member functions ? + +The following picture shows the (simplified) conceptual inheritance +diagram for the %OpenMesh classes. + +\image html inheritance-simple.scaled.png + +The basis for all meshes is the corresponding \c MeshKernel, taking +care of the internal storage of the mesh items (vertices, +(half-)edges, faces). This kernel is inherited by the \c PolyMeshT, +i.e. the general polygonal mesh, adding higher level +functionality. For specialization purposes the class \c TriMeshT is +derived from \c PolyMeshT and overrides some member functions or adds +functions only suitable for pure triangle meshes. + +In most cases a class (e.g. \c PolyMeshT) gets the class it should +derive from (e.g. the mesh kernel) as a template parameter. The +documentation class OpenMesh::Concepts::MeshKernel::KernelT lists the +minimal interface a mesh kernel must provide. Special kernels may +provide some more functionality, in this case refer to this kernel's +documentation (see \ref mesh_kernels_group). Therefore your mesh +provides the pubic member functions of + +
    +
  • The mesh kernel. +
  • The general polygonal mesh. +
  • The specialized triangle mesh (if you use a TriMesh instead of a PolyMesh). +
+ + +\see OpenMesh::Concepts +\see OpenMesh::Concepts::KernelT +\see OpenMesh::PolyMeshT +\see OpenMesh::TriMeshT + +**/ + + +//----------------------------------------------------------------------------- + + +/** \page mesh_io Mesh Input and Output + +This section explains the methods used to read a mesh from a file or +write it to a file. The corresponding functions are defined in the +namespace OpenMesh::MeshIO. This section is divided into three steps. +Step one will give a short example on how to use the %OpenMesh IOManager, +step two will give some background information on how IOManager works and +finally step three will show you how to add your own modules to IOManager. + +\section mesh_io_quick Step 1 - IOManager quick start + +For a quick start you can copy the following code directly to your project. + +\include mesh_io.cc + + +

+ +\section mesh_io_theory Step 2 - The theory behind IOManager + +Usually mesh reader and writer routines are written directly against +the data structure and the respective file format they support. This +approach has the main disadvantage that targeting a different data +structure or adding another file format leads to duplication of code. + +IOManager acts as an interface between persistent data on one side and +an arbitrary data structure on the other side by means of reader/writer +and importer/exporter modules. This is illustrated by the following +diagramm : + +\image html iomanager.gif + +
+ +Persistent data of arbitrary format is first interpreted by a reader +module. The data is then passed - by means of a specified interface - +to an importer module for the target data structure. The process for +writing data is analogous. The IOManager controls the entire process. +Reader/Writer modules are invisible to the user. Importer/Exporter +however have to be specified explicitely as they are specific to a +data structure. + +The complete separation of data structure and persistent data makes it +especially easy to maintain existing code and to extend funtionality +at both ends as will be shown in step three. + +\see OpenMesh::IO::_IOManager_ + +

+ +\section mesh_io_extend Step 3 - How to extend IOManager + +\subsection mesh_io_extend_fileformat Adding support for a new file format + +Adding support for a new file format involves adding a reader and +writer module. Reader modules are classes derived from +OpenMesh::IO::BaseReader. The part of the interface that you +usually have to define is shown below. + +\include BaseReader.hh + +Based on the file extension or the header information the IOManager +decides which reader module to use. The reader then parses the format +and the information will be passed to the target data structure be +means of a class derived from OpenMesh::IO::BaseImporter. + +Writer modules are derived from OpenMesh::IO::BaseWriter and work +the same way as reader modules. + +
+ +\subsection mesh_io_extend_datastruct Adding support for a new data structure + +As we have already seen, Importers receive information from the reader modules. +Reader modules pass information through a specified interface : + +\include BaseImporter.hh + +The Importer is then responsible for filling the target data structure. +Exporting information from a data structure is a little bit more involved than +importing data to it. The writer modules must be able to iterate over all +vectors/texcoords/faces. Therefore an exporter has to provide these iterators : + +\include BaseExporter.hh + +There might be the need for the exporter to cache data from the structure it +refers to. The update() function should be called at the beginning of +each BaseWriter::save() method and it should make sure that cached information +is up to date. + +For further information you are encouraged to take a look at the modules +provided by %OpenMesh which can be found in the IO subdirectory. + +*/ + + +//----------------------------------------------------------------------------- + + +/** \page mesh_iterators Mesh Iterators and Circulators + +The mesh provides linear iterators (that enumerate vertices, +halfedges, edges, and faces) and so called circulators (to iterate \em +around a vertex or a face). These can be used to easily navigate +through a mesh. Each iterator \c XYZIter also exists in a const +version \c ConstXYZIter. + +All iterators and circulators are defined in the namespace +OpenMesh::Iterators. They are template classes that expect a mesh as +template argument to be fully specified. You should use the +iterator/circulator types provided by the mesh itself, i.e. \c +MyMesh::VertexIter instead of \c +OpenMesh::Iterators::VertexIterT. + + + +\subsection subsec_iterators Linear Iterators + +The linear iterators are used to enumerate all mesh items, e.g. for +rendering purposes. The iterators and their \c const counterparts are: + +\include iterators.cc + +The corresponding \c const counterparts are + +\arg \c ConstVertexIter, +\arg \c ConstHalfedgeIter, +\arg \c ConstEdgeIter, +\arg \c ConstFaceIter. + + +The linear iterators are (almost) conformant to STL iterators. For a +description of their interface see OpenMesh::Concepts::IteratorT. + +For efficiency reasons the \c operation++(int) (post-increment) +and \c operation--(int) (post-decrement) are not implemented. +Additionally to the standard operations, each linear iterator +provides a method \c handle(), which returns the handle of the +item referred to by the iterator. + +\note An iterator to an item usually needs more memory than a +handle of an item. To store many references to an item, it is +therefore better to use handles. + + +

+\subsection subsec_circulators Circulators + +Circulators provide means to enumerate items adjacent to +another item of the same or another type. For example, +a \c VertexVertexIter allows to enumerate all vertices +immediately adjacent to a (center) vertex (i.e. it allows +to enumerate the so-called 1-ring of the center vertex). +Analogously, a \c FaceHalfedgeIter enumerates all the +halfedges belonging to a face. +In general, \c CenterItem_AuxiliaryInformation_TargetItem_Iter +designates a circulator that enumarates all the target items +around a given center item. + +The circulators around a vertex are: + +\arg \c VertexVertexIter: iterate over all neighboring vertices. +\arg \c VertexIHalfedgeIter: iterate over all \em incoming halfedges. +\arg \c VertexOHalfedgeIter: iterate over all \em outgoing halfedges. +\arg \c VertexEdgeIter: iterate over all incident edges. +\arg \c VertexFaceIter: iterate over all adjacent faces. + +The circulators around a face are: + +\arg \c FaceVertexIter: iterate over the face's vertices. +\arg \c FaceHalfedgeIter: iterate over the face's halfedges. +\arg \c FaceEdgeIter: iterate over the face's edges. +\arg \c FaceFaceIter: iterate over all edge-neighboring faces. + +The constructor of a circulator is of the form +\c Circulator(MeshType mesh, TargetHandle center_handle), +i.e. it takes a mesh and the handle of the item to iterate +around. + +All circulators provide the operations listed in +OpenMesh::Concepts::CirculatorT, which are basically the same as the +iterator funtions. + +Furthermore, circulators provide \c operator \c bool(), which returns +true, as long as the circulator hasn't reached the end of the +sequence. + +Example: The following code enumerates the 1-ring of each vertex: + +\include circulators.cc + +*/ + + +//----------------------------------------------------------------------------- + +/** \defgroup mesh_property_handle_group Mesh Property Handles + +All custom properties are represented by the property +handles. The handle mechanism allows to add arbitrary data to the mesh +items. It stores the value type (by construction) and a 'reference' to the +property. Use the mesh object to access the property values. + +\see OpenMesh::PropertyT, OpenMesh::BaseKernel, OpenMesh::Concepts::KernelT, + \ref tutorial_03, \ref tutorial_04, \ref tutorial_09 + + */ + +//----------------------------------------------------------------------------- + + +/** \defgroup mesh_kernels_group Mesh Kernels + +This group holds all mesh kernels. Since %OpenMesh makes heavily use +of templates especially in the kernels, there's no direct inheritence +relationship of the kernel classes. For a conceptual overview of the +inheritance graph see \ref mesh_hierarchy. For a list of available +methods see OpenMesh::Concepts::KernelT. + +\see \ref mesh_hierarchy, OpenMesh::Concepts::KernelT + +*/ + + +//----------------------------------------------------------------------------- + + +/** \defgroup mesh_types_group Predefined Mesh Types + +This group holds all the predefind mesh types, i.e. all combinations +of triangle/polygonal mesh and the set of kernels. + +*/ + + +//----------------------------------------------------------------------------- + + +/** \defgroup mesh_concepts_group Interface Concepts + +Since for many classes no virtual inheritace is used one can't enforce +a specific interface by pure virtual functions. Therefore these +interfaces will be described in this group. Everyone implementing +e.g. a new mesh kernel should at least implement the +OpenMesh::Concepts::Kernel concept. + +*/ + + +//----------------------------------------------------------------------------- diff --git a/Doc/misc.docu b/Doc/misc.docu new file mode 100644 index 00000000..e0819a23 --- /dev/null +++ b/Doc/misc.docu @@ -0,0 +1,93 @@ +//----------------------------------------------------------------------------- + + +/** \page naming_conventions Naming Conventions + +The following naming conventions are used for the OpenMesh code: + +Files: + \li \c MyClass.cc for C++-Implementation of class \c MyClass + \li \c MyClass.hh for C++-Header of class \c MyClass + +Classes: + \li Class names start with a capital letter: \c MyClass + \li Class templates end with \c T: \c MyClassTemplateT + +Variables: + \li One leading underscore for parameters in function-calls: \c _var + \li One trailing underscore for member-variables: \c var_ + \li Two trailing underscores for static member-variables: \c var__ + +Functions: + \li Words are separated by underscores: \c my_function() + +Accessing members: + \li To get the member \c xxx_ use const& xxx() const + \li To set the member \c xxx_ use void set_xxx(arg) + +**/ + + +//----------------------------------------------------------------------------- + + +/** \page compiling Compiling OpenMesh + +\section compilers Tested compilers + +%OpenMesh has been tested sucessfully for the following operating +systems / compilers: + + + + + + + + + +
Linux +gcc 4.0.x
+gcc 4.1.x
+gcc 4.2.x
+gcc 4.3.x
+
Windows +Microsoft Visual Studio 2008
+
MacOS X
(Panther and Tiger)
+gcc 3.3
+gcc 4.0
+
+ + +\section sec_compiling_unix Unix + +Download and install the Qt4 framework from Trolltech.
+In order to compile and install OpenMesh, enter following commands in OpenMesh's root directory:

+ +qmake             ## Generates the appropriate Makefiles
+make              ## Builds the project (use 'make debug' to build debug version)
+sudo make install ## Install OpenMesh (as root) +


+When using the \c qmake command, make sure to use Qt version 4 (some linux distributions
+use the link \c qmake-qt4 against the executable). + +\section sec_compiling_windows Windows + +For Microsoft Visual Studio 2008, you can use +the predefined solution file Core/OpenMesh_Core.vcproj and Tools/OpenMesh_Tools.vcproj + +\section sec_compiling_macosx MacOSX + +Download and install the Qt4 framework from Trolltech.
+In order to compile and install OpenMesh, open a Terminal window and enter following commands in OpenMesh's root directory:

+ +qmake -macx       ## Generates the appropriate Makefiles
+make release      ## Builds the project (use 'make debug' to build debug version)
+sudo make install ## Install OpenMesh (as root) +
+ + +**/ + + +//----------------------------------------------------------------------------- diff --git a/Doc/namespaces.docu b/Doc/namespaces.docu new file mode 100644 index 00000000..bad76d59 --- /dev/null +++ b/Doc/namespaces.docu @@ -0,0 +1,82 @@ +//============================================================================= +// +// Documents all used namespaces for doxygen +// +//============================================================================= + + +/** \namespace OpenMesh::Concepts + Descriptions of the concepts used in OpenMesh. +*/ + + +/** \namespace OpenMesh + Contains all the mesh ingredients like the polygonal mesh, + the triangle mesh, different mesh kernels and mesh traits. +**/ + + +/** \namespace OpenMesh::Iterators + Contains all mesh iterators and circulators. The two classes + OpenMesh::Concepts::IteratorT and OpenMesh::Concepts::CirculatorT describe + the interfaces provided by all iterators and circulators, respectively. + + All iterators/circulators defined in this namespace are template classes + that require a mesh a template parameter. Therefore you should use + the iterators/circulators that are defined by the mesh itself. See + OpenMesh::Mesh::PolyMeshT for a complete list of them. + + \see The mesh docu section \ref mesh_iterators for a more detailed + description. + \see OpenMesh::Concepts::IteratorT + \see OpenMesh::Concepts::CirculatorT +*/ + + +/** \namespace OpenMesh::IO + This namespace contains functions for reading and writing polygonal + meshes and a list of supported file formats. +*/ + + +/** \namespace OpenMesh::GenProg + Utilities for generative programming. +*/ + + +/** \namespace OpenMesh::Attributes + This namespace holds per item attributes like normal/color. + There are some macros provided for convenience, see Attributes.hh. + \see Attributes.hh +*/ + + +/** \namespace OpenMesh::Kernel_OSG + In this namespace resides the OpenSG integration of OpenMesh. + Here you find the class + OpenMesh::OSG_Kernel::TriMesh_OSGArrayKernelT<> and the + template function OpenMesh::OSG_Kernel::bindT<> to link such a + mesh with a OpenSG Geometry. */ + + +/** \namespace OpenMesh::Decimater + Software related to mesh decimation. + \see DecimaterT.hh +*/ + + +/** \namespace OpenMesh::Subdivider::Adaptive + * Software related to adaptive subdivision of meshes. + */ + +/** \namespace OpenMesh::Subdivider::Uniform + * Software related to uniform subdivision of meshes. + */ + +/** \namespace OpenMesh::VDPM + * Software related to view dependent progressive meshes. + */ + +/** \namespace OpenMesh::Utils + * Collection of little utility classes and helpers. + */ \ No newline at end of file diff --git a/Doc/subdivider.docu b/Doc/subdivider.docu new file mode 100644 index 00000000..ea24dcaf --- /dev/null +++ b/Doc/subdivider.docu @@ -0,0 +1,17 @@ +//----------------------------------------------------------------------------- + +/** \page subdivider_docu Sudivision Tools + +The %OpenMesh library provides a few tools for uniform and adaptive +subdivision: + +-# Uniform subdivision + -# OpenMesh::Subdivider::Uniform::LoopT + -# OpenMesh::Subdivider::Uniform::Sqrt3T + -# OpenMesh::Subdivider::Uniform::CompositeT +-# Adaptive subdivision + -# OpenMesh::Subdivider::Adaptive::CompositeT + +*/ + +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/Doc/tools.docu b/Doc/tools.docu new file mode 100644 index 00000000..06a8289c --- /dev/null +++ b/Doc/tools.docu @@ -0,0 +1,13 @@ +//----------------------------------------------------------------------------- + +/** \page tools_docu OpenMesh Tools Documentation + +- \ref decimater_docu +- \ref subdivider_docu +- \ref vdpm_docu +- Miscellaneous + - \ref OpenMesh::StripifierT + +*/ + +// ---------------------------------------------------------------------------- diff --git a/Doc/tutorial_01.docu b/Doc/tutorial_01.docu new file mode 100644 index 00000000..2f119b69 --- /dev/null +++ b/Doc/tutorial_01.docu @@ -0,0 +1,64 @@ +/** \page tutorial_01 First Steps + +This small example shows: +\li How to declare your type \c MyMesh, +\li How to add vertices and faces to a mesh, +\li How to write a mesh using the IO functions. + +For each program the first step is to define your type \c +MyMesh. %OpenMesh supports general polygonal meshes (faces are polygons +with varying number of vertices) as well as specialized triangle +meshes (all faces are triangles). In this example we want to build a +cube from six quadrangles, therefore we choose the polygonal mesh. + +%OpenMesh also supports different mesh kernels, specifying how all the +vertices, edges, and faces are stored internally (see also \ref +mesh_kernels_group). However, the storage must provide an array like interface. +For the tutorial we use the supplied ArrayKernel. The predefined +combinations of TriMesh/PolyMesh and the kernel are +contained in \c %OpenMesh/Core/Mesh/Types/, we use the +PolyMesh_ArrayKernelT. + +\dontinclude build_cube.cc +\skipline PolyMesh_ArrayKernel +\skipline MyMesh + +Now since we have declared our type \c MyMesh, we only have to add 8 +vertices and 6 quadrangles to build a cube. Adding a vertex is done +using the add_vertex method. It gets a coordinate and returns +a handle to the inserted vertex. We store all handles in an array, +since we need them for specifying the faces. + +\skipline vhandle[0] +\until vhandle[3] + +
In order to add a face to the mesh, we have to build a vector holding +the handles to the face's vertices. This vector is passed to the +\c add_face method. The following block will create a face from the first +four vertices: + +\skipline face_vhandles +\until add_face + +
The orientation of the face is defined by the order in which the +vertices are given: If you look at the frontfacing side of the +polygon, then the vertices are in counter-clockwise order. + +After creating all of the six faces, we want to write the resulting +mesh to standard output. %OpenMesh provides some basic input/output +methods in the namespace OpenMesh::IO: + +\skipline write_ + +
To use the IO facility of %OpenMesh make sure that the include MeshIO.hh is +included first. + +\dontinclude build_cube.cc +\skipline MeshIO +\until PolyMesh_ArrayKernel + +
The complete source looks like this: + +\include build_cube.cc + +**/ \ No newline at end of file diff --git a/Doc/tutorial_02.docu b/Doc/tutorial_02.docu new file mode 100644 index 00000000..a117c38c --- /dev/null +++ b/Doc/tutorial_02.docu @@ -0,0 +1,62 @@ +/** \page tutorial_02 Using iterators and circulators + +This examples shows: + +- How to use iterators, +- How to use circulators. + +This example is the first version of the simple mesh smoother. Here we +will introduce \em iterators and \em circulators. These two concepts +provide functionality to linearly enumerate e.g. all vertices of a +mesh, and to circulate around a vertex, i.e. to enumerate all its +one-ring neighbors. For a more detailed description, see \ref +mesh_iterators. + +First we have to define the mesh type we want to use. This time we use +a triangle mesh instead of a polygonal mesh: + +\dontinclude 02-iterators/smooth.cc +\skipline TriMesh_ArrayKernel +\skipline MyMesh + +
We read the mesh to be smoothed from a file: + +\skipline read_mesh + +
One smoothing iteration is done in two steps: +
    +
  1. For each vertex: calculate the barycenter of its one-ring neighbors.
  2. +
  3. For each vertex: move the vertex to the computed barycenter.
  4. +
+ +This can easily be implemented using vertex iterators. The mesh +provides begin and end iterators by vertices_begin() and +vertices_end(). + +\skipline VertexIter +\skipline v_it!=v_end + +
For calculating the barycenter, we have to iterate through the +one-ring neighborhood of the current vertex. This functionality +is provided by the VertexVertexIter: + +\dontinclude 02-iterators/smooth.cc +\skipline VertexVertexIter +\skipline vv_it= + +
Now we can calculate the barycenters for each vertex and store them in +the array cogs: + +\dontinclude 02-iterators/smooth.cc +\skipline std::vector +\skipline v_it= +\until cogs.push_back +\until } + +
After we have calculated the barycenters all that is left to do is to +move the vertices to the corresponding barycenters. The complete source +code is listed below. + +\include 02-iterators/smooth.cc + +**/ \ No newline at end of file diff --git a/Doc/tutorial_03.docu b/Doc/tutorial_03.docu new file mode 100644 index 00000000..9a136237 --- /dev/null +++ b/Doc/tutorial_03.docu @@ -0,0 +1,54 @@ +/** \page tutorial_03 Using (custom) properties + +This examples shows: +- How to add and remove custom properties, +- How to get and set the value of a custom property + +In the last example we computed the barycenter of each vertex' +neighborhood and stored it in an array. It would be more convenient +and less error-prone if we could store this data in the mesh and +let %OpenMesh manage the data. +It would be even more helpful if we could attach such properties +dynamically to the mesh. + +%OpenMesh provides dynamic properties, which can be attached to each +mesh entity (vertex, face, edge, halfedge, and the mesh itself). We +distinguish between custom and standard properties. A custom property +is any user-defined property and is accessed via the member function +\c property(..), a handle and an entity handle +(e.g. VertexHandle). Whereas the standard properties are accessed via +special member functions, e.g. the vertex position is accessed with \c +point(..) and a vertex handle. + +In this example we will store the \c cog-value (see previous example) +in an additional vertex property instead of keeping it in a separate +array. To do so we define first a so-called property handle with the desired +type (\c MyMesh::Point) and register the handle at the mesh: + +\dontinclude 03-properties/smooth.cc +\skipline vertex property stores +\until mesh.add + +
The \c mesh allocates enough memory to hold as many elements of type +\c MyMesh::Point as number of vertices exist, and of course the mesh +synchronizes all insert and delete operations on the vertices with the +vertex properties. + +Once the wanted property is registered we can use the property to +calculate the barycenter of the neighborhood of each vertex \c v_it + +\dontinclude 03-properties/smooth.cc +\skipline vv_it= +\until } +\until mesh.prop + +
and finally set the new position for each vertex \c v_it + +\dontinclude 03-properties/smooth.cc +\skipline mesh.set_point + +
Below is the complete source code: + +\include 03-properties/smooth.cc + +*/ \ No newline at end of file diff --git a/Doc/tutorial_04.docu b/Doc/tutorial_04.docu new file mode 100644 index 00000000..9965bb86 --- /dev/null +++ b/Doc/tutorial_04.docu @@ -0,0 +1,50 @@ +/** \page tutorial_04 Using STL algorithms + +Since the %OpenMesh iterators are (almost) conformant to STL iterators, +one can apply the STL algorithms on meshes. The following example +shows how to use the STL \c for_each construct, since it is +easier to read and may be more efficient than hand-written loops. + +We will define a class which provides the smoothing algorithm, hence +define a reusable component. The class must be template class because there +is no such thing as a class %OpenMesh, but many different types of %OpenMesh: + +\dontinclude 04-stl_algorithms/smooth_algo.hh +\skipline template + +The class SmootherT has two functors, one that computes the barycenter +for a given vertex, and a second that sets the vertex position to the +corresponding barycenter. A functor is simply a class with a function +operator()(...). The first functor \c ComputeCOG +computes the barycenter and store it in a custom vertex property \c +cog_: + +\skipline operator +\until } +\until } + +Note, that \c ComputeCOG needs to have access to the mesh object and +the property handle. Here, both are references to member variables of +the smoother object. + +The second functor \c class \c SetCOG, which sets the vertex position, +is constructed analogical. + +Using these functors and std::for_each from the STL +the smoothing algorithm can be realized in a member function of +\c SmootherT: + +\dontinclude 04-stl_algorithms/smooth_algo.hh +\skipline void smooth +\until } +\until } + +
The complete example looks like this: + +\include 04-stl_algorithms/smooth_algo.hh + +
and + +\include 04-stl_algorithms/smooth.cc + +*/ \ No newline at end of file diff --git a/Doc/tutorial_05.docu b/Doc/tutorial_05.docu new file mode 100644 index 00000000..8d2ffe77 --- /dev/null +++ b/Doc/tutorial_05.docu @@ -0,0 +1,136 @@ +/** \page tutorial_05 Using standard properties + +This example shows: + +- How to add and remove a standard property, +- How to get and set the value of a standard property. + +As we already have seen, we can bind additional data to the mesh +entities by means of properties. %OpenMesh provides a set of so-called +standard properties. Unlike the custom properties these have some +special features and a different interface, which are the matter in this +tutorial. + +The following table lists all available standard properties and the suitable +entity for which it can be used. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 VertexFaceEdgeHalfedge
ColorXX  
NormalXX  
Position (*) X   
StatusXXXX
TexCoordX   
+ +To add a standard property to an entity simply use the appropriate +request method, e.g. \c  request_face_normal(). The only exception is +the position (*). It cannot be added because it is +permanently available, hence it cannot be removed as well. + +In this example we +-# add vertex normals to a mesh object +-# load a file +-# check if the file provides vertex normals and calculate them if not +-# move every vertex one unit length along its normal direction +-# print the resulting positions to std::cout + +Let's start with adding vertex normals to the mesh: + +\dontinclude 05-std_properties/properties.cc +\skipline request_vertex_normals + +In a similar manner we can request the other standard properties. For example +the face normals: + +\skipline request_face_normals + +We need them to calculate the vertex normals with \c update_normals(), if the +file didn't provide any. + +But we can do more with standard properties. We can verify if the mesh +has already the property vertex normals + +\dontinclude 05-std_properties/properties.cc +\skipline has_vertex_normals +\until } + +And after usage we remove them again + +\skipline release_vertex_normals + +But, what happens if for example the vertex status property has been +requested twice? Then the first release does nothing, but the second +one will remove it. The standard properties have a reference counter, +which is incremented by one for each request and decremented by one +for each release. If the counter reaches 0 the property will be +removed from memory. + +Now we know how to add and remove standard properties, but how do we +access them? Again we need the mesh object. Unlike the custom +properties, where we accessed one with the mesh member function \c +property(), for each standard property the mesh provides a get and a +set method. We have used one pair of get/set methods already in the +previous three tutorials, where we computed a new location for the +vertex position. Here we move all vertices a unit length along their +normal direction: + +\dontinclude 05-std_properties/properties.cc +\skipline MyMesh::VertexIter +\until { +\skipline mesh.set_point +\skipline } + +The get-methods take an entity handle and return the value of +the desired property, and the set-methods require an additional +parameter to pass the new value to the property. According to the +table not every pair of get/set-methods apply to every entity. For +example a face has normally no texture coordinates, hence a call to \c +mesh.texcoord( _face_handle ) will result in an error when compiling +the code. + +Since we know how to add/remove/access standard properties, one further +question remains. What data types do they have? And are there more hidden +secrets? The next tutorial (\ref tutorial_06) will give the answer. + +The complete source looks like this: + +\include 05-std_properties/properties.cc + +*/ \ No newline at end of file diff --git a/Doc/tutorial_06.docu b/Doc/tutorial_06.docu new file mode 100644 index 00000000..04984f27 --- /dev/null +++ b/Doc/tutorial_06.docu @@ -0,0 +1,74 @@ +/** \page tutorial_06 Using mesh attributes and traits + +this example shows how to change the data type for positions, normals, colors, and texture, + +In the previous tutorial (\ref tutorial_05) we learned to use standard +properties by calling the appropriate \c request method. +Unlike the custom properties, where the user specifies the +data type by passing the type to the handle (e.g. \c +MyMesh::FPropHandleT< int>), the data types of the standard +properties are defined by so-called mesh traits. With traits we can +customize and extend the mesh data structure. We can do this by +changing two important features + +-# changing data type for positions, normals, colors, and texture + coordinates +-# extend mesh entities Vertex, Face, Edge, and Halfedge + (see tutorial '\ref tutorial_07') + +Let's start. Every custom traits should derive from the default traits + +\dontinclude 06-attributes/attributes.cc +\skipline struct MyTraits + +As mentioned, we can change the basic data types for the basic types +\c MyMesh::Point, \c MyMesh::Normal, \c MyMesh::Color, and \c MyMesh::TexCoord. +We can use the provided vector class or we use a +different one from another library. Here we simply replace the default +type \c OpenMesh::Vec3f (defined in the \c OpenMesh::DefaultTraits) +for positions and normals with \c OpenMesh::Vec3d + +\skipline Vec3d +\skipline Vec3d + +(In general it's better to have the same scalar type for the point and +normal vector, for instance \c double in this case. Otherwise we have +to cast quite a lot depending on the implementation of the vector class.) + +Be aware that these settings overwrite the ones of the parent traits +class! As we usually derive from the DefaultTraits let's have a close look. + +Actually the struct \c OpenMesh::DefaultTraits is merely empty. It solely +defines the types for \c Point, \c Normal, \c TexCoord, and \c Color +and one attribute, that we used implicitly all the time: + +\skipline HalfedgeAttributes + +The attribute \c PrevHalfedge is different, as it does not control a +property. Yet it has a great impact on the resulting mesh type, as it +adds additional information to the halfedge structure. The impact +is twofold: + +-# fast access to previous halfedge +-# increase of memory consumption + +Using this feature depends highly on our needs. One situation where +the previous halfedges are quite handy, is the mesh member function +add_face(). The execution time for the member function drops +dramatically, when the information about the previous halfedge is +available. Usually we want to have this information. But if not, because we +must save memory, we can easily remove it with + +\skipline HalfedgeAttributes + +Then we need 8 bytes less per edge, which can be quite a lot as one can +derive from the Euler formula (\f$V-E+F=2 (1-g)\f$), that for a regular +triangle meshes with genus \f$g=0\f$ the number of edges +\f$E\f$ is approximately +three times the number of vertices \f$V\f$: \f$ E \approx 3 \cdot V\f$. + +The complete source looks like this: + +\include 06-attributes/attributes.cc + +*/ \ No newline at end of file diff --git a/Doc/tutorial_07.docu b/Doc/tutorial_07.docu new file mode 100644 index 00000000..11b67e56 --- /dev/null +++ b/Doc/tutorial_07.docu @@ -0,0 +1,46 @@ +/** \page tutorial_07 Extending the mesh using traits + +This examples shows: + +- How to extend the behaviour of entities using traits. + +In the previous tutorial we used attributes and changed the type of +the data types \c Point, \c Normal, \c TexCoord, and \c Color. But we +can do even more with traits. We can change the behaviour of the mesh +entities \c Vertex, \c Face, \c Edge, and \c Halfedge. + +One goal in the design was a highly customizable data structure. Using +the traits technique makes it possible. We pick up the smoother again +and show an alternative way to implement it. Now we place the necessary +data and the functions in the vertex itself + +\dontinclude 07-traits/smooth.cc +\skipline MyTraits +\until }; +\until }; + +Note the definition of the vertex entity. We use the supplied define +\c VertexTraits (which resolves in a rather inconvenient template +definition). Similary we can use the defines \c FaceTraits, \c +EdgeTraits, and \c HalfedgeTraits to extend these entities. Now we +enhanced the vertex, with the additional member variable \c cog_, and +the get/set-method pair to access the new member. + +As before we compute in a first loop the barycenters for all vertices +and store the information at the vertices + +\skipline v_it->set_cog + +In the second pass we set the new position of each vertex + +\skipline set_point + +It looks neat, but on the other hand we can't remove the data anymore +as we could do with properties! By using traits one creates a 'static' +configuration, which can't be changed during runtime. + +The complete source looks like this: + +\include 07-traits/smooth.cc + +*/ \ No newline at end of file diff --git a/Doc/tutorial_08.docu b/Doc/tutorial_08.docu new file mode 100644 index 00000000..1460acbb --- /dev/null +++ b/Doc/tutorial_08.docu @@ -0,0 +1,121 @@ +/** \page tutorial_08 Using IO::Options + +This example shows: + +- How to control the behaviour of \c Mesh::IO::read_mesh(), +- How to control the behaviour of \c Mesh::IO::write_mesh(). + +The class \c OpenMesh::IO::Options can be used when reading/writing a +mesh. It controls the behaviour of the reader/writer modules by means +of enabled/disabled bits in a bitset. The class provides an interface +for enabling, disabling and verifying the bits in the set. We +distinguish between + +-# mode bits - control binary reading/writing + - Options::Binary + - Options::MSB + - Options::LSB + - Options::Swap (MSB|LSB) +-# property bits - controls which standard properties to read/write + - Options::VertexNormal + - Options::VertexTexCoord + - Options::VertexColor + - Options::FaceNormal + - Options::FaceColor + +These bits have different effects when reading or writing. The file +format itself is selected by the extension of the filename. The IO +subsystem of the %OpenMesh library supports currently four +formats. The following table list all formats and indicates whether +the format supports ASCII/binary storage with the apropiate extension. + + + + + + + + + + + + + +
FormatAsciiBinary
OFF.off.off
OBJ.obj
STL.stla, .stl.stlb, .stl
OM.om
+ +The program does not more than providing a command line based +interface to select the option bits for reading/writing and to request +mesh properties. Hence illegal combinations are possible and will +result in a failure of the program. (The input file won't be damaged +in this case, but be careful where you put the ouput file!) + +
Reading meshes
+ +When reading a file the mode bits are used to give the reader an +advice or hint. Depending on the format we can help the reader to +interpret the data correctly. First of all we can tell it that the +file contains binary data. + +\dontinclude 08-io_options/io_options.cc +\skipline ropt += IO::Options::Binary + +Further on we can ask the reader two swap the byte-order. + +\skipline ropt += IO::Options::Swap + +(Both can be done via the command line with the options -b and -s, +respectively.) + +By default the geometry and the topology is restored from the +file. The file might contain more, especially it could provide normals +or texture coordinates. We can examine the property bits after +reading to find out what else is available: + +\dontinclude 08-io_options/io_options.cc +\skipline ropt.check(IO::Options::VertexNormal) + +If a property bit is set it does not mean, that it has been restored +as well. The property must have been requested prior reading the +file. (The demo program offers the command line option \c -Xv[nct] and +\c -Xf[nc] to request vertex and face properties.) + +
Writing meshes
+ +When writing the mesh the mode bits apparently control whether to use +the binary variant and the desired byte-ordering. For example, if we +choose binary mode and want to swap the byte order, we set + +\skipline wopt += IO::Options::Binary +\skipline wopt += IO::Options::Swap + +If the format does not specify the byte order the system byte order is +used. If the format does not support binary storage, the mode bits are +ignored. + +If the format supports storing additional information, which are +conform with the standard properties, we can use the property bits to +tell the writer what we would like to have stored. If we would like to +store the vertex normals we simply set + +\skipline wopt += IO::Options::VertexNormal + +Finally we can write the data to the file + +\dontinclude 08-io_options/io_options.cc +\skipline write_mesh + +The method returns false on error, which might have three different reasons: + +-# the option is not supported by the choosen format +-# a selected standard property is not available +-# a 'system' error like + - could not open the file due to access rights + - disk space exhausted during write + - ... + + +The complete source looks like this: + +\include 08-io_options/io_options.cc + +*/ \ No newline at end of file diff --git a/Doc/tutorial_09.docu b/Doc/tutorial_09.docu new file mode 100644 index 00000000..5f83123a --- /dev/null +++ b/Doc/tutorial_09.docu @@ -0,0 +1,186 @@ +/** \page tutorial_09 Storing custom properties + +The %OpenMesh' proprietary OM format allows to store and restore +custom properties along with the standard properties. For it we have +to use named custom properties like the following one + +\dontinclude 09-persistence/persistence.cc +\skipline VPropHandleT +\skipline mesh.add_property + +Here we registered a float property for the vertices at the mesh with +name "vprop_float". The name of a property, that we want to make +persistent, must follow a few rules + +-# max. 256 characters long +-# The prefixes \c "v:", \c "h:", \c "e:", \c "f:" and \c "m:" are reserved. + +If we stick to this rules we are fine. Furthermore we have to +consider, that the names are handled case-sensitive. + +To actually make a custom property persistent we have to set the +persistent flag in the property with + +\skipline mesh.property(vprop_float).set_persistent + +Now we can use \c IO::mesh_write() to write the mesh to a file on +disk. The custom properties are added after the standard properties +in the file, with the name and it's binary size. These two pieces of +information are evaluated when reading the file again. To successfully +restore the custom properties, the mesh must have registered named +properties with equal names (case-sensitive compare). Additionally, +when reading the data, the number of bytes read for a property must +match the provided number in the file. If the OM reader did not find a +suitable named property, it will simply skip it. If the number of bytes +do not match, the complete restore will be terminated and \c +IO::read_mesh() will return \c false. And if the data cannot be +restored, because the appropriate restore method is not available the +exception std::logic_error() will be thrown. + +Since we now know the behaviour, we need to know what kind of data can +we store? Without any further effort, simply using named properties +and setting the persistent flag, we can store following types + +- bool, stored as a bitset +- all other fundamental types except long double, (unsigned) long and size_t +- std::string, each up to 65536 characters long +- OpenMesh::Vec[1,2,3,4,6][c,uc,s,us,i,ui,f,d] + +For further reading we call these types basic types. Apparently we +cannot store non-basic types, which are + +- pointers +- structs/classes +- even more complex data structures, like container of containers. + +However there is a way to store custom types ( else we could not store +std::string). Let's start with an more simple custom data. For +instance we have a struct \c MyData like this + +\dontinclude 09-persistence/persistence.cc +\skipline struct MyData +\until vec4fval +\skipline }; + +Here we keep an int, bool, double value and a vector of 4 floats, which +are all basic types. Then we need to specialize the template struct +OpenMesh::IO::binary<> within the namespace \c OpenMesh::IO + +\skipline binary + +Remember not to use long double, (unsigned) long and size_t as basic types +because of inconsistencies between 32/64bit architectures. + +Herein we have to implement the following set of static member +variables and functions: + +\skipline is_streamable +\skipline size_of +\skipline size_of +\skipline store +\skipline restore + +The flag \c is_streamable has to be set to \c true. Else the data +cannot be stored at all. + +
\c size_of methods
+ +Since the size of the custom data can be static, which means we know +the size at compile time, or the size of it is dynamic, which means me +the size is known at runtime, we have to provide the two \c size_of() +methods. + +The first declaration is for the static case, while the second for the +dynamic case. Though the static case is more simple, it is not +straight forward. We cannot simply use \c sizeof() to determine the +data size, because it will return the number ob bytes it needs in +memory (possible 32bit alignment). Instead we need the binary size, +hence we have to add up the single elements in the struct. + +\dontinclude 09-persistence/persistence.cc +\skipline return sizeof + +Actually we would need to sum up the single elements of the vector, +but in this case we know for sure the result (4 floats make 16 bytes, +which is 32bit aligned therefore \c sizeof() returns the wanted +size). But keep in mind, that this a potential location for errors, +when writing custom binary support. + +The second declaration is for the dynamic case, where the custom data +contains pointers or references. This static member must properly +count the data, by disolving the pointers/references, if this data has +to be stored as well. In the dynamic stetting the static variant cannot return +the size, therefore it must return \c IO::UnknownSize. + +In this case the dynamic variant simply returns the size by calling the static +variant, as the sizes are identical for both cases. + +
\c store / \c restore
+ +For the dynamic case as for the static case, we have to make up a +scheme how we would store the data. One option is to store the length +of the data and then store the data itself. For instance the type \c +std::string is implemented this way. (We store first the length in a +16bit word (=> max. length 65536), then the characters follow. Hence +\c size_of() returns 2 bytes for the length plus the actual length of +the value \c v.) Since \c MyData contains only basic types we can +implement the necessary methods \c store and \c restore, by simply +breaking up the data into the basic types using the pre-defined +store/restore methods for them: + +\skipline static size_t store +\until } +\skipline static size_t restore +\until } + +It's very important, that the store/restore methods count the +written/read bytes correctly and return the value. On error both +functions must return 0. + +A more complex situation is given with the following property + +\dontinclude 09-persistence/persistence.cc +\skipline MyMap +\skipline mprop_map + +In this case the data contains a container, a map from strings to +integer numbers. If we want to store this as well, we need to make up +a scheme how the map will be stored in a sequential layout. First we +store the number of elements in the map. Then, since the map has an +iterator, we simply iterate over all elements and store each pair +(key/value). This procedure is equal for the \c size_of(), \c store(), and \c +restore() methods. For example the \c size_of() methods look like this + +\dontinclude 09-persistence/persistence.cc +\skip binary< MyMap > +\skipline static size_t size_of +\skipline static size_t size_of +\until } +\until } + +The implementation of \c store() and \c restore() follow a similar pattern. + +The given example program does the following steps + +-# Create a mesh and generate a cube +-# Add a few custom properties +-# Fill them with test data +-# Make the properties persistent +-# Store mesh in a file named 'persistent-check.om' +-# Clear the mesh +-# Restore mesh +-# Check the content on equality with the test data. + +Since the example is a little bit longer than usual the source is in +several files. The main program is in \c persistence.cc, the cube +generator in \c generate_cube.hh, \c stats.hh provides little tools to +display information about the mesh and the properties, the file \c +fill_props.hh providing the test data, and \c int2roman.hh/.cc, which +is used in fill_props.hh. All necessary parts are in \c +persistence.cc, which is displayed in full length below. For the other +files please have a look in the directory \c +OpenMesh/Doc/Tutorial/09-persistence/. + +\include 09-persistence/persistence.cc + +*/ \ No newline at end of file diff --git a/Doc/tutorial_main.docu b/Doc/tutorial_main.docu new file mode 100644 index 00000000..560d9a48 --- /dev/null +++ b/Doc/tutorial_main.docu @@ -0,0 +1,42 @@ +/** \page tutorial Introduction to OpenMesh (Tutorials) + +The %OpenMesh mesh library is a powerful tool for handling polygonal +meshes. Due to its inherent generative structure it allows the user to +create mesh types which are custom tailored to the specific needs of +the application. The user can either supply his own data structures +for representing vertices, edges and faces or he can conveniently use +the predefined structures of %OpenMesh. +Additionally %OpenMesh offers dynamic properties allowing the user to attach +and detach data to the mesh during runtime. + +This document is supposed to introduce the basic concepts of +%OpenMesh. + +In this tutorial we will introduce the %OpenMesh library by means of +simple examples. The first one just builds a polygonal mesh +representing a cube and writes the result to standard output. The +following examples develop a simple mesh smoother: Recall that the +immediate neighbors of a vertex are called the 1-ring of this +vertex. It is well known that a polygonal mesh can be smoothed by +repeatedly replacing each vertex' position by the center of gravity +(cog) of its 1-ring. The basic smoother will + +\li read a polygonal mesh from standard input, +\li compute the cog of the 1-ring of each vertex, +\li replace each vertex' position by its cog and finally, +\li write the mesh to standard output. + +
    +
  1. \ref tutorial_01 +
  2. \ref tutorial_02 +
  3. \ref tutorial_03 +
  4. \ref tutorial_04 +
  5. \ref tutorial_05 +
  6. \ref tutorial_06 +
  7. \ref tutorial_07 +
  8. \ref tutorial_08 +
  9. \ref tutorial_09 +
+ +*/ \ No newline at end of file diff --git a/Doc/vdpm.docu b/Doc/vdpm.docu new file mode 100644 index 00000000..5dd80bdd --- /dev/null +++ b/Doc/vdpm.docu @@ -0,0 +1,18 @@ +//----------------------------------------------------------------------------- + +/** \page vdpm_docu View Dependent Progressive Meshes + + The VDPM software is based on "Truly Selective + Refinement of Progressive Meshes", J. Kim and S. Lee, In + Proc. Graphics Interface 2001. + + The library is located in \c %OpenMesh/Tools/VDPM/ and in + \c %OpenMesh/Apps/VDProgMesh/ are demo applications: + -# \c mkbalancedpm creates balanced progressive meshes + -# \c vdpmanalyzer takes a progressive mesh and generates a view dependent + progressive mesh. + -# \c vdpmsynthezier is viewer for vdpm meshes. + + \todo Complete VDPM documentation. +*/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..5ab7695a --- /dev/null +++ b/LICENSE @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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; either + version 2.1 of the License, or (at your option) any later version. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/OpenMesh.kdevelop b/OpenMesh.kdevelop new file mode 100644 index 00000000..a97a5e20 --- /dev/null +++ b/OpenMesh.kdevelop @@ -0,0 +1,135 @@ + + + + Computer Graphics Group, RWTH Aachen + www.openmesh.org + KDevCustomProject + C++ + + . + false + + + + + + + + + + + + false + false + + + *.o,*.lo,CVS + false + false + + + + + gtk + gnustep + python + php + perl + + + html/ + html/ + + + + + + + + + build + / + bin/meshviewer_dbg + ../../Models/models/animals/bunny_95.off + false + true + + + + + + + make + + + + true + 1 + false + + default + + + + 0 + + + + + + + true + true + true + false + true + true + true + 250 + 400 + 250 + + + + true + true + true + true + -C + + + + + A new empty header file for C or C++. + + + A new empty C++ file. + + + + + + + .h + .cpp + + + + + + + + + + + true + false + false + + + false + true + 10 + + + diff --git a/OpenMesh.kdevelop.filelist b/OpenMesh.kdevelop.filelist new file mode 100644 index 00000000..7fc9b966 --- /dev/null +++ b/OpenMesh.kdevelop.filelist @@ -0,0 +1,839 @@ +# KDevelop Custom Project File List +ACGMakefile +ACGMakefile.proj +CHANGES +LICENSE +make-release.sh +Makefile +migrate.sh +OpenMesh.filelist +OpenMesh.kdevelop +OpenMesh.kdevprj +OpenMesh.kdevses +README +release.howto +TODO +VERSION +Tools/ACGMakefile +Tools/Win32/msvc7/OpenMeshTools.sln +Tools/Win32/msvc7/test_Storage/CVS/Entries +Tools/Win32/msvc7/test_Storage/CVS/Repository +Tools/Win32/msvc7/test_Storage/CVS/Root +Tools/Win32/msvc7/test_Property/test_Property.vcproj +Tools/Win32/msvc7/test_Property/CVS/Entries +Tools/Win32/msvc7/test_Property/CVS/Repository +Tools/Win32/msvc7/test_Property/CVS/Root +Tools/Win32/msvc7/test_mesh/test_mesh.vcproj +Tools/Win32/msvc7/test_mesh/CVS/Entries +Tools/Win32/msvc7/test_mesh/CVS/Repository +Tools/Win32/msvc7/test_mesh/CVS/Root +Tools/Win32/msvc7/test_DynProperty/CVS/Entries +Tools/Win32/msvc7/test_DynProperty/CVS/Repository +Tools/Win32/msvc7/test_DynProperty/CVS/Root +Tools/Win32/msvc7/test_Any/test_Any.vcproj +Tools/Win32/msvc7/test_Any/CVS/Entries +Tools/Win32/msvc7/test_Any/CVS/Repository +Tools/Win32/msvc7/test_Any/CVS/Root +Tools/Win32/msvc7/OpenMeshTools/OpenMeshTools.vcproj +Tools/Win32/msvc7/OpenMeshTools/CVS/Entries +Tools/Win32/msvc7/OpenMeshTools/CVS/Repository +Tools/Win32/msvc7/OpenMeshTools/CVS/Root +Tools/Win32/msvc7/CVS/Entries +Tools/Win32/msvc7/CVS/Entries.Log +Tools/Win32/msvc7/CVS/Repository +Tools/Win32/msvc7/CVS/Root +Tools/Win32/CVS/Entries +Tools/Win32/CVS/Entries.Log +Tools/Win32/CVS/Repository +Tools/Win32/CVS/Root +Tools/Utils/ACGMakefile +Tools/Utils/Config.hh +Tools/Utils/getopt.c +Tools/Utils/getopt.h +Tools/Utils/HeapT.hh +Tools/Utils/MeshCheckerT.cc +Tools/Utils/MeshCheckerT.hh +Tools/Utils/NumLimitsT.hh +Tools/Utils/StripifierT.cc +Tools/Utils/StripifierT.hh +Tools/Utils/TestingFramework.hh +Tools/Utils/Timer.cc +Tools/Utils/Timer.hh +Tools/Utils/Linux9.1_gcc_max/MeshCheckerT.lib.dep +Tools/Utils/Linux9.1_gcc_max/MeshCheckerT.lib.o +Tools/Utils/Linux9.1_gcc_max/StripifierT.lib.dep +Tools/Utils/Linux9.1_gcc_max/StripifierT.lib.o +Tools/Utils/Linux9.1_gcc_max/Timer.lib.dep +Tools/Utils/Linux9.1_gcc_max/Timer.lib.o +Tools/Utils/Linux9.1_gcc_dbg/MeshCheckerT.lib.dep +Tools/Utils/Linux9.1_gcc_dbg/MeshCheckerT.lib.o +Tools/Utils/Linux9.1_gcc_dbg/StripifierT.lib.dep +Tools/Utils/Linux9.1_gcc_dbg/StripifierT.lib.o +Tools/Utils/Linux9.1_gcc_dbg/Timer.lib.dep +Tools/Utils/Linux9.1_gcc_dbg/Timer.lib.o +Tools/Utils/CVS/Entries +Tools/Utils/CVS/Repository +Tools/Utils/CVS/Root +Tools/Test/ACGMakefile +Tools/Test/test_compiler.cc +Tools/Test/test_mesh.cc +Tools/Test/test_MeshIOOptions.cc +Tools/Test/test_StoreRestore.cc +Tools/Test/test_vector_cast.cc +Tools/Test/CVS/Entries +Tools/Test/CVS/Repository +Tools/Test/CVS/Root +Tools/Subdivider/ACGMakefile +Tools/Subdivider/Uniform/ACGMakefile +Tools/Subdivider/Uniform/LoopT.hh +Tools/Subdivider/Uniform/Sqrt3T.hh +Tools/Subdivider/Uniform/CVS/Entries +Tools/Subdivider/Uniform/CVS/Entries.Log +Tools/Subdivider/Uniform/CVS/Repository +Tools/Subdivider/Uniform/CVS/Root +Tools/Subdivider/Uniform/Composite/ACGMakefile +Tools/Subdivider/Uniform/Composite/CompositeT.cc +Tools/Subdivider/Uniform/Composite/CompositeT.hh +Tools/Subdivider/Uniform/Composite/CompositeTraits.hh +Tools/Subdivider/Uniform/Composite/Linux9.1_gcc_max/CompositeT.lib.dep +Tools/Subdivider/Uniform/Composite/Linux9.1_gcc_max/CompositeT.lib.o +Tools/Subdivider/Uniform/Composite/Linux9.1_gcc_dbg/CompositeT.lib.dep +Tools/Subdivider/Uniform/Composite/Linux9.1_gcc_dbg/CompositeT.lib.o +Tools/Subdivider/Uniform/Composite/CVS/Entries +Tools/Subdivider/Uniform/Composite/CVS/Repository +Tools/Subdivider/Uniform/Composite/CVS/Root +Tools/Subdivider/CVS/Entries +Tools/Subdivider/CVS/Entries.Log +Tools/Subdivider/CVS/Repository +Tools/Subdivider/CVS/Root +Tools/Subdivider/Adaptive/ACGMakefile +Tools/Subdivider/Adaptive/CVS/Entries +Tools/Subdivider/Adaptive/CVS/Entries.Log +Tools/Subdivider/Adaptive/CVS/Repository +Tools/Subdivider/Adaptive/CVS/Root +Tools/Subdivider/Adaptive/Composite/ACGMakefile +Tools/Subdivider/Adaptive/Composite/CompositeT.cc +Tools/Subdivider/Adaptive/Composite/CompositeT.hh +Tools/Subdivider/Adaptive/Composite/RuleInterfaceT.hh +Tools/Subdivider/Adaptive/Composite/RulesT.cc +Tools/Subdivider/Adaptive/Composite/RulesT.hh +Tools/Subdivider/Adaptive/Composite/Traits.hh +Tools/Subdivider/Adaptive/Composite/Test/ACGMakefile +Tools/Subdivider/Adaptive/Composite/Test/loop_adaptive_subdivide.cc +Tools/Subdivider/Adaptive/Composite/Test/loop_uniform_subdivide.cc +Tools/Subdivider/Adaptive/Composite/Test/sqrt3_adaptive_subdivide.cc +Tools/Subdivider/Adaptive/Composite/Test/sqrt3_selective_subdivide.cc +Tools/Subdivider/Adaptive/Composite/Test/sqrt3_uniform_subdivide.cc +Tools/Subdivider/Adaptive/Composite/Test/Tvv3_VF_FFc_FV_VV_VVc_uniform_subdivide.cc +Tools/Subdivider/Adaptive/Composite/Test/Tvv3_VF_FV_VF_FV_uniform_subdivide.cc +Tools/Subdivider/Adaptive/Composite/Test/Tvv4_VdE_EV_VE_EdE_EVc_uniform_subdivide.cc +Tools/Subdivider/Adaptive/Composite/Test/CVS/Entries +Tools/Subdivider/Adaptive/Composite/Test/CVS/Repository +Tools/Subdivider/Adaptive/Composite/Test/CVS/Root +Tools/Subdivider/Adaptive/Composite/Linux9.1_gcc_max/CompositeT.dep +Tools/Subdivider/Adaptive/Composite/Linux9.1_gcc_max/CompositeT.o +Tools/Subdivider/Adaptive/Composite/Linux9.1_gcc_max/libOpenMesh_Tools_Subdivider_Adaptive_Composite.so +Tools/Subdivider/Adaptive/Composite/Linux9.1_gcc_max/RulesT.dep +Tools/Subdivider/Adaptive/Composite/Linux9.1_gcc_max/RulesT.o +Tools/Subdivider/Adaptive/Composite/Linux9.1_gcc_dbg/CompositeT.dep +Tools/Subdivider/Adaptive/Composite/Linux9.1_gcc_dbg/CompositeT.o +Tools/Subdivider/Adaptive/Composite/Linux9.1_gcc_dbg/libOpenMesh_Tools_Subdivider_Adaptive_Composite.so +Tools/Subdivider/Adaptive/Composite/Linux9.1_gcc_dbg/RulesT.dep +Tools/Subdivider/Adaptive/Composite/Linux9.1_gcc_dbg/RulesT.o +Tools/Subdivider/Adaptive/Composite/CVS/Entries +Tools/Subdivider/Adaptive/Composite/CVS/Entries.Log +Tools/Subdivider/Adaptive/Composite/CVS/Repository +Tools/Subdivider/Adaptive/Composite/CVS/Root +Tools/Smoother/smooth_mesh.hh +Tools/OpenSG/Mesh/Types/CVS/Entries +Tools/OpenSG/Mesh/Types/CVS/Repository +Tools/OpenSG/Mesh/Types/CVS/Root +Tools/OpenSG/Mesh/Kernels/OSGGeometryKernel/CVS/Entries +Tools/OpenSG/Mesh/Kernels/OSGGeometryKernel/CVS/Repository +Tools/OpenSG/Mesh/Kernels/OSGGeometryKernel/CVS/Root +Tools/OpenSG/Mesh/Kernels/CVS/Entries +Tools/OpenSG/Mesh/Kernels/CVS/Entries.Log +Tools/OpenSG/Mesh/Kernels/CVS/Repository +Tools/OpenSG/Mesh/Kernels/CVS/Root +Tools/OpenSG/Mesh/CVS/Entries +Tools/OpenSG/Mesh/CVS/Entries.Log +Tools/OpenSG/Mesh/CVS/Repository +Tools/OpenSG/Mesh/CVS/Root +Tools/OpenSG/CVS/Entries +Tools/OpenSG/CVS/Entries.Log +Tools/OpenSG/CVS/Repository +Tools/OpenSG/CVS/Root +Tools/Linux9.1_gcc_max/libOpenMesh_Tools.so +Tools/Linux9.1_gcc_dbg/libOpenMesh_Tools.so +Tools/Kernel_OSG/ACGMakefile +Tools/Kernel_OSG/ArrayKernelT.hh +Tools/Kernel_OSG/AttribKernelT.hh +Tools/Kernel_OSG/PropertyKernel.hh +Tools/Kernel_OSG/PropertyT.hh +Tools/Kernel_OSG/Traits.hh +Tools/Kernel_OSG/TriMesh_OSGArrayKernelT.hh +Tools/Kernel_OSG/VectorAdapter.hh +Tools/Kernel_OSG/CVS/Entries +Tools/Kernel_OSG/CVS/Repository +Tools/Kernel_OSG/CVS/Root +Tools/Geometry/ACGMakefile +Tools/Geometry/Config.hh +Tools/Geometry/QuadricT.hh +Tools/Geometry/CVS/Entries +Tools/Geometry/CVS/Repository +Tools/Geometry/CVS/Root +Tools/Doc/CVS/Entries +Tools/Doc/CVS/Repository +Tools/Doc/CVS/Root +Tools/Decimater/ACGMakefile +Tools/Decimater/CollapseInfoT.hh +Tools/Decimater/DecimaterT.cc +Tools/Decimater/DecimaterT.hh +Tools/Decimater/ModBaseT.hh +Tools/Decimater/ModIndependentSetsT.hh +Tools/Decimater/ModNormalFlippingT.hh +Tools/Decimater/ModProgMeshT.cc +Tools/Decimater/ModProgMeshT.hh +Tools/Decimater/ModQuadricT.cc +Tools/Decimater/ModQuadricT.hh +Tools/Decimater/ModRoundnessT.hh +Tools/Decimater/Linux9.1_gcc_max/DecimaterT.lib.dep +Tools/Decimater/Linux9.1_gcc_max/DecimaterT.lib.o +Tools/Decimater/Linux9.1_gcc_max/ModProgMeshT.lib.dep +Tools/Decimater/Linux9.1_gcc_max/ModProgMeshT.lib.o +Tools/Decimater/Linux9.1_gcc_max/ModQuadricT.lib.dep +Tools/Decimater/Linux9.1_gcc_max/ModQuadricT.lib.o +Tools/Decimater/Linux9.1_gcc_dbg/DecimaterT.lib.dep +Tools/Decimater/Linux9.1_gcc_dbg/DecimaterT.lib.o +Tools/Decimater/Linux9.1_gcc_dbg/ModProgMeshT.lib.dep +Tools/Decimater/Linux9.1_gcc_dbg/ModProgMeshT.lib.o +Tools/Decimater/Linux9.1_gcc_dbg/ModQuadricT.lib.dep +Tools/Decimater/Linux9.1_gcc_dbg/ModQuadricT.lib.o +Tools/Decimater/CVS/Entries +Tools/Decimater/CVS/Entries.Log +Tools/Decimater/CVS/Repository +Tools/Decimater/CVS/Root +Tools/Decimater/backup/CVS/Entries +Tools/Decimater/backup/CVS/Repository +Tools/Decimater/backup/CVS/Root +Tools/CVS/Entries +Tools/CVS/Entries.Log +Tools/CVS/Repository +Tools/CVS/Root +templates/cpp +templates/h +openmesh/templates/cpp_template +openmesh/templates/header_template +CVS/Entries +CVS/Entries.Log +CVS/Entries.Static +CVS/Repository +CVS/Root +Core/ACGMakefile +Core/Win32/MSVC/OpenMesh.sln +Core/Win32/MSVC/README +Core/Win32/MSVC/OpenMesh_shared/CVS/Entries +Core/Win32/MSVC/OpenMesh_shared/CVS/Repository +Core/Win32/MSVC/OpenMesh_shared/CVS/Root +Core/Win32/MSVC/OpenMesh/OpenMesh.vcproj +Core/Win32/MSVC/OpenMesh/CVS/Entries +Core/Win32/MSVC/OpenMesh/CVS/Repository +Core/Win32/MSVC/OpenMesh/CVS/Root +Core/Win32/MSVC/CVS/Entries +Core/Win32/MSVC/CVS/Entries.Log +Core/Win32/MSVC/CVS/Repository +Core/Win32/MSVC/CVS/Root +Core/Win32/MSVC/06-generic_algorithms/06-generic_algorithms.vcproj +Core/Win32/MSVC/06-generic_algorithms/CVS/Entries +Core/Win32/MSVC/06-generic_algorithms/CVS/Repository +Core/Win32/MSVC/06-generic_algorithms/CVS/Root +Core/Win32/MSVC/05-attributes/05-attributes.vcproj +Core/Win32/MSVC/05-attributes/CVS/Entries +Core/Win32/MSVC/05-attributes/CVS/Repository +Core/Win32/MSVC/05-attributes/CVS/Root +Core/Win32/MSVC/04-stl_algorithms/04-stl_algorithms.vcproj +Core/Win32/MSVC/04-stl_algorithms/CVS/Entries +Core/Win32/MSVC/04-stl_algorithms/CVS/Repository +Core/Win32/MSVC/04-stl_algorithms/CVS/Root +Core/Win32/MSVC/03-traits/03-traits.vcproj +Core/Win32/MSVC/03-traits/CVS/Entries +Core/Win32/MSVC/03-traits/CVS/Repository +Core/Win32/MSVC/03-traits/CVS/Root +Core/Win32/MSVC/02-iterator/o2-iterators.vcproj +Core/Win32/MSVC/02-iterator/CVS/Entries +Core/Win32/MSVC/02-iterator/CVS/Repository +Core/Win32/MSVC/02-iterator/CVS/Root +Core/Win32/MSVC/01-build_cube/01-build_cube.vcproj +Core/Win32/MSVC/01-build_cube/CVS/Entries +Core/Win32/MSVC/01-build_cube/CVS/Repository +Core/Win32/MSVC/01-build_cube/CVS/Root +Core/Win32/CVS/Entries +Core/Win32/CVS/Entries.Log +Core/Win32/CVS/Repository +Core/Win32/CVS/Root +Core/Utils/ACGMakefile +Core/Utils/AutoPropertyHandleT.hh +Core/Utils/Endian.cc +Core/Utils/Endian.hh +Core/Utils/GenProg.hh +Core/Utils/Noncopyable.hh +Core/Utils/Property.hh +Core/Utils/SingletonT.cc +Core/Utils/SingletonT.hh +Core/Utils/vector_cast.hh +Core/Utils/vector_traits.hh +Core/Utils/Linux9.1_gcc_max/Endian.lib.dep +Core/Utils/Linux9.1_gcc_max/Endian.lib.o +Core/Utils/Linux9.1_gcc_max/SingletonT.lib.dep +Core/Utils/Linux9.1_gcc_max/SingletonT.lib.o +Core/Utils/Linux9.1_gcc_dbg/Endian.lib.dep +Core/Utils/Linux9.1_gcc_dbg/Endian.lib.o +Core/Utils/Linux9.1_gcc_dbg/SingletonT.lib.dep +Core/Utils/Linux9.1_gcc_dbg/SingletonT.lib.o +Core/Utils/CVS/Entries +Core/Utils/CVS/Repository +Core/Utils/CVS/Root +Core/Tools/CVS/Entries +Core/Tools/CVS/Repository +Core/Tools/CVS/Root +Core/Templates/newClass.cc +Core/Templates/newClass.hh +Core/Templates/newClass.sh +Core/Templates/newClassT.cc +Core/Templates/newClassT.hh +Core/Templates/newClassT.sh +Core/Templates/CVS/Entries +Core/Templates/CVS/Repository +Core/Templates/CVS/Root +Core/System/ACGMakefile +Core/System/compiler.h +Core/System/config.h +Core/System/mostream.hh +Core/System/omstream.cc +Core/System/omstream.hh +Core/System/Linux9.1_gcc_max/omstream.lib.dep +Core/System/Linux9.1_gcc_max/omstream.lib.o +Core/System/Linux9.1_gcc_dbg/omstream.lib.dep +Core/System/Linux9.1_gcc_dbg/omstream.lib.o +Core/System/CVS/Entries +Core/System/CVS/Repository +Core/System/CVS/Root +Core/Mesh/ACGMakefile +Core/Mesh/BaseMesh.hh +Core/Mesh/PolyMeshT.cc +Core/Mesh/PolyMeshT.hh +Core/Mesh/Traits.hh +Core/Mesh/TriMeshT.cc +Core/Mesh/TriMeshT.hh +Core/Mesh/Types/PolyMesh_ArrayKernelT.hh +Core/Mesh/Types/TriMesh_ArrayKernelT.hh +Core/Mesh/Types/CVS/Entries +Core/Mesh/Types/CVS/Repository +Core/Mesh/Types/CVS/Root +Core/Mesh/Linux9.1_gcc_max/PolyMeshT.lib.dep +Core/Mesh/Linux9.1_gcc_max/PolyMeshT.lib.o +Core/Mesh/Linux9.1_gcc_max/TriMeshT.lib.dep +Core/Mesh/Linux9.1_gcc_max/TriMeshT.lib.o +Core/Mesh/Linux9.1_gcc_dbg/PolyMeshT.lib.dep +Core/Mesh/Linux9.1_gcc_dbg/PolyMeshT.lib.o +Core/Mesh/Linux9.1_gcc_dbg/TriMeshT.lib.dep +Core/Mesh/Linux9.1_gcc_dbg/TriMeshT.lib.o +Core/Mesh/Kernels/ACGMakefile +Core/Mesh/Kernels/SharedCoordArrayKernel/CVS/Entries +Core/Mesh/Kernels/SharedCoordArrayKernel/CVS/Repository +Core/Mesh/Kernels/SharedCoordArrayKernel/CVS/Root +Core/Mesh/Kernels/ListKernel/CVS/Entries +Core/Mesh/Kernels/ListKernel/CVS/Repository +Core/Mesh/Kernels/ListKernel/CVS/Root +Core/Mesh/Kernels/CVS/Entries +Core/Mesh/Kernels/CVS/Entries.Log +Core/Mesh/Kernels/CVS/Repository +Core/Mesh/Kernels/CVS/Root +Core/Mesh/Kernels/Common/AttribKernelT.hh +Core/Mesh/Kernels/Common/BaseKernel.hh +Core/Mesh/Kernels/Common/FinalMeshItemsT.hh +Core/Mesh/Kernels/Common/Handles.hh +Core/Mesh/Kernels/Common/CVS/Entries +Core/Mesh/Kernels/Common/CVS/Repository +Core/Mesh/Kernels/Common/CVS/Root +Core/Mesh/Kernels/ArrayKernel/ArrayItems.hh +Core/Mesh/Kernels/ArrayKernel/ArrayKernelT.hh +Core/Mesh/Kernels/ArrayKernel/CVS/Entries +Core/Mesh/Kernels/ArrayKernel/CVS/Repository +Core/Mesh/Kernels/ArrayKernel/CVS/Root +Core/Mesh/Iterators/ACGMakefile +Core/Mesh/Iterators/CirculatorsT.hh +Core/Mesh/Iterators/IteratorsT.hh +Core/Mesh/Iterators/gen/circulators_header.hh +Core/Mesh/Iterators/gen/circulators_template.hh +Core/Mesh/Iterators/gen/footer.hh +Core/Mesh/Iterators/gen/generate.sh +Core/Mesh/Iterators/gen/iterators_header.hh +Core/Mesh/Iterators/gen/iterators_template.hh +Core/Mesh/Iterators/gen/CVS/Entries +Core/Mesh/Iterators/gen/CVS/Repository +Core/Mesh/Iterators/gen/CVS/Root +Core/Mesh/Iterators/CVS/Entries +Core/Mesh/Iterators/CVS/Entries.Log +Core/Mesh/Iterators/CVS/Repository +Core/Mesh/Iterators/CVS/Root +Core/Mesh/CVS/Entries +Core/Mesh/CVS/Entries.Log +Core/Mesh/CVS/Repository +Core/Mesh/CVS/Root +Core/Math/ACGMakefile +Core/Math/LoopSchemeMaskT.hh +Core/Math/MathDefs.hh +Core/Math/VectorT.hh +Core/Math/VectorT_inc.hh +Core/Math/CVS/Entries +Core/Math/CVS/Repository +Core/Math/CVS/Root +Core/Linux9.1_gcc_max/libOpenMesh_Core.so +Core/Linux9.1_gcc_dbg/libOpenMesh_Core.so +Core/IO/ACGMakefile +Core/IO/BinaryHelper.cc +Core/IO/BinaryHelper.hh +Core/IO/IOInstances.hh +Core/IO/IOManager.cc +Core/IO/IOManager.hh +Core/IO/MeshIO.hh +Core/IO/OFFFormat.hh +Core/IO/OMFormat.cc +Core/IO/OMFormat.hh +Core/IO/Options.hh +Core/IO/writer/ACGMakefile +Core/IO/writer/BaseWriter.cc +Core/IO/writer/BaseWriter.hh +Core/IO/writer/OBJWriter.cc +Core/IO/writer/OBJWriter.hh +Core/IO/writer/OFFWriter.cc +Core/IO/writer/OFFWriter.hh +Core/IO/writer/OMWriter.cc +Core/IO/writer/OMWriter.hh +Core/IO/writer/STLWriter.cc +Core/IO/writer/STLWriter.hh +Core/IO/writer/Linux9.1_gcc_max/BaseWriter.lib.dep +Core/IO/writer/Linux9.1_gcc_max/BaseWriter.lib.o +Core/IO/writer/Linux9.1_gcc_max/OBJWriter.lib.dep +Core/IO/writer/Linux9.1_gcc_max/OBJWriter.lib.o +Core/IO/writer/Linux9.1_gcc_max/OFFWriter.lib.dep +Core/IO/writer/Linux9.1_gcc_max/OFFWriter.lib.o +Core/IO/writer/Linux9.1_gcc_max/OMWriter.lib.dep +Core/IO/writer/Linux9.1_gcc_max/OMWriter.lib.o +Core/IO/writer/Linux9.1_gcc_max/STLWriter.lib.dep +Core/IO/writer/Linux9.1_gcc_max/STLWriter.lib.o +Core/IO/writer/Linux9.1_gcc_dbg/BaseWriter.lib.dep +Core/IO/writer/Linux9.1_gcc_dbg/BaseWriter.lib.o +Core/IO/writer/Linux9.1_gcc_dbg/OBJWriter.lib.dep +Core/IO/writer/Linux9.1_gcc_dbg/OBJWriter.lib.o +Core/IO/writer/Linux9.1_gcc_dbg/OFFWriter.lib.dep +Core/IO/writer/Linux9.1_gcc_dbg/OFFWriter.lib.o +Core/IO/writer/Linux9.1_gcc_dbg/OMWriter.lib.dep +Core/IO/writer/Linux9.1_gcc_dbg/OMWriter.lib.o +Core/IO/writer/Linux9.1_gcc_dbg/STLWriter.lib.dep +Core/IO/writer/Linux9.1_gcc_dbg/STLWriter.lib.o +Core/IO/writer/CVS/Entries +Core/IO/writer/CVS/Repository +Core/IO/writer/CVS/Root +Core/IO/reader/ACGMakefile +Core/IO/reader/BaseReader.cc +Core/IO/reader/BaseReader.hh +Core/IO/reader/OBJReader.cc +Core/IO/reader/OBJReader.hh +Core/IO/reader/OFFReader.cc +Core/IO/reader/OFFReader.hh +Core/IO/reader/OMReader.cc +Core/IO/reader/OMReader.hh +Core/IO/reader/STLReader.cc +Core/IO/reader/STLReader.hh +Core/IO/reader/Linux9.1_gcc_max/BaseReader.lib.dep +Core/IO/reader/Linux9.1_gcc_max/BaseReader.lib.o +Core/IO/reader/Linux9.1_gcc_max/OBJReader.lib.dep +Core/IO/reader/Linux9.1_gcc_max/OBJReader.lib.o +Core/IO/reader/Linux9.1_gcc_max/OFFReader.lib.dep +Core/IO/reader/Linux9.1_gcc_max/OFFReader.lib.o +Core/IO/reader/Linux9.1_gcc_max/OMReader.lib.dep +Core/IO/reader/Linux9.1_gcc_max/OMReader.lib.o +Core/IO/reader/Linux9.1_gcc_max/STLReader.lib.dep +Core/IO/reader/Linux9.1_gcc_max/STLReader.lib.o +Core/IO/reader/Linux9.1_gcc_dbg/BaseReader.lib.dep +Core/IO/reader/Linux9.1_gcc_dbg/BaseReader.lib.o +Core/IO/reader/Linux9.1_gcc_dbg/OBJReader.lib.dep +Core/IO/reader/Linux9.1_gcc_dbg/OBJReader.lib.o +Core/IO/reader/Linux9.1_gcc_dbg/OFFReader.lib.dep +Core/IO/reader/Linux9.1_gcc_dbg/OFFReader.lib.o +Core/IO/reader/Linux9.1_gcc_dbg/OMReader.lib.dep +Core/IO/reader/Linux9.1_gcc_dbg/OMReader.lib.o +Core/IO/reader/Linux9.1_gcc_dbg/STLReader.lib.dep +Core/IO/reader/Linux9.1_gcc_dbg/STLReader.lib.o +Core/IO/reader/CVS/Entries +Core/IO/reader/CVS/Repository +Core/IO/reader/CVS/Root +Core/IO/loader/CVS/Entries +Core/IO/loader/CVS/Repository +Core/IO/loader/CVS/Root +Core/IO/Linux9.1_gcc_max/BinaryHelper.lib.dep +Core/IO/Linux9.1_gcc_max/BinaryHelper.lib.o +Core/IO/Linux9.1_gcc_max/IOManager.lib.dep +Core/IO/Linux9.1_gcc_max/IOManager.lib.o +Core/IO/Linux9.1_gcc_max/OMFormat.lib.dep +Core/IO/Linux9.1_gcc_max/OMFormat.lib.o +Core/IO/Linux9.1_gcc_dbg/BinaryHelper.lib.dep +Core/IO/Linux9.1_gcc_dbg/BinaryHelper.lib.o +Core/IO/Linux9.1_gcc_dbg/IOManager.lib.dep +Core/IO/Linux9.1_gcc_dbg/IOManager.lib.o +Core/IO/Linux9.1_gcc_dbg/OMFormat.lib.dep +Core/IO/Linux9.1_gcc_dbg/OMFormat.lib.o +Core/IO/importer/ACGMakefile +Core/IO/importer/BaseImporter.hh +Core/IO/importer/ImporterT.hh +Core/IO/importer/CVS/Entries +Core/IO/importer/CVS/Repository +Core/IO/importer/CVS/Root +Core/IO/exporter/ACGMakefile +Core/IO/exporter/BaseExporter.hh +Core/IO/exporter/ExporterT.hh +Core/IO/exporter/CVS/Entries +Core/IO/exporter/CVS/Repository +Core/IO/exporter/CVS/Root +Core/IO/CVS/Entries +Core/IO/CVS/Entries.Log +Core/IO/CVS/Repository +Core/IO/CVS/Root +Core/Docu/ACGMakefile +Core/Docu/history.docu +Core/Docu/mainpage.docu +Core/Docu/mesh.docu +Core/Docu/misc.docu +Core/Docu/namespaces.docu +Core/Docu/tutorial_01.docu +Core/Docu/tutorial_02.docu +Core/Docu/tutorial_03.docu +Core/Docu/tutorial_04.docu +Core/Docu/tutorial_05.docu +Core/Docu/tutorial_06.docu +Core/Docu/tutorial_main.docu +Core/Docu/Tutorial/ACGMakefile +Core/Docu/Tutorial/CVS/Entries +Core/Docu/Tutorial/CVS/Entries.Log +Core/Docu/Tutorial/CVS/Repository +Core/Docu/Tutorial/CVS/Root +Core/Docu/Tutorial/07-properties/ACGMakefile +Core/Docu/Tutorial/07-properties/smooth.cc +Core/Docu/Tutorial/07-properties/smooth_algo.hh +Core/Docu/Tutorial/07-properties/CVS/Entries +Core/Docu/Tutorial/07-properties/CVS/Repository +Core/Docu/Tutorial/07-properties/CVS/Root +Core/Docu/Tutorial/06-generic_algorithms/ACGMakefile +Core/Docu/Tutorial/06-generic_algorithms/smooth.cc +Core/Docu/Tutorial/06-generic_algorithms/smooth_algo.hh +Core/Docu/Tutorial/06-generic_algorithms/CVS/Entries +Core/Docu/Tutorial/06-generic_algorithms/CVS/Repository +Core/Docu/Tutorial/06-generic_algorithms/CVS/Root +Core/Docu/Tutorial/05-attributes/ACGMakefile +Core/Docu/Tutorial/05-attributes/attributes.cc +Core/Docu/Tutorial/05-attributes/CVS/Entries +Core/Docu/Tutorial/05-attributes/CVS/Repository +Core/Docu/Tutorial/05-attributes/CVS/Root +Core/Docu/Tutorial/04-stl_algorithms/ACGMakefile +Core/Docu/Tutorial/04-stl_algorithms/smooth.cc +Core/Docu/Tutorial/04-stl_algorithms/CVS/Entries +Core/Docu/Tutorial/04-stl_algorithms/CVS/Repository +Core/Docu/Tutorial/04-stl_algorithms/CVS/Root +Core/Docu/Tutorial/03-traits/ACGMakefile +Core/Docu/Tutorial/03-traits/smooth.cc +Core/Docu/Tutorial/03-traits/CVS/Entries +Core/Docu/Tutorial/03-traits/CVS/Repository +Core/Docu/Tutorial/03-traits/CVS/Root +Core/Docu/Tutorial/02-iterators/ACGMakefile +Core/Docu/Tutorial/02-iterators/smooth.cc +Core/Docu/Tutorial/02-iterators/CVS/Entries +Core/Docu/Tutorial/02-iterators/CVS/Repository +Core/Docu/Tutorial/02-iterators/CVS/Root +Core/Docu/Tutorial/01-build_cube/ACGMakefile +Core/Docu/Tutorial/01-build_cube/build_cube.cc +Core/Docu/Tutorial/01-build_cube/CVS/Entries +Core/Docu/Tutorial/01-build_cube/CVS/Repository +Core/Docu/Tutorial/01-build_cube/CVS/Root +Core/Docu/images/halfedge_structure.gif +Core/Docu/images/inheritance.fig +Core/Docu/images/inheritance.gif +Core/Docu/images/iomanager.gif +Core/Docu/images/CVS/Entries +Core/Docu/images/CVS/Repository +Core/Docu/images/CVS/Root +Core/Docu/Examples/BaseExporter.hh +Core/Docu/Examples/BaseImporter.hh +Core/Docu/Examples/BaseReader.hh +Core/Docu/Examples/circulators.cc +Core/Docu/Examples/draw_normals.cc +Core/Docu/Examples/iterators.cc +Core/Docu/Examples/mesh_io.cc +Core/Docu/Examples/mymesh.cc +Core/Docu/Examples/traits0.cc +Core/Docu/Examples/traits1.cc +Core/Docu/Examples/traits2.cc +Core/Docu/Examples/traits3.cc +Core/Docu/Examples/traits4.cc +Core/Docu/Examples/traits5.cc +Core/Docu/Examples/CVS/Entries +Core/Docu/Examples/CVS/Repository +Core/Docu/Examples/CVS/Root +Core/Docu/CVS/Entries +Core/Docu/CVS/Entries.Log +Core/Docu/CVS/Repository +Core/Docu/CVS/Root +Core/Docu/Concepts/MeshHandles.hh +Core/Docu/Concepts/MeshItems.hh +Core/Docu/Concepts/MeshKernel.hh +Core/Docu/Concepts/CVS/Entries +Core/Docu/Concepts/CVS/Repository +Core/Docu/Concepts/CVS/Root +Core/Dist/ACGMakefile +Core/Dist/ACGMakefile.proj +Core/Dist/CHANGES +Core/Dist/LICENSE +Core/Dist/make-release.sh +Core/Dist/migrate.sh +Core/Dist/README +Core/Dist/release.howto +Core/Dist/TODO +Core/Dist/VERSION +Core/Dist/CVS/Entries +Core/Dist/CVS/Repository +Core/Dist/CVS/Root +Core/CVS/Entries +Core/CVS/Entries.Log +Core/CVS/Repository +Core/CVS/Root +Core/Attributes/Attributes.hh +Core/Attributes/Status.hh +Core/Attributes/CVS/Entries +Core/Attributes/CVS/Repository +Core/Attributes/CVS/Root +bin/decimater_dbg +bin/decimater_max +bin/decimaterviewer_dbg +bin/decimaterviewer_max +bin/meshviewer_dbg +bin/meshviewer_max +bin/progviewer_dbg +bin/progviewer_max +bin/qtsubdivider_max +bin/smooth_dbg +bin/smooth_max +bin/subdivider_max +Apps/ACGMakefile +Apps/Win32/MSVC/OpenMeshApps.sln +Apps/Win32/MSVC/README +Apps/Win32/MSVC/Subdivider/Subdivider.vcproj +Apps/Win32/MSVC/Subdivider/CVS/Entries +Apps/Win32/MSVC/Subdivider/CVS/Repository +Apps/Win32/MSVC/Subdivider/CVS/Root +Apps/Win32/MSVC/smooth/smooth.vcproj +Apps/Win32/MSVC/smooth/CVS/Entries +Apps/Win32/MSVC/smooth/CVS/Repository +Apps/Win32/MSVC/smooth/CVS/Root +Apps/Win32/MSVC/QtViewer/QtViewer.vcproj +Apps/Win32/MSVC/QtViewer/CVS/Entries +Apps/Win32/MSVC/QtViewer/CVS/Repository +Apps/Win32/MSVC/QtViewer/CVS/Root +Apps/Win32/MSVC/ProgViewer/ProgViewer.vcproj +Apps/Win32/MSVC/ProgViewer/CVS/Entries +Apps/Win32/MSVC/ProgViewer/CVS/Repository +Apps/Win32/MSVC/ProgViewer/CVS/Root +Apps/Win32/MSVC/CVS/Entries +Apps/Win32/MSVC/CVS/Entries.Log +Apps/Win32/MSVC/CVS/Repository +Apps/Win32/MSVC/CVS/Root +Apps/Win32/CVS/Entries +Apps/Win32/CVS/Entries.Log +Apps/Win32/CVS/Repository +Apps/Win32/CVS/Root +Apps/Subdivider/ACGMakefile +Apps/Subdivider/MeshViewerWidget.cc +Apps/Subdivider/MeshViewerWidget.hh +Apps/Subdivider/qtsubdivider.cc +Apps/Subdivider/subdivider.cc +Apps/Subdivider/SubdivideWidget.cc +Apps/Subdivider/SubdivideWidget.hh +Apps/Subdivider/Linux9.1_gcc_max/libOpenMesh_Apps_Subdivider.so +Apps/Subdivider/Linux9.1_gcc_max/MeshViewerWidget.dep +Apps/Subdivider/Linux9.1_gcc_max/MeshViewerWidget.o +Apps/Subdivider/Linux9.1_gcc_max/qtsubdivider +Apps/Subdivider/Linux9.1_gcc_max/qtsubdivider.dep +Apps/Subdivider/Linux9.1_gcc_max/qtsubdivider.o +Apps/Subdivider/Linux9.1_gcc_max/subdivider +Apps/Subdivider/Linux9.1_gcc_max/subdivider.dep +Apps/Subdivider/Linux9.1_gcc_max/subdivider.o +Apps/Subdivider/Linux9.1_gcc_max/SubdivideWidget.dep +Apps/Subdivider/Linux9.1_gcc_max/SubdivideWidget.moc.cc +Apps/Subdivider/Linux9.1_gcc_max/SubdivideWidget.moc.dep +Apps/Subdivider/Linux9.1_gcc_max/SubdivideWidget.moc.o +Apps/Subdivider/Linux9.1_gcc_max/SubdivideWidget.o +Apps/Subdivider/CVS/Entries +Apps/Subdivider/CVS/Repository +Apps/Subdivider/CVS/Root +Apps/Smoothing/ACGMakefile +Apps/Smoothing/smooth.cc +Apps/Smoothing/Linux9.1_gcc_max/smooth +Apps/Smoothing/Linux9.1_gcc_max/smooth.dep +Apps/Smoothing/Linux9.1_gcc_max/smooth.o +Apps/Smoothing/Linux9.1_gcc_dbg/smooth +Apps/Smoothing/Linux9.1_gcc_dbg/smooth.dep +Apps/Smoothing/Linux9.1_gcc_dbg/smooth.o +Apps/Smoothing/CVS/Entries +Apps/Smoothing/CVS/Repository +Apps/Smoothing/CVS/Root +Apps/QtViewer/ACGMakefile +Apps/QtViewer/meshviewer.cc +Apps/QtViewer/MeshViewerWidgetT.cc +Apps/QtViewer/MeshViewerWidgetT.hh +Apps/QtViewer/QGLViewerWidget.cc +Apps/QtViewer/QGLViewerWidget.hh +Apps/QtViewer/Linux9.1_gcc_max/libOpenMesh_Apps_QtViewer.so +Apps/QtViewer/Linux9.1_gcc_max/meshviewer +Apps/QtViewer/Linux9.1_gcc_max/meshviewer.dep +Apps/QtViewer/Linux9.1_gcc_max/meshviewer.o +Apps/QtViewer/Linux9.1_gcc_max/MeshViewerWidgetT.dep +Apps/QtViewer/Linux9.1_gcc_max/MeshViewerWidgetT.o +Apps/QtViewer/Linux9.1_gcc_max/QGLViewerWidget.dep +Apps/QtViewer/Linux9.1_gcc_max/QGLViewerWidget.moc.cc +Apps/QtViewer/Linux9.1_gcc_max/QGLViewerWidget.moc.dep +Apps/QtViewer/Linux9.1_gcc_max/QGLViewerWidget.moc.o +Apps/QtViewer/Linux9.1_gcc_max/QGLViewerWidget.o +Apps/QtViewer/Linux9.1_gcc_dbg/libOpenMesh_Apps_QtViewer.so +Apps/QtViewer/Linux9.1_gcc_dbg/meshviewer +Apps/QtViewer/Linux9.1_gcc_dbg/meshviewer.dep +Apps/QtViewer/Linux9.1_gcc_dbg/meshviewer.o +Apps/QtViewer/Linux9.1_gcc_dbg/MeshViewerWidgetT.dep +Apps/QtViewer/Linux9.1_gcc_dbg/MeshViewerWidgetT.o +Apps/QtViewer/Linux9.1_gcc_dbg/QGLViewerWidget.dep +Apps/QtViewer/Linux9.1_gcc_dbg/QGLViewerWidget.moc.cc +Apps/QtViewer/Linux9.1_gcc_dbg/QGLViewerWidget.moc.dep +Apps/QtViewer/Linux9.1_gcc_dbg/QGLViewerWidget.moc.o +Apps/QtViewer/Linux9.1_gcc_dbg/QGLViewerWidget.o +Apps/QtViewer/CVS/Entries +Apps/QtViewer/CVS/Repository +Apps/QtViewer/CVS/Root +Apps/ProgViewer/ACGMakefile +Apps/ProgViewer/bunny.pm +Apps/ProgViewer/progviewer +Apps/ProgViewer/progviewer.cc +Apps/ProgViewer/ProgViewerWidget.cc +Apps/ProgViewer/ProgViewerWidget.hh +Apps/ProgViewer/pv.tar.gz +Apps/ProgViewer/sphere.pm +Apps/ProgViewer/Linux9.1_gcc_max/libOpenMesh_Apps_ProgViewer.so +Apps/ProgViewer/Linux9.1_gcc_max/progviewer +Apps/ProgViewer/Linux9.1_gcc_max/progviewer.dep +Apps/ProgViewer/Linux9.1_gcc_max/progviewer.o +Apps/ProgViewer/Linux9.1_gcc_max/ProgViewerWidget.dep +Apps/ProgViewer/Linux9.1_gcc_max/ProgViewerWidget.moc.cc +Apps/ProgViewer/Linux9.1_gcc_max/ProgViewerWidget.moc.dep +Apps/ProgViewer/Linux9.1_gcc_max/ProgViewerWidget.moc.o +Apps/ProgViewer/Linux9.1_gcc_max/ProgViewerWidget.o +Apps/ProgViewer/Linux9.1_gcc_dbg/libOpenMesh_Apps_ProgViewer.so +Apps/ProgViewer/Linux9.1_gcc_dbg/progviewer +Apps/ProgViewer/Linux9.1_gcc_dbg/progviewer.dep +Apps/ProgViewer/Linux9.1_gcc_dbg/progviewer.o +Apps/ProgViewer/Linux9.1_gcc_dbg/ProgViewerWidget.dep +Apps/ProgViewer/Linux9.1_gcc_dbg/ProgViewerWidget.moc.cc +Apps/ProgViewer/Linux9.1_gcc_dbg/ProgViewerWidget.moc.dep +Apps/ProgViewer/Linux9.1_gcc_dbg/ProgViewerWidget.moc.o +Apps/ProgViewer/Linux9.1_gcc_dbg/ProgViewerWidget.o +Apps/ProgViewer/CVS/Entries +Apps/ProgViewer/CVS/Repository +Apps/ProgViewer/CVS/Root +Apps/OsgViewer/ACGMakefile +Apps/OsgViewer/meshviewer.cc +Apps/OsgViewer/osgviewer.cc +Apps/OsgViewer/README +Apps/OsgViewer/OpenSG/CVS/Entries +Apps/OsgViewer/OpenSG/CVS/Repository +Apps/OsgViewer/OpenSG/CVS/Root +Apps/OsgViewer/CVS/Entries +Apps/OsgViewer/CVS/Entries.Log +Apps/OsgViewer/CVS/Repository +Apps/OsgViewer/CVS/Root +Apps/IvViewer/ACGMakefile +Apps/IvViewer/ivviewer.cc +Apps/IvViewer/SoOpenMeshNodeT.cc +Apps/IvViewer/SoOpenMeshNodeT.hh +Apps/IvViewer/SoOpenMeshSupport.hh +Apps/IvViewer/CVS/Entries +Apps/IvViewer/CVS/Repository +Apps/IvViewer/CVS/Root +Apps/Decimating/ACGMakefile +Apps/Decimating/CmdOption.hh +Apps/Decimating/decimater.cc +Apps/Decimating/decimaterviewer.cc +Apps/Decimating/DecimaterViewerWidget.cc +Apps/Decimating/DecimaterViewerWidget.hh +Apps/Decimating/Linux9.1_gcc_max/decimater +Apps/Decimating/Linux9.1_gcc_max/decimater.dep +Apps/Decimating/Linux9.1_gcc_max/decimater.o +Apps/Decimating/Linux9.1_gcc_max/decimaterviewer +Apps/Decimating/Linux9.1_gcc_max/decimaterviewer.dep +Apps/Decimating/Linux9.1_gcc_max/decimaterviewer.o +Apps/Decimating/Linux9.1_gcc_max/DecimaterViewerWidget.dep +Apps/Decimating/Linux9.1_gcc_max/DecimaterViewerWidget.moc.cc +Apps/Decimating/Linux9.1_gcc_max/DecimaterViewerWidget.moc.dep +Apps/Decimating/Linux9.1_gcc_max/DecimaterViewerWidget.moc.o +Apps/Decimating/Linux9.1_gcc_max/DecimaterViewerWidget.o +Apps/Decimating/Linux9.1_gcc_max/libOpenMesh_Apps_Decimating.so +Apps/Decimating/Linux9.1_gcc_dbg/decimater +Apps/Decimating/Linux9.1_gcc_dbg/decimater.dep +Apps/Decimating/Linux9.1_gcc_dbg/decimater.o +Apps/Decimating/Linux9.1_gcc_dbg/decimaterviewer +Apps/Decimating/Linux9.1_gcc_dbg/decimaterviewer.dep +Apps/Decimating/Linux9.1_gcc_dbg/decimaterviewer.o +Apps/Decimating/Linux9.1_gcc_dbg/DecimaterViewerWidget.dep +Apps/Decimating/Linux9.1_gcc_dbg/DecimaterViewerWidget.moc.cc +Apps/Decimating/Linux9.1_gcc_dbg/DecimaterViewerWidget.moc.dep +Apps/Decimating/Linux9.1_gcc_dbg/DecimaterViewerWidget.moc.o +Apps/Decimating/Linux9.1_gcc_dbg/DecimaterViewerWidget.o +Apps/Decimating/Linux9.1_gcc_dbg/libOpenMesh_Apps_Decimating.so +Apps/Decimating/CVS/Entries +Apps/Decimating/CVS/Repository +Apps/Decimating/CVS/Root +Apps/CVS/Entries +Apps/CVS/Entries.Log +Apps/CVS/Repository +Apps/CVS/Root +Core/Mesh/Kernels/Common/BaseKernel.cc +Core/Utils/BaseProperty.cc +Core/Mesh/ArrayItems.hh +Core/Mesh/ArrayKernelT.hh +Core/Mesh/Attributes.hh +Core/Mesh/BaseKernel.cc +Core/Mesh/BaseKernel.hh +Core/Mesh/CirculatorsT.hh +Core/Mesh/FinalMeshItemsT.hh +Core/Mesh/Handles.hh +Core/Mesh/IteratorsT.hh +Core/Mesh/PolyMesh_ArrayKernelT.hh +Core/Mesh/Status.hh +Core/Mesh/TriMesh_ArrayKernelT.hh +Core/Geometry/Config.hh +Core/Geometry/LoopSchemeMaskT.hh +Core/Geometry/MathDefs.hh +Core/Geometry/QuadricT.hh +Core/Geometry/VectorT.hh +Core/Geometry/VectorT_inc.hh +Core/Mesh/AttribKernel.hh +Core/Mesh/AttribKernel.cc +Core/Mesh/AttribKernel.cc +Core/Mesh/AttribKernel.cc +Core/Mesh/AttribKernel.cc +Core/Mesh/ArrayKernel.hh +Core/Mesh/ArrayKernel.cc +Core/Utils/BaseProperty.hh +Core/Utils/PropertyContainer.hh +Core/Mesh/PolyConnectivity.hh +Core/Mesh/PolyConnectivity.cc +Core/Mesh/TriConnectivity.hh +Core/Mesh/TriConnectivity.cc +Core/Mesh/AttribKernelT.hh +Core/Mesh/Casts.hh diff --git a/OpenMesh.pro b/OpenMesh.pro new file mode 100644 index 00000000..ad28bea9 --- /dev/null +++ b/OpenMesh.pro @@ -0,0 +1,32 @@ +contains( OPENFLIPPER , OpenFlipper ){ + include( $$TOPDIR/qmake/all.include ) +} else { + include( $$TOPDIR/OpenMesh/qmake/all.include ) +} + +Subdirs() + +addSubdirs( Core ) +addSubdirs( Tools , Core ) + +addSubdirs( Apps/Decimating , Core Tools) +addSubdirs( Apps/mconvert , Core Tools) +addSubdirs( Apps/QtViewer , Core Tools) +addSubdirs( Apps/Smoothing , Core Tools) +addSubdirs( Apps/Subdivider , Core Tools) + +win32 { + !ReleaseBuild{ + !DebugBuild { + MAKECMD = c:\qt4\bin\qmake.exe + + CORELIST += Core Tools Apps/Decimating Apps/mconvert Apps/QtViewer Apps/Smoothing Apps/Subdivider + + for(entry, CORELIST ): { + message( $$entry ) + system( cd $$entry && $$MAKECMD ) + } + } + } +} + diff --git a/OpenMesh.sln b/OpenMesh.sln new file mode 100644 index 00000000..2535ad50 --- /dev/null +++ b/OpenMesh.sln @@ -0,0 +1,41 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenMesh_Apps_Decimating", "Apps\Decimating\OpenMesh_Apps_Decimating.vcproj", "{2F3AB3BA-D857-4328-9CBC-C2A27F8B2CF8}" + ProjectSection(ProjectDependencies) = postProject + {ED38FC0A-3C42-4D41-B234-B2912430DE52} = {ED38FC0A-3C42-4D41-B234-B2912430DE52} + {682CF0FD-24AD-44AC-8438-A6BECD7ABE1C} = {682CF0FD-24AD-44AC-8438-A6BECD7ABE1C} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenMesh_Apps_ProgViewer", "Apps\ProgViewer\OpenMesh_Apps_ProgViewer.vcproj", "{6CC92D44-A0AC-47D0-9482-D983B1F27E63}" + ProjectSection(ProjectDependencies) = postProject + {ED38FC0A-3C42-4D41-B234-B2912430DE52} = {ED38FC0A-3C42-4D41-B234-B2912430DE52} + {682CF0FD-24AD-44AC-8438-A6BECD7ABE1C} = {682CF0FD-24AD-44AC-8438-A6BECD7ABE1C} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenMesh_Core", "Core\OpenMesh_Core.vcproj", "{ED38FC0A-3C42-4D41-B234-B2912430DE52}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenMesh_Tools", "Tools\OpenMesh_Tools.vcproj", "{682CF0FD-24AD-44AC-8438-A6BECD7ABE1C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2F3AB3BA-D857-4328-9CBC-C2A27F8B2CF8}.Debug|Win32.ActiveCfg = Debug|Win32 + {2F3AB3BA-D857-4328-9CBC-C2A27F8B2CF8}.Release|Win32.ActiveCfg = Release|Win32 + {6CC92D44-A0AC-47D0-9482-D983B1F27E63}.Debug|Win32.ActiveCfg = Debug|Win32 + {6CC92D44-A0AC-47D0-9482-D983B1F27E63}.Release|Win32.ActiveCfg = Release|Win32 + {ED38FC0A-3C42-4D41-B234-B2912430DE52}.Debug|Win32.ActiveCfg = Debug|Win32 + {ED38FC0A-3C42-4D41-B234-B2912430DE52}.Debug|Win32.Build.0 = Debug|Win32 + {ED38FC0A-3C42-4D41-B234-B2912430DE52}.Release|Win32.ActiveCfg = Release|Win32 + {ED38FC0A-3C42-4D41-B234-B2912430DE52}.Release|Win32.Build.0 = Release|Win32 + {682CF0FD-24AD-44AC-8438-A6BECD7ABE1C}.Debug|Win32.ActiveCfg = Debug|Win32 + {682CF0FD-24AD-44AC-8438-A6BECD7ABE1C}.Debug|Win32.Build.0 = Debug|Win32 + {682CF0FD-24AD-44AC-8438-A6BECD7ABE1C}.Release|Win32.ActiveCfg = Release|Win32 + {682CF0FD-24AD-44AC-8438-A6BECD7ABE1C}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/README b/README new file mode 100644 index 00000000..86b08e7b --- /dev/null +++ b/README @@ -0,0 +1,22 @@ +OpenMesh, 2-0 +~~~~~~~~~~~~~~~ + +0. Licence + see LICENSE + + +1. Installing +~~~~~~~~~~~~~~ +Unpack the tar-ball to a suitable place and compile with: + +qmake-qt4 ## Build Makefiles +make ## Build project (use 'make debug' for debug version) + + +2. OpenMesh + STLport +~~~~~~~~~~~~~~~~~~~~~~ + +We tested the MS .NET with STLport 4.6 (with STLport iostream) and +encountered on problem in OpenMesh/Core/IO/reader/OBJReader.cc. +A workaround for 4.6 version of STLport has been applied. It might have +to be adjusted for other STLport versions. diff --git a/Tools/ACGMakefile b/Tools/ACGMakefile new file mode 100644 index 00000000..80d64f89 --- /dev/null +++ b/Tools/ACGMakefile @@ -0,0 +1,19 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = Utils Decimater Subdivider VDPM Smoother + +PACKAGES := math + +PROJ_LIBS := OpenMesh/Core + +CXXLIB_BUILD_LIB := yes + +MODULES := cxxlib + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Tools/Decimater/ACGMakefile b/Tools/Decimater/ACGMakefile new file mode 100644 index 00000000..f959ef41 --- /dev/null +++ b/Tools/Decimater/ACGMakefile @@ -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 +#============================================================================== diff --git a/Tools/Decimater/CollapseInfoT.hh b/Tools/Decimater/CollapseInfoT.hh new file mode 100644 index 00000000..96f3d266 --- /dev/null +++ b/Tools/Decimater/CollapseInfoT.hh @@ -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 +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 +inline +CollapseInfoT:: +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 +//============================================================================= + diff --git a/Tools/Decimater/DecimaterT.cc b/Tools/Decimater/DecimaterT.cc new file mode 100644 index 00000000..77127b3d --- /dev/null +++ b/Tools/Decimater/DecimaterT.cc @@ -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 + +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + + +//== NAMESPACE =============================================================== + + +namespace OpenMesh { +namespace Decimater { + + +//== IMPLEMENTATION ========================================================== + + + +template +DecimaterT:: +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 +DecimaterT:: +~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 +void +DecimaterT:: +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() : "") << std::endl; + _os << "is initialized : " << (initialized_ ? "yes" : "no") << std::endl; +} + + +//----------------------------------------------------------------------------- + + +template +bool +DecimaterT:: +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 +bool +DecimaterT::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 +float +DecimaterT::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 +void +DecimaterT::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 +void +DecimaterT:: +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 +size_t +DecimaterT::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 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(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 +//============================================================================= + diff --git a/Tools/Decimater/DecimaterT.hh b/Tools/Decimater/DecimaterT.hh new file mode 100644 index 00000000..5cd3f347 --- /dev/null +++ b/Tools/Decimater/DecimaterT.hh @@ -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 + +#include +#include +#include + + + +//== 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 CollapseInfo; + typedef ModBaseT 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& _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 _prio, + VPropHandleT _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 prio_; + VPropHandleT pos_; + }; + + typedef Utils::HeapT 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 heap_; + + // list of modules + ModuleList bmodules_; + Module* cmodule_; + + bool initialized_; + + + // vertex properties + VPropHandleT collapse_target_; + VPropHandleT priority_; + VPropHandleT 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 +//============================================================================= + diff --git a/Tools/Decimater/ModBaseT.hh b/Tools/Decimater/ModBaseT.hh new file mode 100644 index 00000000..1102d197 --- /dev/null +++ b/Tools/Decimater/ModBaseT.hh @@ -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 +#include +#include + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { +namespace Decimater { + + +//== FORWARD DECLARATIONS ===================================================== + +template class DecimaterT; + + +//== CLASS DEFINITION ========================================================= + +/** Handle for mesh decimation modules + \internal + */ +template +class ModHandleT : private Utils::Noncopyable +{ +public: + + typedef ModHandleT 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 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 +class ModBaseT +{ +public: + + typedef typename DecimaterType::Mesh Mesh; + typedef CollapseInfoT 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& /* _ci */) + { return LEGAL_COLLAPSE; } + + /** After _from_vh has been collapsed into _to_vh, this method + will be called. + */ + virtual void postprocess_collapse(const CollapseInfoT& /* _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 +//============================================================================= + diff --git a/Tools/Decimater/ModIndependentSetsT.hh b/Tools/Decimater/ModIndependentSetsT.hh new file mode 100644 index 00000000..15d75fce --- /dev/null +++ b/Tools/Decimater/ModIndependentSetsT.hh @@ -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 + + +//== 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 ModIndependentSetsT : public ModBaseT +{ +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 +//============================================================================= + diff --git a/Tools/Decimater/ModNormalFlippingT.hh b/Tools/Decimater/ModNormalFlippingT.hh new file mode 100644 index 00000000..3618f712 --- /dev/null +++ b/Tools/Decimater/ModNormalFlippingT.hh @@ -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 + +//== 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 +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 +//============================================================================= + diff --git a/Tools/Decimater/ModProgMeshT.cc b/Tools/Decimater/ModProgMeshT.cc new file mode 100644 index 00000000..395f5dea --- /dev/null +++ b/Tools/Decimater/ModProgMeshT.cc @@ -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 +#include +// -------------------- +#include +#include +#include +// -------------------- +#include + + +//== NAMESPACE =============================================================== + +namespace OpenMesh { +namespace Decimater { + + + +//== IMPLEMENTATION ========================================================== + + +template +bool +ModProgMeshT:: +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 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( 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(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 +//============================================================================= + diff --git a/Tools/Decimater/ModProgMeshT.hh b/Tools/Decimater/ModProgMeshT.hh new file mode 100644 index 00000000..b3fb2d61 --- /dev/null +++ b/Tools/Decimater/ModProgMeshT.hh @@ -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 +#include + + +//== 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 ModProgMeshT : public ModBaseT +{ +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 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).
+ * \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.
+ * \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 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 +//============================================================================= + diff --git a/Tools/Decimater/ModQuadricT.cc b/Tools/Decimater/ModQuadricT.cc new file mode 100644 index 00000000..d096614f --- /dev/null +++ b/Tools/Decimater/ModQuadricT.cc @@ -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 + + +//== NAMESPACE =============================================================== + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Decimater { // BEGIN_NS_DECIMATER + + +//== IMPLEMENTATION ========================================================== + + +template +void +ModQuadricT:: +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(Base::mesh().point(vh0)); + v1 = vector_cast(Base::mesh().point(vh1)); + v2 = vector_cast(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(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 +//============================================================================= diff --git a/Tools/Decimater/ModQuadricT.hh b/Tools/Decimater/ModQuadricT.hh new file mode 100644 index 00000000..45a2d0eb --- /dev/null +++ b/Tools/Decimater/ModQuadricT.hh @@ -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 +#include +#include +#include +#include + + +//== 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 ModQuadricT : public ModBaseT +{ +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 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 > 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 +//============================================================================= + diff --git a/Tools/Decimater/ModRoundnessT.hh b/Tools/Decimater/ModRoundnessT.hh new file mode 100644 index 00000000..1e7ee81e --- /dev/null +++ b/Tools/Decimater/ModRoundnessT.hh @@ -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 +#include + +#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 ModRoundnessT : public ModBaseT +{ +public: + DECIMATING_MODULE( ModRoundnessT, DecimaterType, Roundness ); + +public: + + // typedefs + typedef typename Mesh::Point Point; + typedef typename vector_traits::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(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(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(_ci.p1), B, C ); + + // return the maximum non-roundness + priority = std::max( priority, (1.0-r) ); + + } + } + else // binary mode + { + C = vector_cast(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(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(_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° 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°,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 +//============================================================================= + diff --git a/Tools/Decimater/calc-roundness.m b/Tools/Decimater/calc-roundness.m new file mode 100644 index 00000000..99192be1 --- /dev/null +++ b/Tools/Decimater/calc-roundness.m @@ -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) + diff --git a/Tools/Decimater/roundness.m b/Tools/Decimater/roundness.m new file mode 100644 index 00000000..3cd05588 --- /dev/null +++ b/Tools/Decimater/roundness.m @@ -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) + diff --git a/Tools/Decimater/roundness.sh b/Tools/Decimater/roundness.sh new file mode 100644 index 00000000..dd0d0a15 --- /dev/null +++ b/Tools/Decimater/roundness.sh @@ -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 diff --git a/Tools/Kernel_OSG/ACGMakefile b/Tools/Kernel_OSG/ACGMakefile new file mode 100644 index 00000000..f959ef41 --- /dev/null +++ b/Tools/Kernel_OSG/ACGMakefile @@ -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 +#============================================================================== diff --git a/Tools/Kernel_OSG/ArrayKernelT.hh b/Tools/Kernel_OSG/ArrayKernelT.hh new file mode 100644 index 00000000..ffb0600a --- /dev/null +++ b/Tools/Kernel_OSG/ArrayKernelT.hh @@ -0,0 +1,209 @@ +//============================================================================= +// +// 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) $ +// +//============================================================================= + + +//============================================================================= +// +// CLASS OSGArrayKernelT +// +//============================================================================= + + +#ifndef OPENMESH_KERNELOSG_ARRAY_KERNEL_HH +#define OPENMEHS_KERNELOSG_ARRAY_KERNEL_HH + + +//== INCLUDES ================================================================= + +#include +// -------------------- +#include +#include +#include +// -------------------- +#include + + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Kernel_OSG { + +//== CLASS DEFINITION ========================================================= + + +/** \ingroup mesh_kernels_group + * + * Mesh kernel using arrays for mesh item storage. + * + * This mesh kernel uses the OpenSG GeoProperties as container + * to store the mesh items. + * + * \note You do not have to use this class directly, use the predefined + * mesh-kernel combinations in \ref mesh_types_group. + */ +// \see OpenMesh::ArrayHandleT +// \see \ref mesh_type + + +template +class ArrayKernelT + : public OpenMesh::ArrayKernelT +{ +public: + + typedef ArrayKernelT This; + typedef OpenMesh::ArrayKernelT Base; + + // attributes +// typedef typename Base::HasVertexNormals HasVertexNormals; +// typedef typename Base::HasVertexColors HasVertexColors; +// typedef typename Base::HasVertexTexCoords HasVertexTexCoords; +// typedef typename Base::HasVertexStatus HasVertexStatus; + typedef typename Base::HasPrevHalfedge HasPrevHalfedge; +// typedef typename Base::HasEdgeStatus HasEdgeStatus; +// typedef typename Base::HasFaceNormals HasFaceNormals; +// typedef typename Base::HasFaceColors HasFaceColors; +// typedef typename Base::HasFaceStatus HasFaceStatus; + + // item types + typedef typename FinalMeshItems::Vertex Vertex; + typedef typename FinalMeshItems::Halfedge Halfedge; + typedef typename FinalMeshItems::Edge Edge; + typedef typename FinalMeshItems::Face Face; + typedef typename FinalMeshItems::Point Point; + typedef typename FinalMeshItems::Normal Normal; + typedef typename FinalMeshItems::Color Color; + typedef typename FinalMeshItems::TexCoord TexCoord; + typedef typename FinalMeshItems::Scalar Scalar; + +// // handles +// typedef typename OpenMesh::VertexHandle VertexHandle; +// typedef typename FinalMeshItems::HalfedgeHandle HalfedgeHandle; +// typedef typename FinalMeshItems::EdgeHandle EdgeHandle; +// typedef typename FinalMeshItems::FaceHandle FaceHandle; + + // iterators + typedef std::vector VertexContainer; + typedef std::vector EdgeContainer; + typedef std::vector FaceContainer; + typedef typename VertexContainer::iterator KernelVertexIter; + typedef typename VertexContainer::const_iterator KernelConstVertexIter; + typedef typename EdgeContainer::iterator KernelEdgeIter; + typedef typename EdgeContainer::const_iterator KernelConstEdgeIter; + typedef typename FaceContainer::iterator KernelFaceIter; + typedef typename FaceContainer::const_iterator KernelConstFaceIter; + +public: + + ArrayKernelT() : Base() + { } + + virtual ~ArrayKernelT() + { } + +public: // replacements + + void set_halfedge_handle(VertexHandle _vh, HalfedgeHandle _heh) { + Base::set_halfedge_handle( _vh, _heh ); + } + + void set_halfedge_handle(FaceHandle _fh, HalfedgeHandle _heh) { + Base::set_halfedge_handle( _fh, _heh ); + osg_sync( _fh ); + } + + void set_next_halfedge_handle(HalfedgeHandle _heh, HalfedgeHandle _nheh) { + Base::set_next_halfedge_handle( _heh, _nheh ); + osg_sync( face_handle( _heh ) ); // ##Changed + } + + void garbage_collection(bool _v=true, bool _e=true, bool _f=true); + +protected: + + bool osg_sync( FaceHandle _fh ) + { + return _fh.is_valid() + ? osg_sync( _fh, typename Face::IsTriangle() ) + : false; + } + +private: + + bool osg_sync( FaceHandle _fh, GenProg::Bool2Type ) + { + HalfedgeHandle hh( halfedge_handle(_fh) ); + if ( !hh.is_valid() ) return false; + FaceHandle f1( _fh.idx() * 3 ); + set_face_indices( f1, to_vertex_handle(hh).idx() ); + + hh = next_halfedge_handle(hh); + if ( !hh.is_valid() ) return false; + FaceHandle f2( f1.idx()+1 ); + set_face_indices( f2, to_vertex_handle(hh).idx() ); + + hh = next_halfedge_handle(hh); + if ( !hh.is_valid() ) return false; + FaceHandle f3( f1.idx()+2 ); + set_face_indices( f3, to_vertex_handle(hh).idx() ); + + set_face_types ( _fh, GL_TRIANGLES ); + set_face_lengths( _fh, 3 ); + + return true; + } + + bool osg_sync( FaceHandle _fh, GenProg::Bool2Type ) + { + return false; + } + +}; + + +template +void +ArrayKernelT:: +garbage_collection(bool _v, bool _e, bool _f) +{ + Base::garbage_collection(_v, _e, _f); + for (size_t fidx=0; fidx < n_faces(); ++fidx) + osg_sync( FaceHandle(fidx) ); +} + +//============================================================================= +} // namespace Kernel_OSG +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_ARRAY_KERNEL_HH defined +//============================================================================= diff --git a/Tools/Kernel_OSG/AttribKernelT.hh b/Tools/Kernel_OSG/AttribKernelT.hh new file mode 100644 index 00000000..c8cd0aac --- /dev/null +++ b/Tools/Kernel_OSG/AttribKernelT.hh @@ -0,0 +1,638 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_KERNEL_OSG_ATTRIBKERNEL_HH +#define OPENMESH_KENREL_OSG_ATTRIBKERNEL_HH + + +//== INCLUDES ================================================================= + +#include +#include +// -------------------- +#include +#include +// -------------------- +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Kernel_OSG { + +//== CLASS DEFINITION ========================================================= + + + +/// This class adds the standard properties to the mesh type. +template +class AttribKernelT + : public PropertyKernel< typename MeshItems::Face::IsTriangle > +{ +protected: + + typedef typename MeshItems::Face::IsTriangle IsTriMesh; + typedef PropertyKernel< IsTriMesh > Base; + + typedef typename Base::FPTypesHandle FPTypesHandle; + typedef typename Base::FPLengthsHandle FPLengthsHandle; + typedef typename Base::FIndicesHandle FIndicesHandle; + +public: + + //---------------------------------------------------------------- item types + + typedef typename MeshItems::Vertex Vertex; + typedef typename MeshItems::Halfedge Halfedge; + typedef typename MeshItems::Edge Edge; + typedef typename MeshItems::Face Face; + + typedef typename MeshItems::Point Point; + typedef typename MeshItems::Normal Normal; + typedef typename MeshItems::Color Color; + typedef typename MeshItems::TexCoord TexCoord; + + typedef typename MeshItems::Scalar Scalar; + + typedef Attributes::StatusInfo StatusInfo; + + + enum Attribs { + VAttribs = MeshItems::VAttribs, + HAttribs = MeshItems::HAttribs, + EAttribs = MeshItems::EAttribs, + FAttribs = MeshItems::FAttribs, + }; + + typedef GenProg::Bool2Type<(bool)(HAttribs & Attributes::PrevHalfedge)> + HasPrevHalfedge; + + // + + typedef typename _t2vp< Point >::prop GeoPositions; + typedef typename _t2vn< Normal >::prop GeoNormals; + typedef typename _t2vc< Color >::prop GeoColors; + typedef typename _t2vtc< TexCoord >::prop GeoTexCoords; + +// typedef typename Base::GeoPTypes GeoPTypes; +// typedef typename Base::GeoPLengths GeoPLengths; +// typedef typename Base::GeoIndices GeoIndices; + + //-------------------------------------------------- constructor / destructor + + AttribKernelT() : + + refcount_vnormals_(0), + refcount_vcolors_(0), + refcount_vtexcoords_(0), + refcount_vstatus_(0), + refcount_estatus_(0), + refcount_hstatus_(0), + refcount_fnormals_(0), + refcount_fcolors_(0), + refcount_fstatus_(0) + + { + points_ = add_vpositions( Point(), "v:points" ); + + face_types_ = add_fptypes(); + face_lengths_ = add_fplengths(); + face_indices_ = add_findices( face_types_, face_lengths_); + + if (VAttribs & Attributes::Normal) + request_vertex_normals(); + + if (VAttribs & Attributes::Color) + request_vertex_colors(); + + if (VAttribs & Attributes::TexCoord) + request_vertex_texcoords(); + + if (VAttribs & Attributes::Status) + request_vertex_status(); + + if (EAttribs & Attributes::Status) + request_edge_status(); + + if (FAttribs & Attributes::Normal) + request_face_normals(); + + if (FAttribs & Attributes::Color) + request_face_colors(); + + if (FAttribs & Attributes::Status) + request_face_status(); + } + + ~AttribKernelT() + { + // should remove properties, but this will be done in + // BaseKernel's destructor anyway... + } + + + // ------------------------------------------------------- copy & assignement + + AttribKernelT( const AttribKernelT& _rhs ) + : Base( _rhs ) + { + operator=(_rhs); + } + + AttribKernelT& operator = ( const AttribKernelT& _rhs ) + { + // remove old properties + remove_property(points_); + remove_property(vertex_normals_); + remove_property(vertex_colors_); + remove_property(vertex_texcoords_); + remove_property(vertex_status_); + remove_property(halfedge_status_); + remove_property(edge_status_); + remove_property(face_normals_); + remove_property(face_colors_); + remove_property(face_status_); + + // parent deep-copies properties + BaseKernel::operator=(_rhs); + + // copy property handles + points_ = _rhs.points_; + vertex_normals_ = _rhs.vertex_normals_; + vertex_colors_ = _rhs.vertex_colors_; + vertex_texcoords_ = _rhs.vertex_texcoords_; + vertex_status_ = _rhs.vertex_status_; + halfedge_status_ = _rhs.halfedge_status_; + edge_status_ = _rhs.edge_status_; + face_normals_ = _rhs.face_normals_; + face_colors_ = _rhs.face_colors_; + face_status_ = _rhs.face_status_; + + // copy ref-counts + refcount_vnormals_ = _rhs.refcount_vnormals_; + refcount_vcolors_ = _rhs.refcount_vcolors_; + refcount_vtexcoords_ = _rhs.refcount_vtexcoords_; + refcount_vstatus_ = _rhs.refcount_vstatus_; + refcount_hstatus_ = _rhs.refcount_hstatus_; + refcount_estatus_ = _rhs.refcount_estatus_; + refcount_fnormals_ = _rhs.refcount_fnormals_; + refcount_fcolors_ = _rhs.refcount_fcolors_; + refcount_fstatus_ = _rhs.refcount_fstatus_; + + return *this; + } + + //------------------------------------------------------------ osg properties + + //------------------------------ vertex property + + typename GeoPositions::property_ptr_t osg_vpositions() + { return vpositions(points_).osg_ptr(); } + + typename GeoNormals::property_ptr_t osg_vnormals() + { return vnormals(vertex_normals_).osg_ptr(); } + + typename GeoColors::property_ptr_t osg_vcolors() + { return vcolors(vertex_colors_).osg_ptr(); } + + typename GeoTexCoords::property_ptr_t osg_vtexcoords() + { return vtexcoords(vertex_texcoords_).osg_ptr(); } + + //------------------------------ face property + + GeoPTypes::property_ptr_t osg_ptypes() + { return fptypes( face_types_ ).osg_ptr(); } + + GeoPLengths::property_ptr_t osg_plengths() + { return fplengths( face_lengths_ ).osg_ptr(); } + + typename GeoIndices::property_ptr_t osg_indices() + { return findices( face_indices_ ).osg_ptr(); } + + + //---------------------------------------- set osg geo property + + //------------------------------ face property + + void set_face_types( FaceHandle _fh, GeoPTypes::value_type _t) + { fptypes( face_types_, _fh ) = _t; } + + void set_face_lengths( FaceHandle _fh, GeoPLengths::value_type _l) + { fplengths( face_lengths_, _fh ) = _l; } + + void set_face_indices( FaceHandle _fh, + typename GeoIndices::value_type _i) + { findices( face_indices_, _fh ) = _i; } + + //--------------------------------------------------------- set/get properties + + //---------------------------------------- points + + const Point* points() const + { return vpositions( points_ ).data(); } + + const Point& point(VertexHandle _vh) const + { return vpositions( points_, _vh); } + + void set_point(VertexHandle _vh, const Point& _p) + { vpositions( points_, _vh ) = _p; } + + + //---------------------------------------- vertex normals + + const Normal* vertex_normals() const { + return vnormals(vertex_normals_).data(); + } + + const Normal& normal(VertexHandle _vh) const { + return vnormals(vertex_normals_, _vh); + } + + void set_normal(VertexHandle _vh, const Normal& _n) { + vnormals(vertex_normals_, _vh) = _n; + } + + + //---------------------------------------- vertex colors + + const Color* vertex_colors() const { + return vcolors(vertex_colors_).data(); + } + + const Color& color(VertexHandle _vh) const { + return vcolors(vertex_colors_, _vh); + } + + void set_color(VertexHandle _vh, const Color& _c) { + vcolors(vertex_colors_, _vh) = _c; + } + + + //---------------------------------------- vertex texcoords + + const TexCoord* texcoords() const { + return vtexcoords(vertex_texcoords_).data(); + } + + const TexCoord& texcoord(VertexHandle _vh) const { + return vtexcoords(vertex_texcoords_, _vh); + } + + void set_texcoord(VertexHandle _vh, const TexCoord& _t) { + vtexcoords(vertex_texcoords_, _vh) = _t; + } + + + //---------------------------------------- vertex status + + const StatusInfo& status(VertexHandle _vh) const { + return property(vertex_status_, _vh); + } + + StatusInfo& status(VertexHandle _vh) { + return property(vertex_status_, _vh); + } + + + //---------------------------------------- edge status + + const StatusInfo& status(HalfedgeHandle _eh) const { + return property(halfedge_status_, _eh); + } + + StatusInfo& status(HalfedgeHandle _eh) { + return property(halfedge_status_, _eh); + } + + + //---------------------------------------- edge status + + const StatusInfo& status(EdgeHandle _eh) const { + return property(edge_status_, _eh); + } + + StatusInfo& status(EdgeHandle _eh) { + return property(edge_status_, _eh); + } + + + //---------------------------------------- face status + + const StatusInfo& status(FaceHandle _fh) const { + return property(face_status_, _fh); + } + + StatusInfo& status(FaceHandle _fh) { + return property(face_status_, _fh); + } + + + //---------------------------------------- face normals + + const Normal& normal(FaceHandle _fh) const { + return property(face_normals_, _fh); + } + + void set_normal(FaceHandle _fh, const Normal& _n) { + property(face_normals_, _fh) = _n; + } + + + //---------------------------------------- face colors + + const Color& color(FaceHandle _fh) const { + return property(face_colors_, _fh); + } + + void set_color(FaceHandle _fh, const Color& _c) { + property(face_colors_, _fh) = _c; + } + + + + //------------------------------------------------ request / alloc properties + + void request_vertex_normals() { + if (!refcount_vnormals_++) + vertex_normals_ = add_vnormals( Normal(), "v:normals" ); + } + + void request_vertex_colors() { + if (!refcount_vcolors_++) + vertex_colors_ = add_vcolors( Color(), "v:colors" ); + } + + void request_vertex_texcoords() { + if (!refcount_vtexcoords_++) + vertex_texcoords_ = add_vtexcoords( TexCoord(), "v:texcoords" ); + } + + void request_vertex_status() { + if (!refcount_vstatus_++) + add_property( vertex_status_, "v:status" ); + } + + void request_halfedge_status() { + if (!refcount_hstatus_++) + add_property( halfedge_status_, "h:status" ); + } + + void request_edge_status() { + if (!refcount_estatus_++) + add_property( edge_status_, "e:status" ); + } + + void request_face_normals() { + if (!refcount_fnormals_++) + add_property( face_normals_, "f:normals" ); + } + + void request_face_colors() { + if (!refcount_fcolors_++) + add_property( face_colors_, "f:colors" ); + } + + void request_face_status() { + if (!refcount_fstatus_++) + add_property( face_status_, "f:status" ); + } + + + + //------------------------------------------------- release / free properties + + void release_vertex_normals() { + if ((refcount_vnormals_ > 0) && (! --refcount_vnormals_)) + remove_property(vertex_normals_); + } + + void release_vertex_colors() { + if ((refcount_vcolors_ > 0) && (! --refcount_vcolors_)) + remove_property(vertex_colors_); + } + + void release_vertex_texcoords() { + if ((refcount_vtexcoords_ > 0) && (! --refcount_vtexcoords_)) + remove_property(vertex_texcoords_); + } + + void release_vertex_status() { + if ((refcount_vstatus_ > 0) && (! --refcount_vstatus_)) + remove_property(vertex_status_); + } + + void release_halfedge_status() { + if ((refcount_hstatus_ > 0) && (! --refcount_hstatus_)) + remove_property(halfedge_status_); + } + + void release_edge_status() { + if ((refcount_estatus_ > 0) && (! --refcount_estatus_)) + remove_property(edge_status_); + } + + void release_face_normals() { + if ((refcount_fnormals_ > 0) && (! --refcount_fnormals_)) + remove_property(face_normals_); + } + + void release_face_colors() { + if ((refcount_fcolors_ > 0) && (! --refcount_fcolors_)) + remove_property(face_colors_); + } + + void release_face_status() { + if ((refcount_fstatus_ > 0) && (! --refcount_fstatus_)) + remove_property(face_status_); + } + + + //----------------------------------------------- static check for properties + + typedef + GenProg::Bool2Type<(bool)(VAttribs & Attributes::Normal)> + HasVertexNormals; + + typedef + GenProg::Bool2Type<(bool)(VAttribs & Attributes::Color)> + HasVertexColors; + + typedef + GenProg::Bool2Type<(bool)(VAttribs & Attributes::TexCoord)> + HasVertexTexCoords; + + typedef + GenProg::Bool2Type<(bool)(VAttribs & Attributes::Status)> + HasVertexStatus; + + + typedef + GenProg::Bool2Type<(bool)(HAttribs & Attributes::PrevHalfedge)> + HasPrevHalfedge; + + typedef + GenProg::Bool2Type<(bool)(HAttribs & Attributes::Status)> + HasHalfedgeStatus; + + + typedef + GenProg::Bool2Type<(bool)(EAttribs & Attributes::Status)> + HasEdgeStatus; + + + typedef + GenProg::Bool2Type<(bool)(FAttribs & Attributes::Normal)> + HasFaceNormals; + + typedef + GenProg::Bool2Type<(bool)(FAttribs & Attributes::Color)> + HasFaceColors; + + typedef + GenProg::Bool2Type<(bool)(FAttribs & Attributes::Status)> + HasFaceStatus; + + + //---------------------------------------------- dynamic check for properties + + bool has_vertex_normals() const { return vertex_normals_.is_valid(); } + bool has_vertex_colors() const { return vertex_colors_.is_valid(); } + bool has_vertex_texcoords() const { return vertex_texcoords_.is_valid(); } + bool has_vertex_status() const { return vertex_status_.is_valid(); } + bool has_edge_status() const { return edge_status_.is_valid(); } + bool has_halfedge_status() const { return halfedge_status_.is_valid(); } + bool has_face_normals() const { return face_normals_.is_valid(); } + bool has_face_colors() const { return face_colors_.is_valid(); } + bool has_face_status() const { return face_status_.is_valid(); } + + static bool has_prev_halfedge() { + return (HAttribs & Attributes::PrevHalfedge); + } + + +public: + + osg::GeometryPtr createGeometryPtr() + { + using namespace osg; + GeometryPtr geo=Geometry::create(); + return bind(geo) ? geo : NullFC; + } + + // create new geometry core from mesh + bool bind( osg::GeometryPtr& _geo ) + { + using namespace osg; + + int Mask = + Geometry::TypesFieldMask | + Geometry::LengthsFieldMask | + Geometry::IndicesFieldMask | + Geometry::PositionsFieldMask; + + if ( has_vertex_colors() ) + Mask |= Geometry::ColorsFieldMask; + if ( has_vertex_normals() ) + Mask |= Geometry::NormalsFieldMask; + if ( has_vertex_texcoords() ) + Mask |= Geometry::TexCoordsFieldMask; + +// std::clog << "#ptypes : " << osg_ptypes()->getSize() << std::endl; +// std::clog << "#plengths : " << osg_plengths()->getSize() << std::endl; +// std::clog << "#indices : " << osg_indices()->getSize() << std::endl; +// std::clog << "#points : " << osg_vpositions()->getSize() << std::endl; + + beginEditCP( _geo, Mask ); + { + addRefCP( osg_ptypes() ); + _geo->setTypes ( osg_ptypes() ); + addRefCP( osg_plengths() ); + _geo->setLengths ( osg_plengths() ); + addRefCP( osg_indices() ); + _geo->setIndices ( osg_indices() ); + addRefCP( osg_vpositions() ); + _geo->setPositions( osg_vpositions() ); + + if ( has_vertex_colors() ) + { + addRefCP( osg_vcolors() ); + _geo->setColors ( osg_vcolors() ); + } + if ( has_vertex_normals() ) + { + addRefCP( osg_vnormals() ); + _geo->setNormals ( osg_vnormals() ); + } + if ( has_vertex_texcoords() ) + { + addRefCP( osg_vtexcoords() ); + _geo->setTexCoords( osg_vtexcoords() ); + } + } + endEditCP (_geo, Mask); + + return true; + } + +private: + + VPropHandleT points_; + VPropHandleT vertex_normals_; + VPropHandleT vertex_colors_; + VPropHandleT vertex_texcoords_; + VPropHandleT vertex_status_; + + FPTypesHandle face_types_; + FPLengthsHandle face_lengths_; + FIndicesHandle face_indices_; + + EPropHandleT edge_status_; + HPropHandleT halfedge_status_; + + FPropHandleT face_normals_; + FPropHandleT face_colors_; + FPropHandleT face_status_; + + unsigned int refcount_vnormals_; + unsigned int refcount_vcolors_; + unsigned int refcount_vtexcoords_; + unsigned int refcount_vstatus_; + unsigned int refcount_estatus_; + unsigned int refcount_hstatus_; + unsigned int refcount_fnormals_; + unsigned int refcount_fcolors_; + unsigned int refcount_fstatus_; + +}; + + +//============================================================================= +} // namespace Kernel_OSG +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_KERNEL_OSG_ATTRIBKERNEL_HH defined +//============================================================================= + diff --git a/Tools/Kernel_OSG/PropertyKernel.hh b/Tools/Kernel_OSG/PropertyKernel.hh new file mode 100644 index 00000000..2b8c283d --- /dev/null +++ b/Tools/Kernel_OSG/PropertyKernel.hh @@ -0,0 +1,249 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_KERNEL_OSG_PROPERTYKERNEL_HH +#define OPENMESH_KENREL_OSG_PROPERTYKERNEL_HH + + +//== INCLUDES ================================================================= + +#include +#include +// -------------------- +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Kernel_OSG { + +//== CLASS DEFINITION ========================================================= + +/** Helper class, extending functionaliy of OpenMesh::BaseKernel to OpenSG + * specific property adaptors. + * \internal + * \todo Follow coding convention and rename class to PropertyKernelT + */ +template < typename IsTriMesh > +class PropertyKernel : public OpenMesh::BaseKernel +{ +public: + + // --------------------------------------------------------------- item types + + typedef FPropHandleT FPTypesHandle; + typedef FPropHandleT FPLengthsHandle; + typedef FPropHandleT FIndicesHandle; + + typedef FP::GeoPTypesUI8 GeoPTypes; + typedef FP::GeoPLengthsUI32 GeoPLengths; + typedef FP::GeoIndicesUI32 GeoIndices; + + // ------------------------------------------------- constructor / destructor + + PropertyKernel() {} + virtual ~PropertyKernel() { } + + +protected: // ---------------------------------------------- add osg properties + + // -------------------- vertex properties + + template < typename T > + VPropHandleT add_vpositions( const T& _t, const std::string& _n ) + { return VPropHandleT(_add_vprop( new typename _t2vp::prop(_n))); } + + template < typename T > + VPropHandleT add_vnormals( const T& _t, const std::string& _n ) + { return VPropHandleT(_add_vprop( new typename _t2vn::prop(_n) )); } + + template < typename T > + VPropHandleT add_vcolors( const T& _t, const std::string& _n ) + { return VPropHandleT(_add_vprop( new typename _t2vc::prop(_n) )); } + + template < typename T > + VPropHandleT add_vtexcoords( const T& _t, const std::string& _n ) + { return VPropHandleT(_add_vprop( new typename _t2vtc::prop(_n) )); } + + + // -------------------- face properties + + FPTypesHandle add_fptypes( ) + { return FPTypesHandle(_add_fprop(new GeoPTypes)); } + + FPLengthsHandle add_fplengths( ) + { return FPLengthsHandle(_add_fprop(new GeoPLengths)); } + + FIndicesHandle add_findices( FPTypesHandle _pht, FPLengthsHandle _phl ) + { + GeoIndices *bp = new GeoIndices( fptypes(_pht), fplengths(_phl ) ); + return FIndicesHandle(_add_fprop( bp ) ); + } + +protected: // ------------------------------------------- access osg properties + + template < typename T > + typename _t2vp::prop& vpositions( VPropHandleT _ph ) + { return static_cast::prop&>( _vprop( _ph ) ); } + + template < typename T > + const typename _t2vp::prop& vpositions( VPropHandleT _ph) const + { return static_cast::prop&>( _vprop( _ph ) ); } + + + template < typename T > + typename _t2vn::prop& vnormals( VPropHandleT _ph ) + { return static_cast::prop&>( _vprop( _ph ) ); } + + template < typename T > + const typename _t2vn::prop& vnormals( VPropHandleT _ph) const + { return static_cast::prop&>( _vprop( _ph ) ); } + + + template < typename T > + typename _t2vc::prop& vcolors( VPropHandleT _ph ) + { return static_cast::prop&>( _vprop( _ph ) ); } + + template < typename T > + const typename _t2vc::prop& vcolors( VPropHandleT _ph ) const + { return static_cast::prop&>( _vprop( _ph ) ); } + + + template < typename T > + typename _t2vtc::prop& vtexcoords( VPropHandleT _ph ) + { return static_cast::prop&>( _vprop( _ph ) ); } + + template < typename T > + const typename _t2vtc::prop& vtexcoords( VPropHandleT _ph ) const + { return static_cast::prop&>( _vprop( _ph ) ); } + + + // + GeoPTypes& fptypes( FPTypesHandle _ph ) + { return static_cast( _fprop(_ph) ); } + + const GeoPTypes& fptypes( FPTypesHandle _ph ) const + { return static_cast( _fprop(_ph) ); } + + + GeoPLengths& fplengths( FPLengthsHandle _ph ) + { return static_cast( _fprop(_ph) ); } + + const GeoPLengths& fplengths( FPLengthsHandle _ph ) const + { return static_cast( _fprop(_ph) ); } + + + GeoIndices& findices( FIndicesHandle _ph ) + { return static_cast( _fprop(_ph) ); } + + const GeoIndices& findices( FIndicesHandle _ph ) const + { return static_cast( _fprop(_ph) ); } + + +protected: // ------------------------------------ access osg property elements + + template + T& vpositions( VPropHandleT _ph, VertexHandle _vh ) + { return vpositions(_ph)[_vh.idx()]; } + + template + const T& vpositions( VPropHandleT _ph, VertexHandle _vh ) const + { return vpositions(_ph)[_vh.idx()]; } + + + template < typename T> + T& vnormals( VPropHandleT _ph, VertexHandle _vh ) + { return vnormals(_ph)[_vh.idx()]; } + + template + const T& vnormals( VPropHandleT _ph, VertexHandle _vh ) const + { return vnormals(_ph)[_vh.idx()]; } + + + template < typename T> + T& vcolors( VPropHandleT _ph, VertexHandle _vh ) + { return vcolors(_ph)[_vh.idx()]; } + + template + const T& vcolors( VPropHandleT _ph, VertexHandle _vh ) const + { return vcolors(_ph)[_vh.idx()]; } + + + template < typename T> + T& vtexcoords( VPropHandleT _ph, VertexHandle _vh ) + { return vtexcoords(_ph)[_vh.idx()]; } + + template + const T& vtexcoords( VPropHandleT _ph, VertexHandle _vh ) const + { return vtexcoords(_ph)[_vh.idx()]; } + + + // -------------------- access face property elements + + FPTypesHandle::value_type& + fptypes( FPTypesHandle _ph, FaceHandle _fh ) + { return fptypes( _ph )[ _fh.idx()]; } + + const FPTypesHandle::value_type& + fptypes( FPTypesHandle _ph, FaceHandle _fh ) const + { return fptypes( _ph )[ _fh.idx()]; } + + + FPLengthsHandle::value_type& + fplengths( FPLengthsHandle _ph, FaceHandle _fh ) + { return fplengths( _ph )[ _fh.idx()]; } + + const FPLengthsHandle::value_type& + fplengths( FPLengthsHandle _ph, FaceHandle _fh ) const + { return fplengths( _ph )[ _fh.idx()]; } + + + FIndicesHandle::value_type& + findices( FIndicesHandle _ph, FaceHandle _fh ) + { return findices( _ph )[ _fh.idx()]; } + + const FIndicesHandle::value_type& + findices( FIndicesHandle _ph, FaceHandle _fh ) const + { return findices( _ph )[ _fh.idx()]; } + +public: + + void stats(void) + { + std::cout << "#V : " << n_vertices() << std::endl; + std::cout << "#E : " << n_edges() << std::endl; + std::cout << "#F : " << n_faces() << std::endl; + property_stats(); + } +}; + + +//============================================================================= +} // namespace Kernel_OSG +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_KERNEL_OSG_PROPERTYKERNEL_HH defined +//============================================================================= + diff --git a/Tools/Kernel_OSG/PropertyT.hh b/Tools/Kernel_OSG/PropertyT.hh new file mode 100644 index 00000000..e94c0463 --- /dev/null +++ b/Tools/Kernel_OSG/PropertyT.hh @@ -0,0 +1,393 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +#ifndef OPENMESH_KERNEL_OSG_PROPERTYT_HH +#define OPENMESH_KERNEL_OSG_PROPERTYT_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +// +#include +// +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Kernel_OSG { + + +//== CLASS DEFINITION ========================================================= + + +// ---------------------------------------------------------------------------- + +/** Property adaptor for OpenSG GeoProperties + * + * This class bridges the interfaces of %OpenMesh properties and + * OpenSG GeoProperties. The PropertyKernelT uses these adaptors to + * add all necessary property functions to the kernel, while the + * AttribKernelT extends the kernel with the standard properites. + * Finally the ArrayKernelT completes the kernel build with a specialized + * version of the garbage collections since the GeoIndices require + * special handling. + * + * \attention Data will be shared with a geometry core when linking + * a mesh with a OpenSG geometry node using Kernel_OSG::bind. + * \internal + */ +template +class oPropertyT : public BaseProperty +{ +public: + + // Type of the encapsulated OpenSG Geometry Property + typedef GeoProperty property_t; + typedef typename property_t::PtrType property_ptr_t; + + typedef typename property_t::StoredFieldType field_t; + typedef typename field_t::StoredType element_t; + typedef typename field_t::StoredType value_type; + +public: + + // + oPropertyT( property_ptr_t _geo_prop, + const std::string& _name = "" ) + : BaseProperty(_name), data_( _geo_prop ) + { + osg_init_check(); + } + + // + oPropertyT( const std::string& _name = "" ) + : BaseProperty(_name), data_(NULL) + { + data_ = property_t::create(); + + // make sure data_ is not null. In that case most probably + // osg::osgInit() hasn't been executed! + osg_init_check(); + } + + /// + virtual ~oPropertyT() + { } + +public: + + oPropertyT& operator = (const oPropertyT& _rhs ) + { + // Shallow copy! Remember, data_ is a osg pointer type, and the assign + // operator makes a shallow copy! + data_ = _rhs.data_; + return *this; + + } + + +public: // interface BaseProperty + + virtual void reserve(size_t _n) { data_->getField().reserve( _n ); } + virtual void resize(size_t _n) { data_->resize( _n ); } + virtual void push_back() { data_->resize( data_->size()+1 ); } + virtual void swap(size_t _i0, size_t _i1) + { std::swap( data_->getField()[_i0], data_->getField()[_i1] ); } + + virtual oPropertyT* clone() const + { + oPropertyT *dolly = new oPropertyT(); + if (n_elements() > 0) + { + // OSGGeoProperty does not provide a deep copy + dolly->resize(n_elements()); + element_t *begin = const_cast(data()); + element_t *end = begin+n_elements(); + element_t *dst = const_cast(dolly->data()); + std::copy( begin, end, dst ); + } + return dolly; + } + +public: + + virtual void set_persistent( bool _yn ) + { + check_and_set_persistent(_yn); + } + + virtual size_t n_elements() const + { return data_==osg::NullFC ? UnknownSize : data_->getSize(); } + + virtual size_t element_size() const + { return UnknownSize; } + + virtual size_t store( std::ostream& _ostr, bool _swap ) const + { return 0; } + + virtual size_t restore( std::istream& _istr, bool _swap ) + { return 0; } + + +public: // OpenSG GeoPropertyInterface compatibility + + void clear(void) { data_->clear(); } + + +public: // access to OpenSG GeoProperty + + property_ptr_t& osg_ptr() + { return data_; } + + const property_ptr_t& osg_ptr() const + { return data_; } + + + const element_t *data() const + { return &( (*this)[ 0 ] ); } + + element_t& operator[](size_t idx) + { return data_->getField()[ idx ]; } + + const element_t& operator[](size_t idx) const + { return data_->getField()[ idx ]; } + + +protected: + + property_ptr_t data_; + + +private: + + void osg_init_check(void) + { + // make sure data_ is not null. In that case most probably + // osg::osgInit() hasn't been executed! + if ( data_ == osg::NullFC ) + throw std::logic_error("OpenSG Runtime Environment is not initialized: " \ + "Use osg::osgInit()"); + } + + oPropertyT( const oPropertyT& ); +}; + +// ----------------------------------------------------------------- class ---- + + +// ------------------------------------------------------------ properties ---- + +/// OpenSG Vertex Properties Adaptors. +namespace VP { + + // ---------------------------------------- Positions + /// \name GeoPositions + //@{ + /// Adaptor for osg::GeoPositions + typedef oPropertyT< osg::GeoPositions2d > GeoPositions2d; + typedef oPropertyT< osg::GeoPositions2f > GeoPositions2f; + typedef oPropertyT< osg::GeoPositions3d > GeoPositions3d; + typedef oPropertyT< osg::GeoPositions3f > GeoPositions3f; + typedef oPropertyT< osg::GeoPositions4d > GeoPositions4d; + typedef oPropertyT< osg::GeoPositions4f > GeoPositions4f; + //@} + + // ---------------------------------------- Normals + /// \name GeoNormals + //@{ + /// Adaptor for osg::GeoNormals + typedef oPropertyT< osg::GeoNormals3f > GeoNormals3f; + //@} + + // ---------------------------------------- TexCoords + /// \name GeoTexCoords + //@{ + /// Adaptor for osg::GeoTexCoords + typedef oPropertyT< osg::GeoTexCoords1f > GeoTexCoords1f; + typedef oPropertyT< osg::GeoTexCoords2f > GeoTexCoords2f; + typedef oPropertyT< osg::GeoTexCoords3f > GeoTexCoords3f; + //@} + + // ---------------------------------------- Colors + /// \name GeoColors + //@{ + /// Adaptor for osg::GeoColors + typedef oPropertyT< osg::GeoColors3f > GeoColors3f; + typedef oPropertyT< osg::GeoColors3ub > GeoColors3ub; + typedef oPropertyT< osg::GeoColors4f > GeoColors4f; + typedef oPropertyT< osg::GeoColors4ub > GeoColors4ub; + //@} + +} // namespace VP + + +/// OpenSG Face Properties Adaptors. +namespace FP { + + // ---------------------------------------- Types + /// Adaptor for osg::GeoPTypesUI8 + typedef oPropertyT< osg::GeoPTypesUI8 > GeoPTypesUI8; + + // ---------------------------------------- Lengths + /// Adaptor for osg::GeoPLengthsUI32 + typedef oPropertyT< osg::GeoPLengthsUI32 > GeoPLengthsUI32; + + // ---------------------------------------- Indices + + typedef oPropertyT< osg::GeoIndicesUI32 > _GeoIndicesUI32; + + /// Adaptor for osg::GeoIndicesUI32 + template < typename IsTriMesh > + class GeoIndicesUI32 : public _GeoIndicesUI32 + { + public: // ---------------------------------------- typedefs + + typedef _GeoIndicesUI32 inherited_t; + typedef typename inherited_t::property_ptr_t property_ptr_t; + + public: // ---------------------------------------- ctor/dtor + + GeoIndicesUI32( property_ptr_t _geo_prop, + GeoPTypesUI8& _types, + GeoPLengthsUI32& _lengths) + : inherited_t( _geo_prop ), types_(_types), length_(_lengths) + { } + + GeoIndicesUI32( GeoPTypesUI8& _types, + GeoPLengthsUI32& _lengths) + : inherited_t(), types_(_types), length_(_lengths) + { } + + virtual ~GeoIndicesUI32() + { } + + public: // ---------------------------------------- inherited + + void swap(size_t _i0, size_t _i1) { _swap( _i0, _i1, IsTriMesh() ); } + virtual void reserve(size_t _n) { _reserve( _n, IsTriMesh() ); } + virtual void resize(size_t _n) { _resize( _n, IsTriMesh() ); } + + protected: // ------------------------------------- swap + + void _swap(size_t _i0, size_t _i1, GenProg::False ) + { + omerr() << "Unsupported mesh type!" << std::endl; + assert(0); + } + + void _swap(size_t _i0, size_t _i1, GenProg::True ) + { + size_t j0 = _i0 + _i0 + _i0; + size_t j1 = _i1 + _i1 + _i1; + + inherited_t::swap( j0, j1 ); + inherited_t::swap( ++j0, ++j1 ); + inherited_t::swap( ++j0, ++j1 ); + } + + virtual void _reserve(size_t _n, GenProg::True ) + { inherited_t::reserve( _n + _n + _n ); } + + virtual void _reserve(size_t _n, GenProg::False ) + { assert( false ); } + + virtual void _resize(size_t _n, GenProg::True ) + { inherited_t::resize( _n + _n + _n ); } + + virtual void _resize(size_t _n, GenProg::False ) + { assert( false ); } + + + protected: + + GeoPTypesUI8 &types_; + GeoPLengthsUI32 &length_; + + }; + +} // namespace FP + + +// ---------------------------------------------------------------------------- + +#ifndef DOXY_IGNORE_THIS + +template struct _t2vp; +template <> struct _t2vp< osg::Pnt2f > +{ typedef osg::GeoPositions2f type; typedef VP::GeoPositions2f prop; }; + +template <> struct _t2vp< osg::Pnt3f > +{ typedef osg::GeoPositions3f type; typedef VP::GeoPositions3f prop; }; + +template <> struct _t2vp< osg::Pnt4f > +{ typedef osg::GeoPositions4f type; typedef VP::GeoPositions4f prop; }; + +template <> struct _t2vp< osg::Pnt2d > +{ typedef osg::GeoPositions2d type; typedef VP::GeoPositions2d prop; }; +template <> struct _t2vp< osg::Pnt3d > +{ typedef osg::GeoPositions3d type; typedef VP::GeoPositions3d prop; }; +template <> struct _t2vp< osg::Pnt4d > +{ typedef osg::GeoPositions4d type; typedef VP::GeoPositions4d prop; }; + +template struct _t2vn; +template <> struct _t2vn< osg::Vec3f > +{ typedef osg::GeoNormals3f type; typedef VP::GeoNormals3f prop; }; + +template struct _t2vc; +template <> struct _t2vc< osg::Color3f > +{ typedef osg::GeoColors3f type; typedef VP::GeoColors3f prop; }; + +template <> struct _t2vc< osg::Color4f > +{ typedef osg::GeoColors4f type; typedef VP::GeoColors4f prop; }; + +template <> struct _t2vc< osg::Color3ub > +{ typedef osg::GeoColors3ub type; typedef VP::GeoColors3ub prop; }; + +template <> struct _t2vc< osg::Color4ub > +{ typedef osg::GeoColors4ub type; typedef VP::GeoColors3ub prop; }; + +template struct _t2vtc; +template <> struct _t2vtc< osg::Vec2f > +{ typedef osg::GeoTexCoords2f type; typedef VP::GeoTexCoords2f prop; }; + +template <> struct _t2vtc< osg::Vec3f > +{ typedef osg::GeoTexCoords3f type; typedef VP::GeoTexCoords3f prop; }; + +#endif + +//============================================================================= +} // namespace Kernel_OSG +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_PROPERTYT_HH defined +//============================================================================= + diff --git a/Tools/Kernel_OSG/Traits.hh b/Tools/Kernel_OSG/Traits.hh new file mode 100644 index 00000000..267c30ee --- /dev/null +++ b/Tools/Kernel_OSG/Traits.hh @@ -0,0 +1,87 @@ +//============================================================================= +// +// 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 Tools/Kernel_OSG/Traits.hh + This file defines the default traits and some convenienve macros. +*/ + + +//============================================================================= +// +// CLASS Traits +// +//============================================================================= + +#ifndef OPENMESH_KERNEL_OSG_TRAITS_HH +#define OPENMESH_KERNEL_OSG_TRAITS_HH + + +//== INCLUDES ================================================================= + + +#include +#include +// +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Kernel_OSG { + +//== CLASS DEFINITION ========================================================= + + +//== CLASS DEFINITION ========================================================= + + +/** Base class for all mesh traits using the OSGArrayKernelT. + * + * \see The Mesh docu section on \ref mesh_type. + * \see Traits.hh for a list of macros for traits classes. + */ +struct Traits : DefaultTraits +{ + typedef osg::Pnt3f Point; + typedef osg::Color3ub Color; + typedef osg::Vec3f Normal; + typedef osg::Vec2f TexCoord; + typedef osg::Vec3f::ValueType Scalar; + +}; + +//============================================================================= +} // namespace Kernel_OSG +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_TRAITS_HH defined +//============================================================================= + diff --git a/Tools/Kernel_OSG/TriMesh_OSGArrayKernelT.hh b/Tools/Kernel_OSG/TriMesh_OSGArrayKernelT.hh new file mode 100644 index 00000000..93d97f28 --- /dev/null +++ b/Tools/Kernel_OSG/TriMesh_OSGArrayKernelT.hh @@ -0,0 +1,99 @@ +//============================================================================= +// +// 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) $ +// +//============================================================================= + + +//============================================================================= +// +// CLASS TriMesh_OSGArrayKernelT +// +//============================================================================= + + +#ifndef OPENMESH_KERNEL_OSG_TRIMESH_OSGARRAYKERNEL_HH +#define OPENMESH_KERNEL_OSG_TRIMESH_OSGARRAYKERNEL_HH + + +//== INCLUDES ================================================================= + + +#include +// -------------------- +#include +#include +#include +#include +#include +#include +// -------------------- +#include +#include +#include +// -------------------- +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Kernel_OSG { + +//== CLASS DEFINITION ========================================================= + + +/// Helper class to create a TriMesh-type based on Kernel_OSG::ArrayKernelT +template +struct TriMesh_OSGArrayKernel_GeneratorT +{ + typedef FinalMeshItemsT MeshItems; + typedef AttribKernelT AttribKernel; + typedef ArrayKernelT MeshKernel; + typedef TriMeshT Mesh; +}; + + + +/** \ingroup mesh_types_group + Triangle mesh based on the Kernel_OSG::ArrayKernelT. + \see OpenMesh::TriMeshT + \see OpenMesh::ArrayKernelT +*/ +template +class TriMesh_OSGArrayKernelT + : public TriMesh_OSGArrayKernel_GeneratorT::Mesh +{}; + + +//============================================================================= +} // namespace Kernel_OSG +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_KERNEL_OSG_TRIMESH_OSGARRAYKERNEL_HH +//============================================================================= diff --git a/Tools/Kernel_OSG/VectorAdapter.hh b/Tools/Kernel_OSG/VectorAdapter.hh new file mode 100644 index 00000000..18480f3a --- /dev/null +++ b/Tools/Kernel_OSG/VectorAdapter.hh @@ -0,0 +1,182 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +// ---------------------------------------------------------------------------- + +#ifndef OPENMESH_KERNEL_OSG_VECTORADAPTER_HH +#define OPENMESH_KERNEL_OSG_VECTORADAPTER_HH + + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== CLASS DEFINITION ========================================================= + +// ----------------------------------------------------------------- class ---- + +#define OSG_VECTOR_TRAITS( VecType ) \ + template <> struct vector_traits< VecType > { \ + typedef VecType vector_type; \ + typedef vector_type::ValueType value_type; \ + typedef GenProg::Int2Type< vector_type::_iSize > typed_size; \ + \ + static const size_t size_ = vector_type::_iSize; \ + static size_t size() { return size_; } \ + } + +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Pnt4f ); +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Pnt3f ); +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Pnt2f ); + +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Vec4f ); +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Vec3f ); +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Vec2f ); + +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Pnt4d ); +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Pnt3d ); +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Pnt2d ); + +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Vec4d ); +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Vec3d ); + +/// Vector traits for OpenSG vector type +OSG_VECTOR_TRAITS( osg::Vec4ub ); + + +// ---------------------------------------------------------------------------- + + +#define OSG_COLOR_TRAITS( VecType, N ) \ + template <> struct vector_traits< VecType > { \ + typedef VecType vector_type; \ + typedef vector_type::ValueType value_type; \ + typedef GenProg::Int2Type< N > typed_size; \ + \ + static const size_t size_ = N; \ + static size_t size() { return size_; } \ + } + + +/// Vector traits for OpenSG color type +OSG_COLOR_TRAITS( osg::Color3ub, 3 ); +/// Vector traits for OpenSG color type +OSG_COLOR_TRAITS( osg::Color4ub, 4 ); +/// Vector traits for OpenSG color type +OSG_COLOR_TRAITS( osg::Color3f, 3 ); +/// Vector traits for OpenSG color type +OSG_COLOR_TRAITS( osg::Color4f, 4 ); + +#undef OSG_VECTOR_TRAITS + + +// ---------------------------------------- +#if 1 +#define PNT2VEC_CASTER( DST, SRC ) \ + template <> struct vector_caster< DST, SRC > { \ + typedef DST dst_t; \ + typedef SRC src_t; \ + typedef const dst_t& return_type; \ + inline static return_type cast( const src_t& _src ) {\ + return _src.subZero(); \ + } \ + } + +/// convert Pnt3f to Vec3f +PNT2VEC_CASTER( osg::Vec3f, osg::Pnt3f ); + +/// convert Pnt4f to Vec4f +PNT2VEC_CASTER( osg::Vec4f, osg::Pnt4f ); + +/// convert Pnt3d to Vec3d +PNT2VEC_CASTER( osg::Vec3d, osg::Pnt3d ); + +/// convert Pnt4d to Vec4d +PNT2VEC_CASTER( osg::Vec4d, osg::Pnt4d ); + +#undef PNT2VEC +#else + + template <> + struct vector_caster< osg::Vec3f, osg::Pnt3f > + { + typedef osg::Vec3f dst_t; + typedef osg::Pnt3f src_t; + + typedef const dst_t& return_type; + inline static return_type cast( const src_t& _src ) + { + std::cout << "casting Pnt3f to Vec3f\n"; + return _src.subZero(); + } + }; + +#endif +// ---------------------------------------- + +//@{ +/// Adapter for osg vector member computing a scalar product +inline +osg::Vec3f::ValueType dot( const osg::Vec3f &_v1, const osg::Vec3f &_v2 ) +{ return _v1.dot(_v2); } + + +inline +osg::Vec3f::ValueType dot( const osg::Vec3f &_v1, const osg::Pnt3f &_v2 ) +{ return _v1.dot(_v2); } + + +inline +osg::Vec2f::ValueType dot( const osg::Vec2f &_v1, const osg::Vec2f &_v2 ) +{ return _v1.dot(_v2); } + + +inline +osg::Vec3f cross( const osg::Vec3f &_v1, const osg::Vec3f &_v2 ) +{ return _v1.cross(_v2); } +//@} + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VECTORADAPTER_HH defined +//============================================================================= + diff --git a/Tools/Kernel_OSG/bindT.hh b/Tools/Kernel_OSG/bindT.hh new file mode 100644 index 00000000..80261a10 --- /dev/null +++ b/Tools/Kernel_OSG/bindT.hh @@ -0,0 +1,301 @@ +//============================================================================= +// +// 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 bindT.hh + + Bind an OpenMesh to a OpenSG geometry node. Be aware that due to + this link the geometry node maybe modified. For instance triangle + strips are converted to regular triangles. +*/ + + +//============================================================================= +// +// CLASS Traits +// +//============================================================================= + +#ifndef OPENMESH_KERNEL_OSG_BINDT_HH +#define OPENMESH_KERNEL_OSG_BINDT_HH + + +//== INCLUDES ================================================================= + + +#include +#include +// +#include +#include +#include +#include +// +#include "color_cast.hh" + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Kernel_OSG { + + +//== CLASS DEFINITION ========================================================= + +inline +bool type_is_valid( unsigned char _t ) +{ + return _t == GL_TRIANGLES + || _t == GL_TRIANGLE_STRIP + || _t == GL_QUADS + || _t == GL_POLYGON; +} + + +/** Bind a OpenSG geometry to a mesh. + * + * \param _mesh The mesh object to bind the geometry to. + * \param _geo The geometry object to bind. + * \return true if the connection has been established else false. + */ +template < typename Mesh > inline +bool bind( osg::GeometryPtr& _geo, Mesh& _mesh ) +{ + _geo = _mesh.createGeometryPtr(); +} + +/** Bind a mesh object to geometry. The binder is able to handle + * non-indexed and indexed geometry. Multi-indexed geometry is not + * supported. + * + * \param _mesh The mesh object to bind. + * \param _geo The geometry object to bind to. + * \return true if the connection has been established else false. + */ +template < typename Mesh > inline +bool bind( Mesh& _mesh, osg::GeometryPtr& _geo ) +{ + using namespace OpenMesh; + using namespace osg; + using namespace std; + + bool ok = true; + + // pre-check if types are supported + + GeoPTypesPtr types = _geo->getTypes(); + + if ( (size_t)count_if( types->getData(), types->getData()+types->size(), + ptr_fun(type_is_valid) ) != (size_t)types->size() ) + return false; + + // pre-check if it is a multi-indexed geometry, which is not supported! + + if ( _geo->getIndexMapping().getSize() > 1 ) + { + omerr << "OpenMesh::Kernel_OSG::bind(): Multi-indexed geometry is not supported!\n"; + return false; + } + + + // create shortcuts + + GeoPLengthsPtr lengths = _geo->getLengths(); + GeoIndicesPtr indices = _geo->getIndices(); + GeoPositionsPtr pos = _geo->getPositions(); + GeoNormalsPtr normals = _geo->getNormals(); + GeoColorsPtr colors = _geo->getColors(); + + + // -------------------- now convert everything to polygon/triangles + + size_t tidx, bidx; // types; base index into indices + vector< VertexHandle > vhandles; + + // ---------- initialize geometry + + { + VertexHandle vh; + typedef typename Mesh::Color color_t; + + bool bind_normal = (normals!=NullFC) && _mesh.has_vertex_normals(); + bool bind_color = (colors !=NullFC) && _mesh.has_vertex_colors(); + + for (bidx=0; bidx < pos->size(); ++bidx) + { + vh = _mesh.add_vertex( pos->getValue(bidx) ); + if ( bind_normal ) + _mesh.set_normal(vh, normals->getValue(bidx)); + if ( bind_color ) + _mesh.set_color(vh, color_cast(colors->getValue(bidx))); + } + } + + // ---------- create topology + + FaceHandle fh; + + size_t max_bidx = indices != NullFC ? indices->size() : pos->size(); + + for (bidx=tidx=0; ok && tidxsize() && bidx < max_bidx; ++tidx) + { + switch( types->getValue(tidx) ) + { + case GL_TRIANGLES: + vhandles.resize(3); + for(size_t lidx=0; lidx < lengths->getValue(tidx)-2; lidx+=3) + { + if (indices == NullFC ) { + vhandles[0] = VertexHandle(bidx+lidx); + vhandles[1] = VertexHandle(bidx+lidx+1); + vhandles[2] = VertexHandle(bidx+lidx+2); + } + else { + vhandles[0] = VertexHandle(indices->getValue(bidx+lidx ) ); + vhandles[1] = VertexHandle(indices->getValue(bidx+lidx+1) ); + vhandles[2] = VertexHandle(indices->getValue(bidx+lidx+2) ); + } + + if ( !(fh = _mesh.add_face( vhandles )).is_valid() ) + { + // if fh is complex try swapped order + swap(vhandles[2], vhandles[1]); + fh = _mesh.add_face( vhandles ); + } + ok = fh.is_valid(); + } + break; + + case GL_TRIANGLE_STRIP: + vhandles.resize(3); + for (size_t lidx=0; lidx < lengths->getValue(tidx)-2; ++lidx) + { + if (indices == NullFC ) { + vhandles[0] = VertexHandle(bidx+lidx); + vhandles[1] = VertexHandle(bidx+lidx+1); + vhandles[2] = VertexHandle(bidx+lidx+2); + } + else { + vhandles[0] = VertexHandle(indices->getValue(bidx+lidx ) ); + vhandles[1] = VertexHandle(indices->getValue(bidx+lidx+1) ); + vhandles[2] = VertexHandle(indices->getValue(bidx+lidx+2) ); + } + + if (vhandles[0]!=vhandles[2] && + vhandles[0]!=vhandles[1] && + vhandles[1]!=vhandles[2]) + { + // if fh is complex try swapped order + bool swapped(false); + + if (lidx % 2) // odd numbered triplet must be reordered + swap(vhandles[2], vhandles[1]); + + if ( !(fh = _mesh.add_face( vhandles )).is_valid() ) + { + omlog << "OpenMesh::Kernel_OSG::bind(): complex entity!\n"; + + swap(vhandles[2], vhandles[1]); + fh = _mesh.add_face( vhandles ); + swapped = true; + } + ok = fh.is_valid(); + } + } + break; + + case GL_QUADS: + vhandles.resize(4); + for(size_t nf=_mesh.n_faces(), lidx=0; + lidx < lengths->getValue(tidx)-3; lidx+=4) + { + if (indices == NullFC ) { + vhandles[0] = VertexHandle(bidx+lidx); + vhandles[1] = VertexHandle(bidx+lidx+1); + vhandles[2] = VertexHandle(bidx+lidx+2); + vhandles[3] = VertexHandle(bidx+lidx+3); + } + else { + vhandles[0] = VertexHandle(indices->getValue(bidx+lidx ) ); + vhandles[1] = VertexHandle(indices->getValue(bidx+lidx+1) ); + vhandles[2] = VertexHandle(indices->getValue(bidx+lidx+2) ); + vhandles[3] = VertexHandle(indices->getValue(bidx+lidx+3) ); + } + + fh = _mesh.add_face( vhandles ); + ok = ( Mesh::Face::is_triangle() && (_mesh.n_faces()==(nf+2))) + || fh.is_valid(); + nf = _mesh.n_faces(); + } + break; + + case GL_POLYGON: + { + size_t ne = lengths->getValue(tidx); + size_t nf = _mesh.n_faces(); + + vhandles.resize(ne); + + for(size_t lidx=0; lidx < ne; ++lidx) + vhandles[lidx] = (indices == NullFC) + ? VertexHandle(bidx+lidx) + : VertexHandle(indices->getValue(bidx+lidx) ); + + fh = _mesh.add_face( vhandles ); + ok = ( Mesh::Face::is_triangle() && (_mesh.n_faces()==nf+ne-2) ) + || fh.is_valid(); + + break; + } + default: + cerr << "Warning! Skipping unsupported type " + << types->getValue(tidx) << " '" + << Utils::GLenum_as_string( types->getValue(tidx) ) << "'\n"; + } + + // update base index into indices for next face type + bidx += lengths->getValue(tidx); + } + + if (ok) + ok=_mesh.bind(_geo); + else + _mesh.clear(); + + return ok; +} + + +//============================================================================= +} // namespace Kernel_OSG +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_KERNEL_OSG_BINDT_HH defined +//============================================================================= + diff --git a/Tools/Kernel_OSG/color_cast.hh b/Tools/Kernel_OSG/color_cast.hh new file mode 100644 index 00000000..cff7a7c2 --- /dev/null +++ b/Tools/Kernel_OSG/color_cast.hh @@ -0,0 +1,43 @@ +#ifndef OPENMESH_KERNEL_OSG_COLOR_CAST_HH +#define OPENMESH_KERNEL_OSG_COLOR_CAST_HH + +#include +#include +#include + +namespace OpenMesh { + +/// Helper struct +/// \internal +template <> +struct color_caster +{ + typedef osg::Color3ub return_type; + typedef unsigned char ub; + + inline static return_type cast(const osg::Color3f& _src) + { + return return_type( (ub)std::min((_src[0]* 255.0f + 0.5f),255.0f), + (ub)std::min((_src[1]* 255.0f + 0.5f),255.0f), + (ub)std::min((_src[2]* 255.0f + 0.5f),255.0f) ); + } +}; + +/// Helper struct +/// \internal +template <> +struct color_caster +{ + typedef osg::Color3f return_type; + + inline static return_type cast(const osg::Color3ub& _src) + { + return return_type( (float)(_src[0] / 255.0f ), + (float)(_src[1] / 255.0f ), + (float)(_src[2] / 255.0f ) ); + } +}; + +} // namespace OpenMesh + +#endif // OPENMESH_KERNEL_OSG_COLOR_CAST_HH diff --git a/Tools/OpenMesh_Tools.vcproj b/Tools/OpenMesh_Tools.vcproj new file mode 100755 index 00000000..4a9386a2 --- /dev/null +++ b/Tools/OpenMesh_Tools.vcproj @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/Smoother/JacobiLaplaceSmootherT.cc b/Tools/Smoother/JacobiLaplaceSmootherT.cc new file mode 100644 index 00000000..28290277 --- /dev/null +++ b/Tools/Smoother/JacobiLaplaceSmootherT.cc @@ -0,0 +1,183 @@ +//============================================================================= +// +// 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 JacobiLaplaceSmootherT.cc + + */ + +//============================================================================= +// +// CLASS JacobiLaplaceSmootherT - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_JACOBI_LAPLACE_SMOOTHERT_C + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Smoother { + + +//== IMPLEMENTATION ========================================================== + + +template +void +JacobiLaplaceSmootherT:: +smooth(unsigned int _n) +{ + if (Base::continuity() > Base::C0) + { + Base::mesh_.add_property(umbrellas_); + if (Base::continuity() > Base::C1) + Base::mesh_.add_property(squared_umbrellas_); + } + + LaplaceSmootherT::smooth(_n); + + if (Base::continuity() > Base::C0) + { + Base::mesh_.remove_property(umbrellas_); + if (Base::continuity() > Base::C1) + Base::mesh_.remove_property(squared_umbrellas_); + } +} + + +//----------------------------------------------------------------------------- + + +template +void +JacobiLaplaceSmootherT:: +compute_new_positions_C0() +{ + typename Mesh::VertexIter v_it, v_end(Base::mesh_.vertices_end()); + typename Mesh::CVVIter vv_it; + typename Mesh::Normal u, p, zero(0,0,0); + typename Mesh::Scalar w; + + for (v_it=Base::mesh_.vertices_begin(); v_it!=v_end; ++v_it) + { + if (is_active(v_it)) + { + // compute umbrella + u = zero; + for (vv_it=Base::mesh_.cvv_iter(v_it); vv_it; ++vv_it) + { + w = weight(Base::mesh_.edge_handle(vv_it.current_halfedge_handle())); + u += vector_cast(Base::mesh_.point(vv_it)) * w; + } + u *= weight(v_it); + u -= vector_cast(Base::mesh_.point(v_it)); + + // damping + u *= 0.5; + + // store new position + p = vector_cast(Base::mesh_.point(v_it)); + p += u; + set_new_position(v_it, p); + } + } +} + + +//----------------------------------------------------------------------------- + + +template +void +JacobiLaplaceSmootherT:: +compute_new_positions_C1() +{ + typename Mesh::VertexIter v_it, v_end(Base::mesh_.vertices_end()); + typename Mesh::CVVIter vv_it; + typename Mesh::Normal u, uu, p, zero(0,0,0); + typename Mesh::Scalar w, diag; + + + // 1st pass: compute umbrellas + for (v_it=Base::mesh_.vertices_begin(); v_it!=v_end; ++v_it) + { + u = zero; + for (vv_it=Base::mesh_.cvv_iter(v_it); vv_it; ++vv_it) + { + w = weight(Base::mesh_.edge_handle(vv_it.current_halfedge_handle())); + u -= vector_cast(Base::mesh_.point(vv_it))*w; + } + u *= weight(v_it); + u += vector_cast(Base::mesh_.point(v_it)); + + Base::mesh_.property(umbrellas_, v_it) = u; + } + + + // 2nd pass: compute updates + for (v_it=Base::mesh_.vertices_begin(); v_it!=v_end; ++v_it) + { + if (is_active(v_it)) + { + uu = zero; + diag = 0.0; + for (vv_it=Base::mesh_.cvv_iter(v_it); vv_it; ++vv_it) + { + w = weight(Base::mesh_.edge_handle(vv_it.current_halfedge_handle())); + uu -= Base::mesh_.property(umbrellas_, vv_it); + diag += (w * weight(vv_it) + 1.0) * w; + } + uu *= weight(v_it); + diag *= weight(v_it); + uu += Base::mesh_.property(umbrellas_, v_it); + if (diag) uu *= 1.0/diag; + + // damping + uu *= 0.25; + + // store new position + p = vector_cast(Base::mesh_.point(v_it)); + p -= uu; + set_new_position(v_it, p); + } + } +} + + +//============================================================================= +} // namespace Smoother +} // namespace OpenMesh +//============================================================================= diff --git a/Tools/Smoother/JacobiLaplaceSmootherT.hh b/Tools/Smoother/JacobiLaplaceSmootherT.hh new file mode 100644 index 00000000..03d602d1 --- /dev/null +++ b/Tools/Smoother/JacobiLaplaceSmootherT.hh @@ -0,0 +1,99 @@ +//============================================================================= +// +// 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 JacobiLaplaceSmootherT.hh + + */ + + +//============================================================================= +// +// CLASS JacobiLaplaceSmootherT +// +//============================================================================= + +#ifndef OPENMESH_JACOBI_LAPLACE_SMOOTHERT_HH +#define OPENMESH_JACOBI_LAPLACE_SMOOTHERT_HH + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Smoother { + +//== CLASS DEFINITION ========================================================= + +/** Laplacian Smoothing. + * + */ +template +class JacobiLaplaceSmootherT : public LaplaceSmootherT +{ +private: + typedef LaplaceSmootherT Base; + +public: + + JacobiLaplaceSmootherT( Mesh& _mesh ) : LaplaceSmootherT(_mesh) {} + + // override: alloc umbrellas + void smooth(unsigned int _n); + + +protected: + + virtual void compute_new_positions_C0(); + virtual void compute_new_positions_C1(); + + +private: + + OpenMesh::VPropHandleT umbrellas_; + OpenMesh::VPropHandleT squared_umbrellas_; +}; + + +//============================================================================= +} // namespace Smoother +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_JACOBI_LAPLACE_SMOOTHERT_C) +#define OPENMESH_JACOBI_LAPLACE_SMOOTHERT_TEMPLATES +#include "JacobiLaplaceSmootherT.cc" +#endif +//============================================================================= +#endif // OPENMESH_JACOBI_LAPLACE_SMOOTHERT_HH defined +//============================================================================= + diff --git a/Tools/Smoother/LaplaceSmootherT.cc b/Tools/Smoother/LaplaceSmootherT.cc new file mode 100644 index 00000000..c7ec17cc --- /dev/null +++ b/Tools/Smoother/LaplaceSmootherT.cc @@ -0,0 +1,209 @@ +//============================================================================= +// +// 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 LaplaceSmootherT.cc + + */ + +//============================================================================= +// +// CLASS LaplaceSmootherT - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_LAPLACE_SMOOTHERT_C + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Smoother { + + +//== IMPLEMENTATION ========================================================== + + +template +LaplaceSmootherT:: +LaplaceSmootherT(Mesh& _mesh) + : SmootherT(_mesh) +{ + // custom properties + Base::mesh_.add_property(vertex_weights_); + Base::mesh_.add_property(edge_weights_); +} + + +//----------------------------------------------------------------------------- + + +template +LaplaceSmootherT:: +~LaplaceSmootherT() +{ + // free custom properties + Base::mesh_.remove_property(vertex_weights_); + Base::mesh_.remove_property(edge_weights_); +} + + +//----------------------------------------------------------------------------- + + +template +void +LaplaceSmootherT:: +initialize(Component _comp, Continuity _cont) +{ + SmootherT::initialize(_comp, _cont); + + // calculate weights + switch (_comp) + { + case Base::Tangential: + compute_weights(UniformWeighting); + break; + + + case Base::Normal: + compute_weights(CotWeighting); + break; + + + case Base::Tangential_and_Normal: + compute_weights(UniformWeighting); + break; + } +} + + +//----------------------------------------------------------------------------- + + +template +void +LaplaceSmootherT:: +compute_weights(LaplaceWeighting _weighting) +{ + typename Mesh::VertexIter v_it, v_end(Base::mesh_.vertices_end()); + typename Mesh::EdgeIter e_it, e_end(Base::mesh_.edges_end()); + typename Mesh::HalfedgeHandle heh0, heh1, heh2; + typename Mesh::VertexHandle v0, v1; + const typename Mesh::Point *p0, *p1, *p2; + typename Mesh::Normal d0, d1; + typename Mesh::Scalar weight, lb(-1.0), ub(1.0); + + + + // init vertex weights + for (v_it=Base::mesh_.vertices_begin(); v_it!=v_end; ++v_it) + Base::mesh_.property(vertex_weights_, v_it) = 0.0; + + + + switch (_weighting) + { + // Uniform weighting + case UniformWeighting: + { + for (e_it=Base::mesh_.edges_begin(); e_it!=e_end; ++e_it) + { + heh0 = Base::mesh_.halfedge_handle(e_it.handle(), 0); + heh1 = Base::mesh_.halfedge_handle(e_it.handle(), 1); + v0 = Base::mesh_.to_vertex_handle(heh0); + v1 = Base::mesh_.to_vertex_handle(heh1); + + Base::mesh_.property(edge_weights_, e_it) = 1.0; + Base::mesh_.property(vertex_weights_, v0) += 1.0; + Base::mesh_.property(vertex_weights_, v1) += 1.0; + } + + break; + } + + + // Cotangent weighting + case CotWeighting: + { + for (e_it=Base::mesh_.edges_begin(); e_it!=e_end; ++e_it) + { + weight = 0.0; + + heh0 = Base::mesh_.halfedge_handle(e_it.handle(), 0); + v0 = Base::mesh_.to_vertex_handle(heh0); + p0 = &Base::mesh_.point(v0); + + heh1 = Base::mesh_.halfedge_handle(e_it.handle(), 1); + v1 = Base::mesh_.to_vertex_handle(heh1); + p1 = &Base::mesh_.point(v1); + + heh2 = Base::mesh_.next_halfedge_handle(heh0); + p2 = &Base::mesh_.point(Base::mesh_.to_vertex_handle(heh2)); + d0 = (*p0 - *p2); d0.normalize(); + d1 = (*p1 - *p2); d1.normalize(); + weight += 1.0 / tan(acos(std::max(lb, std::min(ub, dot(d0,d1) )))); + + heh2 = Base::mesh_.next_halfedge_handle(heh1); + p2 = &Base::mesh_.point(Base::mesh_.to_vertex_handle(heh2)); + d0 = (*p0 - *p2); d0.normalize(); + d1 = (*p1 - *p2); d1.normalize(); + weight += 1.0 / tan(acos(std::max(lb, std::min(ub, dot(d0,d1) )))); + + Base::mesh_.property(edge_weights_, e_it) = weight; + Base::mesh_.property(vertex_weights_, v0) += weight; + Base::mesh_.property(vertex_weights_, v1) += weight; + } + break; + } + } + + + // invert vertex weights: + // before: sum of edge weights + // after: one over sum of edge weights + for (v_it=Base::mesh_.vertices_begin(); v_it!=v_end; ++v_it) + { + weight = Base::mesh_.property(vertex_weights_, v_it); + if (weight) + Base::mesh_.property(vertex_weights_, v_it) = 1.0 / weight; + } +} + + + +//============================================================================= +} // namespace Smoother +} // namespace OpenMesh +//============================================================================= diff --git a/Tools/Smoother/LaplaceSmootherT.hh b/Tools/Smoother/LaplaceSmootherT.hh new file mode 100644 index 00000000..61b74f54 --- /dev/null +++ b/Tools/Smoother/LaplaceSmootherT.hh @@ -0,0 +1,113 @@ +//============================================================================= +// +// 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 LaplaceSmootherT.hh + + */ + +//============================================================================= +// +// CLASS LaplaceSmootherT +// +//============================================================================= + +#ifndef OPENMESH_LAPLACE_SMOOTHERT_HH +#define OPENMESH_LAPLACE_SMOOTHERT_HH + + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Smoother { + +//== CLASS DEFINITION ========================================================= + +/// Laplacian Smoothing. +template +class LaplaceSmootherT : public SmootherT +{ +private: + typedef SmootherT Base; +public: + + typedef typename SmootherT::Component Component; + typedef typename SmootherT::Continuity Continuity; + typedef typename SmootherT::Scalar Scalar; + typedef typename SmootherT::VertexHandle VertexHandle; + typedef typename SmootherT::EdgeHandle EdgeHandle; + + + LaplaceSmootherT( Mesh& _mesh ); + virtual ~LaplaceSmootherT(); + + + void initialize(Component _comp, Continuity _cont); + + +protected: + + // misc helpers + + Scalar weight(VertexHandle _vh) const + { return Base::mesh_.property(vertex_weights_, _vh); } + + Scalar weight(EdgeHandle _eh) const + { return Base::mesh_.property(edge_weights_, _eh); } + + +private: + + enum LaplaceWeighting { UniformWeighting, CotWeighting }; + void compute_weights(LaplaceWeighting _mode); + + + OpenMesh::VPropHandleT vertex_weights_; + OpenMesh::EPropHandleT edge_weights_; +}; + + +//============================================================================= +} // namespace Smoother +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_LAPLACE_SMOOTHERT_C) +#define OPENMESH_LAPLACE_SMOOTHERT_TEMPLATES +#include "LaplaceSmootherT.cc" +#endif +//============================================================================= +#endif // OPENMESH_LAPLACE_SMOOTHERT_HH defined +//============================================================================= + diff --git a/Tools/Smoother/SmootherT.cc b/Tools/Smoother/SmootherT.cc new file mode 100644 index 00000000..488f602c --- /dev/null +++ b/Tools/Smoother/SmootherT.cc @@ -0,0 +1,394 @@ +//============================================================================= +// +// 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 SmootherT.cc + + */ + +//============================================================================= +// +// CLASS SmootherT - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_SMOOTHERT_C + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Smoother { + + +//== IMPLEMENTATION ========================================================== + + +template +SmootherT:: +SmootherT(Mesh& _mesh) + : mesh_(_mesh) +{ + // request properties + mesh_.request_vertex_status(); + mesh_.request_face_normals(); + mesh_.request_vertex_normals(); + + // custom properties + mesh_.add_property(original_positions_); + mesh_.add_property(original_normals_); + mesh_.add_property(new_positions_); + mesh_.add_property(is_active_); + + + // default settings + component_ = Tangential_and_Normal; + continuity_ = C0; + tolerance_ = -1.0; +} + + +//----------------------------------------------------------------------------- + + +template +SmootherT:: +~SmootherT() +{ + // free properties + mesh_.release_vertex_status(); + mesh_.release_face_normals(); + mesh_.release_vertex_normals(); + + // free custom properties + mesh_.remove_property(original_positions_); + mesh_.remove_property(original_normals_); + mesh_.remove_property(new_positions_); + mesh_.remove_property(is_active_); +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +initialize(Component _comp, Continuity _cont) +{ + typename Mesh::VertexIter v_it, v_end(mesh_.vertices_end()); + + + // store smoothing settings + component_ = _comp; + continuity_ = _cont; + + + // update normals + mesh_.update_face_normals(); + mesh_.update_vertex_normals(); + + + // store original points & normals + for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) + { + mesh_.property(original_positions_, v_it) = mesh_.point(v_it); + mesh_.property(original_normals_, v_it) = mesh_.normal(v_it); + } +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +set_active_vertices() +{ + typename Mesh::VertexIter v_it, v_end(mesh_.vertices_end()); + + + // is something selected? + bool nothing_selected(true); + for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) + if (mesh_.status(v_it).selected()) + { nothing_selected = false; break; } + + + // tagg all active vertices + bool active; + for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) + { + active = ((nothing_selected || mesh_.status(v_it).selected()) + && !mesh_.is_boundary(v_it) + && !mesh_.status(v_it).locked()); + mesh_.property(is_active_, v_it) = active; + } + + + // C1: remove one ring of boundary vertices + if (continuity_ == C1) + { + typename Mesh::VVIter vv_it; + + for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) + if (mesh_.is_boundary(v_it)) + for (vv_it=mesh_.vv_iter(v_it); vv_it; ++vv_it) + mesh_.property(is_active_, vv_it) = false; + } + + + // C2: remove two rings of boundary vertices + if (continuity_ == C2) + { + typename Mesh::VVIter vv_it; + + for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) + { + mesh_.status(v_it).set_tagged(false); + mesh_.status(v_it).set_tagged2(false); + } + + for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) + if (mesh_.is_boundary(v_it)) + for (vv_it=mesh_.vv_iter(v_it); vv_it; ++vv_it) + mesh_.status(v_it).set_tagged(true); + + for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) + if (mesh_.status(v_it).tagged()) + for (vv_it=mesh_.vv_iter(v_it); vv_it; ++vv_it) + mesh_.status(v_it).set_tagged2(true); + + for (v_it=mesh_.vertices_begin(); v_it!=v_end; ++v_it) + { + if (mesh_.status(v_it).tagged2()) + mesh_.property(is_active_, vv_it) = false; + mesh_.status(v_it).set_tagged(false); + mesh_.status(v_it).set_tagged2(false); + } + } +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +set_relative_local_error(Scalar _err) +{ + if (!mesh_.vertices_empty()) + { + typename Mesh::VertexIter v_it(mesh_.vertices_begin()), + v_end(mesh_.vertices_end()); + + + // compute bounding box + Point bb_min, bb_max; + bb_min = bb_max = mesh_.point(v_it); + for (++v_it; v_it!=v_end; ++v_it) + { + bb_min.minimize(mesh_.point(v_it)); + bb_max.minimize(mesh_.point(v_it)); + } + + + // abs. error = rel. error * bounding-diagonal + set_absolute_error(_err * (bb_max-bb_min).norm()); + } +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +set_absolute_local_error(Scalar _err) +{ + tolerance_ = _err; +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +disable_local_error_check() +{ + tolerance_ = -1.0; +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +smooth(unsigned int _n) +{ + // mark active vertices + set_active_vertices(); + + // smooth _n iterations + while (_n--) + { + compute_new_positions(); + + if (component_ == Tangential) + project_to_tangent_plane(); + + else if (tolerance_ >= 0.0) + local_error_check(); + + move_points(); + } +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +compute_new_positions() +{ + switch (continuity_) + { + case C0: + compute_new_positions_C0(); + break; + + case C1: + compute_new_positions_C1(); + break; + + case C2: + break; + } +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +project_to_tangent_plane() +{ + typename Mesh::VertexIter v_it(mesh_.vertices_begin()), + v_end(mesh_.vertices_end()); + // Normal should be a vector type. In some environment a vector type + // is different from point type, e.g. OpenSG! + typename Mesh::Normal translation, normal; + + + for (; v_it != v_end; ++v_it) + { + if (is_active(v_it)) + { + translation = new_position(v_it)-orig_position(v_it); + normal = orig_normal(v_it); + normal *= dot(translation, normal); + translation -= normal; + translation += vector_cast(orig_position(v_it)); + set_new_position(v_it, translation); + } + } +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +local_error_check() +{ + typename Mesh::VertexIter v_it(mesh_.vertices_begin()), + v_end(mesh_.vertices_end()); + + typename Mesh::Normal translation; + typename Mesh::Scalar s; + + + for (; v_it != v_end; ++v_it) + { + if (is_active(v_it)) + { + translation = new_position(v_it) - orig_position(v_it); + + s = fabs(dot(translation, orig_normal(v_it))); + + if (s > tolerance_) + { + translation *= (tolerance_ / s); + translation += vector_cast(orig_position(v_it)); + set_new_position(v_it, translation); + } + } + } +} + + +//----------------------------------------------------------------------------- + + +template +void +SmootherT:: +move_points() +{ + typename Mesh::VertexIter v_it(mesh_.vertices_begin()), + v_end(mesh_.vertices_end()); + + for (; v_it != v_end; ++v_it) + if (is_active(v_it)) + mesh_.set_point(v_it, mesh_.property(new_positions_, v_it)); +} + + +//============================================================================= +} // namespace Smoother +} // namespace OpenMesh +//============================================================================= diff --git a/Tools/Smoother/SmootherT.hh b/Tools/Smoother/SmootherT.hh new file mode 100644 index 00000000..553064df --- /dev/null +++ b/Tools/Smoother/SmootherT.hh @@ -0,0 +1,188 @@ +//============================================================================= +// +// 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 SmootherT.hh + + */ + +//============================================================================= +// +// CLASS SmootherT +// +//============================================================================= + +#ifndef OPENMESH_SMOOTHER_SMOOTHERT_HH +#define OPENMESH_SMOOTHER_SMOOTHERT_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include + +//== FORWARDDECLARATIONS ====================================================== + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Smoother { + +//== CLASS DEFINITION ========================================================= + +/** Base class for smoothing algorithms. + */ +template +class SmootherT : private Utils::Noncopyable +{ +public: + + typedef typename Mesh::Scalar Scalar; + typedef typename Mesh::Point Point; + typedef typename Mesh::Normal NormalType; + typedef typename Mesh::VertexHandle VertexHandle; + typedef typename Mesh::EdgeHandle EdgeHandle; + + // initialize smoother + enum Component { + Tangential, ///< Smooth tangential direction + Normal, ///< Smooth normal direction + Tangential_and_Normal ///< Smooth tangential and normal direction + }; + + enum Continuity { + C0, + C1, + C2 + }; + +public: + + // constructor & destructor + SmootherT( Mesh& _mesh ); + virtual ~SmootherT(); + + +public: + + /// Initialize smoother + /// \param _comp Determine component to smooth + /// \param _cont + void initialize(Component _comp, Continuity _cont); + + + //@{ + /// Set local error + void set_relative_local_error(Scalar _err); + void set_absolute_local_error(Scalar _err); + void disable_local_error_check(); + //@} + + + /// Do _n smoothing iterations + virtual void smooth(unsigned int _n); + + + + /// Find active vertices. Resets tagged status ! + void set_active_vertices(); + + +private: + + // single steps of smoothing + void compute_new_positions(); + void project_to_tangent_plane(); + void local_error_check(); + void move_points(); + + + +protected: + + // override these + virtual void compute_new_positions_C0() = 0; + virtual void compute_new_positions_C1() = 0; + + + +protected: + + // misc helpers + + const Point& orig_position(VertexHandle _vh) const + { return mesh_.property(original_positions_, _vh); } + + const NormalType& orig_normal(VertexHandle _vh) const + { return mesh_.property(original_normals_, _vh); } + + const Point& new_position(VertexHandle _vh) const + { return mesh_.property(new_positions_, _vh); } + + void set_new_position(VertexHandle _vh, const Point& _p) + { mesh_.property(new_positions_, _vh) = _p; } + + bool is_active(VertexHandle _vh) const + { return mesh_.property(is_active_, _vh); } + + Component component() const { return component_; } + Continuity continuity() const { return continuity_; } + +protected: + + Mesh& mesh_; + + +private: + + Scalar tolerance_; + Scalar normal_deviation_; + Component component_; + Continuity continuity_; + + OpenMesh::VPropHandleT original_positions_; + OpenMesh::VPropHandleT original_normals_; + OpenMesh::VPropHandleT new_positions_; + OpenMesh::VPropHandleT is_active_; +}; + + +//============================================================================= +} // namespace Smoother +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_SMOOTHERT_C) +#define OPENMESH_SMOOTHERT_TEMPLATES +#include "SmootherT.cc" +#endif +//============================================================================= +#endif // OPENMESH_SMOOTHER_SMOOTHERT_HH defined +//============================================================================= + diff --git a/Tools/Smoother/smooth_mesh.hh b/Tools/Smoother/smooth_mesh.hh new file mode 100644 index 00000000..67f2d0c3 --- /dev/null +++ b/Tools/Smoother/smooth_mesh.hh @@ -0,0 +1,92 @@ +//============================================================================= +// +// 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) $ +// +//============================================================================= + +#ifndef SMOOTH_MESH_HH +#define SMOOTH_MESH_HH + +//== INCLUDES ================================================================= + +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { //BEGIN_NS_OPENMESH + +template +void smooth_mesh_property(unsigned int _n_iters, _Mesh& _m, _PropertyHandle _pph) +{ + typedef typename _PropertyHandle::Value Value; + + std::vector temp_values(_m.n_vertices()); + + for (unsigned int i=0; i < _n_iters; ++i) + { + for ( typename _Mesh::ConstVertexIter cv_it = _m.vertices_begin(); + cv_it != _m.vertices_end(); ++cv_it) + { + unsigned int valence = 0; + + Value& temp_value = temp_values[cv_it.handle().idx()]; + + temp_value.vectorize(0); + + for ( typename _Mesh::ConstVertexVertexIter cvv_it = _m.cvv_iter(cv_it); + cvv_it; ++cvv_it) + { + temp_value += _m.property(_pph,cvv_it); + ++valence; + } + if (valence > 0) + {//guard against isolated vertices + temp_value *= (typename Value::value_type)(1.0 / valence); + } + else + { + temp_value = _m.property(_pph, cv_it); + } + } + + for ( typename _Mesh::ConstVertexIter cv_it = _m.vertices_begin(); + cv_it != _m.vertices_end(); ++cv_it) + { + _m.property(_pph,cv_it) = temp_values[cv_it.handle().idx()]; + } + } +} + +template +void smooth_mesh(_Mesh& _m, uint _n_iters) +{ + smooth_mesh_property(_n_iters, _m, _m.points_pph()); +} + +};//namespace OpenMesh + +#endif//SMOOTH_MESH_HH diff --git a/Tools/Subdivider/ACGMakefile b/Tools/Subdivider/ACGMakefile new file mode 100644 index 00000000..bbd4512f --- /dev/null +++ b/Tools/Subdivider/ACGMakefile @@ -0,0 +1,17 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = $(call find-subdirs) + +PACKAGES := + +PROJ_LIBS := + +MODULES := cxxlib + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Tools/Subdivider/Adaptive/ACGMakefile b/Tools/Subdivider/Adaptive/ACGMakefile new file mode 100644 index 00000000..14572293 --- /dev/null +++ b/Tools/Subdivider/Adaptive/ACGMakefile @@ -0,0 +1,17 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = $(call find-subdirs) + +PACKAGES := qt glut opengl x11 math + +PROJ_LIBS = OpenMesh/Core + +MODULES := moc cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Tools/Subdivider/Adaptive/Composite/ACGMakefile b/Tools/Subdivider/Adaptive/Composite/ACGMakefile new file mode 100644 index 00000000..1a042f5d --- /dev/null +++ b/Tools/Subdivider/Adaptive/Composite/ACGMakefile @@ -0,0 +1,17 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = + +PACKAGES := math + +PROJ_LIBS = OpenMesh/Core + +MODULES := cxx + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Tools/Subdivider/Adaptive/Composite/CompositeT.cc b/Tools/Subdivider/Adaptive/Composite/CompositeT.cc new file mode 100644 index 00000000..5b61e080 --- /dev/null +++ b/Tools/Subdivider/Adaptive/Composite/CompositeT.cc @@ -0,0 +1,307 @@ +//============================================================================= +// +// 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 Adaptive/Composite/CompositeT.cc + + */ + +//============================================================================= +// +// CLASS CompositeT - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_SUBDIVIDER_ADAPTIVE_COMPOSITET_CC + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Adaptive { // BEGIN_NS_UNIFORM + + +//== IMPLEMENTATION ========================================================== + + +template +bool +CompositeT :: +initialize( void ) +{ + typename Mesh::VertexIter v_it; + typename Mesh::FaceIter f_it; + typename Mesh::EdgeIter e_it; + const typename Mesh::Point zero_point(0.0, 0.0, 0.0); + + // ---------------------------------------- Init Vertices + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) + { + mesh_.data(v_it).set_state(0); + mesh_.data(v_it).set_final(); + mesh_.data(v_it).set_position(0, mesh_.point(v_it.handle())); + } + + // ---------------------------------------- Init Faces + for (f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it) + { + mesh_.data(f_it).set_state(0); + mesh_.data(f_it).set_final(); + mesh_.data(f_it).set_position(0, zero_point); + } + + // ---------------------------------------- Init Edges + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) + { + mesh_.data(e_it).set_state(0); + mesh_.data(e_it).set_final(); + mesh_.data(e_it).set_position(0, zero_point); + } + + + // ---------------------------------------- Init Rules + + int n_subdiv_rules_ = 0; + + + // look for subdivision rule(s) + for (size_t i=0; i < n_rules(); ++i) { + + if (rule_sequence_[i]->type()[0] == 'T' || + rule_sequence_[i]->type()[0] == 't') + { + ++n_subdiv_rules_; + subdiv_rule_ = rule_sequence_[i]; + subdiv_type_ = rule_sequence_[i]->subdiv_type(); + } + } + + + // check for correct number of subdivision rules + assert(n_subdiv_rules_ == 1); + + if (n_subdiv_rules_ != 1) + { + std::cerr << "Error! More than one subdivision rules not allowed!\n"; + return false; + } + + // check for subdivision type + assert(subdiv_type_ == 3 || subdiv_type_ == 4); + + if (subdiv_type_ != 3 && subdiv_type_ != 4) + { + ::omerr() << "Error! Unknown subdivision type in sequence!" << std::endl; + return false; + } + + // set pointer to last rule +// first_rule_ = rule_sequence_.front(); +// last_rule_ = rule_sequence_.back(); //[n_rules() - 1]; + + // set numbers and previous rule + for (size_t i = 0; i < n_rules(); ++i) + { + rule_sequence_[i]->set_subdiv_type(subdiv_type_); + rule_sequence_[i]->set_n_rules(n_rules()); + rule_sequence_[i]->set_number(i); + rule_sequence_[i]->set_prev_rule(rule_sequence_[(i+n_rules()-1)%n_rules()]); + rule_sequence_[i]->set_subdiv_rule(subdiv_rule_); + } + + return true; +} + + +// ---------------------------------------------------------------------------- +#define MOBJ mesh_.deref +#define TVH to_vertex_handle +#define HEH halfedge_handle +#define NHEH next_halfedge_handle +#define PHEH prev_halfedge_handle +#define OHEH opposite_halfedge_handle +// ---------------------------------------------------------------------------- + + +template +void CompositeT::refine(typename Mesh::FaceHandle& _fh) +{ + std::vector hh_vector; + + // -------------------- calculate new level for faces and vertices + int new_face_level = + t_rule()->number() + 1 + + ((int)floor((float)(mesh_.data(_fh).state() - t_rule()->number() - 1)/n_rules()) + 1) * n_rules(); + + int new_vertex_level = + new_face_level + l_rule()->number() - t_rule()->number(); + + // -------------------- store old vertices + // !!! only triangle meshes supported! + typename Mesh::VertexHandle vh[3]; + + vh[0] = mesh_.TVH(mesh_.HEH(_fh)); + vh[1] = mesh_.TVH(mesh_.NHEH(mesh_.HEH(_fh))); + vh[2] = mesh_.TVH(mesh_.PHEH(mesh_.HEH(_fh))); + + // save handles to incoming halfedges for getting the new vertices + // after subdivision (1-4 split) + if (subdiv_type_ == 4) + { + hh_vector.clear(); + + // green face + if (mesh_.data(_fh).final()) + { + typename Mesh::FaceHalfedgeIter fh_it(mesh_.fh_iter(_fh)); + + for (; fh_it; ++fh_it) + { + hh_vector.push_back(mesh_.PHEH(mesh_.OHEH(fh_it.handle()))); + } + } + + // red face + else + { + + typename Mesh::HalfedgeHandle red_hh(mesh_.data(_fh).red_halfedge()); + + hh_vector.push_back(mesh_.PHEH(mesh_.OHEH(mesh_.NHEH(red_hh)))); + hh_vector.push_back(mesh_.PHEH(mesh_.OHEH(mesh_.PHEH(mesh_.OHEH(red_hh))))); + } + } + + + // -------------------- Average rule before topo rule? + if (t_rule()->number() > 0) + t_rule()->prev_rule()->raise(_fh, new_face_level-1); + + // -------------------- Apply topological operator first + t_rule()->raise(_fh, new_face_level); + +#if 0 // original code + assert(MOBJ(_fh).state() >= + subdiv_rule_->number()+1+(int) (MOBJ(_fh).state()/n_rules())*n_rules()); +#else // improved code (use % operation and avoid floating point division) + assert( mesh_.data(_fh).state() >= ( t_rule()->number()+1+generation(_fh) ) ); +#endif + + // raise new vertices to final levels + if (subdiv_type_ == 3) + { + typename Mesh::VertexHandle new_vh(mesh_.TVH(mesh_.NHEH(mesh_.HEH(_fh)))); + + // raise new vertex to final level + l_rule()->raise(new_vh, new_vertex_level); + } + + if (subdiv_type_ == 4) + { + typename Mesh::HalfedgeHandle hh; + typename Mesh::VertexHandle new_vh; + + while (!hh_vector.empty()) { + + hh = hh_vector.back(); + hh_vector.pop_back(); + + // get new vertex + new_vh = mesh_.TVH(mesh_.NHEH(hh)); + + // raise new vertex to final level + l_rule()->raise(new_vh, new_vertex_level); + } + } + + // raise old vertices to final position + l_rule()->raise(vh[0], new_vertex_level); + l_rule()->raise(vh[1], new_vertex_level); + l_rule()->raise(vh[2], new_vertex_level); +} + + +// ---------------------------------------------------------------------------- + + +template +void CompositeT::refine(typename Mesh::VertexHandle& _vh) +{ + // calculate next final level for vertex + int new_vertex_state = generation(_vh) + l_rule()->number() + 1; + + assert( new_vertex_state == mesh_.data(_vh).state()+1 ); + + // raise vertex to final position + l_rule()->raise(_vh, new_vertex_state); +} + + +// ---------------------------------------------------------------------------- + + +template +std::string CompositeT::rules_as_string(const std::string& _sep) const +{ + std::string seq; + typename RuleSequence::const_iterator it = rule_sequence_.begin(); + + if ( it != rule_sequence_.end() ) + { + seq = (*it)->type(); + for (++it; it != rule_sequence_.end(); ++it ) + { + seq += _sep; + seq += (*it)->type(); + } + } + return seq; +} + +// ---------------------------------------------------------------------------- +#undef MOBJ +#undef TVH +#undef HEH +#undef NHEH +#undef PHEH +#undef OHEH +//============================================================================= +} // END_NS_ADAPTIVE +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= diff --git a/Tools/Subdivider/Adaptive/Composite/CompositeT.hh b/Tools/Subdivider/Adaptive/Composite/CompositeT.hh new file mode 100644 index 00000000..257aad50 --- /dev/null +++ b/Tools/Subdivider/Adaptive/Composite/CompositeT.hh @@ -0,0 +1,298 @@ +//============================================================================= +// +// 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 Adaptive/Composite/CompositeT.hh + + */ + +//============================================================================= +// +// CLASS CompositeT +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_ADAPTIVE_COMPOSITET_HH +#define OPENMESH_SUBDIVIDER_ADAPTIVE_COMPOSITET_HH + + +//== INCLUDES ================================================================= + +#include +#include +// -------------------- +#include +#include +#include + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_SUBDIVIDER +namespace Adaptive { // BEGIN_NS_ADAPTIVE + + +//== CLASS DEFINITION ========================================================= + + +template struct RuleHandleT; +template class RuleInterfaceT; + + +//== CLASS DEFINITION ========================================================= + +/** Adaptive Composite Subdivision framework. + * + * The adaptive composite subdivision framework is based on the work + * done by P. Oswald and P. Schroeder. This framework elevates the + * uniform case of the composite scheme to the adaptive + * setting. + * + * For details on the composite scheme refer to + * - P. Oswald, + * P. Schroeder "Composite primal/dual sqrt(3)-subdivision schemes", + * CAGD 20, 3, 2003, 135--164 + * + * For details on the transition from uniform to adaptive composite + * subdivision please refer to + * - + * + * In the composite scheme a subdivision operator is created by + * combining smaller "atomic" rules. Depending on the selection and + * ordering of the operator many known subdivision schemes can be + * created. + * + * Every rule inherits from RuleInterfaceT and is represented out of + * the subdivider object by a RuleHandleT (as usual within + * %OpenMesh). You can add rules using the CompositeT::add() + * functions. The correct order of adding the rules is very + * important, and furthermore not all rules get along with each other + * very well. (Please read the given literature, especially the + * paper by Oswald and Schröder.) + * + * To use a composite subdivider first define a rule sequence + * describing the order of execution of the rules. In the order the + * rules habe been added they will be executed. E.g. the rules given + * in operator notation have to added from right to left. + * + * After the rule sequence has been defined the subdivider has to be + * intialized using CompositeT::initialize(). If everything went well, + * use CompositeT::refine() to subdivide locally a face or vertex. + * + * \note Not all (topological) operators have been implemented! + * \note Only triangle meshes are supported. + * \note The rule sequence must begin with a topological operator. + * + * \see RuleInterfaceT, RuleHandleT + * + */ +template class CompositeT +{ +public: + + typedef RuleInterfaceT Rule; + typedef M Mesh; + typedef std::vector RuleSequence; + + typedef typename M::VertexHandle VH; + typedef typename M::FaceHandle FH; + typedef typename M::EdgeHandle EH; + typedef typename M::HalfedgeHandle HH; + +public: + + /// Constructor + CompositeT(Mesh& _mesh) + : subdiv_type_(0), + subdiv_rule_(NULL), /*first_rule_(NULL), last_rule_(NULL),*/ mesh_(_mesh) + { } + + /// + virtual ~CompositeT() + { cleanup(); } + + + /// Reset \c self to state after the default constructor except of + /// the mesh. + void cleanup(void) + { + subdiv_type_ = 0; + subdiv_rule_ = NULL; + + std::for_each(rule_sequence_.begin(), + rule_sequence_.end(), DeleteRule() ); + rule_sequence_.clear(); + } + + + /// Initialize faces, edges, vertices, and rules + bool initialize(void); + + + /// Refine one face. + void refine(typename Mesh::FaceHandle& _fh); + + + /// Raise one vertex to next final level. + void refine(typename Mesh::VertexHandle& _vh); + + + /// Return subdivision split type (3 for 1-to-3 split, 4 for 1-to-4 split). + int subdiv_type() { return subdiv_type_; } + + + // Return subdivision rule. + const Rule& subdiv_rule() const { return *subdiv_rule_; } + +public: + + /// \name Managing composite rules + //*@ + + /** Add new rule to rule sequence by passing the type of the wanted + * rule as template argument to the method. + * \return Valid handle on success. Else it is invalid. + */ + template < typename R > + RuleHandleT add() + { + size_t idx = rule_sequence_.size(); + rule_sequence_.push_back( new R( mesh_ ) ); + return RuleHandleT( (idx < rule_sequence_.size()) ? idx : -1 ); + } + + /** Add new rule to rule sequence by passing an appropriate handle + * to the method. + * \return Valid handle on success. Else it is invalid. + */ + template < typename R > + RuleHandleT& add( RuleHandleT& _rh ) + { + return _rh = add< R >(); + } + + /** Get rule in the rule sequence by a handle. + * + * \return The wanted rule if the handle is valid. The return value + * is undefined if the handle is invalid! + */ + template < typename R > + typename RuleHandleT::Rule& rule( const RuleHandleT& _rh ) + { + typedef typename RuleHandleT::Rule rule_t; + assert( _rh.is_valid() ); + return *dynamic_cast(rule_sequence_[ _rh.idx() ]); + } + + + /** Get rule (interface) by index + * + * \return The wanted rule if the handle is valid. The return value + * is undefined if the handle is invalid! + */ + RuleInterfaceT& rule( size_t _idx ) + { + assert( _idx < n_rules() ); + return *rule_sequence_[ _idx ]; + } + + /// Number of rules in the rule sequence + size_t n_rules() const { return rule_sequence_.size(); } + + /// Return the sequence as string + std::string rules_as_string(const std::string& _sep= " * ") const; + + //@} + +protected: + + /// The rule sequence + const RuleSequence& rules() const { return rule_sequence_; } + +protected: // helper + + // get current generation from state + state_t generation(state_t _s) { return _s-(_s % n_rules()); } + state_t generation( VH _vh ) { return generation(mesh_.data(_vh).state()); } + state_t generation( EH _eh ) { return generation(mesh_.data(_eh).state()); } + state_t generation( FH _fh ) { return generation(mesh_.data(_fh).state()); } + +private: + + // short cuts + Rule* t_rule() { return subdiv_rule_; } + Rule* f_rule() { return rule_sequence_.front(); } + Rule* l_rule() { return rule_sequence_.back(); } + +private: + + // + RuleSequence rule_sequence_; + + // Split type + int subdiv_type_; + + Rule *subdiv_rule_; +// Rule *first_rule_; +// Rule *last_rule_; + + // + Mesh &mesh_; + +private: // helper + +#ifndef DOXY_IGNORE_THIS + struct DeleteRule { void operator()( Rule* _r ) { delete _r; } }; +#endif + +private: + + CompositeT( const CompositeT& ); + CompositeT& operator = ( const CompositeT ); + +}; + + +//============================================================================= +} // END_NS_ADAPTIVE +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_SUBDIVIDER_ADAPTIVE_COMPOSITET_CC) +# define OPENMESH_SUBDIVIDER_TEMPLATES +# include "CompositeT.cc" +#endif +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_ADAPTIVE_COMPOSITET_HH defined +//============================================================================= diff --git a/Tools/Subdivider/Adaptive/Composite/CompositeTraits.hh b/Tools/Subdivider/Adaptive/Composite/CompositeTraits.hh new file mode 100644 index 00000000..f6c5e6e2 --- /dev/null +++ b/Tools/Subdivider/Adaptive/Composite/CompositeTraits.hh @@ -0,0 +1,247 @@ +//============================================================================= +// +// 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 Subdivider/Adaptive/Composite/CompositeTraits.hh + Mesh traits for adaptive composite subdivider. + */ + +//============================================================================= +// +// CLASS Traits +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_ADAPTIVE_COMPOSITETRAITS_HH +#define OPENMESH_SUBDIVIDER_ADAPTIVE_COMPOSITETRAITS_HH + + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Adaptive { // BEGIN_NS_UNIFORM + + +//== CLASS DEFINITION ========================================================= + +/** Adaptive Composite Subdivision framework. +*/ + +// typedef unsigned short state_t; +// const state_t mask_final = 1 << ((sizeof(state_t)*8)-1); +// const state_t mask_state = ~mask_final; + +/** Mesh traits for adaptive composite subdivision + */ +struct CompositeTraits : public OpenMesh::DefaultTraits +{ + typedef int state_t; ///< External representation for intermediate state + typedef bool final_t; ///< External representation for final flag + + + /// Storage type for intermediate states and the final flag of a mesh entity. + struct State + { + int state : 31; + unsigned final : 1; + }; + + // ---------------------------------------- attributes + + // add face normals + FaceAttributes( OpenMesh::Attributes::Normal ); + + // add vertex normals + VertexAttributes( OpenMesh::Attributes::Normal ); + + // add previous halfedge handle + HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge ); + + // ---------------------------------------- items + + FaceTraits + { + + private: + + typedef typename Refs::Point Point; + typedef typename Refs::HalfedgeHandle HalfedgeHandle; + typedef std::map PositionHistory; + + State state_; + HalfedgeHandle red_halfedge_; + + PositionHistory pos_map_; + + public: + + // face state + state_t state() const { return state_t(state_.state); } + void set_state(const state_t _s) { state_.state = _s; } + void inc_state() { ++state_.state; } + + // face not final if divided (loop) or edge not flipped (sqrt(3)) + final_t final() const { return final_t(state_.final); } + void set_final() { state_.final = true; } + void set_not_final() { state_.final = false; } + + // halfedge of dividing edge (red-green triangulation) + const HalfedgeHandle& red_halfedge() const { return red_halfedge_; } + void set_red_halfedge(const HalfedgeHandle& _h) { red_halfedge_ = _h; } + + // position of face, depending on generation _i. + void set_position(const int& _i, const Point& _p) { pos_map_[_i] = _p; } + const Point position(const int& _i) { + if (pos_map_.find(_i) != pos_map_.end()) + return pos_map_[_i]; + else { + + if (_i <= 0) { + return Point(0.0, 0.0, 0.0); + } + + return position(_i - 1); + } + } + }; // end class FaceTraits + + + EdgeTraits + { + + private: + + typedef typename Refs::Point Point; + typedef std::map PositionHistory; + + State state_; + PositionHistory pos_map_; + + public: + + typedef typename Refs::Scalar Scalar; + + // Scalar weight_; + + // state of edge + state_t state() const { return state_t(state_.state); } + void set_state(const state_t _s) { state_.state = _s; } + void inc_state() { ++state_.state; } + + // edge not final if dividing face (Loop) or edge not flipped (SQRT(3)) + final_t final() const { return final_t(state_.final); } + void set_final() { state_.final = true; } + void set_not_final() { state_.final = false; } + + // position of edge, depending on generation _i. + void set_position(const int& _i, const Point& _p) { pos_map_[_i] = _p; } + + const Point position(const int& _i) { + + if (pos_map_.find(_i) != pos_map_.end()) + return pos_map_[_i]; + else + { + if (_i <= 0) + { + const Point zero_point(0.0, 0.0, 0.0); + return zero_point; + } + + return position(_i - 1); + } + } + }; // end class EdgeTraits + + + VertexTraits + { + + private: + + typedef typename Refs::Point Point; + typedef std::map PositionHistory; + + State state_; + PositionHistory pos_map_; + + public: + + // state of vertex + state_t state() const { return state_.state; } + void set_state(const state_t _s) { state_.state = _s; } + void inc_state() { ++state_.state; } + + + // usually not needed by loop or sqrt(3) + final_t final() const { return state_.final; } + void set_final() { state_.final = true; } + void set_not_final() { state_.final = false; } + + // position of vertex, depending on generation _i. (not for display) + void set_position(const int& _i, const Point& _p) { pos_map_[_i] = _p; } + const Point position(const int& _i) { + + if (pos_map_.find(_i) != pos_map_.end()) + + return pos_map_[_i]; + + else { + + if (_i <= 0) { + + const Point zero_point(0.0, 0.0, 0.0); + return zero_point; + } + + return position(_i - 1); + } + } + }; // end class VertexTraits +}; // end class CompositeTraits + + +// export items to namespace to maintain compatibility +typedef CompositeTraits::state_t state_t; +typedef CompositeTraits::final_t final_t; +typedef CompositeTraits::State State; + +//============================================================================= +} // END_NS_ADAPTIVE +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_ADAPTIVE_COMPOSITETRAITS_HH defined +//============================================================================= diff --git a/Tools/Subdivider/Adaptive/Composite/RuleInterfaceT.hh b/Tools/Subdivider/Adaptive/Composite/RuleInterfaceT.hh new file mode 100644 index 00000000..bd07fb8e --- /dev/null +++ b/Tools/Subdivider/Adaptive/Composite/RuleInterfaceT.hh @@ -0,0 +1,389 @@ +//============================================================================= +// +// 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) $ +// +//============================================================================= + + +//============================================================================= +// +// CLASS RuleInterfaceT +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_ADAPTIVE_RULEINTERFACET_HH +#define OPENMESH_SUBDIVIDER_ADAPTIVE_RULEINTERFACET_HH + + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_SUBDIVIDER +namespace Adaptive { // BEGIN_NS_ADAPTIVE + + +//== FORWARDS ================================================================= + +template class CompositeT; +template class RuleInterfaceT; + +//== CLASS DEFINITION ========================================================= + + +// ---------------------------------------------------------------------------- + +/** Handle template for adaptive composite subdividion rules + * \internal + * + * Use typed handle of a rule, e.g. Tvv3::Handle. + */ +template < typename R > +struct RuleHandleT : public BaseHandle +{ + explicit RuleHandleT(int _idx=-1) : BaseHandle(_idx) {} + typedef R Rule; + + operator bool() const { return is_valid(); } + +}; + +/** Defines the method type() (RuleInterfaceT::type()) and the + * typedefs Self and Handle. + */ +#define COMPOSITE_RULE( classname, mesh_type ) \ + protected:\ + friend class CompositeT; \ + public: \ + const char *type() const { return #classname; } \ + typedef classname Self; \ + typedef RuleHandleT< Self > Handle + + +// ---------------------------------------------------------------------------- +/** Base class for adaptive composite subdivision rules + * \see class CompositeT + */ +template class RuleInterfaceT +{ +public: + + typedef M Mesh; + typedef RuleInterfaceT Self; + typedef RuleHandleT< Self > Rule; + + typedef typename M::Scalar scalar_t; + +protected: + + /// Default constructor + RuleInterfaceT(Mesh& _mesh) : mesh_(_mesh) {}; + +public: + + /// Destructor + virtual ~RuleInterfaceT() {}; + + + /// Returns the name of the rule. + /// Use define COMPOSITE_RULE to overload this function in a derived class. + virtual const char *type() const = 0; + +public: + + /// \name Raise item + //@{ + /// Raise item to target state \c _target_state. + virtual void raise(typename M::FaceHandle& _fh, state_t _target_state) + { + if (mesh_.data(_fh).state() < _target_state) { + update(_fh, _target_state); + mesh_.data(_fh).inc_state(); + } + } + + virtual void raise(typename M::EdgeHandle& _eh, state_t _target_state) + { + if (mesh_.data(_eh).state() < _target_state) { + update(_eh, _target_state); + mesh_.data(_eh).inc_state(); + } + } + + virtual void raise(typename M::VertexHandle& _vh, state_t _target_state) + { + if (mesh_.data(_vh).state() < _target_state) { + update(_vh, _target_state); + mesh_.data(_vh).inc_state(); + } + } + //@} + + void update(typename M::FaceHandle& _fh, state_t _target_state) + { + typename M::FaceHandle opp_fh; + + while (mesh_.data(_fh).state() < _target_state - 1) { + prev_rule()->raise(_fh, _target_state - 1); + } + + // Don't use unflipped / unfinal faces!!! + if (subdiv_type() == 3) { + + if (mesh_.face_handle(mesh_.opposite_halfedge_handle(mesh_.halfedge_handle(_fh))).is_valid()) { + + while (!mesh_.data(_fh).final()) { + + opp_fh = mesh_.face_handle(mesh_.opposite_halfedge_handle(mesh_.halfedge_handle(_fh))); + + assert (mesh_.data(_fh).state() >= + mesh_.data(opp_fh).state()); + + // different states: raise other face + if (mesh_.data(_fh).state() > mesh_.data(opp_fh).state()){ + + // raise opposite face + prev_rule()->raise(opp_fh, _target_state - 1); + } + + else { + + // equal states + + // flip edge + // typename M::EdgeHandle eh(mesh_.edge_handle(mesh_.halfedge_handle(_fh))); + + // if (mesh_.is_flip_ok(eh)) { + + // std::cout << "Flipping Edge...\n"; + + // mesh_.flip(eh); + + // mesh_.data(_fh).set_final(); + // mesh_.data(opp_fh).set_final(); + // } + + // else { + + // std::cout << "Flip not okay.\n"; + // } + } + } + } + + else { + + // mesh_.data(_fh).set_final(); + } + + // std::cout << "Raising Face to Level " + // << _target_state + // << " with " + // << type() + // << ".\n"; + + } + + assert( subdiv_type() != 4 || + mesh_.data(_fh).final() || + _target_state%n_rules() == (subdiv_rule()->number() + 1)%n_rules() ); + + typename M::FaceEdgeIter fe_it; + typename M::FaceVertexIter fv_it; + typename M::EdgeHandle eh; + typename M::VertexHandle vh; + + std::vector face_vector; + face_vector.clear(); + + if (_target_state > 1) { + + for (fe_it = mesh_.fe_iter(_fh); fe_it; ++fe_it) { + + eh = fe_it.handle(); + prev_rule()->raise(eh, _target_state - 1); + } + + for (fv_it = mesh_.fv_iter(_fh); fv_it; ++fv_it) { + + vh = fv_it.handle(); + prev_rule()->raise(vh, _target_state - 1); + } + } + } + + + void update(typename M::EdgeHandle& _eh, state_t _target_state) + { + state_t state(mesh_.data(_eh).state()); + + // raise edge to correct state + if (state + 1 < _target_state && _target_state > 0) { + + prev_rule()->raise(_eh, _target_state - 1); + } + + typename M::VertexHandle vh; + typename M::FaceHandle fh; + + if (_target_state > 1) + { + vh = mesh_.to_vertex_handle(mesh_.halfedge_handle(_eh, 0)); + prev_rule()->raise(vh, _target_state - 1); + + vh = mesh_.to_vertex_handle(mesh_.halfedge_handle(_eh, 1)); + prev_rule()->raise(vh, _target_state - 1); + + fh = mesh_.face_handle(mesh_.halfedge_handle(_eh, 0)); + if (fh.is_valid()) + prev_rule()->raise(fh, _target_state - 1); + + fh = mesh_.face_handle(mesh_.halfedge_handle(_eh, 1)); + if (fh.is_valid()) + prev_rule()->raise(fh, _target_state - 1); + } + } + + + void update(typename M::VertexHandle& _vh, state_t _target_state) { + + state_t state(mesh_.data(_vh).state()); + + // raise vertex to correct state + if (state + 1 < _target_state) + { + prev_rule()->raise(_vh, _target_state - 1); + } + + std::vector halfedge_vector; + halfedge_vector.clear(); + + typename M::VertexOHalfedgeIter voh_it; + typename M::EdgeHandle eh; + typename M::FaceHandle fh; + + if (_target_state > 1) + { + + for (voh_it = mesh_.voh_iter(_vh); voh_it; ++voh_it) { + halfedge_vector.push_back(voh_it.handle()); + } + + while ( !halfedge_vector.empty() ) { + eh = mesh_.edge_handle(halfedge_vector.back()); + halfedge_vector.pop_back(); + + prev_rule()->raise(eh, _target_state - 1); + } + + for (voh_it = mesh_.voh_iter(_vh); voh_it; ++voh_it) { + halfedge_vector.push_back(voh_it.handle()); + } + + while ( !halfedge_vector.empty() ) { + fh = mesh_.face_handle(halfedge_vector.back()); + halfedge_vector.pop_back(); + + if (fh.is_valid()) + prev_rule()->raise(fh, _target_state - 1); + } + } + } + +public: + + + /// Type of split operation, if it is a topological operator + int subdiv_type() const { return subdiv_type_; } + + + /// Position in rule sequence + int number() const { return number_; } + + /// \name Parameterization of rule + //@{ + + /// Set coefficient - ignored by non-parameterized rules. + virtual void set_coeff( scalar_t _coeff ) { coeff_ = _coeff; } + + /// Get coefficient - ignored by non-parameterized rules. + scalar_t coeff() const { return coeff_; } + + //@} + +protected: + + void set_prev_rule(Self*& _p) { prev_rule_ = _p; } + Self* prev_rule() { return prev_rule_; } + + void set_subdiv_rule(Self*& _n) { subdiv_rule_ = _n; } + Self* subdiv_rule() { return subdiv_rule_; } + + void set_number(int _n) { number_ = _n; } + + void set_n_rules(int _n) { n_rules_ = _n; } + int n_rules() { return n_rules_; } + + void set_subdiv_type(int _n) + { assert(_n == 3 || _n == 4); subdiv_type_ = _n; } + + friend class CompositeT; + +protected: + + Mesh& mesh_; + +private: + + Self* prev_rule_; + Self* subdiv_rule_; + + int subdiv_type_; + int number_; + int n_rules_; + + scalar_t coeff_; + +private: // Noncopyable + + RuleInterfaceT(const RuleInterfaceT&); + RuleInterfaceT& operator=(const RuleInterfaceT&); + +}; + +//============================================================================= +} // END_NS_ADAPTIVE +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_ADAPTIVE_RULEINTERFACET_HH defined +//============================================================================= + diff --git a/Tools/Subdivider/Adaptive/Composite/RulesT.cc b/Tools/Subdivider/Adaptive/Composite/RulesT.cc new file mode 100644 index 00000000..d36409da --- /dev/null +++ b/Tools/Subdivider/Adaptive/Composite/RulesT.cc @@ -0,0 +1,2015 @@ +//============================================================================= +// +// 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 RulesT.cc + + */ + +//============================================================================= +// +// Rules - IMPLEMENTATION +// +//============================================================================= + + +#define OPENMESH_SUBDIVIDER_ADAPTIVE_RULEST_CC + + +//== INCLUDES ================================================================= + +#include +#include +#include "RulesT.hh" +// -------------------- +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + +#if defined(OM_CC_MSVC) +# pragma warning(disable:4244) +#endif + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Adaptive { // BEGIN_NS_UNIFORM + + +//== IMPLEMENTATION ========================================================== + +#define MOBJ Base::mesh_.data +#define FH face_handle +#define VH vertex_handle +#define EH edge_handle +#define HEH halfedge_handle +#define NHEH next_halfedge_handle +#define PHEH prev_halfedge_handle +#define OHEH opposite_halfedge_handle +#define TVH to_vertex_handle +#define FVH from_vertex_handle + +// ------------------------------------------------------------------ Tvv3 ---- + + +template +void +Tvv3::raise(typename M::FaceHandle& _fh, state_t _target_state) +{ + if (MOBJ(_fh).state() < _target_state) + { + update(_fh, _target_state); + + typename M::VertexVertexIter vv_it; + typename M::FaceVertexIter fv_it; + typename M::VertexHandle vh; + typename M::Point position(0.0, 0.0, 0.0); + typename M::Point face_position; + const typename M::Point zero_point(0.0, 0.0, 0.0); + std::vector vertex_vector; + int valence(0); + + // raise all adjacent vertices to level x-1 + for (fv_it = Base::mesh_.fv_iter(_fh); fv_it; ++fv_it) { + + vertex_vector.push_back(fv_it.handle()); + } + + while(!vertex_vector.empty()) { + + vh = vertex_vector.back(); + vertex_vector.pop_back(); + + if (_target_state > 1) + Base::prev_rule()->raise(vh, _target_state - 1); + } + + face_position = MOBJ(_fh).position(_target_state - 1); + + typename M::EdgeHandle eh; + std::vector edge_vector; + + // interior face + if (!Base::mesh_.is_boundary(_fh) || MOBJ(_fh).final()) { + + // insert new vertex + vh = Base::mesh_.new_vertex(); + + Base::mesh_.split(_fh, vh); + + // calculate display position for new vertex + for (vv_it = Base::mesh_.vv_iter(vh); vv_it; ++vv_it) + { + position += Base::mesh_.point(vv_it.handle()); + ++valence; + } + + position /= valence; + + // set attributes for new vertex + Base::mesh_.set_point(vh, position); + MOBJ(vh).set_position(_target_state, zero_point); + MOBJ(vh).set_state(_target_state); + MOBJ(vh).set_not_final(); + + typename M::VertexOHalfedgeIter voh_it; + // check for edge flipping + for (voh_it = Base::mesh_.voh_iter(vh); voh_it; ++voh_it) { + + if (Base::mesh_.FH(voh_it.handle()).is_valid()) { + + MOBJ(Base::mesh_.FH(voh_it.handle())).set_state(_target_state); + MOBJ(Base::mesh_.FH(voh_it.handle())).set_not_final(); + MOBJ(Base::mesh_.FH(voh_it.handle())).set_position(_target_state - 1, face_position); + + + for (state_t j = 0; j < _target_state; ++j) { + MOBJ(Base::mesh_.FH(voh_it.handle())).set_position(j, MOBJ(_fh).position(j)); + } + + if (Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(voh_it.handle()))).is_valid()) { + + if (MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(voh_it.handle())))).state() == _target_state) { + + if (Base::mesh_.is_flip_ok(Base::mesh_.EH(Base::mesh_.NHEH(voh_it.handle())))) { + + edge_vector.push_back(Base::mesh_.EH(Base::mesh_.NHEH(voh_it.handle()))); + } + } + } + } + } + } + + // boundary face + else { + + typename M::VertexHandle vh1 = Base::mesh_.new_vertex(), + vh2 = Base::mesh_.new_vertex(); + + typename M::HalfedgeHandle hh2 = Base::mesh_.HEH(_fh), + hh1, hh3; + + while (!Base::mesh_.is_boundary(Base::mesh_.OHEH(hh2))) + hh2 = Base::mesh_.NHEH(hh2); + + eh = Base::mesh_.EH(hh2); + + hh2 = Base::mesh_.NHEH(hh2); + hh1 = Base::mesh_.NHEH(hh2); + + assert(Base::mesh_.is_boundary(eh)); + + Base::mesh_.split(eh, vh1); + + eh = Base::mesh_.EH(Base::mesh_.PHEH(hh2)); + + assert(Base::mesh_.is_boundary(eh)); + + Base::mesh_.split(eh, vh2); + + hh3 = Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.PHEH(hh1))); + + typename M::VertexHandle vh0(Base::mesh_.TVH(hh1)), + vh3(Base::mesh_.FVH(hh2)); + + // set display position and attributes for new vertices + Base::mesh_.set_point(vh1, (Base::mesh_.point(vh0) * 2.0 + Base::mesh_.point(vh3)) / 3.0); + + MOBJ(vh1).set_position(_target_state, zero_point); + MOBJ(vh1).set_state(_target_state); + MOBJ(vh1).set_not_final(); + + MOBJ(vh0).set_position(_target_state, MOBJ(vh0).position(_target_state - 1) * 3.0); + MOBJ(vh0).set_state(_target_state); + MOBJ(vh0).set_not_final(); + + // set display position and attributes for old vertices + Base::mesh_.set_point(vh2, (Base::mesh_.point(vh3) * 2.0 + Base::mesh_.point(vh0)) / 3.0); + MOBJ(vh2).set_position(_target_state, zero_point); + MOBJ(vh2).set_state(_target_state); + MOBJ(vh2).set_not_final(); + + MOBJ(vh3).set_position(_target_state, MOBJ(vh3).position(_target_state - 1) * 3.0); + MOBJ(vh3).set_state(_target_state); + MOBJ(vh3).set_not_final(); + + // init 3 faces + MOBJ(Base::mesh_.FH(hh1)).set_state(_target_state); + MOBJ(Base::mesh_.FH(hh1)).set_not_final(); + MOBJ(Base::mesh_.FH(hh1)).set_position(_target_state - 1, face_position); + + MOBJ(Base::mesh_.FH(hh2)).set_state(_target_state); + MOBJ(Base::mesh_.FH(hh2)).set_not_final(); + MOBJ(Base::mesh_.FH(hh2)).set_position(_target_state - 1, face_position); + + MOBJ(Base::mesh_.FH(hh3)).set_state(_target_state); + MOBJ(Base::mesh_.FH(hh3)).set_final(); + MOBJ(Base::mesh_.FH(hh3)).set_position(_target_state - 1, face_position); + + + for (state_t j = 0; j < _target_state; ++j) { + MOBJ(Base::mesh_.FH(hh1)).set_position(j, MOBJ(_fh).position(j)); + } + + for (state_t j = 0; j < _target_state; ++j) { + + MOBJ(Base::mesh_.FH(hh2)).set_position(j, MOBJ(_fh).position(j)); + } + + for (state_t j = 0; j < _target_state; ++j) { + + MOBJ(Base::mesh_.FH(hh3)).set_position(j, MOBJ(_fh).position(j)); + } + + // check for edge flipping + if (Base::mesh_.FH(Base::mesh_.OHEH(hh1)).is_valid()) { + + if (MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(hh1))).state() == _target_state) { + + if (Base::mesh_.is_flip_ok(Base::mesh_.EH(hh1))) { + + edge_vector.push_back(Base::mesh_.EH(hh1)); + } + } + } + + if (Base::mesh_.FH(Base::mesh_.OHEH(hh2)).is_valid()) { + + if (MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(hh2))).state() == _target_state) { + + if (Base::mesh_.is_flip_ok(Base::mesh_.EH(hh2))) { + + edge_vector.push_back(Base::mesh_.EH(hh2)); + } + } + } + } + + // flip edges + while (!edge_vector.empty()) { + + eh = edge_vector.back(); + edge_vector.pop_back(); + + assert(Base::mesh_.is_flip_ok(eh)); + + Base::mesh_.flip(eh); + + MOBJ(Base::mesh_.FH(Base::mesh_.HEH(eh, 0))).set_final(); + MOBJ(Base::mesh_.FH(Base::mesh_.HEH(eh, 1))).set_final(); + + MOBJ(Base::mesh_.FH(Base::mesh_.HEH(eh, 0))).set_state(_target_state); + MOBJ(Base::mesh_.FH(Base::mesh_.HEH(eh, 1))).set_state(_target_state); + + MOBJ(Base::mesh_.FH(Base::mesh_.HEH(eh, 0))).set_position(_target_state, face_position); + MOBJ(Base::mesh_.FH(Base::mesh_.HEH(eh, 1))).set_position(_target_state, face_position); + } + } +} + + +template +void Tvv3::raise(typename M::VertexHandle& _vh, state_t _target_state) { + + if (MOBJ(_vh).state() < _target_state) { + + update(_vh, _target_state); + + // multiply old position by 3 + MOBJ(_vh).set_position(_target_state, MOBJ(_vh).position(_target_state - 1) * 3.0); + + MOBJ(_vh).inc_state(); + + assert(MOBJ(_vh).state() == _target_state); + } +} + + +// ------------------------------------------------------------------ Tvv4 ---- + + +template +void +Tvv4::raise(typename M::FaceHandle& _fh, state_t _target_state) +{ + + if (MOBJ(_fh).state() < _target_state) { + + update(_fh, _target_state); + + typename M::FaceVertexIter fv_it; + typename M::VertexHandle temp_vh; + typename M::Point face_position; + const typename M::Point zero_point(0.0, 0.0, 0.0); + std::vector vertex_vector; + std::vector halfedge_vector; + + // raise all adjacent vertices to level x-1 + for (fv_it = Base::mesh_.fv_iter(_fh); fv_it; ++fv_it) { + + vertex_vector.push_back(fv_it.handle()); + } + + while(!vertex_vector.empty()) { + + temp_vh = vertex_vector.back(); + vertex_vector.pop_back(); + + if (_target_state > 1) { + Base::prev_rule()->raise(temp_vh, _target_state - 1); + } + } + + face_position = MOBJ(_fh).position(_target_state - 1); + + typename M::HalfedgeHandle hh[3]; + typename M::VertexHandle vh[3]; + typename M::VertexHandle new_vh[3]; + typename M::FaceHandle fh[4]; + typename M::EdgeHandle eh; + typename M::HalfedgeHandle temp_hh; + + // normal (final) face + if (MOBJ(_fh).final()) { + + // define three halfedge handles around the face + hh[0] = Base::mesh_.HEH(_fh); + hh[1] = Base::mesh_.NHEH(hh[0]); + hh[2] = Base::mesh_.NHEH(hh[1]); + + assert(hh[0] == Base::mesh_.NHEH(hh[2])); + + vh[0] = Base::mesh_.TVH(hh[0]); + vh[1] = Base::mesh_.TVH(hh[1]); + vh[2] = Base::mesh_.TVH(hh[2]); + + new_vh[0] = Base::mesh_.add_vertex(zero_point); + new_vh[1] = Base::mesh_.add_vertex(zero_point); + new_vh[2] = Base::mesh_.add_vertex(zero_point); + + // split three edges + split_edge(hh[0], new_vh[0], _target_state); + eh = Base::mesh_.EH(Base::mesh_.PHEH(hh[2])); + split_edge(hh[1], new_vh[1], _target_state); + split_edge(hh[2], new_vh[2], _target_state); + + assert(Base::mesh_.FVH(hh[2]) == vh[1]); + assert(Base::mesh_.FVH(hh[1]) == vh[0]); + assert(Base::mesh_.FVH(hh[0]) == vh[2]); + + if (Base::mesh_.FH(Base::mesh_.OHEH(hh[0])).is_valid()) + { + temp_hh = Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(hh[0]))); + if (MOBJ(Base::mesh_.FH(temp_hh)).red_halfedge() != temp_hh) + halfedge_vector.push_back(temp_hh); + } + + if (Base::mesh_.FH(Base::mesh_.OHEH(hh[1])).is_valid()) { + + temp_hh = Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(hh[1]))); + if (MOBJ(Base::mesh_.FH(temp_hh)).red_halfedge() != temp_hh) + halfedge_vector.push_back(temp_hh); + } + + if (Base::mesh_.FH(Base::mesh_.OHEH(hh[2])).is_valid()) { + + temp_hh = Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(hh[2]))); + if (MOBJ(Base::mesh_.FH(temp_hh)).red_halfedge() != temp_hh) + halfedge_vector.push_back(temp_hh); + } + } + + // splitted face, check for type + else { + + // define red halfedge handle + typename M::HalfedgeHandle red_hh(MOBJ(_fh).red_halfedge()); + + if (Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh))).is_valid() + && Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh)))).is_valid() + && MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh)))).red_halfedge() == red_hh + && MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh))))).red_halfedge() == red_hh) + { + + // three times divided face + vh[0] = Base::mesh_.TVH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh))))); + vh[1] = Base::mesh_.TVH(red_hh); + vh[2] = Base::mesh_.TVH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh)))); + + new_vh[0] = Base::mesh_.FVH(red_hh); + new_vh[1] = Base::mesh_.TVH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh))); + new_vh[2] = Base::mesh_.TVH(Base::mesh_.NHEH(red_hh)); + + hh[0] = Base::mesh_.PHEH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh))); + hh[1] = Base::mesh_.PHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh)))); + hh[2] = Base::mesh_.NHEH(red_hh); + + eh = Base::mesh_.EH(red_hh); + } + + else + { + + if ((Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh))).is_valid() && + MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh)))).red_halfedge() + == red_hh ) + || (Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh)))).is_valid() + && MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh))))).red_halfedge() == red_hh)) + { + + // double divided face + if (MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh)))).red_halfedge() == red_hh) + { + // first case + vh[0] = Base::mesh_.TVH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh))); + vh[1] = Base::mesh_.TVH(red_hh); + vh[2] = Base::mesh_.TVH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh)))); + + new_vh[0] = Base::mesh_.FVH(red_hh); + new_vh[1] = Base::mesh_.add_vertex(zero_point); + new_vh[2] = Base::mesh_.TVH(Base::mesh_.NHEH(red_hh)); + + hh[0] = Base::mesh_.PHEH(Base::mesh_.OHEH(Base::mesh_.PHEH(red_hh))); + hh[1] = Base::mesh_.PHEH(Base::mesh_.OHEH(red_hh)); + hh[2] = Base::mesh_.NHEH(red_hh); + + // split one edge + eh = Base::mesh_.EH(red_hh); + + split_edge(hh[1], new_vh[1], _target_state); + + assert(Base::mesh_.FVH(hh[2]) == vh[1]); + assert(Base::mesh_.FVH(hh[1]) == vh[0]); + assert(Base::mesh_.FVH(hh[0]) == vh[2]); + + if (Base::mesh_.FH(Base::mesh_.OHEH(hh[1])).is_valid()) + { + temp_hh = Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(hh[1]))); + if (MOBJ(Base::mesh_.FH(temp_hh)).red_halfedge() != temp_hh) + halfedge_vector.push_back(temp_hh); + } + } + else + { + + // second case + vh[0] = Base::mesh_.TVH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh))))); + vh[1] = Base::mesh_.TVH(red_hh); + vh[2] = Base::mesh_.TVH(Base::mesh_.NHEH(red_hh)); + + new_vh[0] = Base::mesh_.FVH(red_hh); + new_vh[1] = Base::mesh_.TVH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh))); + new_vh[2] = Base::mesh_.add_vertex(zero_point); + + hh[0] = Base::mesh_.PHEH(red_hh); + hh[1] = Base::mesh_.PHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh)))); + hh[2] = Base::mesh_.NHEH(red_hh); + + // split one edge + eh = Base::mesh_.EH(red_hh); + + split_edge(hh[2], new_vh[2], _target_state); + + assert(Base::mesh_.FVH(hh[2]) == vh[1]); + assert(Base::mesh_.FVH(hh[1]) == vh[0]); + assert(Base::mesh_.FVH(hh[0]) == vh[2]); + + if (Base::mesh_.FH(Base::mesh_.OHEH(hh[2])).is_valid()) { + + temp_hh = Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(hh[2]))); + if (MOBJ(Base::mesh_.FH(temp_hh)).red_halfedge() != temp_hh) + halfedge_vector.push_back(temp_hh); + } + } + } + + else { + + // one time divided face + vh[0] = Base::mesh_.TVH(Base::mesh_.NHEH(Base::mesh_.OHEH(red_hh))); + vh[1] = Base::mesh_.TVH(red_hh); + vh[2] = Base::mesh_.TVH(Base::mesh_.NHEH(red_hh)); + + new_vh[0] = Base::mesh_.FVH(red_hh); + new_vh[1] = Base::mesh_.add_vertex(zero_point); + new_vh[2] = Base::mesh_.add_vertex(zero_point); + + hh[0] = Base::mesh_.PHEH(red_hh); + hh[1] = Base::mesh_.PHEH(Base::mesh_.OHEH(red_hh)); + hh[2] = Base::mesh_.NHEH(red_hh); + + // split two edges + eh = Base::mesh_.EH(red_hh); + + split_edge(hh[1], new_vh[1], _target_state); + split_edge(hh[2], new_vh[2], _target_state); + + assert(Base::mesh_.FVH(hh[2]) == vh[1]); + assert(Base::mesh_.FVH(hh[1]) == vh[0]); + assert(Base::mesh_.FVH(hh[0]) == vh[2]); + + if (Base::mesh_.FH(Base::mesh_.OHEH(hh[1])).is_valid()) { + + temp_hh = Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(hh[1]))); + if (MOBJ(Base::mesh_.FH(temp_hh)).red_halfedge() != temp_hh) + halfedge_vector.push_back(temp_hh); + } + + if (Base::mesh_.FH(Base::mesh_.OHEH(hh[2])).is_valid()) { + + temp_hh = Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(hh[2]))); + if (MOBJ(Base::mesh_.FH(temp_hh)).red_halfedge() != temp_hh) + halfedge_vector.push_back(temp_hh); + } + } + } + } + + // continue here for all cases + + // flip edge + if (Base::mesh_.is_flip_ok(eh)) { + + Base::mesh_.flip(eh); + } + + // search new faces + fh[0] = Base::mesh_.FH(hh[0]); + fh[1] = Base::mesh_.FH(hh[1]); + fh[2] = Base::mesh_.FH(hh[2]); + fh[3] = Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(hh[0]))); + + assert(_fh == fh[0] || _fh == fh[1] || _fh == fh[2] || _fh == fh[3]); + + // init new faces + for (int i = 0; i <= 3; ++i) { + + MOBJ(fh[i]).set_state(_target_state); + MOBJ(fh[i]).set_final(); + MOBJ(fh[i]).set_position(_target_state, face_position); + MOBJ(fh[i]).set_red_halfedge(Base::mesh_.InvalidHalfedgeHandle); + } + + // init new vertices and edges + for (int i = 0; i <= 2; ++i) { + + MOBJ(new_vh[i]).set_position(_target_state, zero_point); + MOBJ(new_vh[i]).set_state(_target_state); + MOBJ(new_vh[i]).set_not_final(); + + Base::mesh_.set_point(new_vh[i], (Base::mesh_.point(vh[i]) + Base::mesh_.point(vh[(i + 2) % 3])) * 0.5); + + MOBJ(Base::mesh_.EH(hh[i])).set_state(_target_state); + MOBJ(Base::mesh_.EH(hh[i])).set_position(_target_state, zero_point); + MOBJ(Base::mesh_.EH(hh[i])).set_final(); + + MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(hh[i]))).set_state(_target_state); + MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(hh[i]))).set_position(_target_state, zero_point); + MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(hh[i]))).set_final(); + + MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(hh[i]))).set_state(_target_state); + MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(hh[i]))).set_position(_target_state, zero_point); + MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(hh[i]))).set_final(); + } + + // check, if opposite triangle needs splitting + while (!halfedge_vector.empty()) { + + temp_hh = halfedge_vector.back(); + halfedge_vector.pop_back(); + + check_edge(temp_hh, _target_state); + } + + assert(MOBJ(fh[0]).state() == _target_state); + assert(MOBJ(fh[1]).state() == _target_state); + assert(MOBJ(fh[2]).state() == _target_state); + assert(MOBJ(fh[3]).state() == _target_state); + } +} + + +template +void +Tvv4::raise(typename M::VertexHandle& _vh, state_t _target_state) +{ + + if (MOBJ(_vh).state() < _target_state) + { + + update(_vh, _target_state); + + // multiply old position by 4 + MOBJ(_vh).set_position(_target_state, MOBJ(_vh).position(_target_state - 1) * 4.0); + + MOBJ(_vh).inc_state(); + } +} + + +template +void +Tvv4::raise(typename M::EdgeHandle& _eh, state_t _target_state) +{ + if (MOBJ(_eh).state() < _target_state) + { + update(_eh, _target_state); + + typename M::FaceHandle fh(Base::mesh_.FH(Base::mesh_.HEH(_eh, 0))); + + if (!fh.is_valid()) + fh=Base::mesh_.FH(Base::mesh_.HEH(_eh, 1)); + + raise(fh, _target_state); + + assert(MOBJ(_eh).state() == _target_state); + } +} + +#ifndef DOXY_IGNORE_THIS + +template +void +Tvv4::split_edge(typename M::HalfedgeHandle &_hh, + typename M::VertexHandle &_vh, + state_t _target_state) +{ + typename M::HalfedgeHandle temp_hh; + + if (Base::mesh_.FH(Base::mesh_.OHEH(_hh)).is_valid()) + { + if (!MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(_hh))).final()) + { + if (MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(_hh))).red_halfedge().is_valid()) + { + temp_hh = MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(_hh))).red_halfedge(); + } + else + { + // two cases for divided, but not visited face + if (MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(_hh))))).state() + == MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(_hh))).state()) + { + temp_hh = Base::mesh_.PHEH(Base::mesh_.OHEH(_hh)); + } + + else if (MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(_hh))))).state() + == MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(_hh))).state()) + { + temp_hh = Base::mesh_.NHEH(Base::mesh_.OHEH(_hh)); + } + } + } + else + temp_hh = Base::mesh_.InvalidHalfedgeHandle; + } + else + temp_hh = Base::mesh_.InvalidHalfedgeHandle; + + // split edge + Base::mesh_.split(Base::mesh_.EH(_hh), _vh); + + if (Base::mesh_.FVH(_hh) == _vh) + { + MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(Base::mesh_.OHEH(Base::mesh_.PHEH(_hh))))).set_state(MOBJ(Base::mesh_.EH(_hh)).state()); + _hh = Base::mesh_.PHEH(Base::mesh_.OHEH(Base::mesh_.PHEH(_hh))); + } + + if (Base::mesh_.FH(Base::mesh_.OHEH(_hh)).is_valid()) { + + MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(Base::mesh_.OHEH(_hh)))).set_not_final(); + MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(_hh))).set_state(_target_state-1); + MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(_hh)))))).set_state(_target_state-1); + + MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(_hh))).set_not_final(); + MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(_hh)))))).set_not_final(); + + MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(Base::mesh_.OHEH(_hh)))).set_state(_target_state); + + if (temp_hh.is_valid()) { + + MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(_hh))).set_red_halfedge(temp_hh); + MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(_hh)))))).set_red_halfedge(temp_hh); + } + else { + + typename M::FaceHandle + fh1(Base::mesh_.FH(Base::mesh_.OHEH(_hh))), + fh2(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(_hh)))))); + + MOBJ(fh1).set_red_halfedge(Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(_hh)))); + MOBJ(fh2).set_red_halfedge(Base::mesh_.OHEH(Base::mesh_.PHEH(Base::mesh_.OHEH(_hh)))); + + const typename M::Point zero_point(0.0, 0.0, 0.0); + + MOBJ(fh1).set_position(_target_state - 1, zero_point); + MOBJ(fh2).set_position(_target_state - 1, zero_point); + } + } + + // init edges + MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(_hh))))).set_state(_target_state - 1); + MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(Base::mesh_.OHEH(Base::mesh_.NHEH(_hh))))).set_final(); + + MOBJ(Base::mesh_.EH(_hh)).set_state(_target_state - 1); + MOBJ(Base::mesh_.EH(_hh)).set_final(); +} + + +template +void Tvv4::check_edge(const typename M::HalfedgeHandle& _hh, + state_t _target_state) +{ + typename M::FaceHandle fh1(Base::mesh_.FH(_hh)), + fh2(Base::mesh_.FH(Base::mesh_.OHEH(_hh))); + + assert(fh1.is_valid()); + assert(fh2.is_valid()); + + typename M::HalfedgeHandle red_hh(MOBJ(fh1).red_halfedge()); + + if (!MOBJ(fh1).final()) { + + assert (MOBJ(fh1).final() == MOBJ(fh2).final()); + assert (!MOBJ(fh1).final()); + assert (MOBJ(fh1).red_halfedge() == MOBJ(fh2).red_halfedge()); + + const typename M::Point zero_point(0.0, 0.0, 0.0); + + MOBJ(fh1).set_position(_target_state - 1, zero_point); + MOBJ(fh2).set_position(_target_state - 1, zero_point); + + assert(red_hh.is_valid()); + + if (!red_hh.is_valid()) { + + MOBJ(fh1).set_state(_target_state - 1); + MOBJ(fh2).set_state(_target_state - 1); + + MOBJ(fh1).set_red_halfedge(_hh); + MOBJ(fh2).set_red_halfedge(_hh); + + MOBJ(Base::mesh_.EH(_hh)).set_not_final(); + MOBJ(Base::mesh_.EH(_hh)).set_state(_target_state - 1); + } + + else { + + MOBJ(Base::mesh_.EH(_hh)).set_not_final(); + MOBJ(Base::mesh_.EH(_hh)).set_state(_target_state - 1); + + raise(fh1, _target_state); + + assert(MOBJ(fh1).state() == _target_state); + } + } +} + + +// -------------------------------------------------------------------- VF ---- + + +template +void VF::raise(typename M::FaceHandle& _fh, state_t _target_state) +{ + if (MOBJ(_fh).state() < _target_state) { + + update(_fh, _target_state); + + // raise all neighbour vertices to level x-1 + typename M::FaceVertexIter fv_it; + typename M::VertexHandle vh; + std::vector vertex_vector; + + if (_target_state > 1) { + + for (fv_it = Base::mesh_.fv_iter(_fh); fv_it; ++fv_it) { + + vertex_vector.push_back(fv_it.handle()); + } + + while (!vertex_vector.empty()) { + + vh = vertex_vector.back(); + vertex_vector.pop_back(); + + Base::prev_rule()->raise(vh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + int valence(0); + + for (fv_it = Base::mesh_.fv_iter(_fh); fv_it; ++fv_it) { + + ++valence; + position += Base::mesh_.data(fv_it).position(_target_state - 1); + } + + position /= valence; + + // boundary rule + if (Base::number() == Base::subdiv_rule()->number() + 1 && + Base::mesh_.is_boundary(_fh) && + !MOBJ(_fh).final()) + position *= 0.5; + + MOBJ(_fh).set_position(_target_state, position); + MOBJ(_fh).inc_state(); + + assert(_target_state == MOBJ(_fh).state()); + } +} + + +// -------------------------------------------------------------------- FF ---- + + +template +void FF::raise(typename M::FaceHandle& _fh, state_t _target_state) { + + if (MOBJ(_fh).state() < _target_state) { + + update(_fh, _target_state); + + // raise all neighbour faces to level x-1 + typename M::FaceFaceIter ff_it; + typename M::FaceHandle fh; + std::vector face_vector; + + if (_target_state > 1) { + + for (ff_it = Base::mesh_.ff_iter(_fh); ff_it; ++ff_it) { + + face_vector.push_back(ff_it.handle()); + } + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + Base::prev_rule()->raise(fh, _target_state - 1); + } + + for (ff_it = Base::mesh_.ff_iter(_fh); ff_it; ++ff_it) { + + face_vector.push_back(ff_it.handle()); + } + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + while (MOBJ(fh).state() < _target_state - 1) + Base::prev_rule()->raise(fh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + int valence(0); + + for (ff_it = Base::mesh_.ff_iter(_fh); ff_it; ++ff_it) { + + ++valence; + + position += Base::mesh_.data(ff_it).position(_target_state - 1); + } + + position /= valence; + + MOBJ(_fh).set_position(_target_state, position); + MOBJ(_fh).inc_state(); + } +} + + +// ------------------------------------------------------------------- FFc ---- + + +template +void FFc::raise(typename M::FaceHandle& _fh, state_t _target_state) +{ + if (MOBJ(_fh).state() < _target_state) { + + update(_fh, _target_state); + + // raise all neighbour faces to level x-1 + typename M::FaceFaceIter ff_it(Base::mesh_.ff_iter(_fh)); + typename M::FaceHandle fh; + std::vector face_vector; + + if (_target_state > 1) + { + for (; ff_it; ++ff_it) + face_vector.push_back(ff_it.handle()); + + while (!face_vector.empty()) + { + fh = face_vector.back(); + face_vector.pop_back(); + Base::prev_rule()->raise(fh, _target_state - 1); + } + + for (ff_it = Base::mesh_.ff_iter(_fh); ff_it; ++ff_it) + face_vector.push_back(ff_it.handle()); + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + while (MOBJ(fh).state() < _target_state - 1) + Base::prev_rule()->raise(fh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + int valence(0); + + for (ff_it = Base::mesh_.ff_iter(_fh); ff_it; ++ff_it) + { + ++valence; + position += Base::mesh_.data(ff_it).position(_target_state - 1); + } + + position /= valence; + + // choose coefficient c + typename M::Scalar c = Base::coeff(); + + position *= (1.0 - c); + position += MOBJ(_fh).position(_target_state - 1) * c; + + MOBJ(_fh).set_position(_target_state, position); + MOBJ(_fh).inc_state(); + } +} + + +// -------------------------------------------------------------------- FV ---- + + +template +void FV::raise(typename M::VertexHandle& _vh, state_t _target_state) +{ + + if (MOBJ(_vh).state() < _target_state) { + + update(_vh, _target_state); + + // raise all neighbour vertices to level x-1 + typename M::VertexFaceIter vf_it(Base::mesh_.vf_iter(_vh)); + typename M::FaceHandle fh; + std::vector face_vector; + + if (_target_state > 1) { + + for (; vf_it; ++vf_it) { + + face_vector.push_back(vf_it.handle()); + } + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + Base::prev_rule()->raise(fh, _target_state - 1); + } + + for (vf_it = Base::mesh_.vf_iter(_vh); vf_it; ++vf_it) { + + face_vector.push_back(vf_it.handle()); + } + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + while (MOBJ(fh).state() < _target_state - 1) + Base::prev_rule()->raise(fh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + int valence(0); + + for (vf_it = Base::mesh_.vf_iter(_vh); vf_it; ++vf_it) { + + ++valence; + position += Base::mesh_.data(vf_it).position(_target_state - 1); + } + + position /= valence; + + MOBJ(_vh).set_position(_target_state, position); + MOBJ(_vh).inc_state(); + + if (Base::number() == Base::n_rules() - 1) { + + Base::mesh_.set_point(_vh, position); + MOBJ(_vh).set_final(); + } + } +} + + +// ------------------------------------------------------------------- FVc ---- + + +template +void FVc::raise(typename M::VertexHandle& _vh, state_t _target_state) +{ + if (MOBJ(_vh).state() < _target_state) { + + update(_vh, _target_state); + + typename M::VertexOHalfedgeIter voh_it; + typename M::FaceHandle fh; + std::vector face_vector; + int valence(0); + + face_vector.clear(); + + // raise all neighbour faces to level x-1 + if (_target_state > 1) { + + for (voh_it = Base::mesh_.voh_iter(_vh); voh_it; ++voh_it) { + + if (Base::mesh_.FH(voh_it.handle()).is_valid()) { + + face_vector.push_back(Base::mesh_.FH(voh_it.handle())); + + if (Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(voh_it.handle()))).is_valid()) { + + face_vector.push_back(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(voh_it.handle())))); + } + } + } + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + Base::prev_rule()->raise(fh, _target_state - 1); + } + + for (voh_it = Base::mesh_.voh_iter(_vh); voh_it; ++voh_it) { + + if (Base::mesh_.FH(voh_it.handle()).is_valid()) { + + face_vector.push_back(Base::mesh_.FH(voh_it.handle())); + + if (Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(voh_it.handle()))).is_valid()) { + + face_vector.push_back(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(voh_it.handle())))); + } + } + } + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + while (MOBJ(fh).state() < _target_state - 1) + Base::prev_rule()->raise(fh, _target_state - 1); + } + + for (voh_it = Base::mesh_.voh_iter(_vh); voh_it; ++voh_it) { + + if (Base::mesh_.FH(voh_it.handle()).is_valid()) { + + face_vector.push_back(Base::mesh_.FH(voh_it.handle())); + + if (Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(voh_it.handle()))).is_valid()) { + + face_vector.push_back(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(voh_it.handle())))); + } + } + } + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + while (MOBJ(fh).state() < _target_state - 1) + Base::prev_rule()->raise(fh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + typename M::Scalar c; +#if 0 + const typename M::Scalar _2pi(2.0*M_PI); + const typename M::Scalar _2over3(2.0/3.0); + + for (voh_it = Base::mesh_.voh_iter(_vh); voh_it; ++voh_it) + { + ++valence; + } + + // choose coefficient c + c = _2over3 * ( cos( _2pi / valence) + 1.0); +#else + valence = Base::mesh_.valence(_vh); + c = coeff(valence); +#endif + + + for (voh_it = Base::mesh_.voh_iter(_vh); voh_it; ++voh_it) { + + fh = Base::mesh_.FH(voh_it.handle()); + if (fh.is_valid()) + Base::prev_rule()->raise(fh, _target_state - 1); + + fh = Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(voh_it.handle()))); + if (fh.is_valid()) + Base::prev_rule()->raise(fh, _target_state - 1); + + if (Base::mesh_.FH(voh_it.handle()).is_valid()) { + + if (Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(voh_it.handle()))).is_valid()) { + + position += MOBJ(Base::mesh_.FH(voh_it.handle())).position(_target_state - 1) * c; + + position += MOBJ(Base::mesh_.FH(Base::mesh_.OHEH(Base::mesh_.NHEH(voh_it.handle())))).position(_target_state - 1) * (1.0 - c); + } + else { + + position += MOBJ(Base::mesh_.FH(voh_it.handle())).position(_target_state - 1); + } + } + + else { + + --valence; + } + } + + position /= valence; + + MOBJ(_vh).set_position(_target_state, position); + MOBJ(_vh).inc_state(); + + assert(MOBJ(_vh).state() == _target_state); + + // check if last rule + if (Base::number() == Base::n_rules() - 1) { + + Base::mesh_.set_point(_vh, position); + MOBJ(_vh).set_final(); + } + } +} + +template +std::vector FVc::coeffs_; + +template +void FVc::init_coeffs(size_t _max_valence) +{ + if ( coeffs_.size() == _max_valence+1 ) + return; + + if ( coeffs_.size() < _max_valence+1 ) + { + const double _2pi(2.0*M_PI); + const double _2over3(2.0/3.0); + + if (coeffs_.empty()) + coeffs_.push_back(0.0); // dummy for valence 0 + + for(size_t v=coeffs_.size(); v <= _max_valence; ++v) + coeffs_.push_back(_2over3 * ( cos( _2pi / v) + 1.0)); + } +} + + +// -------------------------------------------------------------------- VV ---- + + +template +void VV::raise(typename M::VertexHandle& _vh, state_t _target_state) +{ + if (MOBJ(_vh).state() < _target_state) + { + update(_vh, _target_state); + + // raise all neighbour vertices to level x-1 + typename M::VertexVertexIter vv_it(Base::mesh_.vv_iter(_vh)); + typename M::VertexHandle vh; + std::vector vertex_vector; + + if (_target_state > 1) { + + for (; vv_it; ++vv_it) { + + vertex_vector.push_back(vv_it.handle()); + } + + while (!vertex_vector.empty()) { + + vh = vertex_vector.back(); + vertex_vector.pop_back(); + + Base::prev_rule()->raise(vh, _target_state - 1); + } + + for (; vv_it; ++vv_it) { + + vertex_vector.push_back(vv_it.handle()); + } + + while (!vertex_vector.empty()) { + + vh = vertex_vector.back(); + vertex_vector.pop_back(); + + Base::prev_rule()->raise(vh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + int valence(0); + + for (vv_it = Base::mesh_.vv_iter(_vh); vv_it; ++vv_it) { + + ++valence; + + position += Base::mesh_.data(vv_it).position(_target_state - 1); + } + + position /= valence; + + MOBJ(_vh).set_position(_target_state, position); + MOBJ(_vh).inc_state(); + + // check if last rule + if (Base::number() == Base::n_rules() - 1) { + + Base::mesh_.set_point(_vh, position); + MOBJ(_vh).set_final(); + } + } +} + + +// ------------------------------------------------------------------- VVc ---- + + +template +void VVc::raise(typename M::VertexHandle& _vh, state_t _target_state) +{ + if (MOBJ(_vh).state() < _target_state) { + + update(_vh, _target_state); + + // raise all neighbour vertices to level x-1 + typename M::VertexVertexIter vv_it(Base::mesh_.vv_iter(_vh)); + typename M::VertexHandle vh; + std::vector vertex_vector; + + if (_target_state > 1) { + + for (; vv_it; ++vv_it) { + + vertex_vector.push_back(vv_it.handle()); + } + + while (!vertex_vector.empty()) { + + vh = vertex_vector.back(); + vertex_vector.pop_back(); + + Base::prev_rule()->raise(vh, _target_state - 1); + } + + for (; vv_it; ++vv_it) { + + vertex_vector.push_back(vv_it.handle()); + } + + while (!vertex_vector.empty()) { + + vh = vertex_vector.back(); + vertex_vector.pop_back(); + + Base::prev_rule()->raise(vh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + int valence(0); + typename M::Scalar c; + + for (vv_it = Base::mesh_.vv_iter(_vh); vv_it; ++vv_it) + { + ++valence; + position += Base::mesh_.data(vv_it).position(_target_state - 1); + } + + position /= valence; + + // choose coefficcient c + c = Base::coeff(); + + position *= (1.0 - c); + position += MOBJ(_vh).position(_target_state - 1) * c; + + MOBJ(_vh).set_position(_target_state, position); + MOBJ(_vh).inc_state(); + + if (Base::number() == Base::n_rules() - 1) + { + Base::mesh_.set_point(_vh, position); + MOBJ(_vh).set_final(); + } + } +} + + +// -------------------------------------------------------------------- VE ---- + + +template +void VE::raise(typename M::EdgeHandle& _eh, state_t _target_state) +{ + if (MOBJ(_eh).state() < _target_state) { + + update(_eh, _target_state); + + // raise all neighbour vertices to level x-1 + typename M::VertexHandle vh; + typename M::HalfedgeHandle hh1(Base::mesh_.HEH(_eh, 0)), + hh2(Base::mesh_.HEH(_eh, 1)); + + if (_target_state > 1) { + + vh = Base::mesh_.TVH(hh1); + + Base::prev_rule()->raise(vh, _target_state - 1); + + vh = Base::mesh_.TVH(hh2); + + Base::prev_rule()->raise(vh, _target_state - 1); + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + int valence(0); + + valence = 2; + position += MOBJ(Base::mesh_.TVH(hh1)).position(_target_state - 1); + position += MOBJ(Base::mesh_.TVH(hh2)).position(_target_state - 1); + + position /= valence; + + MOBJ(_eh).set_position(_target_state, position); + MOBJ(_eh).inc_state(); + } +} + + +// ------------------------------------------------------------------- VdE ---- + + +template +void VdE::raise(typename M::EdgeHandle& _eh, state_t _target_state) +{ + if (MOBJ(_eh).state() < _target_state) + { + update(_eh, _target_state); + + // raise all neighbour vertices to level x-1 + typename M::VertexHandle vh; + typename M::HalfedgeHandle hh1(Base::mesh_.HEH(_eh, 0)), + hh2(Base::mesh_.HEH(_eh, 1)); + std::vector vertex_vector; + typename M::FaceHandle fh1, fh2; + + if (_target_state > 1) { + + fh1 = Base::mesh_.FH(hh1); + fh2 = Base::mesh_.FH(hh2); + + if (fh1.is_valid()) { + + Base::prev_rule()->raise(fh1, _target_state - 1); + + vh = Base::mesh_.TVH(Base::mesh_.NHEH(hh1)); + Base::prev_rule()->raise(vh, _target_state - 1); + } + + if (fh2.is_valid()) { + + Base::prev_rule()->raise(fh2, _target_state - 1); + + vh = Base::mesh_.TVH(Base::mesh_.NHEH(hh2)); + Base::prev_rule()->raise(vh, _target_state - 1); + } + + vh = Base::mesh_.TVH(hh1); + Base::prev_rule()->raise(vh, _target_state - 1); + + vh = Base::mesh_.TVH(hh2); + Base::prev_rule()->raise(vh, _target_state - 1); + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + int valence(0); + + valence = 2; + position += MOBJ(Base::mesh_.TVH(hh1)).position(_target_state - 1); + position += MOBJ(Base::mesh_.TVH(hh2)).position(_target_state - 1); + + if (fh1.is_valid()) { + + position += MOBJ(Base::mesh_.TVH(Base::mesh_.NHEH(hh1))).position(_target_state - 1); + ++valence; + } + + if (fh2.is_valid()) { + + position += MOBJ(Base::mesh_.TVH(Base::mesh_.NHEH(hh2))).position(_target_state - 1); + ++valence; + } + + if (Base::number() == Base::subdiv_rule()->Base::number() + 1) + valence = 4; + + position /= valence; + + MOBJ(_eh).set_position(_target_state, position); + MOBJ(_eh).inc_state(); + } +} + + +// ------------------------------------------------------------------ VdEc ---- + + +template +void +VdEc::raise(typename M::EdgeHandle& _eh, state_t _target_state) +{ + if (MOBJ(_eh).state() < _target_state) + { + update(_eh, _target_state); + + // raise all neighbour vertices to level x-1 + typename M::VertexHandle vh; + typename M::HalfedgeHandle hh1(Base::mesh_.HEH(_eh, 0)), + hh2(Base::mesh_.HEH(_eh, 1)); + std::vector vertex_vector; + typename M::FaceHandle fh1, fh2; + + if (_target_state > 1) { + + fh1 = Base::mesh_.FH(Base::mesh_.HEH(_eh, 0)); + fh2 = Base::mesh_.FH(Base::mesh_.HEH(_eh, 1)); + + Base::prev_rule()->raise(fh1, _target_state - 1); + Base::prev_rule()->raise(fh2, _target_state - 1); + + vertex_vector.push_back(Base::mesh_.TVH(hh1)); + vertex_vector.push_back(Base::mesh_.TVH(hh2)); + + vertex_vector.push_back(Base::mesh_.TVH(Base::mesh_.NHEH(hh1))); + vertex_vector.push_back(Base::mesh_.TVH(Base::mesh_.NHEH(hh2))); + + while (!vertex_vector.empty()) { + + vh = vertex_vector.back(); + vertex_vector.pop_back(); + + Base::prev_rule()->raise(vh, _target_state - 1); + } + + vertex_vector.push_back(Base::mesh_.TVH(hh1)); + vertex_vector.push_back(Base::mesh_.TVH(hh2)); + + vertex_vector.push_back(Base::mesh_.TVH(Base::mesh_.NHEH(hh1))); + vertex_vector.push_back(Base::mesh_.TVH(Base::mesh_.NHEH(hh2))); + + while (!vertex_vector.empty()) { + + vh = vertex_vector.back(); + vertex_vector.pop_back(); + + Base::prev_rule()->raise(vh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + int valence(0); + typename M::Scalar c; + + // choose coefficient c + c = Base::coeff(); + + valence = 4; + position += MOBJ(Base::mesh_.TVH(hh1)).position(_target_state - 1) * c; + position += MOBJ(Base::mesh_.TVH(hh2)).position(_target_state - 1) * c; + position += MOBJ(Base::mesh_.TVH(Base::mesh_.NHEH(hh1))).position(_target_state - 1) * (0.5 - c); + position += MOBJ(Base::mesh_.TVH(Base::mesh_.NHEH(hh2))).position(_target_state - 1) * (0.5 - c); + + position /= valence; + + MOBJ(_eh).set_position(_target_state, position); + MOBJ(_eh).inc_state(); + } +} + + +// -------------------------------------------------------------------- EV ---- + + +template +void EV::raise(typename M::VertexHandle& _vh, state_t _target_state) +{ + if (MOBJ(_vh).state() < _target_state) { + + update(_vh, _target_state); + + // raise all neighbour vertices to level x-1 + typename M::VertexEdgeIter ve_it(Base::mesh_.ve_iter(_vh)); + typename M::EdgeHandle eh; + std::vector edge_vector; + + if (_target_state > 1) { + + for (; ve_it; ++ve_it) { + + edge_vector.push_back(ve_it.handle()); + } + + while (!edge_vector.empty()) { + + eh = edge_vector.back(); + edge_vector.pop_back(); + + Base::prev_rule()->raise(eh, _target_state - 1); + } + + for (ve_it = Base::mesh_.ve_iter(_vh); ve_it; ++ve_it) { + + edge_vector.push_back(ve_it.handle()); + } + + while (!edge_vector.empty()) { + + eh = edge_vector.back(); + edge_vector.pop_back(); + + while (MOBJ(eh).state() < _target_state - 1) + Base::prev_rule()->raise(eh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + int valence(0); + + for (ve_it = Base::mesh_.ve_iter(_vh); ve_it; ++ve_it) { + + if (Base::mesh_.data(ve_it).final()) { + + ++valence; + + position += Base::mesh_.data(ve_it).position(_target_state - 1); + } + } + + position /= valence; + + MOBJ(_vh).set_position(_target_state, position); + MOBJ(_vh).inc_state(); + + // check if last rule + if (Base::number() == Base::n_rules() - 1) { + + Base::mesh_.set_point(_vh, position); + MOBJ(_vh).set_final(); + } + } +} + + +// ------------------------------------------------------------------- EVc ---- + +template +std::vector EVc::coeffs_; + +template +void EVc::raise(typename M::VertexHandle& _vh, state_t _target_state) +{ + if (MOBJ(_vh).state() < _target_state) + { + update(_vh, _target_state); + + // raise all neighbour vertices to level x-1 + typename M::VertexOHalfedgeIter voh_it; + typename M::EdgeHandle eh; + typename M::FaceHandle fh; + std::vector edge_vector; + std::vector face_vector; + + if (_target_state > 1) { + + for (voh_it = Base::mesh_.voh_iter(_vh); voh_it; ++voh_it) { + + face_vector.push_back(Base::mesh_.FH(voh_it.handle())); + } + + while (!face_vector.empty()) { + + fh = face_vector.back(); + face_vector.pop_back(); + + if (fh.is_valid()) + Base::prev_rule()->raise(fh, _target_state - 1); + } + + for (voh_it = Base::mesh_.voh_iter(_vh); voh_it; ++voh_it) { + + edge_vector.push_back(Base::mesh_.EH(voh_it.handle())); + + edge_vector.push_back(Base::mesh_.EH(Base::mesh_.NHEH(voh_it.handle()))); + } + + while (!edge_vector.empty()) { + + eh = edge_vector.back(); + edge_vector.pop_back(); + + while (MOBJ(eh).state() < _target_state - 1) + Base::prev_rule()->raise(eh, _target_state - 1); + } + } + + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + typename M::Scalar c; + typename M::Point zero_point(0.0, 0.0, 0.0); + int valence(0); + + valence = Base::mesh_.valence(_vh); + c = coeff( valence ); + + for (voh_it = Base::mesh_.voh_iter(_vh); voh_it; ++voh_it) + { + if (MOBJ(Base::mesh_.EH(voh_it.handle())).final()) + { + position += MOBJ(Base::mesh_.EH(voh_it.handle())).position(_target_state-1)*c; + + if ( Base::mesh_.FH(voh_it.handle()).is_valid() && + MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(voh_it.handle()))).final() && + MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(voh_it.handle()))).position(_target_state - 1) != zero_point) + { + position += MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(voh_it.handle()))).position(_target_state-1) * (1.0-c); + } + else { + position += MOBJ(Base::mesh_.EH(voh_it.handle())).position(_target_state - 1) * (1.0 - c); + } + } + else { + --valence; + } + } + + position /= valence; + + MOBJ(_vh).set_position(_target_state, position); + MOBJ(_vh).inc_state(); + + // check if last rule + if (Base::number() == Base::n_rules() - 1) { + + Base::mesh_.set_point(_vh, position); + MOBJ(_vh).set_final(); + } + } +} + + +template +void +EVc::init_coeffs(size_t _max_valence) +{ + if ( coeffs_.size() == _max_valence+1 ) // equal? do nothing + return; + + if (coeffs_.size() < _max_valence+1) // less than? add additional valences + { + const double _2pi = 2.0*M_PI; + double c; + + if (coeffs_.empty()) + coeffs_.push_back(0.0); // dummy for invalid valences 0,1,2 + + for(size_t v=coeffs_.size(); v <= _max_valence; ++v) + { + // ( 3/2 + cos ( 2 PI / valence ) )² / 2 - 1 + c = 1.5 + cos( _2pi / v ); + c = c * c * 0.5 - 1.0; + coeffs_.push_back(c); + } + } +} + + +// -------------------------------------------------------------------- EF ---- + +template +void +EF::raise(typename M::FaceHandle& _fh, state_t _target_state) { + + if (MOBJ(_fh).state() < _target_state) { + + update(_fh, _target_state); + + // raise all neighbour edges to level x-1 + typename M::FaceEdgeIter fe_it(Base::mesh_.fe_iter(_fh)); + typename M::EdgeHandle eh; + std::vector edge_vector; + + if (_target_state > 1) { + + for (; fe_it; ++fe_it) { + + edge_vector.push_back(fe_it.handle()); + } + + while (!edge_vector.empty()) { + + eh = edge_vector.back(); + edge_vector.pop_back(); + + Base::prev_rule()->raise(eh, _target_state - 1); + } + + for (fe_it = Base::mesh_.fe_iter(_fh); fe_it; ++fe_it) { + + edge_vector.push_back(fe_it.handle()); + } + + while (!edge_vector.empty()) { + + eh = edge_vector.back(); + edge_vector.pop_back(); + + while (MOBJ(eh).state() < _target_state - 1) + Base::prev_rule()->raise(eh, _target_state - 1); + } + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + int valence(0); + + for (fe_it = Base::mesh_.fe_iter(_fh); fe_it; ++fe_it) { + + if (Base::mesh_.data(fe_it).final()) { + + ++valence; + + position += Base::mesh_.data(fe_it).position(_target_state - 1); + } + } + + assert (valence == 3); + + position /= valence; + + MOBJ(_fh).set_position(_target_state, position); + MOBJ(_fh).inc_state(); + } +} + + +// -------------------------------------------------------------------- FE ---- + + +template +void +FE::raise(typename M::EdgeHandle& _eh, state_t _target_state) { + + if (MOBJ(_eh).state() < _target_state) { + + update(_eh, _target_state); + + // raise all neighbour faces to level x-1 + typename M::FaceHandle fh; + + if (_target_state > 1) { + + fh = Base::mesh_.FH(Base::mesh_.HEH(_eh, 0)); + Base::prev_rule()->raise(fh, _target_state - 1); + + fh = Base::mesh_.FH(Base::mesh_.HEH(_eh, 1)); + Base::prev_rule()->raise(fh, _target_state - 1); + + fh = Base::mesh_.FH(Base::mesh_.HEH(_eh, 0)); + Base::prev_rule()->raise(fh, _target_state - 1); + + fh = Base::mesh_.FH(Base::mesh_.HEH(_eh, 1)); + Base::prev_rule()->raise(fh, _target_state - 1); + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + int valence(2); + + position += MOBJ(Base::mesh_.FH(Base::mesh_.HEH(_eh, 0))).position(_target_state - 1); + + position += MOBJ(Base::mesh_.FH(Base::mesh_.HEH(_eh, 1))).position(_target_state - 1); + + position /= valence; + + MOBJ(_eh).set_position(_target_state, position); + MOBJ(_eh).inc_state(); + } +} + + +// ------------------------------------------------------------------- EdE ---- + + +template +void +EdE::raise(typename M::EdgeHandle& _eh, state_t _target_state) { + + if (MOBJ(_eh).state() < _target_state) { + + update(_eh, _target_state); + + // raise all neighbour faces and edges to level x-1 + typename M::HalfedgeHandle hh1, hh2; + typename M::FaceHandle fh; + typename M::EdgeHandle eh; + + hh1 = Base::mesh_.HEH(_eh, 0); + hh2 = Base::mesh_.HEH(_eh, 1); + + if (_target_state > 1) { + + fh = Base::mesh_.FH(hh1); + Base::prev_rule()->raise(fh, _target_state - 1); + + fh = Base::mesh_.FH(hh2); + Base::prev_rule()->raise(fh, _target_state - 1); + + eh = Base::mesh_.EH(Base::mesh_.NHEH(hh1)); + Base::prev_rule()->raise(eh, _target_state - 1); + + eh = Base::mesh_.EH(Base::mesh_.PHEH(hh1)); + Base::prev_rule()->raise(eh, _target_state - 1); + + eh = Base::mesh_.EH(Base::mesh_.NHEH(hh2)); + Base::prev_rule()->raise(eh, _target_state - 1); + + eh = Base::mesh_.EH(Base::mesh_.PHEH(hh2)); + Base::prev_rule()->raise(eh, _target_state - 1); + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + int valence(4); + + position += MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(hh1))).position(_target_state - 1); + position += MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(hh1))).position(_target_state - 1); + position += MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(hh2))).position(_target_state - 1); + position += MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(hh2))).position(_target_state - 1); + + position /= valence; + + MOBJ(_eh).set_position(_target_state, position); + MOBJ(_eh).inc_state(); + } +} + + +// ------------------------------------------------------------------ EdEc ---- + + +template +void +EdEc::raise(typename M::EdgeHandle& _eh, state_t _target_state) +{ + if (MOBJ(_eh).state() < _target_state) { + + update(_eh, _target_state); + + // raise all neighbour faces and edges to level x-1 + typename M::HalfedgeHandle hh1, hh2; + typename M::FaceHandle fh; + typename M::EdgeHandle eh; + + hh1 = Base::mesh_.HEH(_eh, 0); + hh2 = Base::mesh_.HEH(_eh, 1); + + if (_target_state > 1) { + + fh = Base::mesh_.FH(hh1); + Base::prev_rule()->raise(fh, _target_state - 1); + + fh = Base::mesh_.FH(hh2); + Base::prev_rule()->raise(fh, _target_state - 1); + + eh = Base::mesh_.EH(Base::mesh_.NHEH(hh1)); + Base::prev_rule()->raise(eh, _target_state - 1); + + eh = Base::mesh_.EH(Base::mesh_.PHEH(hh1)); + Base::prev_rule()->raise(eh, _target_state - 1); + + eh = Base::mesh_.EH(Base::mesh_.NHEH(hh2)); + Base::prev_rule()->raise(eh, _target_state - 1); + + eh = Base::mesh_.EH(Base::mesh_.PHEH(hh2)); + Base::prev_rule()->raise(eh, _target_state - 1); + } + + // calculate new position + typename M::Point position(0.0, 0.0, 0.0); + int valence(4); + typename M::Scalar c; + + position += MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(hh1))).position(_target_state - 1); + position += MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(hh1))).position(_target_state - 1); + position += MOBJ(Base::mesh_.EH(Base::mesh_.NHEH(hh2))).position(_target_state - 1); + position += MOBJ(Base::mesh_.EH(Base::mesh_.PHEH(hh2))).position(_target_state - 1); + + position /= valence; + + // choose coefficient c + c = Base::coeff(); + + position *= (1.0 - c); + + position += MOBJ(_eh).position(_target_state - 1) * c; + + MOBJ(_eh).set_position(_target_state, position); + MOBJ(_eh).inc_state(); + } +} + +#endif // DOXY_IGNORE_THIS + +#undef FH +#undef VH +#undef EH +#undef HEH +#undef M +#undef MOBJ + +//============================================================================= +} // END_NS_ADAPTIVE +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= diff --git a/Tools/Subdivider/Adaptive/Composite/RulesT.hh b/Tools/Subdivider/Adaptive/Composite/RulesT.hh new file mode 100644 index 00000000..3f51d666 --- /dev/null +++ b/Tools/Subdivider/Adaptive/Composite/RulesT.hh @@ -0,0 +1,525 @@ +//============================================================================= +// +// 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 RulesT.hh + + */ + + +//============================================================================= +// +// Composite Subdivision and Averaging Rules +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_ADAPTIVE_RULEST_HH +#define OPENMESH_SUBDIVIDER_ADAPTIVE_RULEST_HH + + +//== INCLUDES ================================================================= + +#include +#include +// -------------------- STL +#include + + +#if defined(OM_CC_MIPS) // avoid warnings +# define MIPS_WARN_WA( Item ) \ + void raise(typename M:: ## Item ## Handle &_h, state_t _target_state ) \ + { Inherited::raise(_h, _target_state); } +#else +# define MIPS_WARN_WA( Item ) +#endif + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_SUBDIVIDER +namespace Adaptive { // BEGIN_NS_ADAPTIVE + + +//== CLASS DEFINITION ========================================================= + +/** Adaptive Composite Subdivision framework. +*/ + + +//============================================================================= + +/** Topological composite rule Tvv,3 doing a 1-3 split of a face. + */ +template class Tvv3 : public RuleInterfaceT +{ + COMPOSITE_RULE( Tvv3, M ); +private: + typedef RuleInterfaceT Base; + +public: + + typedef RuleInterfaceT Inherited; + + Tvv3(M& _mesh) : Inherited(_mesh) { Base::set_subdiv_type(3); }; + + void raise(typename M::FaceHandle& _fh, state_t _target_state); + void raise(typename M::VertexHandle& _vh, state_t _target_state); + MIPS_WARN_WA(Edge); // avoid warning +}; + + +//============================================================================= + + +/** Topological composite rule Tvv,4 doing a 1-4 split of a face + */ +template class Tvv4 : public RuleInterfaceT +{ + COMPOSITE_RULE( Tvv4, M ); + +private: + typedef RuleInterfaceT Base; +public: + typedef typename M::HalfedgeHandle HEH; + typedef typename M::VertexHandle VH; + + typedef RuleInterfaceT Inherited; + + Tvv4(M& _mesh) : Inherited(_mesh) { Base::set_subdiv_type(4); }; + + void raise(typename M::FaceHandle& _fh, state_t _target_state); + void raise(typename M::VertexHandle& _vh, state_t _target_state); + void raise(typename M::EdgeHandle& _eh, state_t _target_state); + +private: + + void split_edge(HEH& _hh, VH& _vh, state_t _target_state); + void check_edge(const typename M::HalfedgeHandle& _hh, + state_t _target_state); +}; + + +//============================================================================= + + +/** Composite rule VF + */ +template class VF : public RuleInterfaceT +{ + COMPOSITE_RULE( VF, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + VF(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::FaceHandle& _fh, state_t _target_state); + MIPS_WARN_WA(Edge); + MIPS_WARN_WA(Vertex); +}; + + +//============================================================================= + + +/** Composite rule FF + */ +template class FF : public RuleInterfaceT +{ + COMPOSITE_RULE( FF, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + FF(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::FaceHandle& _fh, state_t _target_state); + MIPS_WARN_WA(Vertex); // avoid warning + MIPS_WARN_WA(Edge ); // avoid warning +}; + + +//============================================================================= + + +/** Composite rule FFc + */ +template class FFc : public RuleInterfaceT +{ + COMPOSITE_RULE( FFc, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + FFc(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::FaceHandle& _fh, state_t _target_state); + MIPS_WARN_WA(Vertex); // avoid warning + MIPS_WARN_WA(Edge ); // avoid warning +}; + + +//============================================================================= + + +/** Composite rule FV + */ +template class FV : public RuleInterfaceT +{ + COMPOSITE_RULE( FV, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + FV(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::VertexHandle& _vh, state_t _target_state); + MIPS_WARN_WA(Face); // avoid warning + MIPS_WARN_WA(Edge); // avoid warning +}; + + +//============================================================================= + + +/** Composite rule FVc + */ +template class FVc : public RuleInterfaceT +{ + COMPOSITE_RULE( FVc, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + FVc(M& _mesh) : Inherited(_mesh) { init_coeffs(50); } + + void raise(typename M::VertexHandle& _vh, state_t _target_state); + MIPS_WARN_WA(Face); // avoid warning + MIPS_WARN_WA(Edge); // avoid warning + + static void init_coeffs(size_t _max_valence); + static const std::vector& coeffs() { return coeffs_; } + + double coeff( size_t _valence ) + { + assert(_valence < coeffs_.size()); + return coeffs_[_valence]; + } + +private: + + static std::vector coeffs_; + +}; + + +//============================================================================= + + +/** Composite rule VV + */ +template class VV : public RuleInterfaceT +{ + COMPOSITE_RULE( VV, M ); +private: + typedef RuleInterfaceT Base; + +public: + + typedef RuleInterfaceT Inherited; + + VV(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::VertexHandle& _vh, state_t _target_state); + MIPS_WARN_WA(Face); // avoid warning + MIPS_WARN_WA(Edge); // avoid warning +}; + + +//============================================================================= + + +/** Composite rule VVc + */ +template class VVc : public RuleInterfaceT +{ + COMPOSITE_RULE( VVc, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + VVc(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::VertexHandle& _vh, state_t _target_state); + MIPS_WARN_WA(Face); // avoid warning + MIPS_WARN_WA(Edge); // avoid warning +}; + + +//============================================================================= + + +/** Composite rule VE + */ +template class VE : public RuleInterfaceT +{ + COMPOSITE_RULE( VE, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + VE(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::EdgeHandle& _eh, state_t _target_state); + MIPS_WARN_WA(Face ); // avoid warning + MIPS_WARN_WA(Vertex); // avoid warning +}; + + +//============================================================================= + + +/** Composite rule VdE + */ +template class VdE : public RuleInterfaceT +{ + COMPOSITE_RULE( VdE, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + VdE(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::EdgeHandle& _eh, state_t _target_state); + MIPS_WARN_WA(Face ); // avoid warning + MIPS_WARN_WA(Vertex); // avoid warning +}; + + +//============================================================================= + + +/** Composite rule VdEc + */ +template class VdEc : public RuleInterfaceT +{ + COMPOSITE_RULE( VdEc, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + VdEc(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::EdgeHandle& _eh, state_t _target_state); + MIPS_WARN_WA(Face ); // avoid warning + MIPS_WARN_WA(Vertex); // avoid warning +}; + + +//============================================================================= + + +/** Composite rule EV + */ +template class EV : public RuleInterfaceT +{ + COMPOSITE_RULE( EV, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + EV(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::VertexHandle& _vh, state_t _target_state); + MIPS_WARN_WA(Face); // avoid warning + MIPS_WARN_WA(Edge); // avoid warning +}; + + +//============================================================================= + + +/** Composite rule EVc + */ +template class EVc : public RuleInterfaceT +{ + COMPOSITE_RULE( EVc, M ); +private: + typedef RuleInterfaceT Base; + +public: + + typedef RuleInterfaceT Inherited; + + EVc(M& _mesh) : Inherited(_mesh) { init_coeffs(50); } + + void raise(typename M::VertexHandle& _vh, state_t _target_state); + MIPS_WARN_WA(Face); // avoid warning + MIPS_WARN_WA(Edge); // avoid warning + + static void init_coeffs(size_t _max_valence); + static const std::vector& coeffs() { return coeffs_; } + + double coeff( size_t _valence ) + { + assert(_valence < coeffs_.size()); + return coeffs_[_valence]; + } + +private: + + static std::vector coeffs_; + +}; + + +//============================================================================= + + +/** Composite rule EF + */ +template class EF : public RuleInterfaceT +{ + COMPOSITE_RULE( EF, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + EF(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::FaceHandle& _fh, state_t _target_state); + MIPS_WARN_WA(Edge ); // avoid warning + MIPS_WARN_WA(Vertex); // avoid warning +}; + + +//============================================================================= + + +/** Composite rule FE + */ +template class FE : public RuleInterfaceT +{ + COMPOSITE_RULE( FE, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + FE(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::EdgeHandle& _eh, state_t _target_state); + MIPS_WARN_WA(Face ); // avoid warning + MIPS_WARN_WA(Vertex); // avoid warning +}; + + +//============================================================================= + + +/** Composite rule EdE + */ +template class EdE : public RuleInterfaceT +{ + COMPOSITE_RULE( EdE, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + EdE(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::EdgeHandle& _eh, state_t _target_state); + MIPS_WARN_WA(Face ); // avoid warning + MIPS_WARN_WA(Vertex); // avoid warning +}; + + +//============================================================================= + + +/** Composite rule EdEc + */ +template class EdEc : public RuleInterfaceT +{ + COMPOSITE_RULE( EdEc, M ); +private: + typedef RuleInterfaceT Base; + +public: + typedef RuleInterfaceT Inherited; + + EdEc(M& _mesh) : Inherited(_mesh) {} + + void raise(typename M::EdgeHandle& _eh, state_t _target_state); + MIPS_WARN_WA(Face ); // avoid warning + MIPS_WARN_WA(Vertex); // avoid warning +}; + +// ---------------------------------------------------------------------------- + +#undef MIPS_WARN_WA + +//============================================================================= +} // END_NS_ADAPTIVE +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_SUBDIVIDER_ADAPTIVE_RULEST_CC) +# define OPENMESH_SUBDIVIDER_TEMPLATES +# include "RulesT.cc" +#endif +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_ADAPTIVE_RULEST_HH defined +//============================================================================= + diff --git a/Tools/Subdivider/Adaptive/Composite/Traits.hh b/Tools/Subdivider/Adaptive/Composite/Traits.hh new file mode 100644 index 00000000..2e8b0945 --- /dev/null +++ b/Tools/Subdivider/Adaptive/Composite/Traits.hh @@ -0,0 +1,237 @@ +//============================================================================= +// +// 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 Traits.hh + + */ + +//============================================================================= +// +// CLASS Traits +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_ADAPTIVE_TRAITS_HH +#define OPENMESH_SUBDIVIDER_ADAPTIVE_TRAITS_HH + + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Adaptive { // BEGIN_NS_UNIFORM + + +//== CLASS DEFINITION ========================================================= + +/** Adaptive Composite Subdivision framework. +*/ + +// typedef unsigned short state_t; +// const state_t mask_final = 1 << ((sizeof(state_t)*8)-1); +// const state_t mask_state = ~mask_final; + +typedef int state_t; +typedef bool final_t; + +struct State +{ + int state : 31; + unsigned final : 1; +}; + +struct Traits : public OpenMesh::DefaultTraits +{ + + // add face normals + FaceAttributes( OpenMesh::Attributes::Normal ); + + // add vertex normals + VertexAttributes( OpenMesh::Attributes::Normal ); + + // add previous halfedge handle + HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge ); + + FaceTraits + { + + private: + + typedef typename Refs::Point Point; + typedef typename Refs::HalfedgeHandle HalfedgeHandle; + typedef std::map PositionHistory; + + State state_; + HalfedgeHandle red_halfedge_; + + PositionHistory pos_map_; + + public: + + // face state + state_t state() const { return state_t(state_.state); } + void set_state(const state_t _s) { state_.state = _s; } + void inc_state() { ++state_.state; } + + // face not final if divided (loop) or edge not flipped (sqrt(3)) + final_t final() const { return final_t(state_.final); } + void set_final() { state_.final = true; } + void set_not_final() { state_.final = false; } + + // halfedge of dividing edge (red-green triangulation) + const HalfedgeHandle& red_halfedge() const { return red_halfedge_; } + void set_red_halfedge(const HalfedgeHandle& _h) { red_halfedge_ = _h; } + + // position of face, depending on generation _i. + void set_position(const int& _i, const Point& _p) { pos_map_[_i] = _p; } + const Point position(const int& _i) { + if (pos_map_.find(_i) != pos_map_.end()) + return pos_map_[_i]; + else { + + if (_i <= 0) { + const Point zero_point(0.0, 0.0, 0.0); + return zero_point; + } + + return position(_i - 1); + } + } + }; // end class FaceTraits + + + EdgeTraits + { + + private: + + typedef typename Refs::Point Point; + typedef std::map PositionHistory; + + State state_; + PositionHistory pos_map_; + + public: + + typedef typename Refs::Scalar Scalar; + + // Scalar weight_; + + // state of edge + state_t state() const { return state_t(state_.state); } + void set_state(const state_t _s) { state_.state = _s; } + void inc_state() { ++state_.state; } + + // edge not final if dividing face (Loop) or edge not flipped (SQRT(3)) + final_t final() const { return final_t(state_.final); } + void set_final() { state_.final = true; } + void set_not_final() { state_.final = false; } + + // position of edge, depending on generation _i. + void set_position(const int& _i, const Point& _p) { pos_map_[_i] = _p; } + const Point position(const int& _i) { + + if (pos_map_.find(_i) != pos_map_.end()) + { + return pos_map_[_i]; + } + else + { + if (_i <= 0) + { + const Point zero_point(0.0, 0.0, 0.0); + return zero_point; + } + + return position(_i - 1); + } + } + }; // end class EdgeTraits + + + VertexTraits + { + + private: + + typedef typename Refs::Point Point; + typedef std::map PositionHistory; + + State state_; + + PositionHistory pos_map_; + + public: + + // state of vertex + state_t state() const { return state_.state; } + void set_state(const state_t _s) { state_.state = _s; } + void inc_state() { ++state_.state; } + + + // usually not needed by loop or sqrt(3) + final_t final() const { return state_.final; } + void set_final() { state_.final = true; } + void set_not_final() { state_.final = false; } + + // position of vertex, depending on generation _i. (not for display) + void set_position(const int& _i, const Point& _p) { pos_map_[_i] = _p; } + const Point position(const int& _i) { + + if (pos_map_.find(_i) != pos_map_.end()) + + return pos_map_[_i]; + + else { + + if (_i <= 0) { + + const Point zero_point(0.0, 0.0, 0.0); + return zero_point; + } + + return position(_i - 1); + } + } + }; // end class VertexTraits +}; // end class Traits + +//============================================================================= +} // END_NS_ADAPTIVE +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_ADAPTIVE_TRAITS_HH defined +//============================================================================= diff --git a/Tools/Subdivider/Uniform/ACGMakefile b/Tools/Subdivider/Uniform/ACGMakefile new file mode 100644 index 00000000..bbd4512f --- /dev/null +++ b/Tools/Subdivider/Uniform/ACGMakefile @@ -0,0 +1,17 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = $(call find-subdirs) + +PACKAGES := + +PROJ_LIBS := + +MODULES := cxxlib + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Tools/Subdivider/Uniform/Composite/ACGMakefile b/Tools/Subdivider/Uniform/Composite/ACGMakefile new file mode 100644 index 00000000..bbd4512f --- /dev/null +++ b/Tools/Subdivider/Uniform/Composite/ACGMakefile @@ -0,0 +1,17 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = $(call find-subdirs) + +PACKAGES := + +PROJ_LIBS := + +MODULES := cxxlib + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Tools/Subdivider/Uniform/Composite/CompositeT.cc b/Tools/Subdivider/Uniform/Composite/CompositeT.cc new file mode 100644 index 00000000..47e52ed4 --- /dev/null +++ b/Tools/Subdivider/Uniform/Composite/CompositeT.cc @@ -0,0 +1,1310 @@ +//============================================================================= +// +// 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: 1805 $ +// $Date: 2008-05-19 12:57:50 +0200 (Mo, 19. Mai 2008) $ +// +//============================================================================= + +/** \file Uniform/Composite/CompositeT.cc + + */ + +//============================================================================= +// +// CLASS CompositeT - IMPLEMENTATION +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITE_CC +#define OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITE_CC + + +//== INCLUDES ================================================================= + + +#include +#include + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Uniform { // BEGIN_NS_UNIFORM + + +//== IMPLEMENTATION ========================================================== + + +template +bool CompositeT::prepare( MeshType& _m ) +{ + // store mesh for later usage in subdivide(), cleanup() and all rules. + p_mesh_ = &_m; + + typename MeshType::VertexIter v_it(_m.vertices_begin()); + + for (; v_it != _m.vertices_end(); ++v_it) + _m.data(v_it).set_position(_m.point(v_it.handle())); + + return true; +} + + + +template +void CompositeT::Tvv3() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::VertexHandle vh; + typename MeshType::FaceIter f_it; + typename MeshType::EdgeIter e_it; + typename MeshType::VertexIter v_it; + typename MeshType::Point zero_point(0.0, 0.0, 0.0); + size_t n_edges, n_faces, n_vertices, j; + + // Store number of original edges + n_faces = mesh_.n_faces(); + n_edges = mesh_.n_edges(); + n_vertices = mesh_.n_vertices(); + + // reserve enough memory for iterator + mesh_.reserve(n_vertices + n_faces, n_edges + 3 * n_faces, 3 * n_faces); + + // set new positions for vertices + v_it = mesh_.vertices_begin(); + for (j = 0; j < n_vertices; ++j) { + mesh_.data(v_it).set_position(mesh_.data(v_it).position() * 3.0); + ++v_it; + } + + // Split each face + f_it = mesh_.faces_begin(); + for (j = 0; j < n_faces; ++j) { + + vh = mesh_.add_vertex(zero_point); + + mesh_.data(vh).set_position(zero_point); + + mesh_.split(f_it.handle(), vh); + + ++f_it; + } + + // Flip each old edge + std::vector edge_vector; + edge_vector.clear(); + + e_it = mesh_.edges_begin(); + for (j = 0; j < n_edges; ++j) { + if (mesh_.is_flip_ok(e_it.handle())) { + mesh_.flip(e_it.handle()); + } else { + edge_vector.push_back(e_it.handle()); + } + ++e_it; + } + + // split all boundary edges + while (!edge_vector.empty()) { + vh = mesh_.add_vertex(zero_point); + mesh_.data(vh).set_position(zero_point); + mesh_.split(edge_vector.back(), vh); + edge_vector.pop_back(); + } +} + + +template +void CompositeT::Tvv4() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::VertexHandle vh; + typename MeshType::FaceIter f_it; + typename MeshType::EdgeIter e_it; + typename MeshType::VertexIter v_it; + typename MeshType::Point zero_point(0.0, 0.0, 0.0); + unsigned int n_edges, n_faces, n_vertices, j; + + // Store number of original edges + n_faces = mesh_.n_faces(); + n_edges = mesh_.n_edges(); + n_vertices = mesh_.n_vertices(); + + // reserve memory ahead for the succeeding operations + mesh_.reserve(n_vertices + n_edges, 2 * n_edges + 3 * n_faces, 4 * n_faces); + + // set new positions for vertices + v_it = mesh_.vertices_begin(); + for (j = 0; j < n_vertices; ++j) { + mesh_.data(v_it).set_position(mesh_.data(v_it).position() * 4.0); + ++v_it; + } + + // Split each edge + e_it = mesh_.edges_begin(); + for (j = 0; j < n_edges; ++j) { + + vh = split_edge(mesh_.halfedge_handle(e_it.handle(), 0)); + mesh_.data(vh).set_position(zero_point); + + ++e_it; + } + + // Corner Cutting of Each Face + f_it = mesh_.faces_begin(); + for (j = 0; j < n_faces; ++j) { + typename MeshType::HalfedgeHandle heh1(mesh_.halfedge_handle(f_it.handle())); + typename MeshType::HalfedgeHandle heh2(mesh_.next_halfedge_handle(mesh_.next_halfedge_handle(heh1))); + typename MeshType::HalfedgeHandle heh3(mesh_.next_halfedge_handle(mesh_.next_halfedge_handle(heh2))); + + // Cutting off every corner of the 6_gon + + corner_cutting(heh1); + corner_cutting(heh2); + corner_cutting(heh3); + + ++f_it; + } +} + + +template +void CompositeT::Tfv() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::VertexHandle vh; + typename MeshType::FaceIter f_it; + typename MeshType::EdgeIter e_it; + typename MeshType::VertexIter v_it; + typename MeshType::VertexFaceIter vf_it; + typename MeshType::FaceFaceIter ff_it; + typename MeshType::Point cog; + const typename MeshType::Point zero_point(0.0, 0.0, 0.0); + unsigned int n_edges, n_faces, n_vertices, j, valence; + + // Store number of original edges + n_faces = mesh_.n_faces(); + n_edges = mesh_.n_edges(); + n_vertices = mesh_.n_vertices(); + + // reserve enough space for iterator + mesh_.reserve(n_vertices + n_faces, n_edges + 3 * n_faces, 3 * n_faces); + + // set new positions for vertices + v_it = mesh_.vertices_begin(); + for (j = 0; j < n_vertices; ++j) { + valence = 0; + cog = zero_point; + for (vf_it = mesh_.vf_iter(v_it.handle()); vf_it; ++vf_it) { + ++valence; + cog += vf_it->position(); + } + cog /= valence; + + v_it->set_position(cog); + ++v_it; + } + + // Split each face, insert new vertex and calculate position + f_it = mesh_.faces_begin(); + for (j = 0; j < n_faces; ++j) { + + vh = mesh_.add_vertex(); + + valence = 0; + cog = zero_point; + for (ff_it = mesh_.ff_iter(f_it.handle()); ff_it; ++ff_it) { + ++valence; + cog += ff_it->position(); + } + cog /= valence; + + mesh_.split(f_it.handle(), vh); + + for (vf_it = mesh_.vf_iter(vh); vf_it; ++vf_it) { + vf_it->set_position(f_it->position()); + } + + mesh_.deref(vh).set_position(cog); + + mesh_.set_point(vh, cog); + + ++f_it; + } + + // Flip each old edge + e_it = mesh_.edges_begin(); + for (j = 0; j < n_edges; ++j) { + if (mesh_.is_flip_ok(e_it.handle())) + mesh_.flip(e_it.handle()); + ++e_it; + } +} + + + +template +void CompositeT::VF() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + unsigned int valence; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::FaceVertexIter fv_it; + typename MeshType::FaceIter f_it; + + for (f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it) { + + valence = 0; + cog = zero_point; + + for (fv_it = mesh_.fv_iter(f_it.handle()); fv_it; ++fv_it) { + cog += mesh_.data(fv_it).position(); + ++valence; + } + cog /= valence; + mesh_.data(f_it).set_position(cog); + } +} + + +template +void CompositeT::VFa(Coeff& _coeff) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + unsigned int valence[3], i; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::Scalar alpha; + typename MeshType::FaceIter f_it; + typename MeshType::HalfedgeHandle heh; + typename MeshType::VertexHandle vh[3]; + typename MeshType::VertexOHalfedgeIter voh_it; + typename MeshType::FaceVertexIter fv_it; + + for (f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it) { + + heh = mesh_.halfedge_handle(f_it.handle()); + for (i = 0; i <= 2; ++i) { + + valence[i] = 0; + vh[i] = mesh_.to_vertex_handle(heh); + + for (voh_it = mesh_.voh_iter(vh[i]); voh_it; ++voh_it) { + ++valence[i]; + } + + heh = mesh_.next_halfedge_handle(heh); + } + + if (valence[0] <= valence[1]) + if (valence[0] <= valence[2]) + i = 0; + else + i = 2; + else + if (valence[1] <= valence[2]) + i = 1; + else + i = 2; + + alpha = _coeff(valence[i]); + + cog = zero_point; + + for (fv_it = mesh_.fv_iter(f_it.handle()); fv_it; ++fv_it) { + if (fv_it.handle() == vh[i]) { + cog += fv_it->position() * alpha; + } else { + cog += fv_it->position() * (1.0 - alpha) / 2.0; + } + } + + f_it->set_position(cog); + } +} + + +template +void CompositeT::VFa(scalar_t _alpha) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + unsigned int valence[3], i; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::FaceIter f_it; + typename MeshType::HalfedgeHandle heh; + typename MeshType::VertexHandle vh[3]; + typename MeshType::VertexOHalfedgeIter voh_it; + typename MeshType::FaceVertexIter fv_it; + + for (f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it) { + + heh = mesh_.halfedge_handle(f_it.handle()); + for (i = 0; i <= 2; ++i) { + + valence[i] = 0; + vh[i] = mesh_.to_vertex_handle(heh); + + for (voh_it = mesh_.voh_iter(vh[i]); voh_it; ++voh_it) { + ++valence[i]; + } + + heh = mesh_.next_halfedge_handle(heh); + } + + if (valence[0] <= valence[1]) + if (valence[0] <= valence[2]) + i = 0; + else + i = 2; + else + if (valence[1] <= valence[2]) + i = 1; + else + i = 2; + + cog = zero_point; + + for (fv_it = mesh_.fv_iter(f_it.handle()); fv_it; ++fv_it) { + if (fv_it.handle() == vh[i]) { + cog += fv_it->position() * _alpha; + } else { + cog += fv_it->position() * (1.0 - _alpha) / 2.0; + } + } + + f_it->set_position(cog); + } +} + + +template +void CompositeT::FF() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + unsigned int valence; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::FaceFaceIter ff_it; + typename MeshType::FaceIter f_it; + std::vector point_vector; + + point_vector.clear(); + + for (f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it) + { + valence = 0; + cog = zero_point; + + for (ff_it = mesh_.ff_iter(f_it.handle()); ff_it; ++ff_it) + { + cog += mesh_.data(ff_it).position(); + ++valence; + } + cog /= valence; + point_vector.push_back(cog); + } + + for (f_it = mesh_.faces_end(); f_it != mesh_.faces_begin(); ) + { + --f_it; + mesh_.data(f_it).set_position(point_vector.back()); + point_vector.pop_back(); + } +} + + +template +void CompositeT::FFc(Coeff& _coeff) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + unsigned int valence; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::FaceFaceIter ff_it; + typename MeshType::FaceIter f_it; + typename MeshType::Scalar c; + std::vector point_vector; + + for (f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it) { + + valence = 0; + cog = zero_point; + + for (ff_it = mesh_.ff_iter(f_it.handle()); ff_it; ++ff_it) { + cog += ff_it->position(); + ++valence; + } + cog /= valence; + + c = _coeff(valence); + + cog = cog * (1.0 - c) + f_it->position() * c; + + point_vector.push_back(cog); + + } + for (f_it = mesh_.faces_end(); f_it != mesh_.faces_begin(); ) { + + --f_it; + f_it->set_position(point_vector.back()); + point_vector.pop_back(); + + } +} + + +template +void CompositeT::FFc(scalar_t _c) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + unsigned int valence; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::FaceFaceIter ff_it; + typename MeshType::FaceIter f_it; + std::vector point_vector; + + for (f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it) { + + valence = 0; + cog = zero_point; + + for (ff_it = mesh_.ff_iter(f_it.handle()); ff_it; ++ff_it) { + cog += ff_it->position(); + ++valence; + } + cog /= valence; + + cog = cog * (1.0 - _c) + f_it->position() * _c; + + point_vector.push_back(cog); + + } + for (f_it = mesh_.faces_end(); f_it != mesh_.faces_begin(); ) { + + --f_it; + f_it->set_position(point_vector.back()); + point_vector.pop_back(); + } +} + + +template +void CompositeT::FV() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + unsigned int valence; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::VertexFaceIter vf_it; + typename MeshType::VertexIter v_it; + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) { + + valence = 0; + cog = zero_point; + + for (vf_it = mesh_.vf_iter(v_it.handle()); vf_it; ++vf_it) { + cog += vf_it->position(); + ++valence; + } + cog /= valence; + v_it->set_position(cog); + } +} + + +template +void CompositeT::FVc(Coeff& _coeff) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + unsigned int valence; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + scalar_t c; + typename MeshType::VertexOHalfedgeIter voh_it; + typename MeshType::VertexIter v_it; + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) { + + valence = 0; + cog = zero_point; + + for (voh_it = mesh_.voh_iter(v_it.handle()); voh_it; ++voh_it) { + ++valence; + } + + c = _coeff(valence); + + for (voh_it = mesh_.voh_iter(v_it.handle()); voh_it; ++voh_it) { + + if (mesh_.face_handle(voh_it.handle()).is_valid()) { + + if (mesh_.face_handle(mesh_.opposite_halfedge_handle(mesh_.next_halfedge_handle(voh_it.handle()))).is_valid()) { + cog += mesh_.data(mesh_.face_handle(voh_it.handle())).position() * c; + cog += mesh_.data(mesh_.face_handle(mesh_.opposite_halfedge_handle(mesh_.next_halfedge_handle(voh_it.handle())))).position() * (1.0 - c); + } else { + cog += mesh_.data(mesh_.face_handle(voh_it.handle())).position(); + } + } else { + --valence; + } + } + + if (valence > 0) + cog /= valence; + + mesh_.data(v_it).set_position(cog); + } +} + + +template +void CompositeT::FVc(scalar_t _c) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + unsigned int valence; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::VertexOHalfedgeIter voh_it; + typename MeshType::VertexIter v_it; + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) { + + valence = 0; + cog = zero_point; + + for (voh_it = mesh_.voh_iter(v_it.handle()); voh_it; ++voh_it) { + ++valence; + } + + for (voh_it = mesh_.voh_iter(v_it.handle()); voh_it; ++voh_it) { + + if (mesh_.face_handle(voh_it.handle()).is_valid()) { + + if (mesh_.face_handle(mesh_.opposite_halfedge_handle(mesh_.next_halfedge_handle(voh_it.handle()))).is_valid()) { + cog += mesh_.deref(mesh_.face_handle(voh_it.handle())).position() * _c; + cog += mesh_.deref(mesh_.face_handle(mesh_.opposite_halfedge_handle(mesh_.next_halfedge_handle(voh_it.handle())))).position() * (1.0 - _c); + } else { + cog += mesh_.deref(mesh_.face_handle(voh_it.handle())).position(); + } + } else { + --valence; + } + } + + if (valence > 0) + cog /= valence; + + v_it->set_position(cog); + } +} + + +template +void CompositeT::VdE() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::EdgeIter e_it; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::HalfedgeHandle heh1, heh2; + unsigned int valence; + + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) { + + cog = zero_point; + valence = 2; + + heh1 = mesh_.halfedge_handle(e_it.handle(), 0); + heh2 = mesh_.opposite_halfedge_handle(heh1); + cog += mesh_.data(mesh_.to_vertex_handle(heh1)).position(); + cog += mesh_.data(mesh_.to_vertex_handle(heh2)).position(); + + if (!mesh_.is_boundary(heh1)) { + cog += mesh_.data(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(heh1))).position(); + ++valence; + } + + if (!mesh_.is_boundary(heh2)) { + cog += mesh_.data(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(heh2))).position(); + ++valence; + } + + cog /= valence; + + mesh_.data(e_it).set_position(cog); + } +} + + +template +void CompositeT::VdEc(scalar_t _c) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::EdgeIter e_it; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::HalfedgeHandle heh; + + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) { + + cog = zero_point; + + for (int i = 0; i <= 1; ++i) { + + heh = mesh_.halfedge_handle(e_it.handle(), i); + if (!mesh_.is_boundary(heh)) + { + cog += mesh_.point(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(heh))) * (0.5 - _c); + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * _c; + } + else + { + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position(); + } + } + + mesh_.data(e_it).set_position(cog); + } +} + + +template +void CompositeT::VdEg(scalar_t _gamma) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::EdgeIter e_it; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::HalfedgeHandle heh; + typename MeshType::VertexOHalfedgeIter voh_it; + unsigned int valence[2], i; + + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) { + + cog = zero_point; + + for (i = 0; i <= 1; ++i) + { + heh = mesh_.halfedge_handle(e_it.handle(), i); + valence[i] = 0; + + // look for lowest valence vertex + for (voh_it = mesh_.voh_iter(mesh_.to_vertex_handle(heh)); voh_it; ++voh_it) + { + ++valence[i]; + } + } + + if (valence[0] < valence[1]) + i = 0; + else + i = 1; + + heh = mesh_.halfedge_handle(e_it.handle(), i); + + if (!mesh_.is_boundary(heh)) { + cog += mesh_.point(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(heh))) * (_gamma); + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * (1.0 - 3.0 * _gamma); + } else { + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * (1.0 - 2.0 * _gamma); + } + + + heh = mesh_.halfedge_handle(e_it.handle(), 1-i); + + if (!mesh_.is_boundary(heh)) + { + cog += mesh_.point(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(heh))) * (_gamma); + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * _gamma; + } + else + { + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * 2.0 * _gamma; + } + + mesh_.data(e_it).set_position(cog); + } +} + + +template +void CompositeT::VdEg(Coeff& _coeff) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::EdgeIter e_it; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::HalfedgeHandle heh; + typename MeshType::VertexOHalfedgeIter voh_it; + unsigned int valence[2], i; + scalar_t gamma; + + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) { + + cog = zero_point; + + for (i = 0; i <= 1; ++i) { + + heh = mesh_.halfedge_handle(e_it.handle(), i); + valence[i] = 0; + + // look for lowest valence vertex + for (voh_it = mesh_.voh_iter(mesh_.to_vertex_handle(heh)); voh_it; ++voh_it) + { + ++valence[i]; + } + } + + if (valence[0] < valence[1]) + i = 0; + else + i = 1; + + gamma = _coeff(valence[i]); + + heh = mesh_.halfedge_handle(e_it.handle(), i); + + if (!mesh_.is_boundary(heh)) + { + cog += mesh_.point(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(heh))) * (gamma); + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * (1.0 - 3.0 * gamma); + } + else + { + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * (1.0 - 2.0 * gamma); + } + + + heh = mesh_.halfedge_handle(e_it.handle(), 1-i); + + if (!mesh_.is_boundary(heh)) { + cog += mesh_.point(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(heh))) * (gamma); + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * gamma; + } else { + cog += mesh_.data(mesh_.to_vertex_handle(heh)).position() * 2.0 * gamma; + } + + mesh_.data(e_it).set_position(cog); + } +} + + +template +void CompositeT::EV() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::VertexIter v_it; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + unsigned int valence; + typename MeshType::VertexEdgeIter ve_it; + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) + { + valence = 0; + cog = zero_point; + + for (ve_it = mesh_.ve_iter(v_it.handle()); ve_it; ++ve_it) { + cog += mesh_.data(ve_it).position(); + ++valence; + } + + cog /= valence; + + mesh_.data(v_it).set_position(cog); + } +} + + +template +void CompositeT::EVc(Coeff& _coeff) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::VertexIter v_it; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + unsigned int valence; + typename MeshType::VertexOHalfedgeIter voh_it; + scalar_t c; + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) + { + valence = 0; + cog = zero_point; + + for (voh_it = mesh_.voh_iter(v_it.handle()); voh_it; ++voh_it) + { + ++valence; + } + + c = _coeff(valence); + + for (voh_it = mesh_.voh_iter(v_it.handle()); voh_it; ++voh_it) { + cog += mesh_.data(mesh_.edge_handle(voh_it.handle())).position() * c; + cog += mesh_.data(mesh_.edge_handle(mesh_.next_halfedge_handle(voh_it.handle()))).position() * (1.0 - c); + } + + cog /= valence; + + mesh_.data(v_it).set_position(cog); + } +} + + +template +void CompositeT::EVc(scalar_t _c) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + typename MeshType::VertexIter v_it; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + unsigned int valence; + typename MeshType::VertexOHalfedgeIter voh_it; + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) { + valence = 0; + cog = zero_point; + + for (voh_it = mesh_.voh_iter(v_it.handle()); voh_it; ++voh_it) { + ++valence; + } + + for (voh_it = mesh_.voh_iter(v_it.handle()); voh_it; ++voh_it) { + cog += mesh_.data(mesh_.edge_handle(voh_it.handle())).position() * _c; + cog += mesh_.data(mesh_.edge_handle(mesh_.next_halfedge_handle(voh_it.handle()))).position() * (1.0 - _c); + } + + cog /= valence; + + mesh_.data(v_it).set_position(cog); + } +} + + +template +void CompositeT::EF() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::FaceIter f_it; + typename MeshType::FaceEdgeIter fe_it; + unsigned int valence; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + + for (f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it) { + valence = 0; + cog = zero_point; + + for (fe_it = mesh_.fe_iter(f_it.handle()); fe_it; ++fe_it) { + ++valence; + cog += mesh_.data(fe_it).position(); + } + + cog /= valence; + mesh_.data(f_it).set_position(cog); + } +} + + +template +void CompositeT::FE() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::EdgeIter e_it; + unsigned int valence; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) { + valence = 0; + cog = zero_point; + + if (mesh_.face_handle(mesh_.halfedge_handle(e_it.handle(), 0)).is_valid()) { + cog += mesh_.data(mesh_.face_handle(mesh_.halfedge_handle(e_it.handle(), 0))).position(); + ++valence; + } + + if (mesh_.face_handle(mesh_.halfedge_handle(e_it.handle(), 1)).is_valid()) { + cog += mesh_.data(mesh_.face_handle(mesh_.halfedge_handle(e_it.handle(), 1))).position(); + ++valence; + } + + cog /= valence; + mesh_.data(e_it).set_position(cog); + } +} + + +template +void CompositeT::VE() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + typename MeshType::EdgeIter e_it; + typename MeshType::Point cog; + + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) + { + cog = mesh_.data(mesh_.to_vertex_handle(mesh_.halfedge_handle(e_it.handle(), 0))).position(); + cog += mesh_.data(mesh_.to_vertex_handle(mesh_.halfedge_handle(e_it.handle(), 1))).position(); + cog /= 2.0; + mesh_.data(e_it).set_position(cog); + } +} + + +template +void CompositeT::VV() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + unsigned int valence; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::VertexVertexIter vv_it; + typename MeshType::VertexIter v_it; + std::vector point_vector; + + point_vector.clear(); + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) { + + valence = 0; + cog = zero_point; + + for (vv_it = mesh_.vv_iter(v_it.handle()); vv_it; ++vv_it) { + cog += vv_it->position(); + ++valence; + } + cog /= valence; + point_vector.push_back(cog); + } + + for (v_it = mesh_.vertices_end(); v_it != mesh_.vertices_begin(); ) + { + --v_it; + mesh_.data(v_it).set_position(point_vector.back()); + point_vector.pop_back(); + } +} + + +template +void CompositeT::VVc(Coeff& _coeff) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + unsigned int valence; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::VertexVertexIter vv_it; + typename MeshType::VertexIter v_it; + scalar_t c; + std::vector point_vector; + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) + { + valence = 0; + cog = zero_point; + + for (vv_it = mesh_.vv_iter(v_it.handle()); vv_it; ++vv_it) + { + cog += vv_it->position(); + ++valence; + } + cog /= valence; + c = _coeff(valence); + cog = cog * (1 - c) + mesh_.data(v_it).position() * c; + point_vector.push_back(cog); + } + for (v_it = mesh_.vertices_end(); v_it != mesh_.vertices_begin(); ) + { + --v_it; + mesh_.data(v_it).set_position(point_vector.back()); + point_vector.pop_back(); + } +} + + +template +void CompositeT::VVc(scalar_t _c) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + unsigned int valence; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::VertexVertexIter vv_it; + typename MeshType::VertexIter v_it; + std::vector point_vector; + + for (v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it) { + + valence = 0; + cog = zero_point; + + for (vv_it = mesh_.vv_iter(v_it.handle()); vv_it; ++vv_it) { + cog += mesh_.data(vv_it).position(); + ++valence; + } + cog /= valence; + + cog = cog * (1.0 - _c) + v_it->position() * _c; + + point_vector.push_back(cog); + + } + for (v_it = mesh_.vertices_end(); v_it != mesh_.vertices_begin(); ) { + + --v_it; + mesh_.data(v_it).set_position(point_vector.back()); + point_vector.pop_back(); + + } +} + + +template +void CompositeT::EdE() +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + unsigned int valence; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::EdgeIter e_it; + typename MeshType::HalfedgeHandle heh; + std::vector point_vector; + + point_vector.clear(); + + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) { + + valence = 0; + cog = zero_point; + + for (int i = 0; i <= 1; ++i) { + heh = mesh_.halfedge_handle(e_it.handle(), i); + if (mesh_.face_handle(heh).is_valid()) + { + cog += mesh_.data(mesh_.edge_handle(mesh_.next_halfedge_handle(heh))).position(); + cog += mesh_.data(mesh_.edge_handle(mesh_.next_halfedge_handle(mesh_.next_halfedge_handle(heh)))).position(); + ++valence; + ++valence; + } + } + + cog /= valence; + point_vector.push_back(cog); + } + + for (e_it = mesh_.edges_end(); e_it != mesh_.edges_begin(); ) + { + --e_it; + mesh_.data(e_it).set_position(point_vector.back()); + point_vector.pop_back(); + } +} + + +template +void CompositeT::EdEc(scalar_t _c) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + unsigned int valence; + typename MeshType::Point cog, + zero_point(0.0, 0.0, 0.0); + typename MeshType::EdgeIter e_it; + typename MeshType::HalfedgeHandle heh; + std::vector point_vector; + + point_vector.clear(); + + for (e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it) + { + valence = 0; + cog = zero_point; + + for (int i = 0; i <= 1; ++i) { + heh = mesh_.halfedge_handle(e_it.handle(), i); + if (mesh_.face_handle(heh).is_valid()) + { + cog += mesh_.data(mesh_.edge_handle(mesh_.next_halfedge_handle(heh))).position() * (1.0 - _c); + cog += mesh_.data(mesh_.edge_handle(mesh_.next_halfedge_handle(mesh_.next_halfedge_handle(heh)))).position() * (1.0 - _c); + ++valence; + ++valence; + } + } + + cog /= valence; + cog += mesh_.data(e_it).position() * _c; + point_vector.push_back(cog); + } + + for (e_it = mesh_.edges_end(); e_it != mesh_.edges_begin(); ) { + + --e_it; + mesh_.data(e_it).set_position(point_vector.back()); + point_vector.pop_back(); + } +} + + +/// Corner Cutting +template +void CompositeT::corner_cutting(HalfedgeHandle _heh) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + // Define Halfedge Handles + typename MeshType::HalfedgeHandle heh5(_heh); + typename MeshType::HalfedgeHandle heh6(mesh_.next_halfedge_handle(_heh)); + + // Cycle around the polygon to find correct Halfedge + for (; mesh_.next_halfedge_handle(mesh_.next_halfedge_handle(heh5)) != _heh; + heh5 = mesh_.next_halfedge_handle(heh5)) {}; + + typename MeshType::HalfedgeHandle heh2(mesh_.next_halfedge_handle(heh5)); + typename MeshType::HalfedgeHandle + heh3(mesh_.new_edge(mesh_.to_vertex_handle(_heh), + mesh_.to_vertex_handle(heh5))); + typename MeshType::HalfedgeHandle heh4(mesh_.opposite_halfedge_handle(heh3)); + + // Old and new Face + typename MeshType::FaceHandle fh_old(mesh_.face_handle(heh6)); + typename MeshType::FaceHandle fh_new(mesh_.new_face()); + + // Init new face + mesh_.data(fh_new).set_position(mesh_.data(fh_old).position()); + + // Re-Set Handles around old Face + mesh_.set_next_halfedge_handle(heh4, heh6); + mesh_.set_next_halfedge_handle(heh5, heh4); + + mesh_.set_face_handle(heh4, fh_old); + mesh_.set_face_handle(heh5, fh_old); + mesh_.set_face_handle(heh6, fh_old); + mesh_.set_halfedge_handle(fh_old, heh4); + + // Re-Set Handles around new Face + mesh_.set_next_halfedge_handle(_heh, heh3); + mesh_.set_next_halfedge_handle(heh3, heh2); + + mesh_.set_face_handle(_heh, fh_new); + mesh_.set_face_handle(heh2, fh_new); + mesh_.set_face_handle(heh3, fh_new); + + mesh_.set_halfedge_handle(fh_new, _heh); +} + + +/// Split Edge +template +typename MeshType::VertexHandle +CompositeT::split_edge(HalfedgeHandle _heh) +{ + assert(p_mesh_); MeshType& mesh_ = *p_mesh_; + + HalfedgeHandle heh1; + HalfedgeHandle heh2; + HalfedgeHandle heh3; + HalfedgeHandle temp_heh; + + VertexHandle + vh, + vh1(mesh_.to_vertex_handle(_heh)), + vh2(mesh_.from_vertex_handle(_heh)); + + // Calculate and Insert Midpoint of Edge + vh = mesh_.add_vertex((mesh_.point(vh2) + mesh_.point(vh1)) / 2.0); + // Re-Set Handles + heh2 = mesh_.opposite_halfedge_handle(_heh); + + if (!mesh_.is_boundary(mesh_.edge_handle(_heh))) { + + for (temp_heh = mesh_.next_halfedge_handle(heh2); + mesh_.next_halfedge_handle(temp_heh) != heh2; + temp_heh = mesh_.next_halfedge_handle(temp_heh) ) {} + } else { + for (temp_heh = _heh; + mesh_.next_halfedge_handle(temp_heh) != heh2; + temp_heh = mesh_.opposite_halfedge_handle(mesh_.next_halfedge_handle(temp_heh))) {} + } + + heh1 = mesh_.new_edge(vh, vh1); + heh3 = mesh_.opposite_halfedge_handle(heh1); + mesh_.set_vertex_handle(_heh, vh); + mesh_.set_next_halfedge_handle(temp_heh, heh3); + mesh_.set_next_halfedge_handle(heh1, mesh_.next_halfedge_handle(_heh)); + mesh_.set_next_halfedge_handle(_heh, heh1); + mesh_.set_next_halfedge_handle(heh3, heh2); + if (mesh_.face_handle(heh2).is_valid()) { + mesh_.set_face_handle(heh3, mesh_.face_handle(heh2)); + mesh_.set_halfedge_handle(mesh_.face_handle(heh3), heh3); + } + mesh_.set_face_handle(heh1, mesh_.face_handle(_heh)); + mesh_.set_halfedge_handle(vh, heh1); + mesh_.set_halfedge_handle(mesh_.face_handle(_heh), _heh); + mesh_.set_halfedge_handle(vh1, heh3); + + return vh; +} + + +//============================================================================= +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITE_CC defined +//============================================================================= + diff --git a/Tools/Subdivider/Uniform/Composite/CompositeT.hh b/Tools/Subdivider/Uniform/Composite/CompositeT.hh new file mode 100644 index 00000000..50c34b4a --- /dev/null +++ b/Tools/Subdivider/Uniform/Composite/CompositeT.hh @@ -0,0 +1,233 @@ +//============================================================================= +// +// 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 Uniform/Composite/CompositeT.hh + + */ + +//============================================================================= +// +// CLASS CompositeT +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITE_HH +#define OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITE_HH + + +//== INCLUDES ================================================================= + +#include +#include +// -------------------- +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Uniform { // BEGIN_NS_UNIFORM + + +//== CLASS DEFINITION ========================================================= + +/** This class provides the composite subdivision rules for the uniform case. + * + * To create a subdivider derive from this class and overload the functions + * name() and apply_rules(). In the latter one call the wanted rules. + * + * For details on the composite scheme refer to + * - P. Oswald, + * P. Schroeder "Composite primal/dual sqrt(3)-subdivision schemes", + * CAGD 20, 3, 2003, 135--164 + + * \note Not all rules are implemented! + * \see class Adaptive::CompositeT + */ +template +class CompositeT : public SubdividerT< MeshType, RealType > +{ +public: + + typedef RealType real_t; + typedef MeshType mesh_t; + typedef SubdividerT< mesh_t, real_t > parent_t; + +public: + + CompositeT(void) : parent_t(), p_mesh_(NULL) {} + CompositeT(MeshType& _mesh) : parent_t(_mesh), p_mesh_(NULL) {}; + virtual ~CompositeT() { } + +public: // inherited interface + + virtual const char *name( void ) const = 0; + +protected: // inherited interface + + bool prepare( MeshType& _m ); + + bool subdivide( MeshType& _m, size_t _n ) + { + assert( p_mesh_ == &_m ); + + while(_n--) + { + apply_rules(); + commit(_m); + } + + return true; + } + +#ifdef NDEBUG + bool cleanup( MeshType& ) +#else + bool cleanup( MeshType& _m ) +#endif + { + assert( p_mesh_ == &_m ); + p_mesh_=NULL; + return true; + } + +protected: + + /// Assemble here the rule sequence, by calling the constructor + /// of the wanted rules. + virtual void apply_rules(void) = 0; + +protected: + + /// Move vertices to new positions after the rules have been applied + /// to the mesh (called by subdivide()). + void commit( MeshType &_m) + { + typename MeshType::VertexIter v_it; + + for (v_it=_m.vertices_begin(); v_it != _m.vertices_end(); ++v_it) + _m.set_point(v_it.handle(), _m.data(v_it).position()); + } + + +public: + + /// Abstract base class for coefficient functions + struct Coeff + { + virtual ~Coeff() { } + virtual double operator() (size_t _valence) = 0; + }; + + +protected: + + typedef typename MeshType::Scalar scalar_t; + typedef typename MeshType::VertexHandle VertexHandle; + typedef typename MeshType::FaceHandle FaceHandle; + typedef typename MeshType::EdgeHandle EdgeHandle; + typedef typename MeshType::HalfedgeHandle HalfedgeHandle; + + /// \name Uniform composite subdivision rules + //@{ + + + void Tvv3(); ///< Split Face, using Vertex information (1-3 split) + void Tvv4(); ///< Split Face, using Vertex information (1-4 split) + void Tfv(); ///< Split Face, using Face Information + + void FF(); ///< Face to face averaging. + void FFc(Coeff& _coeff); ///< Weighted face to face averaging. + void FFc(scalar_t _c); ///< Weighted face to face averaging. + + void FV(); ///< Face to vertex averaging. + void FVc(Coeff& _coeff); ///< Weighted face to vertex Averaging with flaps + void FVc(scalar_t _c); ///< Weighted face to vertex Averaging with flaps + + void FE(); ///< Face to edge averaging. + + void VF(); ///< Vertex to Face Averaging. + void VFa(Coeff& _coeff); ///< Vertex to Face Averaging, weighted. + void VFa(scalar_t _alpha); ///< Vertex to Face Averaging, weighted. + + void VV(); ///< Vertex to vertex averaging. + void VVc(Coeff& _coeff); ///< Vertex to vertex averaging, weighted. + void VVc(scalar_t _c); ///< Vertex to vertex averaging, weighted. + + void VE(); ///< VE Step (Vertex to Edge Averaging) + + + void VdE(); ///< Vertex to edge averaging, using diamond of edges. + void VdEc(scalar_t _c); ///< Weighted vertex to edge averaging, using diamond of edges + + /// Weigthed vertex to edge averaging, using diamond of edges for + /// irregular vertices. + void VdEg(Coeff& _coeff); + /// Weigthed vertex to edge averaging, using diamond of edges for + /// irregular vertices. + void VdEg(scalar_t _gamma); + + void EF(); ///< Edge to face averaging. + + void EV(); ///< Edge to vertex averaging. + void EVc(Coeff& _coeff); ///< Weighted edge to vertex averaging. + void EVc(scalar_t _c); ///< Weighted edge to vertex averaging. + + void EdE(); ///< Edge to edge averaging w/ flap rule. + void EdEc(scalar_t _c); ///< Weighted edge to edge averaging w/ flap rule. + + + //@} + + void corner_cutting(HalfedgeHandle _heh); + + VertexHandle split_edge(HalfedgeHandle _heh); + +private: + + MeshType* p_mesh_; + +}; + + +//============================================================================= +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITE_CC) +#define OPENMESH_SUBDIVIDER_TEMPLATES +#include "CompositeT.cc" +#endif +//============================================================================= +#endif // COMPOSITET_HH defined +//============================================================================= + diff --git a/Tools/Subdivider/Uniform/Composite/CompositeTraits.hh b/Tools/Subdivider/Uniform/Composite/CompositeTraits.hh new file mode 100644 index 00000000..fe548a93 --- /dev/null +++ b/Tools/Subdivider/Uniform/Composite/CompositeTraits.hh @@ -0,0 +1,150 @@ +//============================================================================= +// +// 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 Uniform/Composite/CompositeTraits.hh + Mesh traits for uniform composite subdivision. + */ + +//============================================================================= +// +// CLASS Traits +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITETRAITS_HH +#define OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITETRAITS_HH + + +//== INCLUDES ================================================================= + +//#include "Config.hh" +// -------------------- +#include +#include + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Uniform { // BEGIN_NS_UNIFORM + + +//== CLASS DEFINITION ========================================================= + + +/** Uniform Composite Subdivision framework. +*/ + +struct CompositeTraits : public OpenMesh::DefaultTraits +{ + FaceAttributes( OpenMesh::Attributes::Normal ); + + VertexAttributes( OpenMesh::Attributes::Normal ); + + //HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge ); + + FaceTraits + { + private: + typedef typename Refs::HalfedgeHandle HalfedgeHandle; + typedef typename Refs::Scalar Scalar; + typedef typename Refs::Point Point; + HalfedgeHandle red_halfedge_handle_; + unsigned int generation_; + bool red_; + Scalar quality_; + Point midpoint_; + Point position_; + + public: + const unsigned int& generation() { return generation_; } + void set_generation(const unsigned int& _g) { generation_ = _g; } + void inc_generation() { ++generation_; } + void set_red() { red_ = 1; } + void set_green() {red_ = 0; } + bool is_red() { return red_; } + bool is_green() { return !red_; } + void set_red_halfedge_handle(HalfedgeHandle& _heh) + { red_halfedge_handle_ = _heh; } + HalfedgeHandle& red_halfedge_handle() { return red_halfedge_handle_; } + void set_quality(Scalar& _q) { quality_ = _q; } + Scalar& quality() { return quality_; } + const Point& midpoint() const { return midpoint_; } + void set_midpoint(const Point& _p) { midpoint_ = _p; } + const Point& position() const { return position_; } + void set_position(const Point& _p) { position_ = _p; } + }; + + EdgeTraits + { + private: + typedef typename Refs::Point Point; + typedef typename Refs::Scalar Scalar; + Point midpoint_; + Scalar length_; + Point position_; + public: + const Point& midpoint() const { return midpoint_; } + void set_midpoint(const Point& _vh) { midpoint_ = _vh; } + const Scalar& length() const { return length_; } + void set_length(const Scalar& _s) { length_ = _s; } + const Point& position() const { return position_; } + void set_position(const Point& _p) { position_ = _p; } + }; + + VertexTraits + { + private: + typedef typename Refs::Point Point; + Point new_pos_; + Point orig_pos_; + Point position_; + unsigned int generation_; + public: + const Point& new_pos() const { return new_pos_; } + void set_new_pos(const Point& _p) { new_pos_ = _p; } + const unsigned int& generation() const { return generation_; } + void set_generation(const unsigned int& _i) { generation_ = _i; } + const Point& orig_pos() const { return orig_pos_; } + void set_orig_pos(const Point& _p) { orig_pos_ = _p; } + const Point& position() const { return position_; } + void set_position(const Point& _p) { position_ = _p; } + }; +}; + +//============================================================================= +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITETRAITS_HH defined +//============================================================================= + diff --git a/Tools/Subdivider/Uniform/CompositeLoopT.hh b/Tools/Subdivider/Uniform/CompositeLoopT.hh new file mode 100644 index 00000000..082fa743 --- /dev/null +++ b/Tools/Subdivider/Uniform/CompositeLoopT.hh @@ -0,0 +1,139 @@ +//============================================================================= +// +// 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 CompositeLoopT.hh + + */ + +//============================================================================= +// +// CLASS LoopT +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITELOOPT_HH +#define OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITELOOPT_HH + + +//== INCLUDES ================================================================= + +#include "Composite/CompositeT.hh" +#include "Composite/CompositeTraits.hh" + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Uniform { // BEGIN_NS_DECIMATER + + +//== CLASS DEFINITION ========================================================= + +/** Uniform composite Loop subdivision algorithm + */ +template +class CompositeLoopT : public CompositeT +{ +public: + + typedef CompositeT Inherited; + +public: + + CompositeLoopT() : Inherited() {}; + CompositeLoopT(MeshType& _mesh) : Inherited(_mesh) {}; + ~CompositeLoopT() {} + +public: + + const char *name() const { return "Uniform Composite Loop"; } + +protected: // inherited interface + + void apply_rules(void) + { + Inherited::Tvv4(); + Inherited::VdE(); + Inherited::EVc(coeffs_); + Inherited::VdE(); + Inherited::EVc(coeffs_); + } + +protected: + + typedef typename Inherited::Coeff Coeff; + + + /** Helper struct + * \internal + */ + struct EVCoeff : public Coeff + { + EVCoeff() : Coeff() { init(50); } + + void init(size_t _max_valence) + { + weights_.resize(_max_valence); + std::generate(weights_.begin(), + weights_.end(), compute_weight() ); + } + + double operator()(size_t _valence) { return weights_[_valence]; } + + /// \internal + struct compute_weight + { + compute_weight() : val_(0) { } + + double operator()(void) // Loop weights for non-boundary vertices + { + // 1 3 2 * pi + // - * ( --- + cos ( ------- ) )² - 1.0 + // 2 2 valence + double f1 = 1.5 + cos(2.0*M_PI/val_++); + return 0.5 * f1 * f1 - 1.0; + } + size_t val_; + + }; + + std::vector weights_; + } coeffs_; + +}; + +//============================================================================= +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITELOOPT_HH defined +//============================================================================= diff --git a/Tools/Subdivider/Uniform/CompositeSqrt3T.hh b/Tools/Subdivider/Uniform/CompositeSqrt3T.hh new file mode 100644 index 00000000..b2ddca92 --- /dev/null +++ b/Tools/Subdivider/Uniform/CompositeSqrt3T.hh @@ -0,0 +1,135 @@ +//============================================================================= +// +// 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 CompositeSqrt3T.hh + + */ + +//============================================================================= +// +// CLASS SQRT3T +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITESQRT3T_HH +#define OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITESQRT3T_HH + + +//== INCLUDES ================================================================= + +#include "Composite/CompositeT.hh" +#include "Composite/CompositeTraits.hh" + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Uniform { // BEGIN_NS_UNIFORM + + +//== CLASS DEFINITION ========================================================= + +/** Uniform composite sqrt(3) subdivision algorithm + */ +template +class CompositeSqrt3T : public CompositeT +{ +public: + + typedef CompositeT Inherited; + +public: + + CompositeSqrt3T() : Inherited() {}; + CompositeSqrt3T(MeshType& _mesh) : Inherited(_mesh) {}; + ~CompositeSqrt3T() {} + +public: + + const char *name() const { return "Uniform Composite Sqrt3"; } + +protected: // inherited interface + + void apply_rules(void) + { + Inherited::Tvv3(); + Inherited::VF(); + Inherited::FF(); + Inherited::FVc(coeffs_); + } + +protected: + + typedef typename Inherited::Coeff Coeff; + + /** Helper class + * \internal + */ + struct FVCoeff : public Coeff + { + FVCoeff() : Coeff() { init(50); } + + void init(size_t _max_valence) + { + weights_.resize(_max_valence); + std::generate(weights_.begin(), + weights_.end(), compute_weight() ); + } + + double operator()(size_t _valence) { return weights_[_valence]; } + + /** \internal + */ + struct compute_weight + { + compute_weight() : val_(0) { } + + double operator()(void) // sqrt(3) weights for non-boundary vertices + { + return 2.0/3.0 * (cos(2.0*M_PI/val_++)+1.0); + } + size_t val_; + }; + + std::vector weights_; + + } coeffs_; + +}; + + +//============================================================================= +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITESQRT3T_HH defined +//============================================================================= diff --git a/Tools/Subdivider/Uniform/LoopT.hh b/Tools/Subdivider/Uniform/LoopT.hh new file mode 100644 index 00000000..53949bce --- /dev/null +++ b/Tools/Subdivider/Uniform/LoopT.hh @@ -0,0 +1,451 @@ +//============================================================================= +// +// 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 LoopT.hh + + */ + +//============================================================================= +// +// CLASS LoopT +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_LOOPT_HH +#define OPENMESH_SUBDIVIDER_UNIFORM_LOOPT_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +// -------------------- STL +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Uniform { // BEGIN_NS_DECIMATER + + +//== CLASS DEFINITION ========================================================= + +/** %Uniform Loop subdivision algorithm. + * + * Implementation as described in + * + * C. T. Loop, "Smooth Subdivision Surfaces Based on Triangles", + * M.S. Thesis, Department of Mathematics, University of Utah, August 1987. + * + */ +template +class LoopT : public SubdividerT +{ +public: + + typedef RealType real_t; + typedef MeshType mesh_t; + typedef SubdividerT< mesh_t, real_t > parent_t; + + typedef std::pair< real_t, real_t > weight_t; + typedef std::vector< std::pair > weights_t; + +public: + + + LoopT(void) : parent_t(), _1over8( 1.0/8.0 ), _3over8( 3.0/8.0 ) + { init_weights(); } + + + LoopT( mesh_t& _m ) : parent_t(_m), _1over8( 1.0/8.0 ), _3over8( 3.0/8.0 ) + { init_weights(); } + + + ~LoopT() {} + + +public: + + + const char *name() const { return "Uniform Loop"; } + + + /// Pre-compute weights + void init_weights(size_t _max_valence=50) + { + weights_.resize(_max_valence); + std::generate(weights_.begin(), weights_.end(), compute_weight()); + } + + +protected: + + + bool prepare( mesh_t& _m ) + { + _m.add_property( vp_pos_ ); + _m.add_property( ep_pos_ ); + return true; + } + + + bool cleanup( mesh_t& _m ) + { + _m.remove_property( vp_pos_ ); + _m.remove_property( ep_pos_ ); + return true; + } + + + bool subdivide( mesh_t& _m, size_t _n) + { + typename mesh_t::FaceIter fit, f_end; + typename mesh_t::EdgeIter eit, e_end; + typename mesh_t::VertexIter vit; + + // Do _n subdivisions + for (size_t i=0; i < _n; ++i) + { + // compute new positions for old vertices + for ( vit = _m.vertices_begin(); + vit != _m.vertices_end(); ++vit) + smooth( _m, vit.handle() ); + + + // Compute position for new vertices and store them in the edge property + for (eit=_m.edges_begin(); eit != _m.edges_end(); ++eit) + compute_midpoint( _m, eit.handle() ); + + + // Split each edge at midpoint and store precomputed positions (stored in + // edge property ep_pos_) in the vertex property vp_pos_; + + // Attention! Creating new edges, hence make sure the loop ends correctly. + e_end = _m.edges_end(); + for (eit=_m.edges_begin(); eit != e_end; ++eit) + split_edge(_m, eit.handle() ); + + + // Commit changes in topology and reconsitute consistency + + // Attention! Creating new faces, hence make sure the loop ends correctly. + f_end = _m.faces_end(); + for (fit = _m.faces_begin(); fit != f_end; ++fit) + split_face(_m, fit.handle() ); + + + // Commit changes in geometry + for ( vit = _m.vertices_begin(); + vit != _m.vertices_end(); ++vit) + _m.set_point(vit, _m.property( vp_pos_, vit ) ); + +#if defined(_DEBUG) || defined(DEBUG) + // Now we have an consistent mesh! + assert( OpenMesh::Utils::MeshCheckerT(_m).check() ); +#endif + } + + return true; + } + +private: + + /// Helper functor to compute weights for Loop-subdivision + /// \internal + struct compute_weight + { + compute_weight() : valence(-1) { } + weight_t operator() (void) + { +#if !defined(OM_CC_MIPS) + using std::cos; +#endif + // 1 + // alpha(n) = ---- * (40 - ( 3 + 2 cos( 2 Pi / n ) )² ) + // 64 + + if (++valence) + { + double inv_v = 1.0/double(valence); + double t = (3.0 + 2.0 * cos( 2.0 * M_PI * inv_v) ); + double alpha = (40.0 - t * t)/64.0; + + return weight_t( 1.0-alpha, inv_v*alpha); + } + return weight_t(0.0, 0.0); + } + int valence; + }; + +private: // topological modifiers + + void split_face(mesh_t& _m, const typename mesh_t::FaceHandle& _fh) + { + typename mesh_t::HalfedgeHandle + heh1(_m.halfedge_handle(_fh)), + heh2(_m.next_halfedge_handle(_m.next_halfedge_handle(heh1))), + heh3(_m.next_halfedge_handle(_m.next_halfedge_handle(heh2))); + + // Cutting off every corner of the 6_gon + corner_cutting( _m, heh1 ); + corner_cutting( _m, heh2 ); + corner_cutting( _m, heh3 ); + } + + + void corner_cutting(mesh_t& _m, const typename mesh_t::HalfedgeHandle& _he) + { + // Define Halfedge Handles + typename mesh_t::HalfedgeHandle + heh1(_he), + heh5(heh1), + heh6(_m.next_halfedge_handle(heh1)); + + // Cycle around the polygon to find correct Halfedge + for (; _m.next_halfedge_handle(_m.next_halfedge_handle(heh5)) != heh1; + heh5 = _m.next_halfedge_handle(heh5)) + {} + + typename mesh_t::VertexHandle + vh1 = _m.to_vertex_handle(heh1), + vh2 = _m.to_vertex_handle(heh5); + + typename mesh_t::HalfedgeHandle + heh2(_m.next_halfedge_handle(heh5)), + heh3(_m.new_edge( vh1, vh2)), + heh4(_m.opposite_halfedge_handle(heh3)); + + /* Intermediate result + * + * * + * 5 /|\ + * /_ \ + * vh2> * * + * /|\3 |\ + * /_ \|4 \ + * *----\*----\* + * 1 ^ 6 + * vh1 (adjust_outgoing halfedge!) + */ + + // Old and new Face + typename mesh_t::FaceHandle fh_old(_m.face_handle(heh6)); + typename mesh_t::FaceHandle fh_new(_m.new_face()); + + + // Re-Set Handles around old Face + _m.set_next_halfedge_handle(heh4, heh6); + _m.set_next_halfedge_handle(heh5, heh4); + + _m.set_face_handle(heh4, fh_old); + _m.set_face_handle(heh5, fh_old); + _m.set_face_handle(heh6, fh_old); + _m.set_halfedge_handle(fh_old, heh4); + + // Re-Set Handles around new Face + _m.set_next_halfedge_handle(heh1, heh3); + _m.set_next_halfedge_handle(heh3, heh2); + + _m.set_face_handle(heh1, fh_new); + _m.set_face_handle(heh2, fh_new); + _m.set_face_handle(heh3, fh_new); + + _m.set_halfedge_handle(fh_new, heh1); + } + + + void split_edge(mesh_t& _m, const typename mesh_t::EdgeHandle& _eh) + { + typename mesh_t::HalfedgeHandle + heh = _m.halfedge_handle(_eh, 0), + opp_heh = _m.halfedge_handle(_eh, 1); + + typename mesh_t::HalfedgeHandle new_heh, opp_new_heh, t_heh; + typename mesh_t::VertexHandle vh; + typename mesh_t::VertexHandle vh1(_m.to_vertex_handle(heh)); + typename mesh_t::Point zero(0,0,0); + + // new vertex + vh = _m.new_vertex( zero ); + + // memorize position, will be set later + _m.property( vp_pos_, vh ) = _m.property( ep_pos_, _eh ); + + + // Re-link mesh entities + if (_m.is_boundary(_eh)) + { + for (t_heh = heh; + _m.next_halfedge_handle(t_heh) != opp_heh; + t_heh = _m.opposite_halfedge_handle(_m.next_halfedge_handle(t_heh))) + {} + } + else + { + for (t_heh = _m.next_halfedge_handle(opp_heh); + _m.next_halfedge_handle(t_heh) != opp_heh; + t_heh = _m.next_halfedge_handle(t_heh) ) + {} + } + + new_heh = _m.new_edge(vh, vh1); + opp_new_heh = _m.opposite_halfedge_handle(new_heh); + _m.set_vertex_handle( heh, vh ); + + _m.set_next_halfedge_handle(t_heh, opp_new_heh); + _m.set_next_halfedge_handle(new_heh, _m.next_halfedge_handle(heh)); + _m.set_next_halfedge_handle(heh, new_heh); + _m.set_next_halfedge_handle(opp_new_heh, opp_heh); + + if (_m.face_handle(opp_heh).is_valid()) + { + _m.set_face_handle(opp_new_heh, _m.face_handle(opp_heh)); + _m.set_halfedge_handle(_m.face_handle(opp_new_heh), opp_new_heh); + } + + _m.set_face_handle( new_heh, _m.face_handle(heh) ); + _m.set_halfedge_handle( vh, new_heh); + _m.set_halfedge_handle( _m.face_handle(heh), heh ); + _m.set_halfedge_handle( vh1, opp_new_heh ); + + // Never forget this, when playing with the topology + _m.adjust_outgoing_halfedge( vh ); + _m.adjust_outgoing_halfedge( vh1 ); + } + +private: // geometry helper + + void compute_midpoint(mesh_t& _m, const typename mesh_t::EdgeHandle& _eh) + { +#define V( X ) vector_cast< typename mesh_t::Normal >( X ) + typename mesh_t::HalfedgeHandle heh, opp_heh; + + heh = _m.halfedge_handle( _eh, 0); + opp_heh = _m.halfedge_handle( _eh, 1); + + typename mesh_t::Point + pos(_m.point(_m.to_vertex_handle(heh))); + + pos += V( _m.point(_m.to_vertex_handle(opp_heh)) ); + + // boundary edge: just average vertex positions + if (_m.is_boundary(_eh) ) + { + pos *= 0.5; + } + else // inner edge: add neighbouring Vertices to sum + { + pos *= real_t(3.0); + pos += V(_m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)))); + pos += V(_m.point(_m.to_vertex_handle(_m.next_halfedge_handle(opp_heh)))); + pos *= _1over8; + } + _m.property( ep_pos_, _eh ) = pos; +#undef V + } + + + void smooth(mesh_t& _m, const typename mesh_t::VertexHandle& _vh) + { + typename mesh_t::Point pos(0.0,0.0,0.0); + + if (_m.is_boundary(_vh)) // if boundary: Point 1-6-1 + { + typename mesh_t::HalfedgeHandle heh, prev_heh; + heh = _m.halfedge_handle( _vh ); + + if ( heh.is_valid() ) + { + assert( _m.is_boundary( _m.edge_handle( heh ) ) ); + + prev_heh = _m.prev_halfedge_handle( heh ); + + typename mesh_t::VertexHandle + to_vh = _m.to_vertex_handle( heh ), + from_vh = _m.from_vertex_handle( prev_heh ); + + // ( v_l + 6 v + v_r ) / 8 + pos = _m.point( _vh ); + pos *= real_t(6.0); + pos += vector_cast< typename mesh_t::Normal >( _m.point( to_vh ) ); + pos += vector_cast< typename mesh_t::Normal >( _m.point( from_vh ) ); + pos *= _1over8; + + } + else + return; + } + else // inner vertex: (1-a) * p + a/n * Sum q, q in one-ring of p + { + typedef typename mesh_t::Normal Vec; + typename mesh_t::VertexVertexIter vvit; + size_t valence(0); + + // Calculate Valence and sum up neighbour points + for (vvit=_m.vv_iter(_vh); vvit; ++vvit) { + ++valence; + pos += vector_cast< Vec >( _m.point(vvit) ); + } + pos *= weights_[valence].second; // alpha(n)/n * Sum q, q in one-ring of p + pos += weights_[valence].first + * vector_cast(_m.point(_vh)); // + (1-a)*p + } + + _m.property( vp_pos_, _vh ) = pos; + } + +private: // data + + OpenMesh::VPropHandleT< typename mesh_t::Point > vp_pos_; + OpenMesh::EPropHandleT< typename mesh_t::Point > ep_pos_; + + weights_t weights_; + + const real_t _1over8; + const real_t _3over8; + +}; + + +//============================================================================= +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITELOOPT_HH defined +//============================================================================= diff --git a/Tools/Subdivider/Uniform/Sqrt3T.hh b/Tools/Subdivider/Uniform/Sqrt3T.hh new file mode 100644 index 00000000..1468c556 --- /dev/null +++ b/Tools/Subdivider/Uniform/Sqrt3T.hh @@ -0,0 +1,507 @@ +//============================================================================= +// +// 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: 4083 $ +// $Date: 2008-12-29 15:29:38 +0100 (Mo, 29. Dez 2008) $ +// +//============================================================================= + +/** \file Sqrt3T.hh + + */ + +//============================================================================= +// +// CLASS Sqrt3T +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_SQRT3T_HH +#define OPENMESH_SUBDIVIDER_UNIFORM_SQRT3T_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include +#if defined(_DEBUG) || defined(DEBUG) +// Makes life lot easier, when playing/messing around with low-level topology +// changing methods of OpenMesh +# include +# define ASSERT_CONSISTENCY( T, m ) \ + assert(OpenMesh::Utils::MeshCheckerT(m).check()) +#else +# define ASSERT_CONSISTENCY( T, m ) +#endif +// -------------------- STL +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Subdivider { // BEGIN_NS_DECIMATER +namespace Uniform { // BEGIN_NS_DECIMATER + + +//== CLASS DEFINITION ========================================================= + + +/** %Uniform Sqrt3 subdivision algorithm + * + * Implementation as described in + * + * L. Kobbelt, "Sqrt(3) subdivision", Proceedings of SIGGRAPH 2000. + */ +template +class Sqrt3T : public SubdividerT< MeshType, RealType > +{ +public: + + typedef RealType real_t; + typedef MeshType mesh_t; + typedef SubdividerT< mesh_t, real_t > parent_t; + + typedef std::pair< real_t, real_t > weight_t; + typedef std::vector< std::pair > weights_t; + +public: + + + Sqrt3T(void) : parent_t(), _1over3( 1.0/3.0 ), _1over27( 1.0/27.0 ) + { init_weights(); } + + Sqrt3T(MeshType &_m) : parent_t(_m), _1over3( 1.0/3.0 ), _1over27( 1.0/27.0 ) + { init_weights(); } + + virtual ~Sqrt3T() {} + + +public: + + + const char *name() const { return "Uniform Sqrt3"; } + + + /// Pre-compute weights + void init_weights(size_t _max_valence=50) + { + weights_.resize(_max_valence); + std::generate(weights_.begin(), weights_.end(), compute_weight()); + } + + +protected: + + + bool prepare( MeshType& _m ) + { + _m.request_edge_status(); + _m.add_property( vp_pos_ ); + _m.add_property( ep_nv_ ); + _m.add_property( mp_gen_ ); + _m.property( mp_gen_ ) = 0; + + return _m.has_edge_status() && vp_pos_.is_valid() + && ep_nv_.is_valid() && mp_gen_.is_valid(); + } + + + bool cleanup( MeshType& _m ) + { + _m.release_edge_status(); + _m.remove_property( vp_pos_ ); + _m.remove_property( ep_nv_ ); + _m.remove_property( mp_gen_ ); + return true; + } + + + bool subdivide( MeshType& _m, size_t _n ) + { + typename MeshType::VertexIter vit; + typename MeshType::VertexVertexIter vvit; + typename MeshType::EdgeIter eit; + typename MeshType::FaceIter fit; + typename MeshType::FaceVertexIter fvit; + typename MeshType::VertexHandle vh; + typename MeshType::HalfedgeHandle heh; + typename MeshType::Point pos(0,0,0), zero(0,0,0); + size_t &gen = _m.property( mp_gen_ ); + + for (size_t l=0; l<_n; ++l) + { + // tag existing edges + for (eit=_m.edges_begin(); eit != _m.edges_end();++eit) + { + _m.status( eit ).set_tagged( true ); + if ( (gen%2) && _m.is_boundary(eit) ) + compute_new_boundary_points( _m, eit ); // *) creates new vertices + } + + // do relaxation of old vertices, but store new pos in property vp_pos_ + + for (vit=_m.vertices_begin(); vit!=_m.vertices_end(); ++vit) + { + if ( _m.is_boundary(vit) ) + { + if ( gen%2 ) + { + heh = _m.halfedge_handle(vit); + if (heh.is_valid()) // skip isolated newly inserted vertices *) + { + typename OpenMesh::HalfedgeHandle + prev_heh = _m.prev_halfedge_handle(heh); + + assert( _m.is_boundary(heh ) ); + assert( _m.is_boundary(prev_heh) ); + + pos = _m.point(_m.to_vertex_handle(heh)); + pos += _m.point(_m.from_vertex_handle(prev_heh)); + pos *= real_t(4.0); + + pos += real_t(19.0) * _m.point( vit ); + pos *= _1over27; + + _m.property( vp_pos_, vit ) = pos; + } + } + else + _m.property( vp_pos_, vit ) = _m.point( vit ); + } + else + { + size_t valence=0; + + pos = zero; + for ( vvit = _m.vv_iter(vit); vvit; ++vvit) + { + pos += _m.point( vvit ); + ++valence; + } + pos *= weights_[ valence ].second; + pos += weights_[ valence ].first * _m.point(vit); + _m.property( vp_pos_, vit ) = pos; + } + } + + // insert new vertices, but store pos in vp_pos_ + typename MeshType::FaceIter fend = _m.faces_end(); + for (fit = _m.faces_begin();fit != fend; ++fit) + { + if ( (gen%2) && _m.is_boundary(fit)) + { + boundary_split( _m, fit ); + } + else + { + fvit = _m.fv_iter( fit ); + pos = _m.point( fvit); + pos += _m.point(++fvit); + pos += _m.point(++fvit); + pos *= _1over3; + vh = _m.add_vertex( zero ); + _m.property( vp_pos_, vh ) = pos; + _m.split( fit, vh ); + } + } + + // commit new positions (now iterating over all vertices) + for (vit=_m.vertices_begin();vit != _m.vertices_end(); ++vit) + _m.set_point(vit, _m.property( vp_pos_, vit ) ); + + // flip old edges + for (eit=_m.edges_begin(); eit != _m.edges_end(); ++eit) + if ( _m.status( eit ).tagged() && !_m.is_boundary( eit ) ) + _m.flip(eit); + + // Now we have an consistent mesh! + ASSERT_CONSISTENCY( MeshType, _m ); + + // increase generation by one + ++gen; + } + return true; + } + +private: + + /// Helper functor to compute weights for sqrt(3)-subdivision + /// \internal + struct compute_weight + { + compute_weight() : valence(-1) { } + weight_t operator() (void) + { +#if !defined(OM_CC_MIPS) + using std::cos; +#endif + if (++valence) + { + real_t alpha = (4.0-2.0*cos(2.0*M_PI / (double)valence))/9.0; + return weight_t( real_t(1)-alpha, alpha/real_t(valence) ); + } + return weight_t(0.0, 0.0); + } + int valence; + }; + +private: + + // Pre-compute location of new boundary points for odd generations + // and store them in the edge property ep_nv_; + void compute_new_boundary_points( MeshType& _m, + const typename MeshType::EdgeHandle& _eh) + { + assert( _m.is_boundary(_eh) ); + + typename MeshType::HalfedgeHandle heh; + typename MeshType::VertexHandle vh1, vh2, vh3, vh4, vhl, vhr; + typename MeshType::Point zero(0,0,0), P1, P2, P3, P4; + + /* + // *---------*---------* + // / \ / \ / \ + // / \ / \ / \ + // / \ / \ / \ + // / \ / \ / \ + // *---------*--#---#--*---------* + // + // ^ ^ ^ ^ ^ ^ + // P1 P2 pl pr P3 P4 + */ + // get halfedge pointing from P3 to P2 (outer boundary halfedge) + + heh = _m.halfedge_handle(_eh, + _m.is_boundary(_m.halfedge_handle(_eh,1))); + + assert( _m.is_boundary( _m.next_halfedge_handle( heh ) ) ); + assert( _m.is_boundary( _m.prev_halfedge_handle( heh ) ) ); + + vh1 = _m.to_vertex_handle( _m.next_halfedge_handle( heh ) ); + vh2 = _m.to_vertex_handle( heh ); + vh3 = _m.from_vertex_handle( heh ); + vh4 = _m.from_vertex_handle( _m.prev_halfedge_handle( heh )); + + P1 = _m.point(vh1); + P2 = _m.point(vh2); + P3 = _m.point(vh3); + P4 = _m.point(vh4); + + vhl = _m.add_vertex(zero); + vhr = _m.add_vertex(zero); + + _m.property(vp_pos_, vhl ) = (P1 + 16.0f*P2 + 10.0f*P3) * _1over27; + _m.property(vp_pos_, vhr ) = (10.0f*P2 + 16.0f*P3 + P4) * _1over27; + _m.property(ep_nv_, _eh).first = vhl; + _m.property(ep_nv_, _eh).second = vhr; + } + + + void boundary_split( MeshType& _m, const typename MeshType::FaceHandle& _fh ) + { + assert( _m.is_boundary(_fh) ); + + typename MeshType::VertexHandle vhl, vhr; + typename MeshType::FaceEdgeIter fe_it; + typename MeshType::HalfedgeHandle heh; + + // find boundary edge + for( fe_it=_m.fe_iter( _fh ); fe_it && !_m.is_boundary( fe_it ); ++fe_it ); + + // use precomputed, already inserted but not linked vertices + vhl = _m.property(ep_nv_, fe_it).first; + vhr = _m.property(ep_nv_, fe_it).second; + + /* + // *---------*---------* + // / \ / \ / \ + // / \ / \ / \ + // / \ / \ / \ + // / \ / \ / \ + // *---------*--#---#--*---------* + // + // ^ ^ ^ ^ ^ ^ + // P1 P2 pl pr P3 P4 + */ + // get halfedge pointing from P2 to P3 (inner boundary halfedge) + + heh = _m.halfedge_handle(fe_it, + _m.is_boundary(_m.halfedge_handle(fe_it,0))); + + typename MeshType::HalfedgeHandle pl_P3; + + // split P2->P3 (heh) in P2->pl (heh) and pl->P3 + boundary_split( _m, heh, vhl ); // split edge + pl_P3 = _m.next_halfedge_handle( heh ); // store next halfedge handle + boundary_split( _m, heh ); // split face + + // split pl->P3 in pl->pr and pr->P3 + boundary_split( _m, pl_P3, vhr ); + boundary_split( _m, pl_P3 ); + + assert( _m.is_boundary( vhl ) && _m.halfedge_handle(vhl).is_valid() ); + assert( _m.is_boundary( vhr ) && _m.halfedge_handle(vhr).is_valid() ); + } + + void boundary_split(MeshType& _m, + const typename MeshType::HalfedgeHandle& _heh, + const typename MeshType::VertexHandle& _vh) + { + assert( _m.is_boundary( _m.edge_handle(_heh) ) ); + + typename MeshType::HalfedgeHandle + heh(_heh), + opp_heh( _m.opposite_halfedge_handle(_heh) ), + new_heh, opp_new_heh; + typename MeshType::VertexHandle to_vh(_m.to_vertex_handle(heh)); + typename MeshType::HalfedgeHandle t_heh; + + /* + * P5 + * * + * /|\ + * / \ + * / \ + * / \ + * / \ + * /_ heh new \ + * *-----\*-----\*\-----* + * ^ ^ t_heh + * _vh to_vh + * + * P1 P2 P3 P4 + */ + // Re-Setting Handles + + // find halfedge point from P4 to P3 + for(t_heh = heh; + _m.next_halfedge_handle(t_heh) != opp_heh; + t_heh = _m.opposite_halfedge_handle(_m.next_halfedge_handle(t_heh))) + {} + + assert( _m.is_boundary( t_heh ) ); + + new_heh = _m.new_edge( _vh, to_vh ); + opp_new_heh = _m.opposite_halfedge_handle(new_heh); + + // update halfedge connectivity + + _m.set_next_halfedge_handle(t_heh, opp_new_heh); // P4-P3 -> P3-P2 + // P2-P3 -> P3-P5 + _m.set_next_halfedge_handle(new_heh, _m.next_halfedge_handle(heh)); + _m.set_next_halfedge_handle(heh, new_heh); // P1-P2 -> P2-P3 + _m.set_next_halfedge_handle(opp_new_heh, opp_heh); // P3-P2 -> P2-P1 + + // both opposite halfedges point to same face + _m.set_face_handle(opp_new_heh, _m.face_handle(opp_heh)); + + // let heh finally point to new inserted vertex + _m.set_vertex_handle(heh, _vh); + + // let heh and new_heh point to same face + _m.set_face_handle(new_heh, _m.face_handle(heh)); + + // let opp_new_heh be the new outgoing halfedge for to_vh + // (replaces for opp_heh) + _m.set_halfedge_handle( to_vh, opp_new_heh ); + + // let opp_heh be the outgoing halfedge for _vh + _m.set_halfedge_handle( _vh, opp_heh ); + } + + void boundary_split( MeshType& _m, + const typename MeshType::HalfedgeHandle& _heh) + { + assert( _m.is_boundary( _m.opposite_halfedge_handle( _heh ) ) ); + + typename MeshType::HalfedgeHandle + heh(_heh), + n_heh(_m.next_halfedge_handle(heh)); + + typename MeshType::VertexHandle + to_vh(_m.to_vertex_handle(heh)); + + typename MeshType::HalfedgeHandle + heh2(_m.new_edge(to_vh, + _m.to_vertex_handle(_m.next_halfedge_handle(n_heh)))), + heh3(_m.opposite_halfedge_handle(heh2)); + + typename MeshType::FaceHandle + new_fh(_m.new_face()), + fh(_m.face_handle(heh)); + + // Relink (half)edges + +#define set_next_heh set_next_halfedge_handle +#define next_heh next_halfedge_handle + + _m.set_face_handle(heh, new_fh); + _m.set_face_handle(heh2, new_fh); + _m.set_next_heh(heh2, _m.next_heh(_m.next_heh(n_heh))); + _m.set_next_heh(heh, heh2); + _m.set_face_handle( _m.next_heh(heh2), new_fh); + + // _m.set_face_handle( _m.next_heh(_m.next_heh(heh2)), new_fh); + + _m.set_next_heh(heh3, n_heh); + _m.set_next_heh(_m.next_halfedge_handle(n_heh), heh3); + _m.set_face_handle(heh3, fh); + // _m.set_face_handle(n_heh, fh); + + _m.set_halfedge_handle( fh, n_heh); + _m.set_halfedge_handle(new_fh, heh); + +#undef set_next_halfedge_handle +#undef next_halfedge_handle + + } + +private: + + weights_t weights_; + OpenMesh::VPropHandleT< typename MeshType::Point > vp_pos_; + OpenMesh::EPropHandleT< std::pair< typename MeshType::VertexHandle, + typename MeshType::VertexHandle> > ep_nv_; + OpenMesh::MPropHandleT< size_t > mp_gen_; + + const real_t _1over3; + const real_t _1over27; +}; + + +//============================================================================= +} // END_NS_UNIFORM +} // END_NS_SUBDIVIDER +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_UNIFORM_SQRT3T_HH +//============================================================================= diff --git a/Tools/Subdivider/Uniform/SubdividerT.hh b/Tools/Subdivider/Uniform/SubdividerT.hh new file mode 100644 index 00000000..ad695101 --- /dev/null +++ b/Tools/Subdivider/Uniform/SubdividerT.hh @@ -0,0 +1,179 @@ +//============================================================================= +// +// 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 SubdividerT.hh + + */ + +//============================================================================= +// +// CLASS SubdividerT +// +//============================================================================= + +#ifndef OPENMESH_SUBDIVIDER_UNIFORM_SUDIVIDERT_HH +#define OPENMESH_SUBDIVIDER_UNIFORM_SUDIVIDERT_HH + +//== INCLUDE ================================================================== + +#include +#include +#if defined(_DEBUG) || defined(DEBUG) +// Makes life lot easier, when playing/messing around with low-level topology +// changing methods of OpenMesh +# include +# define ASSERT_CONSISTENCY( T, m ) \ + assert(OpenMesh::Utils::MeshCheckerT(m).check()) +#else +# define ASSERT_CONSISTENCY( T, m ) +#endif + +//== NAMESPACE ================================================================ + +namespace OpenMesh { +namespace Subdivider { +namespace Uniform { + + +//== CLASS DEFINITION ========================================================= + +/** Abstract base class for uniform subdivision algorithms. + * + * A derived class must overload the following functions: + * -# name() + * -# prepare() + * -# subdivide() + * -# cleanup() + */ +template +class SubdividerT : private Utils::Noncopyable +{ +public: + + typedef MeshType mesh_t; + typedef RealType real_t; + +public: + + /// \name Constructors + //@{ + /// Constructor to be used with interface 2 + /// \see attach(), operator()(size_t), detach() + SubdividerT(void) : attached_(NULL) { } + + /// Constructor to be used with interface 1 (calls attach()) + /// \see operator()( MeshType&, size_t ) + SubdividerT( MeshType &_m ) : attached_(NULL) { attach(_m); } + + //@} + + /// Descructor (calls detach()) + virtual ~SubdividerT() + { detach(); } + + /// Return name of subdivision algorithm + virtual const char *name( void ) const = 0; + + +public: /// \name Interface 1 + + //@{ + /// Subdivide the mesh \c _m \c _n times. + /// \see SubdividerT(MeshType&) + bool operator () ( MeshType& _m, size_t _n ) + { + return prepare(_m) && subdivide( _m, _n ) && cleanup( _m ); + } + //@} + +public: /// \name Interface 2 + //@{ + /// Attach mesh \c _m to self + /// \see SubdividerT(), operator()(size_t), detach() + bool attach( MeshType& _m ) + { + if ( attached_ == &_m ) + return true; + + detach(); + if (prepare( _m )) + { + attached_ = &_m; + return true; + } + return false; + } + + /// Subdivide the attached \c _n times. + /// \see SubdividerT(), attach(), detach() + bool operator()( size_t _n ) + { + return attached_ ? subdivide( *attached_, _n ) : false; + } + + /// Detach an eventually attached mesh. + /// \see SubdividerT(), attach(), operator()(size_t) + void detach(void) + { + if ( attached_ ) + { + cleanup( *attached_ ); + attached_ = NULL; + } + } + //@} + +protected: + + /// \name Overload theses methods + //@{ + /// Prepare mesh, e.g. add properties + virtual bool prepare( MeshType& _m ) = 0; + + /// Subdivide mesh \c _m \c _n times + virtual bool subdivide( MeshType& _m, size_t _n ) = 0; + + /// Cleanup mesh after usage, e.g. remove added properties + virtual bool cleanup( MeshType& _m ) = 0; + //@} + +private: + + MeshType *attached_; + +}; + +//============================================================================= +} // namespace Uniform +} // namespace Subdivider +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_SUBDIVIDER_UNIFORM_SUBDIVIDERT_HH +//============================================================================= diff --git a/Tools/Tools.pro b/Tools/Tools.pro new file mode 100644 index 00000000..ce7a29ef --- /dev/null +++ b/Tools/Tools.pro @@ -0,0 +1,31 @@ +################################################################################ +# +################################################################################ + +contains( OPENFLIPPER , OpenFlipper ){ + include( $$TOPDIR/qmake/all.include ) +} else { + include( $$TOPDIR/OpenMesh/qmake/all.include ) +} + +Library() + +DIRECTORIES = . Decimater Smoother Subdivider/Adaptive/Composite \ + Subdivider/Uniform/Composite Subdivider/Uniform \ + Utils + +INCLUDEPATH += ../.. + +win32 { + DEFINES += _USE_MATH_DEFINES NOMINMAX + CONFIG += static +} + +# Input +HEADERS += $$getFilesFromDir($$DIRECTORIES,*.hh) +SOURCES += $$getFilesFromDir($$DIRECTORIES,*.c) +SOURCES += $$getFilesFromDir($$DIRECTORIES,*.cc) +FORMS += $$getFilesFromDir($$DIRECTORIES,*.ui) + + +################################################################################ diff --git a/Tools/Utils/ACGMakefile b/Tools/Utils/ACGMakefile new file mode 100644 index 00000000..bbd4512f --- /dev/null +++ b/Tools/Utils/ACGMakefile @@ -0,0 +1,17 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + + +SUBDIRS = $(call find-subdirs) + +PACKAGES := + +PROJ_LIBS := + +MODULES := cxxlib + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Tools/Utils/Config.hh b/Tools/Utils/Config.hh new file mode 100644 index 00000000..f840b814 --- /dev/null +++ b/Tools/Utils/Config.hh @@ -0,0 +1,57 @@ +//============================================================================= +// +// 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 Tools/Utils/Config.hh + */ + +//============================================================================= +// +// Defines +// +//============================================================================= + +#ifndef OPENMESH_UTILS_CONFIG_HH +#define OPENMESH_UTILS_CONFIG_HH + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +#define BEGIN_NS_UTILS namespace Utils { +#define END_NS_UTILS } + + +//============================================================================= +#endif // OPENMESH_UTILS_CONFIG_HH defined +//============================================================================= diff --git a/Tools/Utils/GLConstAsString.hh b/Tools/Utils/GLConstAsString.hh new file mode 100644 index 00000000..f26a9fc5 --- /dev/null +++ b/Tools/Utils/GLConstAsString.hh @@ -0,0 +1,80 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= + + +#ifndef OPENMESH_UTILS_GLCONSTASSTRING_HH +#define OPENMESH_UTILS_GLCONSTASSTRING_HH + + +//== INCLUDES ================================================================= + +#include +#include + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace Utils { + +//== CLASS DEFINITION ========================================================= + +inline +const char *GLenum_as_string( GLenum _m ) +{ +#define MODE(M) case M:return #M + switch( _m ) + { + MODE(GL_POINTS); + MODE(GL_LINES); + MODE(GL_LINE_STRIP); + MODE(GL_LINE_LOOP); + MODE(GL_TRIANGLES); + MODE(GL_TRIANGLE_STRIP); + MODE(GL_TRIANGLE_FAN); + MODE(GL_QUADS); + MODE(GL_QUAD_STRIP); + MODE(GL_POLYGON); + default: return ""; + } +#undef MODE +} + +//============================================================================= +} // namespace Utils +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_UTILS_GLCONSTASSTRING_HH defined +//============================================================================= + diff --git a/Tools/Utils/Gnuplot.cc b/Tools/Utils/Gnuplot.cc new file mode 100644 index 00000000..e872d715 --- /dev/null +++ b/Tools/Utils/Gnuplot.cc @@ -0,0 +1,498 @@ +//////////////////////////////////////////// +// +// A C++ interface to gnuplot. +// +// This is a direct translation from the C interface +// written by N. Devillard (which is available from +// http://ndevilla.free.fr/gnuplot/). +// +// As in the C interface this uses pipes and so wont +// run on a system that does'nt have POSIX pipe +// support +// +// Rajarshi Guha +// +// +// 07/03/03 +// +//////////////////////////////////////////// + +#include "Gnuplot.hh" +#include +#ifdef WIN32 +# include +#else +# include // X_OK +# include // access +# define PATH_MAXNAMESZ 4096 +#endif +#include +#include +#include +#include + +#if defined(WIN32) +# define pclose _pclose +# define popen _popen +# define access _access +# define ACCESS_OK 0 +# define PATH_SEP ";" +# define MKTEMP_AND_CHECK_FAILED(name) (_mktemp(name) == NULL) +#else +# define ACCESS_OK X_OK +# define PATH_SEP ":" +# define MKTEMP_AND_CHECK_FAILED(name) (mkstemp(name) == -1) +#endif + +#ifndef WIN32 +#include +#include +#endif + +using namespace std; + +///////////////////////////// +// +// A string tokenizer taken from +// http://www.sunsite.ualberta.ca/ +// Documentation/Gnu/libstdc++-2.90.8/html/21_strings/stringtok_std_h.txt +// +///////////////////////////// + +template +void +stringtok (Container &container, string const &in, + const char * const delimiters = " \t\n") +{ + const string::size_type len = in.length(); + + string::size_type i = 0; + + while ( i < len ) + { + // eat leading whitespace + i = in.find_first_not_of (delimiters, i); + if (i == string::npos) + return; // nothing left but white space + + // find the end of the token + string::size_type j = in.find_first_of (delimiters, i); + + // push token + if (j == string::npos) + { + container.push_back (in.substr(i)); + return; + } else + container.push_back (in.substr(i, j-i)); + + // set up for next loop + i = j + 1; + } +} + +// ---------------------------------------------------------------------------- + +#ifdef WIN32 + std::string Gnuplot::gnuplot_executable_ = "pgnuplot.exe"; +#else + std::string Gnuplot::gnuplot_executable_ = "gnuplot"; +#endif + +// ---------------------------------------------------------------------------- + +Gnuplot::Gnuplot(void) +{ + init(); + set_style("points"); +} + +// ---------------------------------------------------------------------------- + +Gnuplot::Gnuplot(const string &style) +{ + init(); + set_style(style); +} + +// ---------------------------------------------------------------------------- + +Gnuplot::Gnuplot(const string &title, + const string &style, + const string &labelx, const string &labely, + vector x, vector y) +{ + init(); + + if (x.size() == 0 || y.size() == 0) + throw GnuplotException("vectors too small"); + + if (style == "") + this->set_style("lines"); + else + this->set_style(style); + + if (labelx == "") + this->set_xlabel("X"); + else + this->set_xlabel(labelx); + if (labely == "") + this->set_ylabel("Y"); + else + this->set_ylabel(labely); + + this->plot_xy(x,y,title); + + cout << "Press enter to continue" << endl; + while (getchar() != '\n'){} +} + +// ---------------------------------------------------------------------------- + +Gnuplot::Gnuplot(const string &title, const string &style, + const string &labelx, const string &labely, + vector x) +{ + init(); + + if (x.size() == 0) + throw GnuplotException("vector too small"); + if (!this->gnucmd) + throw GnuplotException("Could'nt open connection to gnuplot"); + + if (style == "") + this->set_style("lines"); + else + this->set_style(style); + + if (labelx == "") + this->set_xlabel("X"); + else + this->set_xlabel(labelx); + if (labely == "") + this->set_ylabel("Y"); + else + this->set_ylabel(labely); + + this->plot_x(x,title); + + cout << "Press enter to continue" << endl; + while (getchar() != '\n'){} +} + +// ---------------------------------------------------------------------------- + +Gnuplot::~Gnuplot() +{ + if ((this->to_delete).size() > 0) + { + for (size_t i = 0; i < this->to_delete.size(); i++) + remove(this->to_delete[i].c_str()); + } + + if (pclose(this->gnucmd) == -1) + cerr << "Problem closing communication to gnuplot" << endl; + + return; +} + +// ---------------------------------------------------------------------------- + +bool Gnuplot::get_program_path(const string pname) +{ + list ls; + char *path; + + path = getenv("PATH"); + if (!path) + return false; + + stringtok(ls, path, PATH_SEP); + + for (list::const_iterator i = ls.begin(); i != ls.end(); ++i) + { + string tmp = (*i) + "/" + pname; + if ( access(tmp.c_str(), ACCESS_OK) == 0 ) + return true; + } + + return false; +} + +// ---------------------------------------------------------------------------- + +void Gnuplot::reset_plot(void) +{ + if (this->to_delete.size() > 0) + { + for (size_t i = 0; i < this->to_delete.size(); i++) + remove(this->to_delete[i].c_str()); + } + this->nplots = 0; + return; +} + +// ---------------------------------------------------------------------------- + +void Gnuplot::set_style(const string &stylestr) +{ + if (stylestr != "lines" && + stylestr != "points" && + stylestr != "linespoints" && + stylestr != "impulses" && + stylestr != "dots" && + stylestr != "steps" && + stylestr != "errorbars" && + stylestr != "boxes" && + stylestr != "boxerrorbars") + this->pstyle = string("points"); + else + this->pstyle = stylestr; +} + +// ---------------------------------------------------------------------------- + +void Gnuplot::cmd(const char *_cmd, ...) +{ + va_list ap; + char local_cmd[GP_CMD_SIZE]; + + va_start(ap, _cmd); + vsprintf(local_cmd, _cmd, ap); + va_end(ap); + + strcat(local_cmd,"\n"); + fputs(local_cmd,this->gnucmd); + fflush(this->gnucmd); + return; +} + +// ---------------------------------------------------------------------------- + +void Gnuplot::set_ylabel(const string &label) +{ + ostringstream cmdstr; + + cmdstr << "set xlabel \"" << label << "\""; + this->cmd(cmdstr.str().c_str()); + + return; +} + +// ---------------------------------------------------------------------------- + +void Gnuplot::set_xlabel(const string &label) +{ + ostringstream cmdstr; + + cmdstr << "set xlabel \"" << label << "\""; + this->cmd(cmdstr.str().c_str()); + + return; +} + +// ---------------------------------------------------------------------------- + +// Plots a linear equation (where you supply the +// slope and intercept) +// +void Gnuplot::plot_slope(double a, double b, const string &title) +{ + ostringstream stitle; + ostringstream cmdstr; + + if (title == "") + stitle << "no title"; + else + stitle << title; + + if (this->nplots > 0) + cmdstr << "replot " << a << " * x + " << b << " title \"" << stitle.str() << "\" with " << pstyle; + else + cmdstr << "plot " << a << " * x + " << b << " title \"" << stitle.str() << "\" with " << pstyle; + this->cmd(cmdstr.str().c_str()); + this->nplots++; + return; +} + +// ---------------------------------------------------------------------------- + +// Plot an equation which is supplied as a string +// +void Gnuplot::plot_equation(const string &equation, const string &title) +{ + string titlestr, plotstr; + ostringstream cmdstr; + + if (title == "") + titlestr = "no title"; + else + titlestr = title; + + if (this->nplots > 0) + plotstr = "replot"; + else + plotstr = "plot"; + + cmdstr << plotstr << " " << equation << " " << "title \"" << titlestr << "\" with " << this->pstyle; + this->cmd(cmdstr.str().c_str()); + this->nplots++; + + return; +} + +// ---------------------------------------------------------------------------- + +void Gnuplot::plot_x(vector d, const string &title) +{ + ofstream tmp; + ostringstream cmdstr; +#ifdef WIN32 + char name[] = "gnuplotiXXXXXX"; +#else + char name[] = "/tmp/gnuplotiXXXXXX"; +#endif + + if (this->to_delete.size() == GP_MAX_TMP_FILES - 1) + { + cerr << "Maximum number of temporary files reached (" << GP_MAX_TMP_FILES << "): cannot open more files" << endl; + return; + } + + // + //open temporary files for output +#ifdef WIN32 + if ( _mktemp(name) == NULL) +#else + if ( mkstemp(name) == -1 ) +#endif + { + cerr << "Cannot create temporary file: exiting plot" << endl; + return; + } + tmp.open(name); + if (tmp.bad()) + { + cerr << "Cannot create temorary file: exiting plot" << endl; + return; + } + + // + // Save the temporary filename + // + this->to_delete.push_back(name); + + // + // write the data to file + // + for (size_t i = 0; i < d.size(); i++) + tmp << d[i] << endl; + tmp.flush(); + tmp.close(); + + // + // command to be sent to gnuplot + // + cmdstr << ( (this->nplots > 0) ? "replot " : "plot "); + + if (title.empty()) + cmdstr << "\"" << name << "\" with " << this->pstyle; + else + cmdstr << "\"" << name << "\" title \"" << title << "\" with " + << this->pstyle; + + // + // Do the actual plot + // + this->cmd(cmdstr.str().c_str()); + this->nplots++; + + return; +} + +// ---------------------------------------------------------------------------- + +void Gnuplot::plot_xy(vector x, vector y, const string &title) +{ + ofstream tmp; + ostringstream cmdstr; +#ifdef WIN32 + char name[] = "gnuplotiXXXXXX"; +#else + char name[] = "/tmp/gnuplotiXXXXXX"; +#endif + + // should raise an exception + if (x.size() != y.size()) + return; + + if ((this->to_delete).size() == GP_MAX_TMP_FILES - 1) + { + std::stringstream s; + s << "Maximum number of temporary files reached (" + << GP_MAX_TMP_FILES << "): cannot open more files" << endl; + throw GnuplotException( s.str() ); + } + + //open temporary files for output + // + if (MKTEMP_AND_CHECK_FAILED(name)) + throw GnuplotException("Cannot create temporary file: exiting plot"); + + tmp.open(name); + if (tmp.bad()) + throw GnuplotException("Cannot create temorary file: exiting plot"); + + // Save the temporary filename + // + this->to_delete.push_back(name); + + // Write the data to file + // + size_t N = std::min(x.size(), y.size()); + for (size_t i = 0; i < N; i++) + tmp << x[i] << " " << y[i] << endl; + tmp.flush(); + tmp.close(); + + // + // command to be sent to gnuplot + // + if (this->nplots > 0) + cmdstr << "replot "; + else cmdstr << "plot "; + if (title == "") + cmdstr << "\"" << name << "\" with " << this->pstyle; + else + cmdstr << "\"" << name << "\" title \"" << title << "\" with " << this->pstyle; + + // + // Do the actual plot + // + this->cmd(cmdstr.str().c_str()); + this->nplots++; + + return; +} + +// ---------------------------------------------------------------------------- + +void Gnuplot::init() +{ + if (!this->get_program_path(gnuplot_executable_)) + { + this->valid = false; + throw GnuplotException("Can't find gnuplot in your PATH"); + } + + this->gnucmd = popen(gnuplot_executable_.c_str(),"w"); + if (!this->gnucmd) + { + this->valid = false; + throw GnuplotException("Couldn't open connection to gnuplot"); + } + this->nplots = 0; + this->valid = true; +} + +// ============================================================================ diff --git a/Tools/Utils/Gnuplot.hh b/Tools/Utils/Gnuplot.hh new file mode 100644 index 00000000..45f8d429 --- /dev/null +++ b/Tools/Utils/Gnuplot.hh @@ -0,0 +1,184 @@ +//////////////////////////////////////////// +// +// A C++ interface to gnuplot. +// +// This is a direct translation from the C interface +// written by N. Devillard (which is available from +// http://ndevilla.free.fr/gnuplot/). +// +// As in the C interface this uses pipes and so wont +// run on a system that doesn't have POSIX pipe +// support +// +// Rajarshi Guha +// +// +// 07/03/03 +// +//////////////////////////////////////////// +// +// A little correction for Win32 compatibility +// and MS VC 6.0 done by V.Chyzhdzenka +// +// Notes: +// 1. Added private method Gnuplot::init(). +// 2. Temporary file is created in th current +// folder but not in /tmp. +// 3. Added #indef WIN32 e.t.c. where is needed. +// 4. Added private member m_sGNUPlotFileName is +// a name of executed GNUPlot file. +// +// Viktor Chyzhdzenka +// e-mail: chyzhdzenka@mail.ru +// +// 20/05/03 +// +//////////////////////////////////////////// + +#ifndef _GNUPLOT_HH +#define _GNUPLOT_HH + +#include +// #ifndef WIN32 +// # include +// #else +// # pragma warning (disable : 4786) // Disable 4786 warning for MS VC 6.0 +// #endif +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif +#include +#include +#include + +// ---------------------------------------------------------------------------- + +#ifdef WIN32 +# define GP_MAX_TMP_FILES 27 //27 temporary files it's Microsoft restriction +#else +# define GP_MAX_TMP_FILES 64 +# define GP_TMP_NAME_SIZE 512 +# define GP_TITLE_SIZE 80 +#endif +#define GP_CMD_SIZE 1024 + +// ---------------------------------------------------------------------------- + +using namespace std; + +// ---------------------------------------------------------------------------- + +/// Exception thrown by class Gnuplot +class GnuplotException : public runtime_error +{ +public: + GnuplotException(const string &msg) : runtime_error(msg){} +}; + +// ---------------------------------------------------------------------------- + +/** Utility class interfacing with Gnuplot. + * + * \note The plot will be visible as long as the object is not destructed. + * + * \author Rajarshi Guha (C++ API based on the C API by Nicolas Devillard) + * + * \see http://ndevilla.free.fr/gnuplot/ + * more information. + */ +class Gnuplot +{ +private: + + FILE *gnucmd; + string pstyle; + vector to_delete; + int nplots; + bool get_program_path(const string); + bool valid; + + // Name of executed GNUPlot file + static string gnuplot_executable_; + + void init(); + +public: + + /// \name Constructors + //@{ + /// Default constructor. + Gnuplot(); + + /// Set a style during construction. + Gnuplot(const string & _style); + + /// Constructor calling plot_xy(). + Gnuplot(const string & _title, + const string & _style, + const string & _xlabel, + const string & _ylabel, + vector _x, vector _y); + + /// Constructor calling plot_x(). + Gnuplot(const string &_title, + const string &_style, + const string &_xlabel, + const string &_ylabel, + vector _x); + //@} + + ~Gnuplot(); + + /// Send a command to gnuplot (low-level function use by all plot functions.) + void cmd(const char *_cmd, ...); + + /// \name Gnuplot settings + //@{ + void set_style(const string & _style); ///< set line style + void set_ylabel(const string & _ylabel); ///< set x axis label + void set_xlabel(const string & _xlabel); ///< set x axis label + //@} + + /// \name plot functions + //@{ + + /// Plot a single vector + void plot_x(vector _x, const string &_title); + + /// Plot x,y pairs + void plot_xy(vector _x, vector _y, const string &_title); + + /// Plot an equation of the form: y = ax + b + /// You supply a and b + void plot_slope( + double _a, + double _b, + const string & _title + ); + + /// Plot an equation supplied as a string + void plot_equation( + const string & _equation, + const string & _title + ); + + /// If multiple plots are present it will clear the plot area + void reset_plot(void); + + //@} + + /// Is \c Self valid? + bool is_valid(void) const { return valid; } + + /// Is \c Self active, i.e. does it have an active plot? + bool is_active(void) const { return this->nplots > 0; } +}; + + +// ---------------------------------------------------------------------------- +#endif // _GNUPLOT_HH +// ============================================================================ + diff --git a/Tools/Utils/HeapT.hh b/Tools/Utils/HeapT.hh new file mode 100644 index 00000000..a2558eb1 --- /dev/null +++ b/Tools/Utils/HeapT.hh @@ -0,0 +1,353 @@ +//============================================================================= +// +// 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 HeapT.hh + A generic heap class +**/ +/** Martin, 26.12.2004: + 1) replaced resize(size()-1) with pop_back(), since the later is more efficient + 2) replaced interface_.set_heap_position(entry(0), -1); with reset_heap_position() + 3) added const modifier to various functions + TODO: in the moment the heap does not conform to the HeapInterface specification, + i.e., copies are passed instead of references. This is especially important + for set_heap_position(), where the reference argument is non-const. The + specification should be changed to reflect that the heap actually (only?) + works when the heap entry is nothing more but a handle. + TODO: change the specification of HeapInterface to make less(), greater() and + get_heap_position() const. Needs changing DecimaterT. Might break + someone's code. +*/ + + +//============================================================================= +// +// CLASS HeapT +// +//============================================================================= + +#ifndef OPENMESH_UTILS_HEAPT_HH +#define OPENMESH_UTILS_HEAPT_HH + + +//== INCLUDES ================================================================= + +#include "Config.hh" +#include +#include + +//== NAMESPACE ================================================================ + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Utils { // BEGIN_NS_UTILS + +//== CLASS DEFINITION ========================================================= + + +/** This class demonstrates the HeapInterface's interface. If you + * want to build your customized heap you will have to specity a heap + * interface class and use this class as a template parameter for the + * class HeapT. This class defines the interface that this heap + * interface has to implement. + * + * \see HeapT + */ +template +struct HeapInterfaceT +{ + /// Comparison of two HeapEntry's: strict less + bool less(const HeapEntry& _e1, const HeapEntry& _e2); + + /// Comparison of two HeapEntry's: strict greater + bool greater(const HeapEntry& _e1, const HeapEntry& _e2); + + /// Get the heap position of HeapEntry _e + int get_heap_position(const HeapEntry& _e); + + /// Set the heap position of HeapEntry _e + void set_heap_position(HeapEntry& _e, int _i); +}; + + + +/** \class HeapT HeapT.hh + * + * An efficient, highly customizable heap. + * + * The main difference (and performace boost) of this heap compared + * to e.g. the heap of the STL is that here to positions of the + * heap's elements are accessible from the elements themself. + * Therefore if one changes the priority of an element one does not + * have to remove and re-insert this element, but can just call the + * update(HeapEntry) method. + * + * This heap class is parameterized by two template arguments: + * \li the class \c HeapEntry, that will be stored in the heap + * \li the HeapInterface telling the heap how to compare heap entries and + * how to store the heap positions in the heap entries. + * + * As an example how to use the class see declaration of class + * Decimater::DecimaterT. + * + * \see HeapInterfaceT + */ + +template +class HeapT : private std::vector +{ +private: + typedef std::vector Base; + +public: + + /// Constructor + HeapT() : HeapVector() {} + + /// Construct with a given \c HeapIterface. + HeapT(const HeapInterface& _interface) + : HeapVector(), interface_(_interface) + {} + + /// Destructor. + ~HeapT(){}; + + + /// clear the heap + void clear() { HeapVector::clear(); } + + /// is heap empty? + bool empty() const { return HeapVector::empty(); } + + /// returns the size of heap + unsigned int size() const { return HeapVector::size(); } + + /// reserve space for _n entries + void reserve(unsigned int _n) { HeapVector::reserve(_n); } + + /// reset heap position to -1 (not in heap) + void reset_heap_position(HeapEntry _h) + { interface_.set_heap_position(_h, -1); } + + /// is an entry in the heap? + bool is_stored(HeapEntry _h) + { return interface_.get_heap_position(_h) != -1; } + + /// insert the entry _h + void insert(HeapEntry _h) + { + push_back(_h); + upheap(size()-1); + } + + /// get the first entry + HeapEntry front() const + { + assert(!empty()); + return entry(0); + } + + /// delete the first entry + void pop_front() + { + assert(!empty()); + reset_heap_position(entry(0)); + if (size() > 1) + { + entry(0, entry(size()-1)); + Base::pop_back(); + downheap(0); + } + else + { + Base::pop_back(); + } + } + + /// remove an entry + void remove(HeapEntry _h) + { + int pos = interface_.get_heap_position(_h); + reset_heap_position(_h); + + assert(pos != -1); + assert((unsigned int) pos < size()); + + // last item ? + if ((unsigned int) pos == size()-1) + { + Base::pop_back(); + } + else + { + entry(pos, entry(size()-1)); // move last elem to pos + Base::pop_back(); + downheap(pos); + upheap(pos); + } + } + + /** update an entry: change the key and update the position to + reestablish the heap property. + */ + void update(HeapEntry _h) + { + int pos = interface_.get_heap_position(_h); + assert(pos != -1); + assert((unsigned int)pos < size()); + downheap(pos); + upheap(pos); + } + + /// check heap condition + bool check() + { + bool ok(true); + unsigned int i, j; + for (i=0; i HeapVector; + + + /// Upheap. Establish heap property. + void upheap(unsigned int _idx); + + + /// Downheap. Establish heap property. + void downheap(unsigned int _idx); + + + /// Get the entry at index _idx + inline HeapEntry entry(unsigned int _idx) const + { + assert(_idx < size()); + return (Base::operator[](_idx)); + } + + + /// Set entry _h to index _idx and update _h's heap position. + inline void entry(unsigned int _idx, HeapEntry _h) + { + assert(_idx < size()); + Base::operator[](_idx) = _h; + interface_.set_heap_position(_h, _idx); + } + + + /// Get parent's index + inline unsigned int parent(unsigned int _i) { return (_i-1)>>1; } + /// Get left child's index + inline unsigned int left(unsigned int _i) { return (_i<<1)+1; } + /// Get right child's index + inline unsigned int right(unsigned int _i) { return (_i<<1)+2; } + +}; + + + + +//== IMPLEMENTATION ========================================================== + + +template +void +HeapT:: +upheap(unsigned int _idx) +{ + HeapEntry h = entry(_idx); + unsigned int parentIdx; + + while ((_idx>0) && + interface_.less(h, entry(parentIdx=parent(_idx)))) + { + entry(_idx, entry(parentIdx)); + _idx = parentIdx; + } + + entry(_idx, h); +} + + +//----------------------------------------------------------------------------- + + +template +void +HeapT:: +downheap(unsigned int _idx) +{ + HeapEntry h = entry(_idx); + unsigned int childIdx; + unsigned int s = size(); + + while(_idx < s) + { + childIdx = left(_idx); + if (childIdx >= s) break; + + if ((childIdx+1 < s) && + (interface_.less(entry(childIdx+1), entry(childIdx)))) + ++childIdx; + + if (interface_.less(h, entry(childIdx))) break; + + entry(_idx, entry(childIdx)); + _idx = childIdx; + } + + entry(_idx, h); +} + + +//============================================================================= +} // END_NS_UTILS +} // END_NS_OPENMESH +//============================================================================= +#endif // OSG_HEAP_HH defined +//============================================================================= + diff --git a/Tools/Utils/MeshCheckerT.cc b/Tools/Utils/MeshCheckerT.cc new file mode 100644 index 00000000..cb7fb62e --- /dev/null +++ b/Tools/Utils/MeshCheckerT.cc @@ -0,0 +1,222 @@ +//============================================================================= +// +// 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: 2433 $ +// $Date: 2008-08-27 13:43:05 +0200 (Mi, 27. Aug 2008) $ +// +//============================================================================= + + +#define OPENMESH_MESHCHECKER_C + + +//== INCLUDES ================================================================= + + +#include + + +//== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace Utils { + +//== IMPLEMENTATION ========================================================== + + +template +bool +MeshCheckerT:: +check(unsigned int _targets, std::ostream& _os) +{ + bool ok(true); + + + + //--- vertex checks --- + + if (_targets & CHECK_VERTICES) + { + typename Mesh::ConstVertexIter v_it(mesh_.vertices_begin()), + v_end(mesh_.vertices_end()); + typename Mesh::VertexHandle vh; + typename Mesh::ConstVertexVertexIter vv_it; + typename Mesh::HalfedgeHandle heh; + unsigned int count; + const unsigned int max_valence(10000); + + + for (; v_it != v_end; ++v_it) + { + if (!is_deleted(v_it)) + { + vh = v_it.handle(); + + + /* The outgoing halfedge of a boundary vertex has to be a + boundary halfedge */ + heh = mesh_.halfedge_handle(vh); + if (heh.is_valid() && !mesh_.is_boundary(heh)) + { + for (typename Mesh::ConstVertexOHalfedgeIter vh_it(mesh_, vh); + vh_it; ++vh_it) + { + if (mesh_.is_boundary(vh_it.handle())) + { + _os << "MeshChecker: vertex " << vh + << ": outgoing halfedge not on boundary error\n"; + ok = false; + } + } + } + + + + // outgoing halfedge has to refer back to vertex + if (mesh_.halfedge_handle(vh).is_valid() && + mesh_.from_vertex_handle(mesh_.halfedge_handle(vh)) != vh) + { + _os << "MeshChecker: vertex " << vh + << ": outgoing halfedge does not reference vertex\n"; + ok = false; + } + + + // check whether circulators are still in order + vv_it = mesh_.cvv_iter(vh); + for (count=0; vv_it && (count < max_valence); ++vv_it, ++count) {}; + if (count == max_valence) + { + _os << "MeshChecker: vertex " << vh + << ": ++circulator problem, one ring corrupt\n"; + ok = false; + } + vv_it = mesh_.cvv_iter(vh); + for (count=0; vv_it && (count < max_valence); --vv_it, ++count) {}; + if (count == max_valence) + { + _os << "MeshChecker: vertex " << vh + << ": --circulator problem, one ring corrupt\n"; + ok = false; + } + } + } + } + + + + //--- halfedge checks --- + + if (_targets & CHECK_EDGES) + { + typename Mesh::ConstHalfedgeIter h_it(mesh_.halfedges_begin()), + h_end(mesh_.halfedges_end()); + typename Mesh::HalfedgeHandle hh, hstart, hhh; + unsigned int count, n_halfedges = 2*mesh_.n_edges(); + + for (; h_it != h_end; ++h_it) + { + if (!is_deleted(mesh_.edge_handle(h_it.handle()))) + { + hh = h_it.handle(); + + + // degenerated halfedge ? + if (mesh_.from_vertex_handle(hh) == mesh_.to_vertex_handle(hh)) + { + _os << "MeshChecker: halfedge " << hh + << ": to-vertex == from-vertex\n"; + ok = false; + } + + + // next <-> prev check + if (mesh_.next_halfedge_handle(mesh_.prev_halfedge_handle(hh)) != hh) + { + _os << "MeshChecker: halfedge " << hh + << ": prev->next != this\n"; + ok = false; + } + + + // halfedges should form a cycle + count=0; hstart=hhh=hh; + do + { + hhh = mesh_.next_halfedge_handle(hhh); + ++count; + } while (hhh != hstart && count < n_halfedges); + + if (count == n_halfedges) + { + _os << "MeshChecker: halfedges starting from " << hh + << " do not form a cycle\n"; + ok = false; + } + } + } + } + + + + //--- face checks --- + + if (_targets & CHECK_FACES) + { + typename Mesh::ConstFaceIter f_it(mesh_.faces_begin()), + f_end(mesh_.faces_end()); + typename Mesh::FaceHandle fh; + typename Mesh::ConstFaceHalfedgeIter fh_it; + + for (; f_it != f_end; ++f_it) + { + if (!is_deleted(f_it)) + { + fh = f_it.handle(); + + for (fh_it=mesh_.cfh_iter(fh); fh_it; ++fh_it) + { + if (mesh_.face_handle(fh_it.handle()) != fh) + { + _os << "MeshChecker: face " << fh + << ": its halfedge does not reference face\n"; + ok = false; + } + } + } + } + } + + + + return ok; +} + + +//============================================================================= +} // naespace Utils +} // namespace OpenMesh +//============================================================================= diff --git a/Tools/Utils/MeshCheckerT.hh b/Tools/Utils/MeshCheckerT.hh new file mode 100644 index 00000000..25df36ea --- /dev/null +++ b/Tools/Utils/MeshCheckerT.hh @@ -0,0 +1,114 @@ +//============================================================================= +// +// 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) $ +// +//============================================================================= + + +#ifndef OPENMESH_MESHCHECKER_HH +#define OPENMESH_MESHCHECKER_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include + + +//== NAMESPACES =============================================================== + + +namespace OpenMesh { +namespace Utils { + +//== CLASS DEFINITION ========================================================= + + +/** Check integrity of mesh. + * + * This class provides several functions to check the integrity of a mesh. + */ +template +class MeshCheckerT +{ +public: + + /// constructor + MeshCheckerT(const Mesh& _mesh) : mesh_(_mesh) {} + + /// destructor + ~MeshCheckerT() {} + + + /// what should be checked? + enum CheckTargets + { + CHECK_EDGES = 1, + CHECK_VERTICES = 2, + CHECK_FACES = 4, + CHECK_ALL = 255, + }; + + + /// check it, return true iff ok + bool check( unsigned int _targets=CHECK_ALL, + std::ostream& _os= omerr()); + + +private: + + bool is_deleted(typename Mesh::VertexHandle _vh) + { return (mesh_.has_vertex_status() ? mesh_.status(_vh).deleted() : false); } + + bool is_deleted(typename Mesh::EdgeHandle _eh) + { return (mesh_.has_edge_status() ? mesh_.status(_eh).deleted() : false); } + + bool is_deleted(typename Mesh::FaceHandle _fh) + { return (mesh_.has_face_status() ? mesh_.status(_fh).deleted() : false); } + + + // ref to mesh + const Mesh& mesh_; +}; + + +//============================================================================= +} // namespace Utils +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_MESHCHECKER_C) +#define OPENMESH_MESHCHECKER_TEMPLATES +#include "MeshCheckerT.cc" +#endif +//============================================================================= +#endif // OPENMESH_MESHCHECKER_HH defined +//============================================================================= + diff --git a/Tools/Utils/NumLimitsT.hh b/Tools/Utils/NumLimitsT.hh new file mode 100644 index 00000000..6c91dea8 --- /dev/null +++ b/Tools/Utils/NumLimitsT.hh @@ -0,0 +1,136 @@ +//============================================================================= +// +// 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: 4254 $ +// $Date: 2009-01-12 14:44:00 +0100 (Mo, 12. Jan 2009) $ +// +//============================================================================= + +/** \file NumLimitsT.hh + Temporary solution until std::numeric_limits is standard. + */ + +//============================================================================= +// +// CLASS NumLimitsT +// +//============================================================================= + +#ifndef OPENMESH_UTILS_NUMLIMITS_HH +#define OPENMESH_UTILS_NUMLIMITS_HH + + +//== INCLUDES ================================================================= + +#include "Config.hh" +#include +#include + + +//== NAMESPEACES ============================================================== + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Utils { // BEGIN_NS_UTILS + + +//== CLASS DEFINITION ========================================================= + + +/** \class NumLimitsT NumLimitsT.hh + + int float_min = OpenMesh::NumLimitsT::min(); + float double_max = OpenMesh::NumLimitsT::max(); + \endcode + + \note This functionality should be provided by + std::numeric_limits. This template does not exist on gcc <= + 2.95.3. The class template NumLimitsT is just a workaround. +**/ +template +class NumLimitsT +{ +public: + /// Return the smallest \em absolte value a scalar type can store. + static inline Scalar min() { return 0; } + /// Return the maximum \em absolte value a scalar type can store. + static inline Scalar max() { return 0; } + + static inline bool is_float() { return false; } + static inline bool is_integer() { return !NumLimitsT::is_float(); } + static inline bool is_signed() { return true; } +}; + + // is_float + +template<> +inline bool NumLimitsT::is_float() { return true; } + +template<> +inline bool NumLimitsT::is_float() { return true; } + +template<> +inline bool NumLimitsT::is_float() { return true; } + + // is_signed + +template<> +inline bool NumLimitsT::is_signed() { return false; } + +template<> +inline bool NumLimitsT::is_signed() { return false; } + +template<> +inline bool NumLimitsT::is_signed() { return false; } + +template<> +inline bool NumLimitsT::is_signed() { return false; } + +template<> +inline bool NumLimitsT::is_signed() { return false; } + + // min/max +template<> inline int NumLimitsT::min() { return INT_MIN; } +template<> inline int NumLimitsT::max() { return INT_MAX; } + +template<> inline float NumLimitsT::min() { return FLT_MIN; } +template<> inline float NumLimitsT::max() { return FLT_MAX; } + +template<> inline double NumLimitsT::min() { return DBL_MIN; } +template<> inline double NumLimitsT::max() { return DBL_MAX; } + + +//============================================================================= +} // END_NS_UTILS +} // END_NS_OPENMESH +//============================================================================= +#endif // OPENMESH_NUMLIMITS_HH defined +//============================================================================= + diff --git a/Tools/Utils/StripifierT.cc b/Tools/Utils/StripifierT.cc new file mode 100644 index 00000000..3838e151 --- /dev/null +++ b/Tools/Utils/StripifierT.cc @@ -0,0 +1,253 @@ +//============================================================================= +// +// OpenMesh +// Copyright (C) 2001-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) $ +// +//============================================================================= + +//============================================================================= +// +// CLASS StripifierT - IMPLEMENTATION +// +//============================================================================= + +#define OPENMESH_STRIPIFIERT_C + +//== INCLUDES ================================================================= + +#include +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + + //== IMPLEMENTATION ========================================================== + + +template +unsigned int +StripifierT:: +stripify() +{ + // preprocess: add new properties + mesh_.add_property( processed_ ); + mesh_.add_property( used_ ); + mesh_.request_face_status(); + + + // build strips + clear(); + build_strips(); + + + // postprocess: remove properties + //mesh_.remove_property(processed_); + //mesh_.remove_property(used_); + //mesh_.release_face_status(); + + + return n_strips(); +} + + +//----------------------------------------------------------------------------- + + +template +void +StripifierT:: +build_strips() +{ + Strip experiments[3]; + typename Mesh::HalfedgeHandle h[3]; + unsigned int best_idx, best_length, length; + FaceHandles faces[3]; + typename FaceHandles::iterator fh_it, fh_end; + typename Mesh::FaceIter f_it, f_end=mesh_.faces_end(); + + + + // init faces to be un-processed and un-used + // deleted or hidden faces are marked processed + if (mesh_.has_face_status()) + { + for (f_it=mesh_.faces_begin(); f_it!=f_end; ++f_it) + if (mesh_.status(f_it).hidden() || mesh_.status(f_it).deleted()) + processed(f_it) = used(f_it) = true; + else + processed(f_it) = used(f_it) = false; + } + else + { + for (f_it=mesh_.faces_begin(); f_it!=f_end; ++f_it) + processed(f_it) = used(f_it) = false; + } + + + + for (f_it=mesh_.faces_begin(); true; ) + { + // find start face + for (; f_it!=f_end; ++f_it) + if (!processed(f_it)) + break; + if (f_it==f_end) break; // stop if all have been processed + + + // collect starting halfedges + h[0] = mesh_.halfedge_handle(f_it.handle()); + h[1] = mesh_.next_halfedge_handle(h[0]); + h[2] = mesh_.next_halfedge_handle(h[1]); + + + // build 3 strips, take best one + best_length = best_idx = 0; + for (unsigned int i=0; i<3; ++i) + { + build_strip(h[i], experiments[i], faces[i]); + if ((length = experiments[i].size()) > best_length) + { + best_length = length; + best_idx = i; + } + + for (fh_it=faces[i].begin(), fh_end=faces[i].end(); + fh_it!=fh_end; ++fh_it) + used(*fh_it) = false; + } + + + // update processed status + fh_it = faces[best_idx].begin(); + fh_end = faces[best_idx].end(); + for (; fh_it!=fh_end; ++fh_it) + processed(*fh_it) = true; + + + + // add best strip to strip-list + strips_.push_back(experiments[best_idx]); + } +} + + +//----------------------------------------------------------------------------- + + +template +void +StripifierT:: +build_strip(typename Mesh::HalfedgeHandle _start_hh, + Strip& _strip, + FaceHandles& _faces) +{ + std::list strip; + typename Mesh::HalfedgeHandle hh; + typename Mesh::FaceHandle fh; + + + // reset face list + _faces.clear(); + + + // init strip + strip.push_back(mesh_.from_vertex_handle(_start_hh).idx()); + strip.push_back(mesh_.to_vertex_handle(_start_hh).idx()); + + + // walk along the strip: 1st direction + hh = mesh_.prev_halfedge_handle(mesh_.opposite_halfedge_handle(_start_hh)); + while (1) + { + // go right + hh = mesh_.next_halfedge_handle(hh); + hh = mesh_.opposite_halfedge_handle(hh); + hh = mesh_.next_halfedge_handle(hh); + if (mesh_.is_boundary(hh)) break; + fh = mesh_.face_handle(hh); + if (processed(fh) || used(fh)) break; + _faces.push_back(fh); + used(fh) = true; + strip.push_back(mesh_.to_vertex_handle(hh).idx()); + + // go left + hh = mesh_.opposite_halfedge_handle(hh); + hh = mesh_.next_halfedge_handle(hh); + if (mesh_.is_boundary(hh)) break; + fh = mesh_.face_handle(hh); + if (processed(fh) || used(fh)) break; + _faces.push_back(fh); + used(fh) = true; + strip.push_back(mesh_.to_vertex_handle(hh).idx()); + } + + + // walk along the strip: 2nd direction + bool flip(false); + hh = mesh_.prev_halfedge_handle(_start_hh); + while (1) + { + // go right + hh = mesh_.next_halfedge_handle(hh); + hh = mesh_.opposite_halfedge_handle(hh); + hh = mesh_.next_halfedge_handle(hh); + if (mesh_.is_boundary(hh)) break; + fh = mesh_.face_handle(hh); + if (processed(fh) || used(fh)) break; + _faces.push_back(fh); + used(fh) = true; + strip.push_front(mesh_.to_vertex_handle(hh).idx()); + flip = true; + + // go left + hh = mesh_.opposite_halfedge_handle(hh); + hh = mesh_.next_halfedge_handle(hh); + if (mesh_.is_boundary(hh)) break; + fh = mesh_.face_handle(hh); + if (processed(fh) || used(fh)) break; + _faces.push_back(fh); + used(fh) = true; + strip.push_front(mesh_.to_vertex_handle(hh).idx()); + flip = false; + } + + if (flip) strip.push_front(strip.front()); + + + + // copy final strip to _strip + _strip.clear(); + _strip.reserve(strip.size()); + std::copy(strip.begin(), strip.end(), std::back_inserter(_strip)); +} + + +//============================================================================= +} // namespace OpenMesh + //============================================================================= diff --git a/Tools/Utils/StripifierT.hh b/Tools/Utils/StripifierT.hh new file mode 100644 index 00000000..da26db58 --- /dev/null +++ b/Tools/Utils/StripifierT.hh @@ -0,0 +1,141 @@ +//============================================================================= +// +// OpenMesh +// Copyright (C) 2001-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) $ +// +//============================================================================= + +//============================================================================= +// +// CLASS StripifierT +// +//============================================================================= + + +#ifndef OPENMESH_STRIPIFIERT_HH +#define OPENMESH_STRIPIFIERT_HH + + +//== INCLUDES ================================================================= + +#include +#include + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + + +//== CLASS DEFINITION ========================================================= + + + + +/** \class StripifierT StripifierT.hh + This class decomposes a triangle mesh into several triangle strips. +*/ + +template +class StripifierT +{ +public: + + typedef unsigned int Index; + typedef std::vector Strip; + typedef typename Strip::const_iterator IndexIterator; + typedef std::vector Strips; + typedef typename Strips::const_iterator StripsIterator; + + + /// Default constructor + StripifierT(Mesh& _mesh) : mesh_(_mesh) {} + + /// Destructor + ~StripifierT() {} + + + /// Compute triangle strips, returns number of strips + unsigned int stripify(); + + /// delete all strips + void clear() { Strips().swap(strips_); } + + /// returns number of strips + unsigned int n_strips() const { return strips_.size(); } + + /// are strips computed? + bool is_valid() const { return !strips_.empty(); } + + /// Access strips + StripsIterator begin() const { return strips_.begin(); } + /// Access strips + StripsIterator end() const { return strips_.end(); } + + +private: + + typedef std::vector FaceHandles; + + + /// this method does the main work + void build_strips(); + + /// build a strip from a given halfedge (in both directions) + void build_strip(typename Mesh::HalfedgeHandle _start_hh, + Strip& _strip, + FaceHandles& _faces); + + FPropHandleT::reference processed(typename Mesh::FaceHandle _fh) { + return mesh_.property(processed_, _fh); + } + FPropHandleT::reference used(typename Mesh::FaceHandle _fh) { + return mesh_.property(used_, _fh); + } + + + +private: + + Mesh& mesh_; + Strips strips_; + FPropHandleT processed_, used_; +}; + + +//============================================================================= +} // namespace OpenMesh +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_STRIPIFIERT_C) +#define OPENMESH_STRIPIFIERT_TEMPLATES +#include "StripifierT.cc" +#endif +//============================================================================= +#endif // OPENMESH_STRIPIFIERT_HH defined +//============================================================================= diff --git a/Tools/Utils/TestingFramework.hh b/Tools/Utils/TestingFramework.hh new file mode 100644 index 00000000..783e66d3 --- /dev/null +++ b/Tools/Utils/TestingFramework.hh @@ -0,0 +1,330 @@ +// ============================================================================ +// $Id: TestingFramework.hh,v 1.1.1.1 2006-10-25 16:14:15 habbecke Exp $ +// ---------------------------------------------------------------------------- +#ifndef TESTINGFRAMEWORK_HH +#define TESTINGFRAMEWORK_HH +// ---------------------------------------------------------------------------- + +/** \file TestingFramework.hh + This file contains a little framework for test programms +*/ + + +// ---------------------------------------------------------------------------- + +#include "Config.hh" +#include +#include +#include +#include +#include +#include + +// ------------------------------------------------------------- namespace ---- + +namespace OpenMesh { // BEGIN_NS_OPENMESH +namespace Utils { // BEGIN_NS_UTILS + + +// ----------------------------------------------------------------- class ---- +// +// Usage Example +// +// #include +// #include <.../TestingFramework.hh> +// +// struct test_func : public TestingFramework::TestFunc +// { +// typedef test_func Self; +// +// // define ctor and copy-ctor +// test_func( TestingFramework& _th, std::string _n ) : TestingFramework::TestFunc( _th, _n ) { } +// test_func( Self& _cpy ) : TestingFramework::TestFunc(_cpy) { } +// +// // overload body() +// void body() +// { +// +// // Do the tests +// // direct call to verify +// verify( testResult, expectedResult, "additional information" ); +// +// // or use the define TH_VERIFY. The test-expression will be used as the message string +// TH_VERIFY( testResult, expectedResult ); +// +// ... +// } +// }; +// +// int main(...) +// { +// TestingFramework testSuite(std::cout); // send output to stdout +// +// new test_func(testSuite); // create new test instance. It registers with testSuite. +// return testSuite.run(); +// } +// + +// +#define TH_VERIFY( expr, expt ) \ + verify( expr, expt, #expr ) + +// +#define TH_VERIFY_X( expr, expt ) \ + verify_x( expr, expt, #expr ) + +/** Helper class for test programms. + \internal + */ +class TestingFramework : Noncopyable +{ +public: + + typedef TestingFramework Self; + typedef std::logic_error verify_error; + +#ifndef DOXY_IGNORE_THIS + class TestFunc + { + public: + TestFunc( TestingFramework& _th, const std::string& _n ) + : th_(_th), name_(_n) + { + th_.reg(this); + } + + virtual ~TestFunc() + { } + + void operator() ( void ) + { + prolog(); + try + { + body(); + } + catch( std::exception& x ) + { + std::cerr << "<>: Cannot proceed test due to failure of last" + << " test: " << x.what() << std::endl; + } + catch(...) + { + std::cerr << "Fatal: cannot proceed test due to unknown error!" + << std::endl; + } + epilog(); + } + + const TestingFramework& testHelper() const { return th_; } + + protected: + + virtual void prolog(void) + { + begin(name_); + } + + virtual void body(void) = 0; + + virtual void epilog(void) + { + end(); + } + + protected: + + TestingFramework& testHelper() { return th_; } + + TestFunc( const TestFunc& _cpy ) : th_(_cpy.th_), name_(_cpy.name_) { } + + + // Use the following method in prolog() + TestFunc& begin(std::string _title, const std::string& _info = "") + { th_.begin(_title,_info); return *this; } + + + // Use the following method in epilog() + TestFunc& end(void) + { th_.end(); return *this; } + + + // Use the followin methods in body() + + template + bool + verify( const ValueType& _rc, const ValueType& _expected, + std::string _info ) + { return th_.verify( _rc, _expected, _info ); } + + template + void + verify_x( const ValueType& _rc, const ValueType& _expected, + std::string _info ) + { + if ( !verify(_rc, _expected, _info) ) + throw verify_error(_info); + } + + TestFunc& info(const std::string& _info) + { th_.info(_info); return *this; } + + TestFunc& info(const std::ostringstream& _ostr) + { th_.info(_ostr); return *this; } + + private: + TestFunc(); + + protected: + TestingFramework& th_; + std::string name_; + }; +#endif + + typedef TestFunc* TestFuncPtr; + typedef std::vector TestSet; + +public: + + TestingFramework(std::ostream& _os) + : errTotal_(0), errCount_(0), + verifyTotal_(0), verifyCount_(0), + testTotal_(0), testCount_(0), + os_(_os) + { } + +protected: + +#ifndef DOXY_IGNORE_THIS + struct TestDeleter + { + void operator() (TestFuncPtr _tfptr) { delete _tfptr; } + }; +#endif + +public: + + virtual ~TestingFramework() + { + std::for_each(tests_.begin(), tests_.end(), TestDeleter() ); + } + +public: + + template + bool verify(const ValueType& _rc, + const ValueType& _expected, + const std::string& _info) + { + ++verifyTotal_; + if ( _rc == _expected ) + { + os_ << " " << _info << ", result: " << _rc << ", OK!" << std::endl; + return true; + } + ++errTotal_; + os_ << " " << _info << ", result: " << _rc << " != " << _expected + << " <>" << std::endl; + return false; + } + + Self& begin(std::string _title, const std::string& _info = "") + { + std::ostringstream ostr; + + testTitle_ = _title; + errCount_ = errTotal_; + ++testTotal_; + + ostr << _title; + if ( !_info.empty() ) + ostr << " ["<< _info << "]"; + testTitle_ = ostr.str(); + os_ << "Begin " << testTitle_ << std::endl; + return *this; + } + + Self& end() + { + if (errorCount()==0) + ++testCount_; + + os_ << "End " << testTitle_ << ": " << errorCount() << " Error(s)." << std::endl; + return *this; + } + + Self& info(const std::string& _info) + { + os_ << " + " << _info << std::endl; + return *this; + } + + Self& info(const std::ostringstream& _ostr) + { + os_ << " + " << _ostr.str() << std::endl; + return *this; + } + + size_t errorTotal() const { return errTotal_; } + size_t errorCount() const { return errTotal_ - errCount_; } + size_t verifyTotal() const { return verifyTotal_; } + size_t verifyCount() const { return verifyTotal_ - verifyCount_; } + size_t goodTotal() const { return verifyTotal() - errorTotal(); } + size_t goodCount() const { return verifyCount() - errorCount(); } + + size_t testTotal() const { return testTotal_; } + size_t testCount() const { return testCount_; } + +public: + + int run(void) + { + os_ << "Test started\n"; + TestRunner executer; + std::for_each(tests_.begin(), tests_.end(), executer ); + os_ << std::endl; + os_ << "All tests completed" << std::endl + << " #Tests: " << testCount() << "/" << testTotal() << std::endl + << " #Errors: " << errorTotal() << "/" << verifyTotal() << std::endl; + return errorTotal(); + } + +protected: + +#ifndef DOXY_IGNORE_THIS + struct TestRunner + { + void operator() (TestFuncPtr _tfptr) { (*_tfptr)(); } + }; +#endif + + int reg(TestFuncPtr _tfptr) + { + tests_.push_back(_tfptr); + return true; + } + + friend class TestFunc; + +private: + + size_t errTotal_; + size_t errCount_; + size_t verifyTotal_; + size_t verifyCount_; + size_t testTotal_; // #Tests + size_t testCount_; // #Tests ohne Fehler + + std::string testTitle_; + std::ostream& os_; + + TestSet tests_; + +}; + +// ============================================================================ +} // END_NS_UTILS +} // END_NS_OPENMESH +// ============================================================================ +#endif // TESTINGFRMEWORK_HH +// ============================================================================ diff --git a/Tools/Utils/Timer.cc b/Tools/Utils/Timer.cc new file mode 100644 index 00000000..604e4002 --- /dev/null +++ b/Tools/Utils/Timer.cc @@ -0,0 +1,397 @@ +// ============================================================================ +// $Id: Timer.cc,v 1.1.1.1 2006-10-25 16:14:15 habbecke Exp $ +// ---------------------------------------------------------------------------- +#ifndef DOXY_IGNORE_THIS +// ---------------------------------------------------------------------------- +#include +#if defined(OM_CC_MIPS) +# include +# include +#else +# include +# include +#endif +#include "Timer.hh" +// ---------------------------------------------------------------------------- + +// ------------------------------------------------------------- namespace ---- + +namespace OpenMesh { +namespace Utils { + + +// ---------------------------------------------------------------------------- + +using namespace std; + +// -------------------------------------------------------------- TimerImpl ---- +// just a base class for the implementation +class TimerImpl +{ +protected: +public: + TimerImpl() { ; } + virtual ~TimerImpl() { ; } + + virtual void reset(void) = 0; + virtual void start(void) = 0; + virtual void stop(void) = 0; + virtual void cont(void) = 0; + virtual double seconds(void) const = 0; +}; + +// compiler and os dependent implementation + +// ------------------------------------------------------------- windows 32 ---- +#if defined(WIN32) && (defined(_MSC_VER) || defined(__INTEL_COMPILER)) + +#include + +class TimerImplWin32 : public TimerImpl +{ +protected: + LARGE_INTEGER freq_; + LARGE_INTEGER count_; + LARGE_INTEGER start_; + +public: + TimerImplWin32(void); + ~TimerImplWin32(void) { ; } + + virtual void reset(void); + virtual void start(void); + virtual void stop(void); + virtual void cont(void); + virtual double seconds(void) const; +}; + +TimerImplWin32::TimerImplWin32(void) +{ + if (QueryPerformanceFrequency(&freq_)==FALSE) + throw std::runtime_error("Performance counter of of stock!"); + reset(); +} + +void TimerImplWin32::reset(void) +{ + memset(&count_,0,sizeof(count_)); + memset(&start_,0,sizeof(count_)); +} + +void TimerImplWin32::start(void) +{ + reset(); + QueryPerformanceCounter(&start_); +} + +void TimerImplWin32::stop(void) +{ + LARGE_INTEGER stop_; + + QueryPerformanceCounter(&stop_); + count_.QuadPart += stop_.QuadPart - start_.QuadPart; +} + +void TimerImplWin32::cont(void) +{ + QueryPerformanceCounter(&start_); +} + +double TimerImplWin32::seconds(void) const +{ + return (double)count_.QuadPart/(double)freq_.QuadPart; +} + +// ------------------------------------------------------------- posix time ---- +#elif defined(__GNUC__) && defined(__POSIX__) + +# include + +template +class TimerImplPosix : public TimerImpl +{ +public: + TimerImplPosix() : id_(N), seconds_(0.0) + { } + + ~TimerImplPosix() + { } + + virtual void reset(void) { seconds_ = 0.0; } + + virtual void start(void) { seconds_ = 0.0; clock_gettime( id_, &start_ ); } + virtual void stop(void) + { + timespec stop; + clock_gettime( id_, &stop ); + seconds_ += ( stop.tv_sec - start_.tv_sec ); + seconds_ += ( (double(stop.tv_nsec-start_.tv_nsec)*1e-9) ); + } + + virtual void cont(void) { clock_gettime( id_, &start_ ); } + + virtual double seconds() const { return seconds_; } + +protected: + clockid_t id_; + double seconds_; + timespec start_; +}; + +// ----------------------------------------------------------- gettimeofday ---- +#elif defined(__GNUC__) || (defined(__INTEL_COMPILER) && !defined(WIN32)) + +# include +# include +# include + +class TimerImplGToD: public TimerImpl +{ +public: + TimerImplGToD() : seconds_(0.0) + { } + + ~TimerImplGToD() + { } + + virtual void reset(void) { seconds_ = 0.0; } + virtual void start(void) { seconds_ = 0.0; gettimeofday( &start_, &tz_ ); } + + virtual void stop(void) + { + gettimeofday( &stop_, &tz_ ); + + seconds_ += (double)(stop_.tv_sec - start_.tv_sec); + seconds_ += (double)(stop_.tv_usec- start_.tv_usec)*1e-6; + } + + virtual void cont(void) { gettimeofday( &start_, &tz_); } + + virtual double seconds() const { return seconds_; } + +private: + + struct timeval start_, stop_; + struct timezone tz_; + + double seconds_; +}; + + +#else // ---------------------------------------- standard implementation ---- + +#include + +static const unsigned long clockticks = CLOCKS_PER_SEC; + +class TimerImplStd : public TimerImpl +{ +public: + TimerImplStd() : freq_(clockticks) { reset(); } + ~TimerImplStd() { ; } + + virtual void reset(void) { count_ = 0; } + virtual void start(void) { count_ = 0; start_ = clock(); } + virtual void stop(void); + virtual void cont(void) { start_ = clock(); } + virtual double seconds(void) const { return (double)count_/(double)freq_; } + +protected: + unsigned long freq_; + unsigned long count_; + unsigned long start_; +}; + +void TimerImplStd::stop(void) +{ + unsigned long stop_ = clock(); + count_ += stop_-start_; +} + +#endif + +// ----------------------------------------------------------------- Timer ---- + +Timer::Timer(void) +{ +#if defined(WIN32) && defined(_MSC_VER) + impl_ = new TimerImplWin32; +#elif defined(__GNUC__) && defined(__POSIX__) +// CLOCK_REALTIME +// CLOCK_MONOTONIC - ? +// CLOCK_REALTIME_HR - RTlinux +// CLOCK_MONOTONIC_HR - ? +# if defined(CLOCK_REALTIME_HR) + impl_ = new TimerImplPosix; +# else + impl_ = new TimerImplPosix; +# endif +#elif defined(__GNUC__) || (defined(__INTEL_COMPILER) && !defined(WIN32)) + impl_ = new TimerImplGToD; +#else + impl_ = new TimerImplStd; +#endif + state_ = Stopped; +} + +Timer::~Timer(void) +{ + delete impl_; + state_ = Stopped; +} + +void Timer::reset(void) +{ + state_ = Stopped; + impl_->reset(); +} + +void Timer::start(void) +{ + state_ = Running; + impl_->start(); +} + +void Timer::stop(void) +{ + impl_->stop(); + state_ = Stopped; +} + +void Timer::cont(void) +{ + impl_->cont(); + state_ = Running; +} + +double Timer::seconds(void) const +{ + return state_==Stopped ? impl_->seconds() : 0.0; +} + +std::string Timer::as_string(Timer::Format format) +{ + if (state_ == Running) + return "Running"; + return as_string(impl_->seconds(),format); +} + +std::string Timer::as_string(double seconds, Timer::Format format) +{ + char string[32]; + + double fraction; + double integer; + unsigned long t; +// double rest; + short hour,min,sec; + bool negative = false; + + if ( seconds < 0 ) + { + negative = true; + seconds *= -1; + } + + fraction = modf(seconds,&integer); + + t = (unsigned long)integer; + + hour = short( t / 3600L ); + t %= 3600L; + min = short( t / 60L ); + t %= 60L; + sec = short( t ); +// rest = (double)t + fraction; + + char *ptr = string; + if (negative) + *ptr++ = '-'; + + switch(format) + { + case Timer::Automatic: + if (hour) + ptr += sprintf(ptr,"%02dh:",hour); + + if (min) + ptr += sprintf(ptr,"%02dm:",min); + else if (ptr>string && hour) + ptr += sprintf(ptr,"00m:"); + + if (sec) + ptr += sprintf(ptr,"%02d",sec); + else if (ptr>string && min) + ptr += sprintf(ptr,"00"); + + if (!hour && !min) // higher resolution necessary + { + if (ptr > string && sec) + { + sprintf(ptr,".%.3fs",fraction); + ptr++; + while(*(ptr+2)) + { + *ptr = *(ptr+2); + ptr++; + } + *ptr = '\0'; + } + else if ( fraction * 1e2 > 0.1) + sprintf(ptr,"%.3fcs",fraction*1.e2); + else if ( fraction * 1e3 > 0.1) + sprintf(ptr,"%.3fms",fraction*1.e3); + else if ( fraction * 1e6 > 0.1) + sprintf(ptr,"%.1f\xb5s",fraction*1.e6); + else if ( fraction * 1e9 > 0.1) + sprintf(ptr,"%.1fns",fraction*1.e9); + else + sprintf(ptr,"%.1fps",fraction*1.e12); + } else // append a 's' for seconds! + { + ptr[0] = 's'; + ptr[1] = '\0'; + } + break; + case Timer::Long: + ptr += sprintf(ptr,"%02dh:%02dm:%02d",hour,min,sec); + sprintf(ptr,".%.12fs",fraction); + ptr++; + while(*(ptr+2)) + { + *ptr = *(ptr+2); + ptr++; + } + *ptr = '\0'; + break; + case Timer::Hours: + sprintf(ptr,"%02dh:%02dm:%02ds",hour,min,sec); break; + case Timer::Minutes: + ptr += sprintf(ptr,"%02dm:%02d", min, sec); + sprintf(ptr,".%.2fs",fraction); + ptr++; + while(*(ptr+2)) + { + *ptr = *(ptr+2); + ptr++; + } + *ptr = '\0'; + break; + case Timer::Seconds: sprintf(ptr,"%.3fs",seconds); break; + case Timer::HSeconds: sprintf(ptr,"%.3fcs",seconds*1e2); break; + case Timer::MSeconds: sprintf(ptr,"%.3fms",seconds*1e3); break; + case Timer::MicroSeconds: sprintf(ptr,"%.1f\xb5s",seconds*1e6); break; + case Timer::NanoSeconds: sprintf(ptr,"%.1fns",seconds*1e9); break; + } + return string; +} + +// ============================================================================ +} // END_NS_UTILS +} // END_NS_OPENMESH +// ---------------------------------------------------------------------------- +#endif // DOXY_IGNORE_THIS +// ============================================================================ +// end of file Timer.cc +// ============================================================================ + diff --git a/Tools/Utils/Timer.hh b/Tools/Utils/Timer.hh new file mode 100644 index 00000000..c44350ff --- /dev/null +++ b/Tools/Utils/Timer.hh @@ -0,0 +1,169 @@ +// ============================================================================ +// $Id: Timer.hh,v 1.1.1.1 2006-10-25 16:14:15 habbecke Exp $ +// ---------------------------------------------------------------------------- +#ifndef TIMER_HH +#define TIMER_HH +// ---------------------------------------------------------------------------- + +/** \file Timer.hh + A timer class +*/ + + +// ---------------------------------------------------------------------------- + +#include +// +#include +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + + +// ------------------------------------------------------------- namespace ---- + +namespace OpenMesh { +namespace Utils { + + +// -------------------------------------------------------------- forwards ---- + + +class TimerImpl; + + +// ----------------------------------------------------------------- class ---- + +/** Timer class + */ +class Timer +{ +public: + + /// Formatting options for member Timer::as_string() + enum Format { + Automatic, + Long, + Hours, + Minutes, + Seconds, + HSeconds, + MSeconds, + MicroSeconds, + NanoSeconds + }; + + Timer(void); + ~Timer(void); + + /// Returns true if self is in a valid state! + bool is_valid() const { return state_!=Invalid; } + + bool is_stopped() const { return state_==Stopped; } + + /// Reset the timer + void reset(void); + + /// Start measurement + void start(void); + + /// Stop measurement + void stop(void); + + /// Continue measurement + void cont(void); + + /// Give resolution of timer. Depends on the underlying measurement method. + float resolution() const; + + /// Returns measured time in seconds, if the timer is in state 'Stopped' + double seconds(void) const; + + /// Returns measured time in hundredth seconds, if the timer is in state 'Stopped' + double hseconds(void) const { return seconds()*1e2; } + + /// Returns measured time in milli seconds, if the timer is in state 'Stopped' + double mseconds(void) const { return seconds()*1e3; } + + /// Returns measured time in micro seconds, if the timer is in state 'Stopped' + double useconds(void) const { return seconds()*1e6; } + + /** Returns the measured time as a string. Use the format flags to specify + a wanted resolution. + */ + std::string as_string(Format format = Automatic); + + /** Returns a given measured time as a string. Use the format flags to + specify a wanted resolution. + */ + static std::string as_string(double seconds, Format format = Automatic); + +public: + + //@{ + /// Compare timer values + bool operator < (const Timer& t2) const + { + assert( is_stopped() && t2.is_stopped() ); + return (seconds() < t2.seconds()); + } + + bool operator > (const Timer& t2) const + { + assert( is_stopped() && t2.is_stopped() ); + return (seconds() > t2.seconds()); + } + + bool operator == (const Timer& t2) const + { + assert( is_stopped() && t2.is_stopped() ); + return (seconds() == t2.seconds()); + } + + bool operator <= (const Timer& t2) const + { + assert( is_stopped() && t2.is_stopped() ); + return (seconds() <= t2.seconds()); + } + + bool operator >=(const Timer& t2) const + { + assert( is_stopped() && t2.is_stopped() ); + return (seconds() >= t2.seconds()); + } + //@} + +protected: + + TimerImpl *impl_; + + enum { + Invalid = -1, + Stopped = 0, + Running = 1 + } state_; + +}; + + +/** Write seconds to output stream. + * Timer must be stopped before. + * \relates Timer + */ +inline std::ostream& operator << (std::ostream& _o, const Timer& _t) +{ + return (_o << _t.seconds()); +} + + +// ============================================================================ +} // END_NS_UTILS +} // END_NS_OPENMESH +// ============================================================================ +#endif +// end of Timer.hh +// =========================================================================== + diff --git a/Tools/Utils/conio.cc b/Tools/Utils/conio.cc new file mode 100644 index 00000000..f024fb82 --- /dev/null +++ b/Tools/Utils/conio.cc @@ -0,0 +1,183 @@ +// ============================================================================ + +#include +#include + +// ----------------------------------------------------------------- Win32 ---- +#ifdef WIN32 + +#include + +namespace OpenMesh { +namespace Utils { + +int kbhit() { return ::kbhit(); } +int getch() { return ::getch(); } +int getche() { return ::getche(); } + +} // Tools +} // AS +// ----------------------------------------------------------------- Other ---- +#else + +// Based on code published by Floyd Davidson in a newsgroup. + +#include /* stdout, fflush() */ +#if !defined(POSIX_1003_1_2001) +# include +# include +#else +# include /* select() */ +#endif +#include /* tcsetattr() */ +#include /* ioctl() */ +#include /* struct timeval */ + +namespace OpenMesh { +namespace Utils { + +#ifdef CTIME +# undef CTIME +#endif +#define CTIME 1 +#define CMIN 1 + + +int kbhit(void) +{ + int cnt = 0; + int error; + static struct termios Otty, Ntty; + + tcgetattr(0, &Otty); + Ntty = Otty; + + Ntty.c_iflag = 0; /* input mode */ + Ntty.c_oflag = 0; /* output mode */ + Ntty.c_lflag &= ~ICANON; /* raw mode */ + Ntty.c_cc[VMIN] = CMIN; /* minimum chars to wait for */ + Ntty.c_cc[VTIME] = CTIME; /* minimum wait time */ + + if (0 == (error = tcsetattr(0, TCSANOW, &Ntty))) + { + struct timeval tv; + error += ioctl(0, FIONREAD, &cnt); + error += tcsetattr(0, TCSANOW, &Otty); + tv.tv_sec = 0; + tv.tv_usec = 100; /* insert at least a minimal delay */ + select(1, NULL, NULL, NULL, &tv); + } + return (error == 0 ? cnt : -1 ); +} + + +int getch(void) +{ + char ch; + int error; + static struct termios Otty, Ntty; + + fflush(stdout); + tcgetattr(0, &Otty); + Ntty = Otty; + + Ntty.c_iflag = 0; // input mode + Ntty.c_oflag = 0; // output mode + Ntty.c_lflag &= ~ICANON; // line settings + Ntty.c_lflag &= ~ECHO; // enable echo + Ntty.c_cc[VMIN] = CMIN; // minimum chars to wait for + Ntty.c_cc[VTIME] = CTIME; // minimum wait time + + // Conditionals allow compiling with or without flushing pre-existing + // existing buffered input before blocking. +#if 1 + // use this to flush the input buffer before blocking for new input +# define FLAG TCSAFLUSH +#else + // use this to return a char from the current input buffer, or block if + // no input is waiting. +# define FLAG TCSANOW +#endif + + if (0 == (error = tcsetattr(0, FLAG, &Ntty))) + { + error = read(0, &ch, 1 ); // get char from stdin + error += tcsetattr(0, FLAG, &Otty); // restore old settings + } + return (error == 1 ? (int) ch : -1 ); +} + + +int getche(void) +{ + char ch; + int error; + static struct termios Otty, Ntty; + + fflush(stdout); + tcgetattr(0, &Otty); + Ntty = Otty; + + Ntty.c_iflag = 0; // input mode + Ntty.c_oflag = 0; // output mode + Ntty.c_lflag &= ~ICANON; // line settings + Ntty.c_lflag |= ECHO; // enable echo + Ntty.c_cc[VMIN] = CMIN; // minimum chars to wait for + Ntty.c_cc[VTIME] = CTIME; // minimum wait time + + // Conditionals allow compiling with or without flushing pre-existing + // existing buffered input before blocking. +#if 1 + // use this to flush the input buffer before blocking for new input +# define FLAG TCSAFLUSH +#else + // use this to return a char from the current input buffer, or block if + // no input is waiting. +# define FLAG TCSANOW +#endif + + if (0 == (error = tcsetattr(0, FLAG, &Ntty))) { + error = read(0, &ch, 1 ); // get char from stdin + error += tcsetattr(0, FLAG, &Otty); // restore old settings + } + + return (error == 1 ? (int) ch : -1 ); +} + +} // namespace Tools +} // namespace AS +// ---------------------------------------------------------------------------- +#endif // System dependent parts +// ============================================================================ + +//#define Test +#if defined(Test) + +#include + +int main (void) +{ + char msg[] = "press key to continue..."; + char *ptr = msg, tmp; + + while ( !OpenMesh::Utils::kbhit() ) + { + tmp = *ptr; + *ptr = islower(tmp) ? toupper(tmp) : tolower(tmp); + printf("\r%s", msg); fflush(stdout); + *ptr = (char)tmp; + if (!*(++ptr)) + ptr = msg; + usleep(20000); + } + + printf("\r%s.", msg); fflush(stdout); + OpenMesh::Utils::getch(); + printf("\r%s..", msg); fflush(stdout); + OpenMesh::Utils::getche(); + return 0; +} + +#endif // Test + +// ============================================================================ diff --git a/Tools/Utils/conio.hh b/Tools/Utils/conio.hh new file mode 100644 index 00000000..19d302d7 --- /dev/null +++ b/Tools/Utils/conio.hh @@ -0,0 +1,37 @@ +#ifndef OPENMESH_UTILS_CONIO_HH +#define OPENMESH_UTILS_CONIO_HH +// ---------------------------------------------------------------------------- +namespace OpenMesh { +namespace Utils { +// ---------------------------------------------------------------------------- + +/** Check if characters a pending in stdin. + * + * \return Number of characters available to read. + * + * \see getch(), getche() + */ +int kbhit(void); + + +/** A blocking single character input from stdin + * + * \return Character, or -1 if an input error occurs. + * + * \see getche(), kbhit() + */ +int getch(void); + +/** A blocking single character input from stdin with echo. + * + * \return Character, or -1 if an input error occurs. + * \see getch(), kbhit() + */ +int getche(void); + +// ---------------------------------------------------------------------------- +} // namespace Utils +} // namespace OpenMesh +// ---------------------------------------------------------------------------- +#endif // OPENMESH_UTILS_CONIO_HH +// ============================================================================ diff --git a/Tools/Utils/getopt.c b/Tools/Utils/getopt.c new file mode 100644 index 00000000..182062c4 --- /dev/null +++ b/Tools/Utils/getopt.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include "getopt.h" + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(int nargc, char * const *nargv, const char *ostr) +{ +# define __progname nargv[0] + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __progname, optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname, optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} + diff --git a/Tools/Utils/getopt.h b/Tools/Utils/getopt.h new file mode 100644 index 00000000..912300d2 --- /dev/null +++ b/Tools/Utils/getopt.h @@ -0,0 +1,26 @@ +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +#include + +#if defined(WIN32) +#if defined(__cplusplus) + +extern "C" { + +extern int opterr; +extern int optind; +extern int optopt; +extern int optreset; +extern char *optarg; + +extern int getopt(int nargc, char * const *nargv, const char *ostr); + +} + +# endif +#else +# include +#endif + +#endif /* _GETOPT_H_ */ diff --git a/Tools/VDPM/ACGMakefile b/Tools/VDPM/ACGMakefile new file mode 100644 index 00000000..97abf4fe --- /dev/null +++ b/Tools/VDPM/ACGMakefile @@ -0,0 +1,18 @@ +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Config +#============================================================================== + +CXX_CFLAGS += -DQT_THREAD_SUPPORT + +SUBDIRS = $(call find-subdirs) + +PACKAGES := qt glut opengl x11 math + +PROJ_LIBS = OpenMesh/Core + +MODULES := cxxlib + + +#== SYSTEM PART -- DON'T TOUCH ============================================== +include $(ACGMAKE)/Rules +#============================================================================== diff --git a/Tools/VDPM/MeshTraits.hh b/Tools/VDPM/MeshTraits.hh new file mode 100644 index 00000000..81f5839a --- /dev/null +++ b/Tools/VDPM/MeshTraits.hh @@ -0,0 +1,102 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS VDPMTraits +// +//============================================================================= + + +#ifndef OPENMESH_VDPM_TRAITS_HH +#define OPENMESH_VDPM_TRAITS_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** \class MeshTraits MeshTraits.hh + + Mesh traits for View Dependent Progressive Meshes +*/ + +struct MeshTraits : public DefaultTraits +{ + VertexTraits + { + public: + + VHierarchyNodeHandle vhierarchy_node_handle() + { + return node_handle_; + } + + void set_vhierarchy_node_handle(VHierarchyNodeHandle _node_handle) + { + node_handle_ = _node_handle; + } + + bool is_ancestor(const VHierarchyNodeIndex &_other) + { + return false; + } + + private: + + VHierarchyNodeHandle node_handle_; + + }; + + VertexAttributes(OpenMesh::Attributes::Status | + OpenMesh::Attributes::Normal); + HalfedgeAttributes(OpenMesh::Attributes::PrevHalfedge); + EdgeAttributes(OpenMesh::Attributes::Status); + FaceAttributes(OpenMesh::Attributes::Status | + OpenMesh::Attributes::Normal); +}; + + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VDPM_TRAITS_HH defined +//============================================================================= + diff --git a/Tools/VDPM/StreamingDef.hh b/Tools/VDPM/StreamingDef.hh new file mode 100644 index 00000000..16beeb60 --- /dev/null +++ b/Tools/VDPM/StreamingDef.hh @@ -0,0 +1,72 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= + + +#ifndef OPENMESH_VDPM_STREAMINGDEF_HH +#define OPENMESH_VDPM_STREAMINGDEF_HH + +//== INCLUDES ================================================================= + +//== FORWARDDECLARATIONS ====================================================== + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + + +//== CLASS DEFINITION ========================================================= + +#define VDPM_STREAMING_PORT 4096 + +#define DEBUG_COUT +//#define QDATASTREAM + +#ifdef DEBUG_COUT +static bool debug_print_; +static bool debug_print() { return debug_print_; } +static void set_debug_print(bool flag) { debug_print_ = flag; } +#endif + +enum VDPMDownLinkStatus { kStarted, kFinished, kStartable }; +enum VDPMStreamingPhase { kBaseMesh, kVSplitHeader, kVSplits }; +enum VDPMClientMode { kStatic, kDynamic }; +enum VHierarchySearchMode { kBruteForce, kUseHashing }; + + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VDPROGMESH_VDPMSTREAMINGDEF_HH defined +//============================================================================= + + diff --git a/Tools/VDPM/VFront.cc b/Tools/VDPM/VFront.cc new file mode 100644 index 00000000..b63c750e --- /dev/null +++ b/Tools/VDPM/VFront.cc @@ -0,0 +1,95 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass - IMPLEMENTATION +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== IMPLEMENTATION ========================================================== + + +VFront::VFront() +{ +} + + +void +VFront:: +add(VHierarchyNodeHandle _node_handle) +{ + front_location_[_node_handle.idx()] = front_.insert(front_.end(), _node_handle); +} + + +void +VFront:: +remove(VHierarchyNodeHandle _node_handle) +{ + VHierarchyNodeHandleListIter node_it = front_location_[_node_handle.idx()]; + VHierarchyNodeHandleListIter next_it = front_.erase(node_it); + front_location_[_node_handle.idx()] = front_.end(); + + if (front_it_ == node_it) + front_it_ = next_it; +} + +bool +VFront:: +is_active(VHierarchyNodeHandle _node_handle) +{ + return (front_location_[_node_handle.idx()] != front_.end()) ? true : false; +} + +void +VFront:: +init(VHierarchyNodeHandleContainer &_roots, unsigned int _n_details) +{ + unsigned int i; + + front_location_.resize(_roots.size() + 2*_n_details); + for (i=0; i +#include +#include + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** Active nodes in vertex hierarchy. + \todo VFront documentation +*/ +class VFront +{ +private: + + typedef VHierarchyNodeHandleList::iterator VHierarchyNodeHandleListIter; + enum VHierarchyNodeStatus { kSplit, kActive, kCollapse }; + + VHierarchyNodeHandleList front_; + VHierarchyNodeHandleListIter front_it_; + std::vector front_location_; + +public: + + VFront(); + + void clear() { front_.clear(); front_location_.clear(); } + void begin() { front_it_ = front_.begin(); } + bool end() { return (front_it_ == front_.end()) ? true : false; } + void next() { ++front_it_; } + int size() { return (int) front_.size(); } + VHierarchyNodeHandle node_handle() { return *front_it_; } + + void add(VHierarchyNodeHandle _node_handle); + void remove(VHierarchyNodeHandle _node_handle); + bool is_active(VHierarchyNodeHandle _node_handle); + void init(VHierarchyNodeHandleContainer &_roots, unsigned int _n_details); +}; + + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VDPROGMESH_VFRONT_HH defined +//============================================================================= diff --git a/Tools/VDPM/VHierarchy.cc b/Tools/VDPM/VHierarchy.cc new file mode 100644 index 00000000..652a0b47 --- /dev/null +++ b/Tools/VDPM/VHierarchy.cc @@ -0,0 +1,156 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass - IMPLEMENTATION +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== IMPLEMENTATION ========================================================== + + +VHierarchy:: +VHierarchy() +{ + clear(); +} + +void +VHierarchy:: +set_num_roots(unsigned int _n_roots) +{ + n_roots_ = _n_roots; + + tree_id_bits_ = 0; + while (n_roots_ > ((unsigned int) 0x00000001 << tree_id_bits_)) + ++tree_id_bits_; +} + + +VHierarchyNodeHandle +VHierarchy:: +add_node() +{ + return add_node(VHierarchyNode()); +} + +VHierarchyNodeHandle +VHierarchy:: +add_node(const VHierarchyNode &_node) +{ + nodes_.push_back(_node); + + return VHierarchyNodeHandle(nodes_.size() - 1); +} + + +void +VHierarchy:: +make_children(VHierarchyNodeHandle &_parent_handle) +{ + VHierarchyNodeHandle lchild_handle = add_node(); + VHierarchyNodeHandle rchild_handle = add_node(); + + VHierarchyNode &parent = node(_parent_handle); + VHierarchyNode &lchild = node(lchild_handle); + VHierarchyNode &rchild = node(rchild_handle); + + parent.set_children_handle(lchild_handle); + lchild.set_parent_handle(_parent_handle); + rchild.set_parent_handle(_parent_handle); + + lchild.set_index(VHierarchyNodeIndex(parent.node_index().tree_id(tree_id_bits_), 2*parent.node_index().node_id(tree_id_bits_), tree_id_bits_)); + rchild.set_index(VHierarchyNodeIndex(parent.node_index().tree_id(tree_id_bits_), 2*parent.node_index().node_id(tree_id_bits_)+1, tree_id_bits_)); +} + +VHierarchyNodeHandle +VHierarchy:: +node_handle(VHierarchyNodeIndex _node_index) +{ + if (_node_index.is_valid(tree_id_bits_) != true) + return InvalidVHierarchyNodeHandle; + + VHierarchyNodeHandle node_handle = root_handle(_node_index.tree_id(tree_id_bits_)); + unsigned int node_id = _node_index.node_id(tree_id_bits_); + unsigned int flag = 0x80000000; + + while (!(node_id & flag)) flag >>= 1; + flag >>= 1; + + while (flag > 0 && is_leaf_node(node_handle) != true) + { + if (node_id & flag) // 1: rchild + { + node_handle = rchild_handle(node_handle); + } + else // 0: lchild + { + node_handle = lchild_handle(node_handle); + } + flag >>= 1; + } + + return node_handle; +} + +bool +VHierarchy:: +is_ancestor(VHierarchyNodeIndex _ancestor_index, VHierarchyNodeIndex _descendent_index) +{ + if (_ancestor_index.tree_id(tree_id_bits_) != _descendent_index.tree_id(tree_id_bits_)) + return false; + + unsigned int ancestor_node_id = _ancestor_index.node_id(tree_id_bits_); + unsigned int descendent_node_id = _descendent_index.node_id(tree_id_bits_); + + if (ancestor_node_id > descendent_node_id) + return false; + + while (descendent_node_id > 0) + { + if (ancestor_node_id == descendent_node_id) + return true; + descendent_node_id >>= 1; // descendent_node_id /= 2 + } + + return false; +} + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= diff --git a/Tools/VDPM/VHierarchy.hh b/Tools/VDPM/VHierarchy.hh new file mode 100644 index 00000000..d5fd60dc --- /dev/null +++ b/Tools/VDPM/VHierarchy.hh @@ -0,0 +1,170 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= + +#ifndef OPENMESH_VDPROGMESH_VHIERARCHY_HH +#define OPENMESH_VDPROGMESH_VHIERARCHY_HH + + +//== INCLUDES ================================================================= + +#include +#include + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** Keeps the vertex hierarchy build during analyzing a progressive mesh. + */ +class VHierarchy +{ +public: + + typedef unsigned int id_t; ///< Type for tree and node ids + +private: + + VHierarchyNodeContainer nodes_; + unsigned int n_roots_; + unsigned char tree_id_bits_; // node_id_bits_ = 32-tree_id_bits_; + +public: + + VHierarchy(); + + void clear() { nodes_.clear(); n_roots_ = 0; } + unsigned char tree_id_bits() const { return tree_id_bits_; } + unsigned int num_roots() const { return n_roots_; } + unsigned int num_nodes() const { return nodes_.size(); } + + VHierarchyNodeIndex generate_node_index(id_t _tree_id, id_t _node_id) + { + return VHierarchyNodeIndex(_tree_id, _node_id, tree_id_bits_); + } + + + void set_num_roots(unsigned int _n_roots); + + VHierarchyNodeHandle root_handle(unsigned int i) const + { + return VHierarchyNodeHandle( (int)i ); + } + + + const VHierarchyNode& node(VHierarchyNodeHandle _vhierarchynode_handle) const + { + return nodes_[_vhierarchynode_handle.idx()]; + } + + + VHierarchyNode& node(VHierarchyNodeHandle _vhierarchynode_handle) + { + return nodes_[_vhierarchynode_handle.idx()]; + } + + VHierarchyNodeHandle add_node(); + VHierarchyNodeHandle add_node(const VHierarchyNode &_node); + + void make_children(VHierarchyNodeHandle &_parent_handle); + + bool is_ancestor(VHierarchyNodeIndex _ancestor_index, + VHierarchyNodeIndex _descendent_index); + + bool is_leaf_node(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].is_leaf(); } + + bool is_root_node(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].is_root(); } + + + const OpenMesh::Vec3f& normal(VHierarchyNodeHandle _node_handle) const + { + return nodes_[_node_handle.idx()].normal(); + } + + const VHierarchyNodeIndex& + node_index(VHierarchyNodeHandle _node_handle) const + { return nodes_[_node_handle.idx()].node_index(); } + + VHierarchyNodeIndex& node_index(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].node_index(); } + + const VHierarchyNodeIndex& + fund_lcut_index(VHierarchyNodeHandle _node_handle) const + { return nodes_[_node_handle.idx()].fund_lcut_index(); } + + VHierarchyNodeIndex& fund_lcut_index(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].fund_lcut_index(); } + + const VHierarchyNodeIndex& + fund_rcut_index(VHierarchyNodeHandle _node_handle) const + { return nodes_[_node_handle.idx()].fund_rcut_index(); } + + VHierarchyNodeIndex& fund_rcut_index(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].fund_rcut_index(); } + + VertexHandle vertex_handle(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].vertex_handle(); } + + VHierarchyNodeHandle parent_handle(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].parent_handle(); } + + VHierarchyNodeHandle lchild_handle(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].lchild_handle(); } + + VHierarchyNodeHandle rchild_handle(VHierarchyNodeHandle _node_handle) + { return nodes_[_node_handle.idx()].rchild_handle(); } + + VHierarchyNodeHandle node_handle(VHierarchyNodeIndex _node_index); + +private: + + VHierarchyNodeHandle compute_dependency(VHierarchyNodeIndex index0, + VHierarchyNodeIndex index1); + +}; + + + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VDPROGMESH_VHIERARCHY_HH defined +//============================================================================= diff --git a/Tools/VDPM/VHierarchyNode.hh b/Tools/VDPM/VHierarchyNode.hh new file mode 100644 index 00000000..8976109d --- /dev/null +++ b/Tools/VDPM/VHierarchyNode.hh @@ -0,0 +1,176 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= + +#ifndef OPENMESH_VDPROGMESH_VHIERARCHYNODE_HH +#define OPENMESH_VDPROGMESH_VHIERARCHYNODE_HH + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** Handle for vertex hierarchy nodes + */ +struct VHierarchyNodeHandle : public BaseHandle +{ + explicit VHierarchyNodeHandle(int _idx=-1) : BaseHandle(_idx) {} +}; + + +/// Invalid handle +static const VHierarchyNodeHandle InvalidVHierarchyNodeHandle; + + +/** Vertex hierarchy node + * \todo Complete documentation + */ +class VHierarchyNode +{ +public: + + VHierarchyNode() { } + + /// Returns true, if node is root else false. + bool is_root() const + { return (parent_handle_.is_valid() == false) ? true : false; } + + /// Returns true, if node is leaf else false. + bool is_leaf() const + { return (lchild_handle_.is_valid() == false) ? true : false; } + + /// Returns parent handle. + VHierarchyNodeHandle parent_handle() { return parent_handle_; } + + /// Returns handle to left child. + VHierarchyNodeHandle lchild_handle() { return lchild_handle_; } + + /// Returns handle to right child. + VHierarchyNodeHandle rchild_handle() + { return VHierarchyNodeHandle(lchild_handle_.idx()+1); } + + void set_parent_handle(VHierarchyNodeHandle _parent_handle) + { parent_handle_ = _parent_handle; } + + void set_children_handle(VHierarchyNodeHandle _lchild_handle) + { lchild_handle_ = _lchild_handle; } + + VertexHandle vertex_handle() const { return vh_; } + float radius() const { return radius_; } + const OpenMesh::Vec3f& normal() const { return normal_; } + float sin_square() const { return sin_square_; } + float mue_square() const { return mue_square_; } + float sigma_square() const { return sigma_square_; } + + void set_vertex_handle(OpenMesh::VertexHandle _vh) { vh_ = _vh; } + void set_radius(float _radius) { radius_ = _radius; } + void set_normal(const OpenMesh::Vec3f &_normal) { normal_ = _normal; } + + void set_sin_square(float _sin_square) { sin_square_ = _sin_square; } + void set_mue_square(float _mue_square) { mue_square_ = _mue_square; } + void set_sigma_square(float _sigma_square) { sigma_square_ = _sigma_square; } + + void set_semi_angle(float _semi_angle) + { float f=sinf(_semi_angle); sin_square_ = f*f; } + + void set_mue(float _mue) { mue_square_ = _mue * _mue; } + void set_sigma(float _sigma) { sigma_square_ = _sigma * _sigma; } + + const VHierarchyNodeIndex& node_index() const { return node_index_; } + const VHierarchyNodeIndex& fund_lcut_index() const + { return fund_cut_node_index_[0]; } + + const VHierarchyNodeIndex& fund_rcut_index() const + { return fund_cut_node_index_[1]; } + + VHierarchyNodeIndex& node_index() + { return node_index_; } + + VHierarchyNodeIndex& fund_lcut_index() { return fund_cut_node_index_[0]; } + VHierarchyNodeIndex& fund_rcut_index() { return fund_cut_node_index_[1]; } + + void set_index(const VHierarchyNodeIndex &_node_index) + { node_index_ = _node_index; } + + void set_fund_lcut(const VHierarchyNodeIndex &_node_index) + { fund_cut_node_index_[0] = _node_index; } + + void set_fund_rcut(const VHierarchyNodeIndex &_node_index) + { fund_cut_node_index_[1] = _node_index; } + +private: + VertexHandle vh_; + float radius_; + Vec3f normal_; + float sin_square_; + float mue_square_; + float sigma_square_; + + VHierarchyNodeHandle parent_handle_; + VHierarchyNodeHandle lchild_handle_; + + + VHierarchyNodeIndex node_index_; + VHierarchyNodeIndex fund_cut_node_index_[2]; +}; + +/// Container for vertex hierarchy nodes +typedef std::vector VHierarchyNodeContainer; + +/// Container for vertex hierarchy node handles +typedef std::vector VHierarchyNodeHandleContainer; + +/// Container for vertex hierarchy node handles +typedef std::list VHierarchyNodeHandleList; + + +//============================================================================= +} // namesapce VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VDPROGMESH_VHIERARCHYNODE_HH defined +//============================================================================= diff --git a/Tools/VDPM/VHierarchyNodeIndex.cc b/Tools/VDPM/VHierarchyNodeIndex.cc new file mode 100644 index 00000000..cd5c4af2 --- /dev/null +++ b/Tools/VDPM/VHierarchyNodeIndex.cc @@ -0,0 +1,55 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass - IMPLEMENTATION +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#include + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + + +//== IMPLEMENTATION ========================================================== + + +const VHierarchyNodeIndex +VHierarchyNodeIndex::InvalidIndex = VHierarchyNodeIndex(); + + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= + diff --git a/Tools/VDPM/VHierarchyNodeIndex.hh b/Tools/VDPM/VHierarchyNodeIndex.hh new file mode 100644 index 00000000..d8fdad9c --- /dev/null +++ b/Tools/VDPM/VHierarchyNodeIndex.hh @@ -0,0 +1,110 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= + +#ifndef OPENMESH_VDPROGMESH_VHIERARCHYNODEINDEX_HH +#define OPENMESH_VDPROGMESH_VHIERARCHYNODEINDEX_HH + +//== INCLUDES ================================================================= + +#include +#include + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** Index of vertex hierarchy node + */ + + +class VHierarchyNodeIndex +{ +private: + unsigned int value_; + +public: + + static const VHierarchyNodeIndex InvalidIndex; + +public: + + VHierarchyNodeIndex() + { value_ = 0; } + + VHierarchyNodeIndex(unsigned int _value) + { value_ = _value; } + + VHierarchyNodeIndex(const VHierarchyNodeIndex &_other) + { value_ = _other.value_; } + + VHierarchyNodeIndex(unsigned int _tree_id, + unsigned int _node_id, + unsigned short _tree_id_bits) + { + assert(_tree_id < ((unsigned int) 0x00000001 << _tree_id_bits)); + assert(_node_id < ((unsigned int) 0x00000001 << (32 - _tree_id_bits))); + value_ = (_tree_id << (32 - _tree_id_bits)) | _node_id; + } + + bool is_valid(unsigned short _tree_id_bits) const + { return node_id(_tree_id_bits) != 0 ? true : false; } + + unsigned int tree_id(unsigned short _tree_id_bits) const + { return value_ >> (32 - _tree_id_bits); } + + unsigned int node_id(unsigned short _tree_id_bits) const + { return value_ & ((unsigned int) 0xFFFFFFFF >> _tree_id_bits); } + + bool operator< (const VHierarchyNodeIndex &other) const + { return (value_ < other.value_) ? true : false; } + + unsigned int value() const + { return value_; } +}; + + +/// Container for vertex hierarchy node indices +typedef std::vector VHierarchyNodeIndexContainer; + + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VDPROGMESH_VHIERARCHYNODEINDEX_HH defined +//============================================================================= diff --git a/Tools/VDPM/VHierarchyWindow.cc b/Tools/VDPM/VHierarchyWindow.cc new file mode 100644 index 00000000..6ffd9e76 --- /dev/null +++ b/Tools/VDPM/VHierarchyWindow.cc @@ -0,0 +1,188 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass - IMPLEMENTATION +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#include + +#ifndef WIN32 +#include +#include +#endif + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + + +//== IMPLEMENTATION ========================================================== + + +VHierarchyWindow:: +VHierarchyWindow() +{ + vhierarchy_ = NULL; + buffer_ = NULL; + + buffer_min_ = 0; + buffer_max_ = 0; + + window_min_ = 0; + window_max_ = 0; + current_pos_ = 0; + + n_shift_ = 0; +} + + +VHierarchyWindow:: +VHierarchyWindow(VHierarchy &_vhierarchy) +{ + vhierarchy_ = &_vhierarchy; + buffer_ = NULL; +} + + +VHierarchyWindow:: +~VHierarchyWindow(void) +{ + if (buffer_ != NULL) + free(buffer_); +} + + +bool +VHierarchyWindow:: +update_buffer(VHierarchyNodeHandle _node_handle) +{ + if (underflow(_node_handle) != true && overflow(_node_handle) != true) + return false; + + // tightly update window_min_ & window_max_ + int none_zero_pos; + for (none_zero_pos=buffer_size()-1; none_zero_pos >= 0; --none_zero_pos) + { + if (buffer_[none_zero_pos] != 0) break; + } + window_max_ = buffer_min_ + none_zero_pos + 1; + for(none_zero_pos=0; none_zero_pos < buffer_size(); ++none_zero_pos) + { + if (buffer_[none_zero_pos] != 0) break; + } + window_min_ = buffer_min_ + none_zero_pos; + + assert(window_min_ < window_max_); + + while (underflow(_node_handle) == true) buffer_min_ /= 2; + while (overflow(_node_handle) == true) + { + buffer_max_ *= 2; + if (buffer_max_ > (int) vhierarchy_->num_nodes() / 8) + buffer_max_ = (int) (1 + vhierarchy_->num_nodes() / 8); + } + + unsigned char *new_buffer = (unsigned char *) malloc(buffer_size()); + memset(new_buffer, 0, buffer_size()); + memcpy(&(new_buffer[window_min_-buffer_min_]), + &(buffer_[none_zero_pos]), + window_size()); + free(buffer_); + buffer_ = new_buffer; + + return true; +} + +void +VHierarchyWindow::init(VHierarchyNodeHandleContainer &_roots) +{ + if (buffer_ != NULL) + free(buffer_); + + buffer_min_ = 0; + buffer_max_ = _roots.size() / 8; + if (_roots.size() % 8 > 0) + ++buffer_max_; + + buffer_ = (unsigned char *) malloc(buffer_size()); + memset(buffer_, 0, buffer_size()); + + window_min_ = 0; + window_max_= 0; + current_pos_ = 0; + n_shift_ = 0; + + for (unsigned int i=0; i<_roots.size(); i++) + { + activate(VHierarchyNodeHandle((int) i)); + } +} + + +void +VHierarchyWindow:: +update_with_vsplit(VHierarchyNodeHandle _parent_handle) +{ + VHierarchyNodeHandle + lchild_handle = vhierarchy_->lchild_handle(_parent_handle), + rchild_handle = vhierarchy_->rchild_handle(_parent_handle); + + assert(is_active(_parent_handle) == true); + assert(is_active(lchild_handle) != true); + assert(is_active(rchild_handle) != true); + + inactivate(_parent_handle); + activate(rchild_handle); + activate(lchild_handle); +} + +void +VHierarchyWindow:: +update_with_ecol(VHierarchyNodeHandle _parent_handle) +{ + VHierarchyNodeHandle + lchild_handle = vhierarchy_->lchild_handle(_parent_handle), + rchild_handle = vhierarchy_->rchild_handle(_parent_handle); + + assert(is_active(_parent_handle) != true); + assert(is_active(lchild_handle) == true); + assert(is_active(rchild_handle) == true); + + activate(_parent_handle); + inactivate(rchild_handle); + inactivate(lchild_handle); +} + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= diff --git a/Tools/VDPM/VHierarchyWindow.hh b/Tools/VDPM/VHierarchyWindow.hh new file mode 100644 index 00000000..1935bbc1 --- /dev/null +++ b/Tools/VDPM/VHierarchyWindow.hh @@ -0,0 +1,201 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= + +#ifndef OPENMESH_VDPROGMESH_VHIERARCHYWINDOWS_HH +#define OPENMESH_VDPROGMESH_VHIERARCHYWINDOWS_HH + + +//== INCLUDES ================================================================= + +#include + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** \todo VHierarchyWindow documentation +*/ +class VHierarchyWindow +{ +private: + + // reference of vertex hierarchy + VHierarchy *vhierarchy_; + + // bits buffer (byte units) + unsigned char *buffer_; + int buffer_min_; + int buffer_max_; + int current_pos_; + + // window (byte units) + int window_min_; + int window_max_; + + + // # of right shift (bit units) + unsigned char n_shift_; // [0, 7] + + unsigned char flag8(unsigned char n_shift) const + { return 0x80 >> n_shift; } + + unsigned char flag8(VHierarchyNodeHandle _node_handle) const + { + assert(_node_handle.idx() >= 0); + return 0x80 >> (unsigned int) (_node_handle.idx() % 8); + } + int byte_idx(VHierarchyNodeHandle _node_handle) const + { + assert(_node_handle.idx() >= 0); + return _node_handle.idx() / 8; + } + int buffer_idx(VHierarchyNodeHandle _node_handle) const + { return byte_idx(_node_handle) - buffer_min_; } + + bool before_window(VHierarchyNodeHandle _node_handle) const + { return (_node_handle.idx()/8 < window_min_) ? true : false; } + + bool after_window(VHierarchyNodeHandle _node_handle) const + { return (_node_handle.idx()/8 < window_max_) ? false : true; } + + bool underflow(VHierarchyNodeHandle _node_handle) const + { return (_node_handle.idx()/8 < buffer_min_) ? true : false; } + + bool overflow(VHierarchyNodeHandle _node_handle) const + { return (_node_handle.idx()/8 < buffer_max_) ? false : true; } + + bool update_buffer(VHierarchyNodeHandle _node_handle); + +public: + VHierarchyWindow(); + VHierarchyWindow(VHierarchy &_vhierarchy); + ~VHierarchyWindow(void); + + void set_vertex_hierarchy(VHierarchy &_vhierarchy) + { vhierarchy_ = &_vhierarchy; } + + void begin() + { + int new_window_min = window_min_; + for (current_pos_=window_min_-buffer_min_; + current_pos_ < window_size(); ++current_pos_) + { + if (buffer_[current_pos_] == 0) + ++new_window_min; + else + { + n_shift_ = 0; + while ((buffer_[current_pos_] & flag8(n_shift_)) == 0) + ++n_shift_; + break; + } + } + window_min_ = new_window_min; + } + + void next() + { + ++n_shift_; + if (n_shift_ == 8) + { + n_shift_ = 0; + ++current_pos_; + } + + while (current_pos_ < window_max_-buffer_min_) + { + if (buffer_[current_pos_] != 0) // if the current byte has non-zero bits + { + while (n_shift_ != 8) + { + if ((buffer_[current_pos_] & flag8(n_shift_)) != 0) + return; // find 1 bit in the current byte + ++n_shift_; + } + } + n_shift_ = 0; + ++current_pos_; + } + } + bool end() { return !(current_pos_ < window_max_-buffer_min_); } + + int window_size() const { return window_max_ - window_min_; } + int buffer_size() const { return buffer_max_ - buffer_min_; } + + VHierarchyNodeHandle node_handle() + { + return VHierarchyNodeHandle(8*(buffer_min_+current_pos_) + (int)n_shift_); + } + + void activate(VHierarchyNodeHandle _node_handle) + { + update_buffer(_node_handle); + buffer_[buffer_idx(_node_handle)] |= flag8(_node_handle); + window_min_ = std::min(window_min_, byte_idx(_node_handle)); + window_max_ = std::max(window_max_, 1+byte_idx(_node_handle)); + } + + + void inactivate(VHierarchyNodeHandle _node_handle) + { + if (is_active(_node_handle) != true) return; + buffer_[buffer_idx(_node_handle)] ^= flag8(_node_handle); + } + + + bool is_active(VHierarchyNodeHandle _node_handle) const + { + if (before_window(_node_handle) == true || + after_window(_node_handle) == true) + return false; + return ((buffer_[buffer_idx(_node_handle)] & flag8(_node_handle)) > 0); + } + + void init(VHierarchyNodeHandleContainer &_roots); + void update_with_vsplit(VHierarchyNodeHandle _parent_handle); + void update_with_ecol(VHierarchyNodeHandle _parent_handle); +}; + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VDPROGMESH_VHIERARCHYWINDOWS_HH +//============================================================================= + diff --git a/Tools/VDPM/ViewingParameters.cc b/Tools/VDPM/ViewingParameters.cc new file mode 100644 index 00000000..b1d2b591 --- /dev/null +++ b/Tools/VDPM/ViewingParameters.cc @@ -0,0 +1,142 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass - IMPLEMENTATION +// +//============================================================================= + + +//== INCLUDES ================================================================= + +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + + +//== IMPLEMENTATION ========================================================== + + +ViewingParameters:: +ViewingParameters() +{ + fovy_ = 45.0f; + aspect_ = 1.0f; + tolerance_square_ = 0.001f; +} + +void +ViewingParameters:: +update_viewing_configurations() +{ + // |a11 a12 a13|-1 | a33a22-a32a23 -(a33a12-a32a13) a23a12-a22a13 | + // |a21 a22 a23| = 1/DET*|-(a33a21-a31a23) a33a11-a31a13 -(a23a11-a21a13)| + // |a31 a32 a33| | a32a21-a31a22 -(a32a11-a31a12) a22a11-a21a12 | + // DET = a11(a33a22-a32a23)-a21(a33a12-a32a13)+a31(a23a12-a22a13) + + float invdet; + float a11, a12, a13, a21, a22, a23, a31, a32, a33; + Vec3f inv_rot[3], trans; + + a11 = (float) modelview_matrix_[0]; + a12 = (float) modelview_matrix_[4]; + a13 = (float) modelview_matrix_[8]; + trans[0] = (float) modelview_matrix_[12]; + + a21 = (float) modelview_matrix_[1]; + a22 = (float) modelview_matrix_[5]; + a23 = (float) modelview_matrix_[9]; + trans[1] = (float) modelview_matrix_[13]; + + a31 = (float) modelview_matrix_[2]; + a32 = (float) modelview_matrix_[6]; + a33 = (float) modelview_matrix_[10]; + trans[2] = (float) modelview_matrix_[14]; + + invdet=a11*(a33*a22-a32*a23) - a21*(a33*a12-a32*a13) + a31*(a23*a12-a22*a13); + invdet= (float) 1.0/invdet; + + (inv_rot[0])[0] = (a33*a22-a32*a23) * invdet; + (inv_rot[0])[1] = -(a33*a12-a32*a13) * invdet; + (inv_rot[0])[2] = (a23*a12-a22*a13) * invdet; + (inv_rot[1])[0] = -(a33*a21-a31*a23) * invdet; + (inv_rot[1])[1] = (a33*a11-a31*a13) * invdet; + (inv_rot[1])[2] = -(a23*a11-a21*a13) * invdet; + (inv_rot[2])[0] = (a32*a21-a31*a22) * invdet; + (inv_rot[2])[1] = -(a32*a11-a31*a12) * invdet; + (inv_rot[2])[2] = (a22*a11-a21*a12) * invdet; + + eye_pos_ = - Vec3f(dot(inv_rot[0], trans), + dot(inv_rot[1], trans), + dot(inv_rot[2], trans)); + right_dir_ = Vec3f(a11, a12, a13); + up_dir_ = Vec3f(a21, a22, a23); + view_dir_ = - Vec3f(a31, a32, a33); + + Vec3f normal[4]; + //float aspect = width() / height(); + float half_theta = fovy() * 0.5f; + float half_phi = atanf(aspect() * tanf(half_theta)); + + float sin1 = sinf(half_theta); + float cos1 = cosf(half_theta); + float sin2 = sinf(half_phi); + float cos2 = cosf(half_phi); + + normal[0] = cos2 * right_dir_ + sin2 * view_dir_; + normal[1] = -cos1 * up_dir_ - sin1 * view_dir_; + normal[2] = -cos2 * right_dir_ + sin2 * view_dir_; + normal[3] = cos1 * up_dir_ - sin1 * view_dir_; + + for (int i=0; i<4; i++) + frustum_plane_[i] = Plane3d(normal[i], eye_pos_); +} + +void +ViewingParameters:: +PrintOut() +{ + std::cout << " ModelView matrix: " << std::endl; + std::cout << " |" << modelview_matrix_[0] << " " << modelview_matrix_[4] << " " << modelview_matrix_[8] << " " << modelview_matrix_[12] << "|" << std::endl; + std::cout << " |" << modelview_matrix_[1] << " " << modelview_matrix_[5] << " " << modelview_matrix_[9] << " " << modelview_matrix_[13] << "|" << std::endl; + std::cout << " |" << modelview_matrix_[2] << " " << modelview_matrix_[6] << " " << modelview_matrix_[10] << " " << modelview_matrix_[14] << "|" << std::endl; + std::cout << " |" << modelview_matrix_[3] << " " << modelview_matrix_[7] << " " << modelview_matrix_[11] << " " << modelview_matrix_[15] << "|" << std::endl; + std::cout << " Fovy: " << fovy_ << std::endl; + std::cout << " Aspect: " << aspect_ << std::endl; + std::cout << " Tolerance^2: " << tolerance_square_ << std::endl; + std::cout << " Eye Pos: " << eye_pos_ << std::endl; + std::cout << " Right dir: " << right_dir_ << std::endl; + std::cout << " Up dir: " << up_dir_ << std::endl; + std::cout << " View dir: " << view_dir_ << std::endl; +} + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= diff --git a/Tools/VDPM/ViewingParameters.hh b/Tools/VDPM/ViewingParameters.hh new file mode 100644 index 00000000..c309e29c --- /dev/null +++ b/Tools/VDPM/ViewingParameters.hh @@ -0,0 +1,124 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-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. * + * * +\*===========================================================================*/ + +//============================================================================= +// +// CLASS newClass +// +//============================================================================= + +#ifndef OPENMESH_VDPROGMESH_VIEWINGPARAMETERS_HH +#define OPENMESH_VDPROGMESH_VIEWINGPARAMETERS_HH + + +//== INCLUDES ================================================================= + +#include +#include + + +//== FORWARDDECLARATIONS ====================================================== + + +//== NAMESPACES =============================================================== + +namespace OpenMesh { +namespace VDPM { + +//== CLASS DEFINITION ========================================================= + + +/** \todo ViewerParameters documentation + */ +class ViewingParameters +{ +private: + double modelview_matrix_[16]; + float fovy_; + float aspect_; + float tolerance_square_; + + Vec3f eye_pos_; + Vec3f right_dir_; + Vec3f up_dir_; + Vec3f view_dir_; + + Plane3d frustum_plane_[4]; + +public: + + ViewingParameters(); + + void increase_tolerance() { tolerance_square_ *= 5.0f; } + void decrease_tolerance() { tolerance_square_ /= 5.0f; } + + float fovy() const { return fovy_; } + float aspect() const { return aspect_; } + float tolerance_square() const { return tolerance_square_; } + + void set_fovy(float _fovy) { fovy_ = _fovy; } + void set_aspect(float _aspect) { aspect_ = _aspect; } + void set_tolerance_square(float _tolerance_square) { tolerance_square_ = _tolerance_square; } + + const Vec3f& eye_pos() const { return eye_pos_; } + const Vec3f& right_dir() const { return right_dir_; } + const Vec3f& up_dir() const { return up_dir_; } + const Vec3f& view_dir() const { return view_dir_; } + Vec3f& eye_pos() { return eye_pos_; } + Vec3f& right_dir() { return right_dir_; } + Vec3f& up_dir() { return up_dir_; } + Vec3f& view_dir() { return view_dir_; } + + void frustum_planes( Plane3d _plane[4] ) + { + for (unsigned int i=0; i<4; ++i) + _plane[i] = frustum_plane_[i]; + } + + void get_modelview_matrix(double _modelview_matrix[16]) + { + for (unsigned int i=0; i<16; ++i) + _modelview_matrix[i] = modelview_matrix_[i]; + } + + void set_modelview_matrix(const double _modelview_matrix[16]) + { + for (unsigned int i=0; i<16; ++i) + modelview_matrix_[i] = _modelview_matrix[i]; + } + + void update_viewing_configurations(); + + void PrintOut(); +}; + + +//============================================================================= +} // namespace VDPM +} // namespace OpenMesh +//============================================================================= +#endif // OPENMESH_VDPROGMESH_VIEWINGPARAMETERS_HH defined +//============================================================================= + diff --git a/Tools/VDPM/xpm/fileopen.xpm b/Tools/VDPM/xpm/fileopen.xpm new file mode 100644 index 00000000..a46d3f7d --- /dev/null +++ b/Tools/VDPM/xpm/fileopen.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static const char *fileopen[] = { +" 16 13 5 1", +". c #040404", +"# c #808304", +"a c None", +"b c #f3f704", +"c c #f3f7f3", +"aaaaaaaaa...aaaa", +"aaaaaaaa.aaa.a.a", +"aaaaaaaaaaaaa..a", +"a...aaaaaaaa...a", +".bcb.......aaaaa", +".cbcbcbcbc.aaaaa", +".bcbcbcbcb.aaaaa", +".cbcb...........", +".bcb.#########.a", +".cb.#########.aa", +".b.#########.aaa", +"..#########.aaaa", +"...........aaaaa" +}; diff --git a/Tools/VDPM/xpm/fileprint.xpm b/Tools/VDPM/xpm/fileprint.xpm new file mode 100644 index 00000000..629102dc --- /dev/null +++ b/Tools/VDPM/xpm/fileprint.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static const char *fileprint[] = { +" 16 14 6 1", +". c #000000", +"# c #848284", +"a c #c6c3c6", +"b c #ffff00", +"c c #ffffff", +"d c None", +"ddddd.........dd", +"dddd.cccccccc.dd", +"dddd.c.....c.ddd", +"ddd.cccccccc.ddd", +"ddd.c.....c....d", +"dd.cccccccc.a.a.", +"d..........a.a..", +".aaaaaaaaaa.a.a.", +".............aa.", +".aaaaaa###aa.a.d", +".aaaaaabbbaa...d", +".............a.d", +"d.aaaaaaaaa.a.dd", +"dd...........ddd" +}; diff --git a/Tools/VDPM/xpm/filesave.xpm b/Tools/VDPM/xpm/filesave.xpm new file mode 100644 index 00000000..d944b63b --- /dev/null +++ b/Tools/VDPM/xpm/filesave.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static const char *filesave[] = { +" 14 14 4 1", +". c #040404", +"# c #808304", +"a c #bfc2bf", +"b c None", +"..............", +".#.aaaaaaaa.a.", +".#.aaaaaaaa...", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".#.aaaaaaaa.#.", +".##........##.", +".############.", +".##.........#.", +".##......aa.#.", +".##......aa.#.", +".##......aa.#.", +"b............." +}; diff --git a/VERSION b/VERSION new file mode 100644 index 00000000..23d6d35c --- /dev/null +++ b/VERSION @@ -0,0 +1,2 @@ +2-0 +$Name: $ diff --git a/migrate.sh b/migrate.sh new file mode 100644 index 00000000..b2a7d99a --- /dev/null +++ b/migrate.sh @@ -0,0 +1,209 @@ +#!/bin/sh +# +# $Id: migrate.sh,v 1.1.1.1 2006-10-25 16:13:26 habbecke Exp $ + +if [ "$1" == "-s" ]; then + shift 1 + show_skipped=1 +fi + +echo "This script prepares your source for OpenMesh Version 1-0-x" +echo +echo "Warning! This script visits ALL subdirectories of the current" +echo "working directory and" +echo +echo " 1. changes includes path in text files" +echo " 2. changes any occurence of 'MeshIO' into 'IO'" +echo " 3. changes any occurence of 'DefaultAttributer' into 'Attributes'" +echo " 4. changes any occurence of 'Attributer.hh' into 'Attributes.hh'" +echo " 5. changes any occurence of 'Base::Refs::*' into 'Refs::*'" +echo " 6. changes in all ACGMakefile the OpenMesh library names" +echo "" +echo -n "Proceed [yes/NO]? " +read +if [ -z $REPLY ] || [ $REPLY != "yes" ]; then + echo "Aborted!" + exit 0 +fi + +# ------------------------------------------------------------------------------ +# include path + +echo "" +echo "# changing include paths" +TMP=`grep -rl include .` +for I in $TMP ; do + if [[ "$I" != *_dbg* ]] && [[ $I != *_max* ]] && \ + [[ "$I" != *_opt* ]] && [[ $I != *_prf* ]] && \ + [[ "$I" != *.so ]]; then + + echo -n "processing $I.." + # "correct" include path to MeshCheckerT.hh + # OpenMesh/Tools/MeshCheckerT.hh -> OpenMeshTools/Utils/MeshCheckerT.hh + if (grep -q "include.*OpenMesh/Tools/MeshCheckerT.hh" $I); then + cat $I | \ + perl -pe 's/^(\s*#\s*include\s*<.*)\/Tools\/MeshCheckerT.hh/\1Tools\/Utils\/MeshCheckerT.hh/' > $I.out + mv $I.out $I + if [ $? -eq 0 ]; then + echo -n "." + fi + fi + + # correct include path to modules + if (grep -q "include.*OpenMesh" $I) && \ + !(grep -q "include.*OpenMesh/Core" $I) && \ + !(grep -q "include.*OpenMesh/Tools" $I) && \ + !(grep -q "include.*OpenMesh/Apps" $I); then + cat $I | \ + perl -pe 's/^(\s*#\s*include\s*<)\s*OpenMesh(\/.*)$/\1OpenMesh\/Core\2/' | \ + perl -pe 's/^(\s*#\s*include\s*<)\s*OpenMeshTools(\/.*)$/\1OpenMesh\/Tools\2/' | \ + perl -pe 's/^(\s*#\s*include\s*<)\s*OpenMeshApps(\/.*)$/\1OpenMesh\/Apps\2/' > $I.out + + mv $I.out $I + if [ $? -gt 0 ]; then + echo "ERROR" + else + echo "done" + fi + elif (($show_skipped)); then + echo "skipped" + else + echo -ne "\r \r" + fi + + fi +done + +# ------------------------------------------------------------------------------ +echo "# changing namespaces" +TMP=`grep -rl MeshIO .` +for I in $TMP ; do + if [[ "$I" != *_dbg* ]] && [[ $I != *_max* ]] && \ + [[ "$I" != *_opt* ]] && [[ $I != *_prf* ]] && \ + [[ "$I" != *.so ]]; then + + echo -n "processing $I.." + if (grep -qE "MeshIO[^\.h]" $I); then + cat $I | \ + perl -pe 's/MeshIO([^\.h])/IO\1/' > $I.out + mv $I.out $I + if [ $? -gt 0 ]; then + echo "ERROR" + else + echo "done" + fi + elif (($show_skipped)); then + echo "skipped" + else + echo -ne "\r \r" + fi + fi +done + +# ------------------------------------------------------------------------------ +echo "# Change DefaultAttributer to Attributes" +TMP=`grep -rl DefaultAttributer .` +for I in $TMP ; do + if [[ "$I" != *_dbg* ]] && [[ $I != *_max* ]] && \ + [[ "$I" != *_opt* ]] && [[ $I != *_prf* ]] && \ + [[ "$I" != *.so ]]; then + + echo -n "processing $I.." + if (grep -qE "DefaultAttributer" $I); then + cat $I | \ + perl -pe 's/DefaultAttributer/Attributes/' > $I.out + mv $I.out $I + if [ $? -gt 0 ]; then + echo "ERROR" + else + echo "done" + fi + elif (($show_skipped)); then + echo "skipped" + else + echo -ne "\r \r" + fi + fi +done + +# ------------------------------------------------------------------------------ +echo "# Change Attributer.hh to Attributes.hh" +TMP=`grep -rl Attributer.hh .` +for I in $TMP ; do + if [[ "$I" != *_dbg* ]] && [[ $I != *_max* ]] && \ + [[ "$I" != *_opt* ]] && [[ $I != *_prf* ]] && \ + [[ "$I" != *.so ]]; then + + echo -n "processing $I.." + if (grep -q "Attributer.hh" $I); then + cat $I | \ + perl -pe 's/Attributer\.hh/Attributes.hh/' > $I.out + mv $I.out $I + if [ $? -gt 0 ]; then + echo "ERROR" + else + echo "done" + fi + elif (($show_skipped)); then + echo "skipped" + else + echo -ne "\r \r" + fi + fi +done + +# ------------------------------------------------------------------------------ +echo "# Change Base::Refs::* to Refs::*" +TMP=`grep -rl Base::Refs:: .` +for I in $TMP ; do + if [[ "$I" != *_dbg* ]] && [[ $I != *_max* ]] && \ + [[ "$I" != *_opt* ]] && [[ $I != *_prf* ]] && \ + [[ "$I" != *.so ]]; then + + echo -n "processing $I.." + if (grep -q "Base::Refs::" $I); then + cat $I | \ + perl -pe 's/Base::Refs::/Refs::/' > $I.out + mv $I.out $I + if [ $? -gt 0 ]; then + echo "ERROR" + else + echo "done" + fi + elif (($show_skipped)); then + echo "skipped" + else + echo -ne "\r \r" + fi + fi +done + +# ------------------------------------------------------------------------------ +echo "# changing ACGMakefiles" +for I in `find . -name 'ACGMakefile'`; do + if [[ "$I" != *_dbg* ]] && [[ $I != *_max* ]] && \ + [[ "$I" != *_opt* ]] && [[ $I != *_prf* ]] && \ + [[ "$I" != *.so ]]; then + + echo -n "processing $I.." + if (grep -q ".*OpenMesh" $I) && \ + !(grep -q ".*OpenMesh/Core" $I) && \ + !(grep -q ".*OpenMesh/Apps" $I); then + cat $I | \ + perl -pe 's/OpenMesh/OpenMesh\/Core/' | \ + perl -pe 's/OpenMeshApps/OpenMesh\/Apps/' > $I.out + mv $I.out $I + if [ $? -gt 0 ]; then + echo "ERROR" + else + echo "done"; + fi + elif (($show_skipped)); then + echo "skipped" + else + echo -ne "\r \r" + fi + fi +done + + diff --git a/openmesh/templates/cpp_template b/openmesh/templates/cpp_template new file mode 100644 index 00000000..cef60339 --- /dev/null +++ b/openmesh/templates/cpp_template @@ -0,0 +1,25 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) |YEAR| by |AUTHOR| * + * |EMAIL| * + * * + *---------------------------------------------------------------------------* + * * + * 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. * + * * +\*===========================================================================*/ + diff --git a/openmesh/templates/header_template b/openmesh/templates/header_template new file mode 100644 index 00000000..77f6ab38 --- /dev/null +++ b/openmesh/templates/header_template @@ -0,0 +1,24 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) |YEAR| by |AUTHOR| * + * |EMAIL| * + * * + *---------------------------------------------------------------------------* + * * + * 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. * + * * +\*===========================================================================*/ diff --git a/porting.txt b/porting.txt new file mode 100644 index 00000000..fcbdd6eb --- /dev/null +++ b/porting.txt @@ -0,0 +1,45 @@ +Porting to OpenMesh 1.0: +======================== + +(Numbered items are handled by migrate.sh!) + +1 Include path has changed due to the change of the directory + structure. Therefore one has to modifiy the include path as follows: + + OpenMeshApps -> OpenMesh/Apps + OpenMeshTools -> OpenMesh/Tools + OpenMesh -> OpenMesh/Core + +2 Namespace "MeshIO" has been renamed to "IO". + +3 DefaultAttributer has been removed: + replace DefaultAttributer::* by Attributes::* + +4 Replace by + + +5 Replace Base::Refs::* by Refs::* in Traits + +6 The entry PROJ_LIBS in the ACGMakefiles have to be adjusted similarly to 1. + +* When using I/O functionality make sure that MeshIO.hh is included + before any kernel type has been included. + +* Vector cast is now explicit, have to insert (Vec3f) + +* Replace Mesh::point(Vertex&) by Mesh::point(VertexHandle): + mesh.point(*v_it) -> mesh.point(v_it) + +* Replace Vertex::{color(),normal(),texcoord()} by + mesh_.{color,normal,texcoord}(vh) + +* Replace Vertex::set_{color(),normal(),texcoord()} by + mesh_.set_{color,normal,texcoord}(VertexHandle, *) + +* Replace Face::{color(),normal()} by + mesh_.{color,normal}(FaceHandle) + +* Replace Face::set_{color(),normal()} by + mesh_.set_{color,normal}(FaceHandle, *) + +* Status: mesh.status(vh).locked() diff --git a/qmake/all.include b/qmake/all.include new file mode 100644 index 00000000..b6ff179e --- /dev/null +++ b/qmake/all.include @@ -0,0 +1,167 @@ + +################################################################################ +# This is a library +################################################################################ + + +################################################################################ +# Needed Qt packages and build plugin +################################################################################ + +CONFIG += qt uitools opengl thread debug_and_release + +QT += opengl network script sql webkit + +################################################################################ +# Add toplevel directory to include path +# TOPDIR has to be specified in a .qmake.cach file in your projects toplevel +# directory +################################################################################ +INCLUDEPATH = $$quote( $${TOPDIR} ) +DEPENDPATH = $$quote( $${TOPDIR} ) + +################################################################################ +# Define header Extension +# This will also override the header extension for uic output +# ( Do not change to += otherwise uic output will end with .h ! ) +################################################################################ +QMAKE_EXT_H = .hh .h + +################################################################################ +# Architecture detection +################################################################################ +include( architecture.include ) + +################################################################################ +# Helper functions +################################################################################ +include( functions.include ) + +################################################################################ +# Custom settings for compiler flags and similar +################################################################################ +include( compiler.include) + +################################################################################ +# Extra target definitions +################################################################################ +include( targets.include ) + +################################################################################ +# Global package definitions +################################################################################ +include( packages/packages.$${SYSTEMTYPE} ) + +################################################################################ +# Local package definitions +# These lines will include a file from a .qmake directory inside your home. +# this file will overwrite existing setting +################################################################################ + +unix { + HOME=$$system(echo ~) +} +#else { + #message( TODO : Define Home in Windows ) +#} + +exists( $${HOME}/.qmake/config.$${SYSTEMTYPE} ) { + include( $${HOME}/.qmake/config.$${SYSTEMTYPE} ) +} + +################################################################################ +# Set standard build directories +# ( Everything generated while compiling will go # into a per architecture +# directory ) +################################################################################ +OBJECTS_DIR = tmp/$$BUILDDIRECTORY +MOC_DIR = tmp/$$BUILDDIRECTORY +UI_DIR = tmp/$$BUILDDIRECTORY + +################################################################################ +# type definitions +################################################################################ + +# This function sets all parameters required to build a plugin +defineTest(Plugin) { + unix{ + TEMPLATE = lib + } + win32 { + TEMPLATE = vclib + TARGET = $$replace(TARGET, - , _) + export(TARGET) + QMAKE_INCDIR += $${TOPDIR}/OpenFlipper/BasePlugin + export(QMAKE_INCDIR) + LIBS+= -L$${TOPDIR}/OpenFlipper/$${BUILDDIRECTORY} -lPluginLib + export(LIBS) + DEPENDPATH += $${TOPDIR}/OpenFlipper/$${BUILDDIRECTORY} + DEFINES += ACGDLL USEACG + export(DEFINES) + export(DEPENDPATH) + glut() + } + macx { + glut() + } + export(TEMPLATE) + CONFIG *= plugin + export(CONFIG) + DESTDIR = $${TOPDIR}/OpenFlipper/Plugins/$${SYSTEMTYPE}/$${ARCHITECTURE}/$${MODE} + export(DESTDIR) + acg() + openmesh() + glew() + defineTargets() +} + +defineTest(Library) { + unix{ + TEMPLATE = lib + contains( OPERATING_SYSTEM, Darwin) { + CONFIG -= static + export(CONFIG) + } + } + win32 { + TEMPLATE = vclib + } + export(TEMPLATE) + DESTDIR = lib/$$BUILDDIRECTORY + export(DESTDIR) + defineTargets() + UI_DIR = include + export(UI_DIR) +} + +defineTest(Application) { + unix { + TEMPLATE = app + } + win32 { + TEMPLATE = vcapp + } + macx { + CONFIG -= app_bundle + export( CONFIG ) + } + export(TEMPLATE) + DESTDIR = $$BUILDDIRECTORY + export(DESTDIR) + defineTargets() +} + + +defineTest(Subdirs) { + unix { + TEMPLATE = subdirs + } + win32 { + TEMPLATE = vcsubdirs + } + export(TEMPLATE) + CONFIG += ordered + export(CONFIG) + defineTargets() +} + diff --git a/qmake/architecture.include b/qmake/architecture.include new file mode 100644 index 00000000..a365f1a7 --- /dev/null +++ b/qmake/architecture.include @@ -0,0 +1,86 @@ + +################################################################################ +# Architecture detection +# The following Variables are defined by this include: +# OPERATING_SYSTEM : Debian / Fedora / Windows +# ARCHITECTURE : 32 / 64 +# MODE : Debug / Release +# BUILDDIRECTORY : Concat of all above variables sesparated by underscores e.g. Debian_64_debug +################################################################################ + +unix { + + OPERATING_SYSTEM = UNKNOWN_OS + + exists( /etc/debian_version ) | exists( /etc/debian_release ) { + OPERATING_SYSTEM = Debian + } + + exists( /etc/fedora-release ) { + OPERATING_SYSTEM = Fedora + } + + exists( /etc/gentoo-release ) { + OPERATING_SYSTEM = Gentoo + } + + exists( /etc/lfs-release ) { + OPERATING_SYSTEM = Linux_From_Scratch + } + + exists( /etc/mandrake-release ) | exists( /etc/mandrakelinux-release ) { + OPERATING_SYSTEM = Mandrake + } + + exists( /etc/mandriva-release ) { + OPERATING_SYSTEM = Mandriva + } + + exists( /etc/redhat-release ) | exists( /etc/redhat_version ) { + OPERATING_SYSTEM = Redhat + } + + exists( /etc/SuSE-release ) | exists( /etc/novell-release ) { + OPERATING_SYSTEM = SuSE + } + + exists( /etc/lsb-release ) { + OPERATING_SYSTEM = Ubuntu + } + + TEST_DARWIN = $$system(uname -s) + contains( TEST_DARWIN, Darwin) { + OPERATING_SYSTEM = Darwin + DEFINES += ARCH_DARWIN + export(DEFINES) + } + + HARDWARE_PLATFORM = $$system(uname -a) + contains( HARDWARE_PLATFORM, x86_64 ) { + # 64-bit Linux + ARCHITECTURE = 64 + } else { + # 32-bit Linux + ARCHITECTURE = 32 + } + + contains(TEST_DARWIN, Darwin) { + SYSTEMTYPE = Darwin + } else { + SYSTEMTYPE = Linux + } +} + +win32 { + OPERATING_SYSTEM = Windows + ARCHITECTURE = 32 + SYSTEMTYPE = Windows +} + +CONFIG( debug, debug|release ){ + MODE = Debug +} else { + MODE = Release +} + +BUILDDIRECTORY = $${OPERATING_SYSTEM}_$${ARCHITECTURE}_$${MODE} diff --git a/qmake/compiler.include b/qmake/compiler.include new file mode 100644 index 00000000..88a4b8be --- /dev/null +++ b/qmake/compiler.include @@ -0,0 +1,18 @@ +################################################################################ +# Custom settings for compiler flags and similar +################################################################################ + +unix { + QMAKE_CC = gcc-4.3 + QMAKE_CXX = g++-4.3 + macx { + QMAKE_CC = gcc-4.0 + QMAKE_CXX = g++-4.0 + } + + QMAKE_CFLAGS_RELEASE = -O3 -DINCLUDE_TEMPLATES -W -Wall -Wno-unused -DNDEBUG + QMAKE_CXXFLAGS_RELEASE = -O3 -DINCLUDE_TEMPLATES -ftemplate-depth-100 -W -Wall -Wno-unused -DNDEBUG + QMAKE_CFLAGS_DEBUG = -g -DINCLUDE_TEMPLATES -W -Wall -Wno-unused -DDEBUG + QMAKE_CXXFLAGS_DEBUG = -g -DINCLUDE_TEMPLATES -ftemplate-depth-100 -W -Wall -Wno-unused -DDEBUG +} + diff --git a/qmake/functions.include b/qmake/functions.include new file mode 100644 index 00000000..5e5771c6 --- /dev/null +++ b/qmake/functions.include @@ -0,0 +1,76 @@ + +################################################################################ +# functions collecting all headers in the directory +################################################################################ + +# getFilesFromDir( directory, pattern ) +# returns a list of all files matching pattern in directory +defineReplace(getFilesFromDir) { + dirs = $$1 + pattern = $$2 + + files = + + for(dir, dirs) { + found = $$files( $${dir}/$${pattern} ) + files += $$found + } + + return( $$files ) +} + +# addSubdirs(subdirs,deps): Adds directories to the project that depend on +# other directories +defineTest( addSubdirs ) { + for(subdirs, 1) { + entries = $$files($$subdirs) + for(entry, entries) { + name = $$replace(entry, [/\\\\], _) + name = $$replace(name, - , _) + SUBDIRS += $$name + eval ($${name}.subdir = $$entry) + for(dep, 2): { + tempval = $$replace(dep, [/\\\\], _) + eval ($${name}.depends += $$replace(tempval, - , _) ) + } + export ($${name}.subdir) + export ($${name}.depends) + } + } + export (SUBDIRS) +} + +# given a list of paths and a libname this function checks if the lib is there +# adds the path and returns true if found otherwise false +defineTest( addLib ) { + dirs = $$1 + name = $$2 + + # check for the library + for(dir , dirs) { + check = $${dir}/lib$${name}.so + + # Found, so use it + exists( $$check ) { + LIBS *= -L$${dir} -l$$name + export(LIBS) + return(true) + } + } + + return(false) +} + + +defineReplace( getCurrentDir ) { + DIR = '' + unix { + DIR = $$system( pwd ) + } + + win32 { + DIR = $$system( cd ) + } + + return( $$DIR ) +} diff --git a/qmake/packages/packages.Darwin b/qmake/packages/packages.Darwin new file mode 100644 index 00000000..29107b03 --- /dev/null +++ b/qmake/packages/packages.Darwin @@ -0,0 +1,30 @@ + +################################################################################ +# INCLUDE Packages +################################################################################ + +defineTest( qt ) { + QT += opengl network script sql + export(QT) +} + +defineTest( glew ) { + INCLUDEPATH *= /Users/sattler/acg/glew/include/GL + export(INCLUDEPATH) + LIBS *= -L/Users/sattler/acg/glew/lib -lGLEW + export(LIBS) +} + +defineTest( glut ) { + INCLUDEPATH *= /System/Library/Frameworks/GLUT.framework/Headers + export(INCLUDEPATH) + LIBS *= -framework GLUT + export(LIBS) +} + +defineTest( openmesh ) { + QMAKE_LIBDIR += $${TOPDIR}/OpenMesh/Core/lib/$${BUILDDIRECTORY} + LIBS+= -install_name$${TOPDIR}/OpenMesh/Core/lib/$${BUILDDIRECTORY} -lCore + export(QMAKE_LIBDIR) + export(LIBS) +} diff --git a/qmake/packages/packages.Linux b/qmake/packages/packages.Linux new file mode 100644 index 00000000..fcf1f885 --- /dev/null +++ b/qmake/packages/packages.Linux @@ -0,0 +1,62 @@ + +################################################################################ +# INCLUDE Packages +################################################################################ + +defineTest( qt ) { + CONFIG *= uitools + export(CONFIG) + QT += opengl network script sql + export(QT) +} + +defineTest( qwt ) { + INCLUDEPATH *= /usr/include/qwt-qt4/ + export(INCLUDEPATH) + LIBS *= -L/usr/lib/ -lqwt-qt4 + export(LIBS) +} + +defineTest( glew ) { + INCLUDEPATH *= /usr/include/GL + export(INCLUDEPATH) + LIBS *= -L/usr/lib -lGLEW + export(LIBS) +} + +defineTest( glut ) { + INCLUDEPATH *=$${ACG}/OpenGL/include + export(INCLUDEPATH) + LIBS *= -L/usr/X11R6/lib -lglut + export(LIBS) +} + +defineTest( openmesh ) { + QMAKE_LIBDIR += $${TOPDIR}/OpenMesh/Core/lib/$${BUILDDIRECTORY} + LIBS+= -Wl,-rpath=$${TOPDIR}/OpenMesh/Core/lib/$${BUILDDIRECTORY} -lCore + export(QMAKE_LIBDIR) + export(LIBS) +} + +defineTest( openmp ) { + + addLib( /usr/lib/gcc/x86_64-linux-gnu/4.3 /usr/lib, gomp ) { + + QMAKE_CXXFLAGS_RELEASE += -fopenmp + QMAKE_CXXFLAGS_DEBUG += -fopenmp + QMAKE_CFLAGS_RELEASE += -fopenmp + QMAKE_CFLAGS_DEBUG += -fopenmp + QMAKE_LFLAGS_DEBUG += -fopenmp + QMAKE_LFLAGS_RELEASE += -fopenmp + + export(QMAKE_CXXFLAGS_RELEASE) + export(QMAKE_CFLAGS_RELEASE) + export(QMAKE_CXXFLAGS_DEBUG) + export(QMAKE_CFLAGS_DEBUG) + export(QMAKE_LFLAGS_DEBUG) + export(QMAKE_LFLAGS_RELEASE) + } else { + message("Unable to find OpenMP lib for linking. OpenMP support will be disabled!!") + } + +} \ No newline at end of file diff --git a/qmake/packages/packages.Windows b/qmake/packages/packages.Windows new file mode 100644 index 00000000..5105e09c --- /dev/null +++ b/qmake/packages/packages.Windows @@ -0,0 +1,41 @@ + +################################################################################ +# INCLUDE Packages +################################################################################ + + +defineTest( glew ) { + INCLUDEPATH *= c:\glew\include + export(INCLUDEPATH) + LIBS *= -Lc:\glew\lib -lglew32 + export(LIBS) +} + +defineTest( qt ) { + +} + +defineTest( glut ) { + INCLUDEPATH *= c:\glut\include + export(INCLUDEPATH) + LIBS *= -Lc:\glut\lib -lglut32 + export(LIBS) +} + +defineTest( openmp ) { + QMAKE_CXXFLAGS_DEBUG += /openmp + QMAKE_CXXFLAGS_RELEASE += /openmp + export(QMAKE_CXXFLAGS_DEBUG) + export(QMAKE_CXXFLAGS_RELEASE) +} + +defineTest( openmesh ) { + DEFINES += _USE_MATH_DEFINES NOMINMAX + QMAKE_LIBDIR += $${TOPDIR}/OpenMesh/Core/lib/$${BUILDDIRECTORY} + LIBS+= -L$${TOPDIR}/OpenMesh/Core/lib/$${BUILDDIRECTORY} -lCore + LIBS+= -L$${TOPDIR}/OpenMesh/Tools/lib/$${BUILDDIRECTORY} -lTools + export(DEFINES) + export(QMAKE_LIBDIR) + export(LIBS) +} + diff --git a/qmake/targets.include b/qmake/targets.include new file mode 100644 index 00000000..57da389c --- /dev/null +++ b/qmake/targets.include @@ -0,0 +1,126 @@ +################################################################################ +# Custom targets +################################################################################ + +defineTest( defineTargets ) { + + # internal target ... Use allclean instead! + # cleanDirs target called by subAllclean. + # removes all lib tmp and Builddirectories created by these qmake scripts + !contains( QMAKE_EXTRA_TARGETS , cleanDirs) { + # Remove temp dirs when doing allclean + cleanDirs.target = cleanDirs + cleanDirs.commands = rm -rf tmp + + contains( TEMPLATE, app ) { + cleanDirs.commands += ; rm -rf $${BUILDDIRECTORY} + } + + + contains( TEMPLATE, lib ) { + cleanDirs.commands += ; rm -rf lib + } + + export(cleanDirs.target) + export(cleanDirs.commands) + export(cleanDirs.depends) + export(cleanDirs.CONFIG) + + QMAKE_EXTRA_TARGETS += cleanDirs + export(QMAKE_EXTRA_TARGETS) + } + + # internal target ... Use allclean instead! + # main local subAllclean target called by allclean (see below) + # this one calls + # 1. clean to remove temporary files created + # 2. cleanDirs to remove all tmp and lib directories created by qmake + # 3. distclean to remove the rest + !contains( QMAKE_EXTRA_TARGETS , subAllclean) { + # Remove temp dirs when doing allclean + subAllclean.target = subAllclean + subAllclean.depends = clean cleanDirs distclean + + export(subAllclean.target) + export(subAllclean.depends) + + QMAKE_EXTRA_TARGETS += subAllclean + export(QMAKE_EXTRA_TARGETS) + } + + + # basic allclean target, will cleate a recursive target calling subAllclean in the subdirectories makefiles + !contains( QMAKE_EXTRA_TARGETS , allclean) { + allclean.target = allclean + allclean.CONFIG = recursive + allclean.recurse_target = subAllclean + + export(allclean.target) + export(allclean.CONFIG) + export(allclean.recurse_target) + + QMAKE_EXTRA_TARGETS += allclean + export(QMAKE_EXTRA_TARGETS) + } + + !contains( QMAKE_EXTRA_TARGETS , plugindoc ) { + exists ( Documentation ) { + plugindoc.target = plugindoc + PLUGINNAME = $$getCurrentDir() + PLUGINNAME = $$section( PLUGINNAME, "/" ,-1, -1) + + unix { + plugindoc.commands += rm -rf $${TOPDIR}/OpenFlipper/Docs/User/$$PLUGINNAME ; + plugindoc.commands += mkdir $${TOPDIR}/OpenFlipper/Docs/User/$$PLUGINNAME ; + plugindoc.commands += cp Documentation/*.html $${TOPDIR}/OpenFlipper/Docs/User/$$PLUGINNAME ; + exists ( Documentation/pics ) { + plugindoc.commands += cp -r Documentation/pics $${TOPDIR}/OpenFlipper/Docs/User/$$PLUGINNAME ; + } + } + + win32 { + message(Documentaion copy not supported on windows platform) + #plugindoc.commands += rmdir /s $${TOPDIR}/OpenFlipper/Docs/User/$$PLUGINNAME ; + #plugindoc.commands += mkdir $${TOPDIR}/OpenFlipper/Docs/User/$$PLUGINNAME ; + #plugindoc.commands += xcopy /f Documentation/*.html $${TOPDIR}/OpenFlipper/Docs/User/$$PLUGINNAME ; + #exists ( Documentation/pics ) { + # plugindoc.commands += xcopy /f /s Documentation/pics $${TOPDIR}/OpenFlipper/Docs/User/$$PLUGINNAME ; + #} + } + + export(plugindoc.target) + export(plugindoc.commands) + export(plugindoc.depends) + + QMAKE_EXTRA_TARGETS += plugindoc + export(QMAKE_EXTRA_TARGETS) + } + } + + +} + +# target for libraries +# this target will copy all headers to an include subdirectory +# You have to call this after you defined evertything else for your library. +# Otherwise this target doesnt know about the required headers. + +defineTest( installs ) { + + !contains( INSTALLS , includes ) { + contains( TEMPLATE, lib ) { + + includes.path = include/ + includes.extra = cp -f --parents $${HEADERS} include/ + + export(includes.path) + export(includes.extra) + + INSTALLS *= includes + export(INSTALLS) + } + } +} + + + diff --git a/release.howto b/release.howto new file mode 100644 index 00000000..d282cd8a --- /dev/null +++ b/release.howto @@ -0,0 +1,13 @@ +1. check files +2. check files with release numbers: + Docu/history.docu + Dist/Readme + VERSION +3. cvs export -r OpenMesh- -d OpenMesh- OM_DIST +4. Create HTML-Documentation in OpenMesh/Docu/ (!) +5. check for directories acgmake and OpenMeshApps +6. Create tar-ball and zip-archive + > tar cvzf OpenMesh-.tar.gz OpenMesh-/ + > tar cvjf OpenMesh-.tar.bz2 OpenMesh-/ + > zip -9 -r OpenMesh-.zip OpenMesh-/ +7. Release Upload diff --git a/templates/cc b/templates/cc new file mode 100644 index 00000000..742f7645 --- /dev/null +++ b/templates/cc @@ -0,0 +1,25 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) $YEAR$ by $AUTHOR$ * + * $EMAIL$ * + * * + *---------------------------------------------------------------------------* + * * + * 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. * + * * +\*===========================================================================*/ + diff --git a/templates/cpp b/templates/cpp new file mode 100644 index 00000000..742f7645 --- /dev/null +++ b/templates/cpp @@ -0,0 +1,25 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) $YEAR$ by $AUTHOR$ * + * $EMAIL$ * + * * + *---------------------------------------------------------------------------* + * * + * 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. * + * * +\*===========================================================================*/ + diff --git a/templates/h b/templates/h new file mode 100644 index 00000000..7642204a --- /dev/null +++ b/templates/h @@ -0,0 +1,24 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) $YEAR$ by $AUTHOR$ * + * $EMAIL$ * + * * + *---------------------------------------------------------------------------* + * * + * 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. * + * * +\*===========================================================================*/ diff --git a/templates/hh b/templates/hh new file mode 100644 index 00000000..7642204a --- /dev/null +++ b/templates/hh @@ -0,0 +1,24 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) $YEAR$ by $AUTHOR$ * + * $EMAIL$ * + * * + *---------------------------------------------------------------------------* + * * + * 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. * + * * +\*===========================================================================*/