First checkin for OpenMesh 2.0

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

28
Doc/ACGMakefile Normal file
View File

@@ -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
#==============================================================================

188
Doc/Concepts/MeshItems.hh Normal file
View File

@@ -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 Refs_> 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 Refs_> 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 Refs_> 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 Refs_> 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
//=============================================================================

510
Doc/Concepts/MeshKernel.hh Normal file
View File

@@ -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 FinalMeshItems> 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 <typename T> bool add_property( [VEHFM]PropHandleT<T>& _ph,
const std::string& _name = "" );
//@}
/// \name Property management - remove property
//@{
/// Remove property
template <typename T> void remove_property( [VEHFM]PropHandleT<T>& );
//@}
/// \name Property management - get property by name
//@{
/// Get property handle by name
template <typename T>
bool get_property_handle( [VEHFM]PropHandleT<T>& ph, const std::string& _n ) const;
//@}
/// \name Property management - get property
//@{
/// Get property
template <typename T> PropertyT<T>& property( [VEHF]PropHandleT<T> _ph );
template <typename T> const PropertyT<T>& property( [VEHF]PropHandleT<T> _ph ) const;
template <typename T> PropertyT<T>& mproperty( MPropHandleT<T> _ph );
template <typename T> const PropertyT<T>& mproperty( MPropHandleT<T> _ph ) const;
//@}
/// \name Property management - get property value for an item
//@{
/// Get value for item represented by the handle.
template <typename T>
T& property( VPropHandleT<T> _ph, VertexHandle _vh );
template <typename T>
const T& property( VPropHandleT<T> _ph, VertexHandle _vh ) const;
template <typename T>
T& property( EPropHandleT<T> _ph, EdgeHandle _vh );
template <typename T>
const T& property( EPropHandleT<T> _ph, EdgeHandle _vh ) const;
template <typename T>
T& property( HPropHandleT<T> _ph, HalfedgeHandle _vh );
template <typename T>
const T& property( HPropHandleT<T> _ph, HalfedgeHandle _vh ) const;
template <typename T>
T& property( FPropHandleT<T> _ph, FaceHandle _vh );
template <typename T>
const T& property( FPropHandleT<T> _ph, FaceHandle _vh ) const;
template <typename T>
T& property( MPropHandleT<T> _ph );
template <typename T>
const T& property( MPropHandleT<T> _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
//=============================================================================

1417
Doc/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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;
};

View File

@@ -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&) {};
};

View File

@@ -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;
...
};

50
Doc/Examples/adasub.cc Normal file
View File

@@ -0,0 +1,50 @@
#include <iostream>
#include <algorithm>
#include <iterator>
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <OpenMesh/Tools/Subdivider/Adaptive/CompositeT.hh>
// ----------------------------------------
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<MyMesh>::Handle >();
subdivider.add< VF<MyMesh>::Handle >();
subdivider.add< FF<MyMesh>::Handle >();
// 'named' registration
FVc<MyMesh>::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<double>(std::cout, ", "));
// prepare subdivider and the traits
if (!subdivider.initialize())
return 1; // error initializing subdivider
MyMesh::FaceHandle fh; // select a face
subdivider.refine(fh);
}

View File

@@ -0,0 +1,8 @@
template <class Traits>
struct TriMesh_ArrayKernel_GeneratorT
{
typedef FinalMeshItemsT<ArrayItems, Traits, true> MeshItems;
typedef AttribKernelT<MeshItems> AttribKernel;
typedef ArrayKernelT<AttribKernel, MeshItems> MeshKernel;
typedef TriMeshT<MeshKernel> Mesh;
};

View File

@@ -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)
}
}

30
Doc/Examples/decimater.cc Normal file
View File

@@ -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

View File

@@ -0,0 +1,14 @@
#include <OpenMesh/Core/Utils/GenProg.hh>
// draw a face normal if we have one
void drawFaceNormal(const MyMesh::Face& _f) {
drawFaceNormal(_f, GenProg::Bool2Type<OM_Check_Attrib(MyMesh::Face, Normal)>());
}
// normal exists -> use it
void drawFaceNormal(const MyMesh::Face& _f, GenProg::Bool2Type<true>) {
glNormal3fv(_f.normal());
}
// empty dummy (no normals)
void drawFaceNormal(const MyMesh::Face& _f, GenProg::Bool2Type<false>){}

18
Doc/Examples/iterators.cc Normal file
View File

@@ -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()

17
Doc/Examples/mesh_io.cc Normal file
View File

@@ -0,0 +1,17 @@
#include <OpenMesh/Core/IO/MeshIO.hh>
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);
}

51
Doc/Examples/mymesh.cc Normal file
View File

@@ -0,0 +1,51 @@
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
// 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<MyTraits> 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
...;
}

17
Doc/Examples/traits0.cc Normal file
View File

@@ -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);
};

4
Doc/Examples/traits1.cc Normal file
View File

@@ -0,0 +1,4 @@
struct MyTraits : public OpenMesh::DefaultTraits
{
typedef OpenMesh::Vec3d Point; // use double-values points
};

7
Doc/Examples/traits2.cc Normal file
View File

@@ -0,0 +1,7 @@
struct MyTraits : public OpenMesh::DefaultTraits
{
VertexTraits
{
int some_additional_index;
};
};

7
Doc/Examples/traits3.cc Normal file
View File

@@ -0,0 +1,7 @@
struct MyTraits : public OpenMesh::DefaultTraits
{
template <class Base, class Refs> struct VertexT : public Base
{
int some_additional_index;
};
};

8
Doc/Examples/traits4.cc Normal file
View File

@@ -0,0 +1,8 @@
struct MyTraits : public OpenMesh::DefaultTraits
{
VertexTraits
{
int some_additional_index;
typename Base::Refs::FaceHandle my_face_handle;
};
};

7
Doc/Examples/traits5.cc Normal file
View File

@@ -0,0 +1,7 @@
struct MyTraits : public OpenMesh::DefaultTraits
{
VertexAttributes( OpenMesh::Attributes::Normal |
OpenMesh::Attributes::Color );
FaceAttributes( OpenMesh::Attributes::Normal );
};

View File

@@ -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
#==============================================================================

View File

@@ -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 <iostream>
// -------------------- OpenMesh
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh>
// ----------------------------------------------------------------------------
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<MyMesh::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);
// 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;
}

View File

@@ -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
#==============================================================================

View File

@@ -0,0 +1,76 @@
#include <iostream>
#include <vector>
// -------------------- OpenMesh
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
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<MyMesh::Point> cogs;
std::vector<MyMesh::Point>::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;
}

View File

@@ -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
#==============================================================================

View File

@@ -0,0 +1,74 @@
#include <iostream>
#include <vector>
// --------------------
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
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<MyMesh::Point> 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;
}

View File

@@ -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
#==============================================================================

View File

@@ -0,0 +1,59 @@
#include <iostream>
#include <vector>
// -------------------- OpenMesh
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
// --------------------
#include "smooth_algo.hh"
// ----------------------------------------------------------------------------
#ifndef DOXY_IGNORE_THIS
struct MyTraits : public OpenMesh::DefaultTraits
{
HalfedgeAttributes(OpenMesh::Attributes::PrevHalfedge);
};
#endif
typedef OpenMesh::TriMesh_ArrayKernelT<MyTraits> 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<MyMesh> 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;
}

View File

@@ -0,0 +1,106 @@
#include <algorithm>
#include <OpenMesh/Core/Utils/Property.hh>
#ifndef DOXY_IGNORE_THIS
template <class Mesh> 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

View File

@@ -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
#==============================================================================

View File

@@ -0,0 +1,71 @@
#include <iostream>
// --------------------
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh;
int main(int argc, char **argv)
{
MyMesh mesh;
if (argc!=2)
{
std::cerr << "Usage: " << argv[0] << " <input>\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;
}

View File

@@ -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
#==============================================================================

View File

@@ -0,0 +1,94 @@
#include <iostream>
#include <typeinfo>
// --------------------
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <OpenMesh/Core/Geometry/VectorT.hh>
#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<MyTraits> MyMesh;
// ------------------------------------------------------------------ main ----
int main(int argc, char **argv)
{
MyMesh mesh;
if (argc!=2)
{
std::cerr << "Usage: " << argv[0] << " <input>\n";
return 1;
}
// Just make sure that point element type is double
if ( typeid( OpenMesh::vector_traits<MyMesh::Point>::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<MyMesh::Normal>::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;
}

View File

@@ -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
#==============================================================================

View File

@@ -0,0 +1,132 @@
#include <iostream>
#include <vector>
// -------------------- OpenMesh
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#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<MyTraits> MyMesh;
typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh2;
// ---------------------------------------------------------------------------
#define SIZEOF( entity,b ) \
std::cout << _prefix << "size of " << #entity << ": " \
<< sizeof( entity ) << std::endl; \
b += sizeof( entity )
template <typename Mesh>
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<MyMesh>(" ");
std::cout << "Default mesh size statistics\n";
print_size<MyMesh2>(" ");
}
// 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;
}

View File

@@ -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
#==============================================================================

View File

@@ -0,0 +1,297 @@
#include <iostream>
#include <iterator>
// -------------------- OpenMesh
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <OpenMesh/Tools/Utils/getopt.h>
// ----------------------------------------------------------------------------
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] <input> <output>\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
// ============================================================================

View File

@@ -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
#==============================================================================

View File

@@ -0,0 +1,123 @@
#ifndef FILL_PROPS_HH
#define FILL_PROPS_HH
#include <OpenMesh/Core/Utils/Property.hh>
#include "int2roman.hh"
template <typename Mesh>
bool
fill_props( Mesh& _m, OpenMesh::VPropHandleT<float> _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 <typename Mesh>
bool
fill_props( Mesh& _m, OpenMesh::EPropHandleT<bool> _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 <typename Mesh>
bool
fill_props(Mesh& _m, OpenMesh::FPropHandleT<std::string> _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 <typename Mesh, typename T>
bool
fill_props( Mesh& _m, OpenMesh::HPropHandleT<T> _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 <typename Mesh, typename T>
bool
fill_props( Mesh& _m, OpenMesh::MPropHandleT<T> _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

View File

@@ -0,0 +1,70 @@
#ifndef GENERATE_CUBE_HH
#define GENERATE_CUBE_HH
template <typename MeshType>
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

View File

@@ -0,0 +1,45 @@
#include <OpenMesh/Core/System/config.hh>
#if defined(OM_CC_MIPS)
# include <assert.h>
#else
# include <cassert>
#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;
}

View File

@@ -0,0 +1,8 @@
#ifndef INT2ROMAN_HH
#define INT2ROMAN_HH
#include <string>
std::string int2roman( size_t decimal, size_t length=30 );
#endif

View File

@@ -0,0 +1,347 @@
#include <iostream>
#include <string>
#include <map>
// -------------------- OpenMesh
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh>
// -------------------- 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<MyData>
{
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<N && _is.good(); ++i)
{
bytes += IO::restore( _is, key, _swap );
bytes += IO::restore( _is, val, _swap );
_v[key] = val;
}
return _is.good() ? bytes : 0;
}
};
}
}
#endif
// ----------------------------------------------------------------------------
int main(void)
{
//
Mesh mesh;
// generate a geometry
generate_cube<Mesh>(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<float> vprop_float;
OpenMesh::EPropHandleT<bool> eprop_bool;
OpenMesh::FPropHandleT<std::string> fprop_string;
OpenMesh::HPropHandleT<MyData> hprop_mydata;
OpenMesh::MPropHandleT<MyMap> 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
// ============================================================================

View File

@@ -0,0 +1,20 @@
#ifndef STATS_HH
#define STATS_HH
template <typename Mesh>
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 <typename Mesh>
void mesh_property_stats(Mesh& _m)
{
std::cout << "Current set of properties:\n";
_m.property_stats(std::cout);
}
#endif

17
Doc/Tutorial/ACGMakefile Normal file
View File

@@ -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
#==============================================================================

89
Doc/decimater.docu Normal file
View File

@@ -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
*/

509
Doc/history.docu Normal file
View File

@@ -0,0 +1,509 @@
/** \page history Version history
\htmlonly
<table border=1 cellpadding=4 cellspacing=2>
<!-- --------------------------------------------------------------------- -->
<tr valign=top><td><b>2.0</b> (2009/01/28)</td><td>
<ul>
<li>Reader / writer have been updated</li>
<li>Some general bugfixes</li>
<li>Improved Documentation</li>
<li>Dropped support for acgmake which has been entirely replaced by qmake</li>
</ul>
</tr>
<!-- --------------------------------------------------------------------- -->
<tr valign=top><td><b>1.9.7</b> (2008/10/13)</td><td>
<ul>
<li>Ported applications to qt4</li>
<li>Bugfixes in Decimater</li>
<li>Improved Documentation</li>
<li>Dropped support for gcc 3.x compilers (This does not mean that it does not work anymore)</li>
<li>Dropped support for Versions of Visual Studio older than 2008</li>
</ul>
</tr>
<!-- --------------------------------------------------------------------- -->
<tr valign=top><td><b>1.1.0</b> (2007/02/26)</td><td>
<ul>
<li>Fixed a VS 2005 compilation issue regarding the Sqrt3 subdivision class.</li>
<li>Fixed GCC-4.1 compilation problems.</li>
<li>The STL writer routine now correctly closes the <tt>"solid"</tt> block with <tt>"endsolid"</tt>.</li>
<li>The API of the vector class has been changed slightly due to problems with some versions of GCC:<br/>
The cast operator to the scalar type has been removed and replaced by
the function <tt>data()</tt>. Hence, existing code like
<blockquote>
<tt>Vec3f vertex;</tt><br/>
<tt>...</tt><br/>
<tt>glVertex3fv( vertex );</tt>
</blockquote>
has to be changed to
<blockquote>
<tt>Vec3f vertex;</tt><br/>
<tt>...</tt><br/>
<tt>glVertex3fv( vertex.data() );</tt>
</blockquote>
</li>
</ul>
</tr>
<!-- --------------------------------------------------------------------- -->
<tr valign=top><td><b>1.0.0</b> (2005/09/20)</td><td>
<ul>
<li>Mainly fixed the bugs collected in beta4.</li>
<li>Slightly changed module handling in the Decimater.</li>
<li>Removed some parts to keep the project maintainable.</li>
<li>Fixed MacOS compilation problems.</li>
<li>Compatibility for latest gcc4 compilers.</li>
</ul>
</tr>
<!-- --------------------------------------------------------------------- -->
<tr valign=top><td><b>1.0.0-beta4</b> (2004/01/20)</td><td>
<ul>
<li>Bugs fixed: 1.0.0-beta3:001</li>
<li>Documentation of module Core completed.</li>
<li>Documentation of module Tools::Decimater and
Tools::Subdivider completed.</li>
<li>Revised class structure for uniform subdivision.</li>
<li>Revised rule handling for composite adaptive subdivision.</li>
</ul>
</tr>
<!-- --------------------------------------------------------------------- -->
<tr valign=top><td><b>1.0.0-beta3</b> (2003/12/04)</td><td>
The beta3 fixes only the known bugs in beta2.
<ul>
<li>Bugs fixed: 1.0.0-beta2:{001, 002, 003, 004}</li>
<li><b>Known Bugs</b>:
<ul>
<li>001: OFFReader: Option bit not cleared before analyzing .off header.
<br>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.
</li>
</ul>
</li>
</ul>
</tr>
<!-- --------------------------------------------------------------------- -->
<tr valign=top><td><b>1.0.0-beta2</b> (2003/11/05)</td><td>
<ul>
<li>Change of directory structure
<pre>
+- %OpenMesh/
+- Core/ # previously %OpenMesh
+- Tools/ # previously OpenMeshTools
+- Apps/ # previously OpenMeshApps
+- Win/ # contains all solutions files and projects for MS VC++
+- Doc/ # contains all documentation
</pre>
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.)
</li>
<li><b>Porting issues</b>: Due to a number of major changes in the
structure of %OpenMesh a few incompatibilities have been
introduced. Have look in <b>\c %OpenMesh/porting.txt </b> for hints how to
treat your source when updating from 0.11.x to
1.0.0.<br>Hint! The supplied script \c %OpenMesh/migrate.sh does a
few of the necessary modifications.
</li>
<li><b>The list kernel has been removed</b>
</li>
<li>Improved IO support:
<ul>
<li>Read/write ascii and binary STL </li>
<li>Read/write ascii and binary OFF </li>
<li>Support for vertex normals and vertex texcoords in OFF and OBJ</li>
<li>Support importing diffuse material into face color property from
OBJ files.
</li>
<li>Properietary binary format OM, supporting read/write of custom properties
</li>
</ul>
</li>
<li>Improved coordinate class OpenMesh::VectorT:
<ul>
<li> <tt>VectorT::vectorize(Scalar)</tt> is no longer static, now
it changes the vector. Use it e.g. to clear vector values.
</li>
<li> Casts between two vector classes of the same dimension are now
explicit. This avoids unwanted and expensive casts.
</li>
<li> 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.
</li>
</ul>
</li>
<li>OpenSG Support:
<ul>
<li>New kernel type \c class TriMesh_OSGArrayKernelT<>.
<ul>
<li>Uses OpenSG geometry types!</li>
<li>PolyMesh not supported, yet!</li>
</ul>
<li>Use \c OpenMesh::Kernel_OSG::bind<> to link a mesh obj with an
\c osg::Geometry and vice versa.<br>Please note that both objects
share the same data!
<ul>
<li>Binding a mesh to an \c osg::Geometry changes the content
of the \c osg::Geometry!
<li>Triangulates non-triangular faces!</li>
<li>Multi-indexed geometry not supported!</li>
<li>Transfer of vertex normals</li>
<li>Limited capability to transfer colors:
So far, only \c osg::Color3f <-> \c OpenMesh::Vec3ub
</ul>
</li>
</ul>
</li>
<li>Microsoft VC++ 7.0 projects files
<ul>
<li>Tutorial solution file
</ul>
</li>
<li> New tools/applications:
<ul>
<li>\c Tools/VDPM (View Dependent Progressive Mesh Library)
<ul>
<li>\c Apps/VDProgMesh/mkbalancedpm - Create a balanced
progressive mesh.
</li>
<li>\c Apps/VDProgMesh/Analyzer - Create a view dependent
progressive mesh file.
</li>
<li>\c Apps/VDProgMesh/Synthesizer - A viewer for the VDPM file.</li>
</ul>
</li>
<li>Apps/mconvert</li>
<li>Apps/IvViewer - added support for Coin</li>
</ul>
</li>
<li><b>Known Bugs</b>:
The following bugs are related to the TriMesh_OSGArrayKernelT<>:
<ul>
<li>001: Cannot request/release the default attribute
<tt>halfedge_status</tt>.
</li>
<li>002: Cannot release the default attribute <tt>vertex_texcoords</tt>
</li>
<li>003: Assignment operator = () does not work properly.</li>
<li>004: No copy-constructor available!</li>
</ul>
</li>
</ul>
</td></tr>
<!-- --------------------------------------------------------------------- -->
<tr valign=top><td><b>0.11.1</b> (2002/12/02)</td><td>
<ul>
<li>Bugs fixed: 0.11.0:{001, 002, 003, 004, 006}<br><br>
006: Use acgmake version 1.1.1.
</li>
<li>Preprocessor warnings of gcc >= 3 fixed.
</li>
<li>Added some more dynamic ways to append properties to items:
OpenMesh::Any and OpenMesh::PropertyT .
</li>
<li>VectorT: standard operator less added, Vec4f is now
16-bit aligned using gcc compiler (for later SIMD usage).
</li>
<li>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.
</li>
<li>The read_mesh() methods now clears the mesh before reading a new one.
</li>
<li>Added can_read() and can_write() methods to the IOManager.
</li>
</ul>
</td></tr>
<!-- --------------------------------------------------------------------- -->
<tr valign=top><td><b>0.11.0</b> (2002/09/07)</td><td>
<ul>
<li>Bugs fixed: 0.10.2:{001, 002, 003, 004, 005}
</li>
<li>Added MS VC++ 7.0 project files for the tutorial programms.
(Have a look in <OpenMesh>/Win32/MSVC/)
</li>
<li>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.
</li>
<li>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.
</li>
<li>Added generic handle <-> item conversions, see
<ul>
<li> OpenMesh::Concepts::KernelT::handle() and
<li> OpenMesh::PolyMeshT::deref().
</ul>
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.
</li>
<li>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.
</li>
<li>Added convenience methods for the mesh kernels:
<ul>
<li>OpenMesh::Concepts::KernelT::n_halfedges()
<li>OpenMesh::Concepts::KernelT::halfedges_empty()
<li>OpenMesh::Concepts::KernelT::halfedge_handle(unsigned int _i)
</ul>
</li>
<li><b>Known Bugs</b>:
<ul>
<li>001: Ambigous auto_ptr<> cast in ExporterT.hh.</li>
<li>002: BaseImporter and BaseExporter have no virtual destructor.</li>
<li>003: Reader does not work correctly, when reading from a istream.</li>
<li>004: cross(VectorT, VectorT) returns Scalar instead of VectorT.</li>
<li>005: PolyMeshT::calc_face_normal() may give wrong results if the
first 3 points of the polygon are colinear or concave.</li>
<li>006: Reading/writing (MeshIO) of files does not work when using acgmake
with SuSE 8.1.</li>
</ul>
</li>
</ul>
</td></tr>
<!-- --------------------------------------------------------------------- -->
<tr valign=top><td><b>0.10.2</b> (2002/06/25)</td><td>
<ul>
<li>Bugs fixed: 0.10.1:{001, 002}
</li>
<li>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.
</li>
<li>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.
</li>
<li>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.
</li>
<li><b>Known Bugs</b>:
<ul>
<li>001: OpenMesh::PolyMeshT::operator=() does not return \c *this.
<li>002: OpenMesh::DefaultAttributer added unnecessary 20 bits to the
elementary mesh types.
</ul>
</li>
</ul>
</td></tr>
<!-- --------------------------------------------------------------------- -->
<tr valign=top><td><b>0.10.1</b> (2002/04/22)</td><td>
<ul>
<li>Bugs fixed: 0.10.0:{001, 002, 003, 004, 005}
</li>
<li>Added: Predefined attribute \c TexCoord.
</li>
<li>Added: Support for MS VC++ 6.0 IDE with Intel Compiler.
</li>
<li>Added: Tutorial 6 on generic algorithms.
</li>
<li>SharedCoordArrayKernelT is now derived from ArrayKernelT.
</li>
<li>Added: Assignment operator operator=() for PolyMeshT and TriMeshT.
</li>
<li>Added: Method TriMeshT::is_collapse_ok(), checking topological conditions
for a given halfedge collapse.
</li>
<li><b>Known Bugs</b>:
<ul>
<li>001: PolyMeshT::delete_face(): Outgoing halfedge handle of
a vertex can incorrectly be invalidated. Influences
vertex circulators, find_halfedge() and therefore
add_face().<br>
Workaround: Replace <tt>v0</tt> by <tt>v1</tt> in line 585 of
PolyMeshT.cc
</li>
<li>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.
</li>
</ul>
</li>
</ul>
</td></tr>
<!-- --------------------------------------------------------------------- -->
<tr valign=top><td><b>0.10.0</b> (2002/03/19)</td><td>
<ul>
<li>Interface for specifying the traits classes simplified (see
Traits.hh).
</li>
<li>Changed attribute handling; the attributer class (the class that
adds and registers attributes to mesh items) can be provided by
the user.
</li>
<li>Removed MyMesh::Face::n_vertices() and
MyMesh::Face::set_n_vertices().
</li>
<li>MeshWriter::write_* changed accordingly.
</li>
<li>Bug fix: PolyMeshT::delete_[face,edge,vertex] now work correctly.
</li>
<li>Removed cyclic dependency between items and kernel, because MS
VC++ cannot handle the resulting template forward declaration
:-(. Therefore the <tt>Base::Refs</tt> 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.
</li>
<li>Finally: MS VC++ 7.0 supported.
</li>
<li><b>Known Bugs</b>:
<ul>
<li>001: TriMeshT.cc::vertex_split(): call to undefined
method Face::set_n_vertices().<br>
Workaround: Comment out the two occurences of the call.
</li>
<li>002: Missing <tt>\#include
<OpenMesh/Mesh/Kernels/ListKernel/ListHandles.hh></tt>
in OpenMesh/Mesh/Types/PolyMesh_ListKernelT.hh.
</li>
<li>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.
</li>
<li>004: PolyMeshT::delete_edge did not pass its argument
_delete_isolated_vertices to PolyMeshT::delete_face.
</li>
<li>005: PolyMeshT::assign() was not linked because of an \#if error.
</ul>
</li>
</ul>
</td></tr>
<!-- --------------------------------------------------------------------- -->
<tr valign=top><td><b>0.9.2</b> (-) </td><td>
<ul>
<li>PolyMeshT::add_face() now detects more topological errors.
</li>
<li>Added mesh kernel methods: remove_last_[vertex,edge,face]().
</li>
</ul>
</td></tr>
<!-- --------------------------------------------------------------------- -->
<tr valign=top><td><b>0.9.1</b> (2002/02/07)</td><td>
<ul>
<li>Changed the main namespace from ACG to OpenMesh.
</li>
<li>Added invalid handle constants, e.g. PolyMeshT::InvalidVertexHandle.
</li>
<li>Mesh provides circulators: PolyMeshT::vv_iter(VertexHandle).
</li>
</ul>
</td></tr>
<!-- --------------------------------------------------------------------- -->
<tr valign=top><td><b> 0.9</b> (2002/01/25)</td><td>
<ul>
<li>initial release</li>
</ul>
</td></tr>
</table>
\endhtmlonly
**/

16
Doc/html/acg_footer.html Normal file
View File

@@ -0,0 +1,16 @@
<hr>
<address>
<small>
<a href="http://www.rwth-graphics.de" style="text-decoration:none;">
<img src="acg_icon.gif" alt="acg pic" align="middle" border=0>
</a>
Project <b>$projectname</b>,
&copy;&nbsp; Computer Graphics Group, RWTH Aachen.
Documentation generated using
<a class="el" href="http://www.doxygen.org/index.html">
<b>doxygen</b>
</a>.
</small>
</address>
</body>
</html>

7
Doc/html/acg_header.html Normal file
View File

@@ -0,0 +1,7 @@
<html>
<head>
<title>$title</title>
<link href="acg_style.css" rel="stylesheet" text="text/css">
<link href="acg_tabs.css" rel="stylesheet" type="text/css">
</head>
<body bgcolor="#003010">

BIN
Doc/html/acg_icon.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

367
Doc/html/acg_style.css Normal file
View File

@@ -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%; }

BIN
Doc/html/acg_tab_b.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

BIN
Doc/html/acg_tab_l.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

BIN
Doc/html/acg_tab_r.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

107
Doc/html/acg_tabs.css Normal file
View File

@@ -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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
Doc/images/diagrams.sxi Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -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

BIN
Doc/images/inheritance.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
Doc/images/iomanager.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
Doc/images/om-format.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

10
Doc/mainpage.docu Normal file
View File

@@ -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
**/

877
Doc/mesh.docu Normal file
View File

@@ -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):
<h3>There is no such thing like the %OpenMesh class</h3>
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 <typename Parent> class B : public Parent {}
typedef B<P1> fooB1;
typedef B<P2> 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.
<h3>Therefore documentation resides in two spaces</h3>
-# 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:
<ul>
<li> Flexibility:
<ul>
<li> Choose suitable types for scalars and coordinates (e.g. float,
double, exact arithmetic and two-, three-, or n-dimensional
points).
<li> Enhance each item type by your own attributes/properties, like
e.g. adding a normal vector or a \c FaceHandle to class \c
Vertex.
</ul>
<li> Efficiency:
<ul>
<li> Avoid the overhead of virtual inheritance and virtual function calls.
<li> 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).
</ul>
<li> Type-safety for handles, <b>no type-casting (*)</b>: Vertices,
(Half-)Edges, Faces know each other and their corresponding
handles.
<b>(*)</b> 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.<br>
As soon as the compiler adheres to the C++ standard the type-safe version
will be restored.
</ul>
*/
//-----------------------------------------------------------------------------
/** \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, <em> The C++ Programming Language </em>,
\li Matthew H. Austern, <em> Generic Programming and the STL: Using
and Extending the C++ Standard Template Library </em>,
\li Andrei Alexandrescu, <em> Modern C++ Design: Generic Programming
and Design Patterns Applied </em>,
\li Krzysztof Czarnecki, Ulrich Eisenecker, <em> Generative Programming:
Methods, Tools, and Applications </em>.
*/
//-----------------------------------------------------------------------------
/** \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 <em> halfedge
data structure </em>. While <em> face-based </em> structures store
their connectivity in faces referencing their vertices and neighbors,
<em> edge-based </em> 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 <em>
directed halfeges </em> from \c A to \c B and vice versa) one gets a
<em> halfedge-based </em> data structure. The following figure
illustrates the way connectivity is stored in this structure:
<table>
<tr valign=top>
<td> \image html halfedge_structure3.png
<td>
<ul>
<li> Each \b vertex references one outgoing halfedge, i.e. a halfedge that
starts at this vertex (1).
<li> Each \b face references one of the halfedges bounding it (2).
<li> Each \b halfedge provides a handle to
<ul>
<li> the vertex it points to (3),
<li> the face it belongs to (4)
<li> the next halfedge inside the face (ordered counter-clockwise) (5),
<li> the opposite halfedge (6),
<li> (optionally: the previous halfedge in the face (7)).
</ul>
</ul>
</td>
</tr>
</table>
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 <em> circulators </em>, described in
\ref mesh_iterators.
\attention In order to efficiently classify a boundary
vertex, the outgoing halfedge of these vertices <b> must be a boundary
halfedge </b> (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 <tt>if-then</tt> branchings,
the halfedge structure provides this funcionality without
conditional branching in constant time.
<b>References</b>
S. Campagna, L. Kobbelt, H.-P. Seidel, <em> Directed Edges - A
Scalable Representation For Triangle Meshes </em>, ACM Journal of
Graphics Tools 3 (4), 1998.
Lutz Kettner, <em> Using Generic Programming for Designing a Data
Structure for Polyhedral Surfaces</em>, 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:
<ol>
<li> Choose between triangle mesh and general polygonal mesh.
<li> Select the mesh kernel
<li> 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.
<li> Dynamically bind data to the mesh or the mesh entities (vertex,
(half-)edge, face) using \em custom \em properties.
</ol>
We will explain these four parameterization steps and give a code
example at the end of this page.
<br><br>
\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
<br><br>
\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
<br><br>
\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:
<ul>
<li> The <i>point</i> and <i>scalar</i> type: \c MyMesh::Point and \c
MyMesh::Scalar.
<li> The <i>mesh items</i>: \c MyMesh::Vertex, \c MyMesh::Halfedge, \c
MyMesh::Edge, \c MyMesh::Face.
<li> The <i>handle</i> types: \c MyMesh::VertexHandle, \c
MyMesh::HalfedgeHandle, \c MyMesh::EdgeHandle, \c
MyMesh::FaceHandle.
</ul>
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
<ol>
<li> change the coordinate type \c MyMesh::Point and the resulting
scalar type \c MyMesh::Scalar == \c MyMesh::Point::value_type,
<li> change the normal type \c MyMesh::Normal
<li> change the color type \c MyMesh::Color
<li> use predefined attributes like normal vector, color, texture
coordinates, ... for the
mesh items.
<li> add arbitrary classes to the mesh items.
</ol>
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<MyTraits> 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.
<br>
\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.
<br>
\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
<tt>unsigned int</tt> 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<true> and
\c Bool2Type<false>. 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
<br>
\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 <class Base, class Refs> 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.
<br>
\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.
<br><br>
\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.
<br><br>
\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
<tt>%OpenMesh/Mesh/Types</tt>. 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
<ul>
<li> The mesh kernel.
<li> The general polygonal mesh.
<li> The specialized triangle mesh (if you use a TriMesh instead of a PolyMesh).
</ul>
\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
<br><br>
\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
<br>
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_
<br><br>
\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.
<br>
\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<MyMesh>.
\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.
<br><br>
\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.
*/
//-----------------------------------------------------------------------------

93
Doc/misc.docu Normal file
View File

@@ -0,0 +1,93 @@
//-----------------------------------------------------------------------------
/** \page naming_conventions Naming Conventions
The following naming conventions are used for the OpenMesh code:
<b>Files:</b>
\li \c MyClass.cc for C++-Implementation of class \c MyClass
\li \c MyClass.hh for C++-Header of class \c MyClass
<b>Classes:</b>
\li Class names start with a capital letter: \c MyClass
\li Class templates end with \c T: \c MyClassTemplateT
<b>Variables:</b>
\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__
<b>Functions:</b>
\li Words are separated by underscores: \c my_function()
<b>Accessing members:</b>
\li To get the member \c xxx_ use <tt> const& xxx() const </tt>
\li To set the member \c xxx_ use <tt> void set_xxx(arg) </tt>
**/
//-----------------------------------------------------------------------------
/** \page compiling Compiling OpenMesh
\section compilers Tested compilers
%OpenMesh has been tested sucessfully for the following operating
systems / compilers:
<table>
<tr><td> Linux </td><td>
gcc 4.0.x<br>
gcc 4.1.x<br>
gcc 4.2.x<br>
gcc 4.3.x<br>
</td></tr>
<tr><td> Windows </td><td>
Microsoft Visual Studio 2008<br>
</td></tr>
<tr><td> MacOS X <br>(Panther and Tiger)</td><td>
gcc 3.3 <br>
gcc 4.0 <br>
</td></tr>
</table>
\section sec_compiling_unix Unix
Download and install the Qt4 framework from <a href="http://www.qtsoftware.com/downloads" target="_blank">Trolltech</a>.<br>
In order to compile and install OpenMesh, enter following commands in OpenMesh's root directory:<br><br>
<tt>
qmake&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;## Generates the appropriate Makefiles<br>
make&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;## Builds the project (use 'make debug' to build debug version)<br>
sudo make install&nbsp;## Install OpenMesh (as root)
</tt><br><br>
When using the \c qmake command, make sure to use Qt version 4 (some linux distributions<br>
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 <tt>Core/OpenMesh_Core.vcproj</tt> and <tt>Tools/OpenMesh_Tools.vcproj</tt>
\section sec_compiling_macosx MacOSX
Download and install the Qt4 framework from <a href="http://www.qtsoftware.com/downloads" target="_blank">Trolltech</a>.<br>
In order to compile and install OpenMesh, open a Terminal window and enter following commands in OpenMesh's root directory:<br><br>
<tt>
qmake -macx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;## Generates the appropriate Makefiles<br>
make release&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;## Builds the project (use 'make debug' to build debug version)<br>
sudo make install&nbsp;## Install OpenMesh (as root)
</tt>
**/
//-----------------------------------------------------------------------------

82
Doc/namespaces.docu Normal file
View File

@@ -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.
*/

17
Doc/subdivider.docu Normal file
View File

@@ -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
*/
//-----------------------------------------------------------------------------

13
Doc/tools.docu Normal file
View File

@@ -0,0 +1,13 @@
//-----------------------------------------------------------------------------
/** \page tools_docu OpenMesh Tools Documentation
- \ref decimater_docu
- \ref subdivider_docu
- \ref vdpm_docu
- Miscellaneous
- \ref OpenMesh::StripifierT
*/
// ----------------------------------------------------------------------------

64
Doc/tutorial_01.docu Normal file
View File

@@ -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
<tt>PolyMesh_ArrayKernelT</tt>.
\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 <tt>add_vertex</tt> 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]
<br>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
<br>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_
<br>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
<br>The complete source looks like this:
\include build_cube.cc
**/

62
Doc/tutorial_02.docu Normal file
View File

@@ -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
<br>We read the mesh to be smoothed from a file:
\skipline read_mesh
<br>One smoothing iteration is done in two steps:
<ol>
<li>For each vertex: calculate the barycenter of its one-ring neighbors.</li>
<li>For each vertex: move the vertex to the computed barycenter.</li>
</ol>
This can easily be implemented using vertex iterators. The mesh
provides begin and end iterators by <tt>vertices_begin()</tt> and
<tt>vertices_end()</tt>.
\skipline VertexIter
\skipline v_it!=v_end
<br>For calculating the barycenter, we have to iterate through the
one-ring neighborhood of the current vertex. This functionality
is provided by the <tt>VertexVertexIter</tt>:
\dontinclude 02-iterators/smooth.cc
\skipline VertexVertexIter
\skipline vv_it=
<br>Now we can calculate the barycenters for each vertex and store them in
the array <tt>cogs</tt>:
\dontinclude 02-iterators/smooth.cc
\skipline std::vector
\skipline v_it=
\until cogs.push_back
\until }
<br>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
**/

54
Doc/tutorial_03.docu Normal file
View File

@@ -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
<br>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
<br>and finally set the new position for each vertex \c v_it
\dontinclude 03-properties/smooth.cc
\skipline mesh.set_point
<br>Below is the complete source code:
\include 03-properties/smooth.cc
*/

50
Doc/tutorial_04.docu Normal file
View File

@@ -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
<tt>operator()(...)</tt>. 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 <tt>std::for_each</tt> 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 }
<br>The complete example looks like this:
\include 04-stl_algorithms/smooth_algo.hh
<br>and
\include 04-stl_algorithms/smooth.cc
*/

136
Doc/tutorial_05.docu Normal file
View File

@@ -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.
<table>
<tr>
<td>&nbsp;</td>
<td>Vertex</td>
<td>Face</td>
<td>Edge</td>
<td>Halfedge</td>
</tr>
<tr>
<td>Color</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>Normal</td>
<td>X</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>Position <sup> (*) </sup> </td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>Status</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td>TexCoord</td>
<td>X</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
</table>
To add a standard property to an entity simply use the appropriate
request method, e.g. \c <20>request_face_normal(). The only exception is
the position <sup>(*)</sup>. 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
*/

74
Doc/tutorial_06.docu Normal file
View File

@@ -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< <b>int</b>>), 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 <b style="background-color:#FFFFFF;">(\f$V-E+F=2 (1-g)\f$)</b>, that for a regular
triangle meshes with genus <b style="background-color:#FFFFFF;">\f$g=0\f$</b> the number of edges
<b style="background-color:#FFFFFF;">\f$E\f$</b> is approximately
three times the number of vertices <b style="background-color:#FFFFFF;">\f$V\f$: \f$ E \approx 3 \cdot V\f$</b>.
The complete source looks like this:
\include 06-attributes/attributes.cc
*/

46
Doc/tutorial_07.docu Normal file
View File

@@ -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
*/

121
Doc/tutorial_08.docu Normal file
View File

@@ -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.
<table border=0>
<tr>
<td>Format</td><td colspan=2>Ascii</td><td>Binary</td>
</tr><tr>
<td>OFF</td><td>.off</td><td>.off</td>
</tr><tr>
<td>OBJ</td><td>.obj</td><td></td>
</tr><tr>
<td>STL</td><td>.stla, .stl</td><td>.stlb, .stl</td>
</tr><tr>
<td>OM</td><td></td><td>.om</td>
</tr>
</table>
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!)
<h5>Reading meshes</h5>
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.)
<h5>Writing meshes</h5>
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
*/

186
Doc/tutorial_09.docu Normal file
View File

@@ -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<MyData>
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.
<h5>\c size_of methods </h5>
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.
<h5>\c store / \c restore </h5>
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
*/

42
Doc/tutorial_main.docu Normal file
View File

@@ -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. <!--For detailed information, consult the online documentation
(\ref mesh_docu).-->
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.
<ol>
<li> \ref tutorial_01
<li> \ref tutorial_02
<li> \ref tutorial_03
<li> \ref tutorial_04
<li> \ref tutorial_05
<li> \ref tutorial_06
<li> \ref tutorial_07
<li> \ref tutorial_08
<li> \ref tutorial_09
</ol>
*/

18
Doc/vdpm.docu Normal file
View File

@@ -0,0 +1,18 @@
//-----------------------------------------------------------------------------
/** \page vdpm_docu View Dependent Progressive Meshes
The VDPM software is based on <a
href="http://www.postech.ac.kr/~leesy/ftp/gi01.pdf">"Truly Selective
Refinement of Progressive Meshes", J. Kim and S. Lee, In
Proc. Graphics Interface 2001</a>.
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.
*/