1
0
forked from 0ad/0ad
0ad/source/dcdt/se/se_mesh.h

420 lines
20 KiB
C++

# ifndef SE_MESH_H
# define SE_MESH_H
/** \file se_mesh.h
* Symmetrical Edge Mesh Data Structure */
# include "sr_array.h"
# include "sr_input.h"
# include "sr_output.h"
# include "sr_class_manager.h"
# include "se.h"
// ====================================== SeMeshBase ======================================
// SeMeshBase documentation in the end of this file
class SeMeshBase
{ public :
/*! Enumerator with the possible results of check_all(). */
enum ChkMsg { ChkOk, //!< The check_all() method had success
ChkNxtError, //!< Some face loop defined by the nxt() operators is wrong
ChkRotError, //!< Some vertex loop defined by the rot() operators is wrong
ChkVtxError, //!< Vertex referencing is wrong
ChkEdgError, //!< Edge referencing is wrong
ChkFacError //!< Face referencing is wrong
};
/*! Enumerator with possible errors raised during the use of the topological operators. */
enum OpMsg { OpNoErrors, //!< No Errors occured with operators
OpMevParmsEqual, //!< Parms in mev are equal
OpMevNotSameVtx, //!< Parms in mev not in the same vertex
OpMefNotSameFace, //!< Parms in mef not in the same face
OpKevLastEdge, //!< Cannot delete the last edge with kev
OpKevManyEdges, //!< More then one edge in parm vertex in kev
OpKevOneEdge, //!< Vertex of parm has only one edge in kev
OpKefSameFace, //!< Parm in kef must be between two different faces
OpMgUncompatibleFaces,//!< Parms are adjacent to faces with diferent number of vertices
OpMgSameFace, //!< Parm in mg must be between two different faces
OpFlipOneFace, //!< Parm in flip must be between two different faces
OpEdgColOneFace, //!< Parm in EdgCol must be between two different faces
OpVtxSplitNotSameVtx, //!< Parms in vtxsplit are not in the same vertex
OpVtxSplitParmsEqual //!< Parms in VtxSplit are equal
};
/*! Enumerator with the type of elements used in many methods arguments. */
enum ElemType { TypeVertex,
TypeEdge,
TypeFace
};
private : // Data ===================================================================================
SeBase* _first; // A pointer to the symedge of the mesh that is considered the first
char _op_check_parms; // Flag to tell if must check operators parameters (default false)
char _op_last_msg; // Keeps the last result of an operator (OpMsg type)
char _output_op_errors; // Flag that outputs all errors ocurred during operators (default true)
int _vertices, _edges, _faces; // Elem counters
semeshindex _curmark; // Current values for marking
char _marking, _indexing; // flags to indicate that marking or indexing is on
SrClassManagerBase *_vtxman, *_edgman, *_facman; // keep used managers
private : // Private methods ==========================================================================
void _defaults ();
SeBase* _op_error ( OpMsg m );
public : // General mesh functions ===================================================================
/*! Inits an empty mesh. It requires to receive three manager classes
dynamically allocated with operator new. These classes will manage data
stored in vertices, edges and faces. If no associated data is required,
the user can simply pass as argument "new SrClassManagerMeshElementManager", otherwise
an allocated user-derived object must be created and passed to this
constructor. SeMeshBase destructor will automatically delete them. */
SeMeshBase ( SrClassManagerBase* vtxman, SrClassManagerBase* edgman, SrClassManagerBase* facman );
/*! Deletes all associated data: internal buffer, all mesh and its infos. */
virtual ~SeMeshBase ();
/*! Returns the initial symedge of the mesh, can be 0. */
SeBase* first () const { return _first; }
/*! Returns true if the mesh is empty, what happens when first() is null. */
bool empty () const { return _first? false:true; }
/*! Returns v-e+f. */
int euler () const;
/*! Returns (v-e+f-2)/(-2). */
int genus () const;
/*! Returns the number of elements of the given type. */
int elems ( ElemType type ) const;
/*! Returns the number of vertices in the mesh. */
int vertices () const { return _vertices; }
/*! Returns the number of edges in the mesh. */
int edges () const { return _edges; }
/*! Returns the number of faces in the mesh. */
int faces () const { return _faces; }
/*! Invert orientation of all faces. */
void invert_faces ();
/*! Returns the number of vertices in the face adjacent of the given symedge e. */
int vertices_in_face ( SeBase* e ) const;
/*! Returns the number of edges incident to the vertex adjacent of the given symedge e,
ie, the degree of the vertex. */
int vertex_degree ( SeBase* e ) const;
/*! Returns the mean vertex degree of the whole mesh */
float mean_vertex_degree () const;
/*! Returns true if the face incident to the given symedge e has exactly three edges. */
bool is_triangle ( SeBase* e ) const { return e->nxt()->nxt()->nxt()==e? true:false; }
private : // Marking and Indexing =====================================================
void _normalize_mark ();
public :
/*! Allows the user to safely mark elements with mark(), marked() and unmark()
methods. Marking elements is necessary for many algorithms.
SeMeshBase mantains a current marker value, so that each time begin_marking()
is called, the marker value is incremented, guaranteing that old marked
elements have a different mark value.
When the max marking value is reached, a global normalization is done.
Attention: Marking and indexing can not be used at the same time. Also,
end_marking() must be called when marking operations are finished! */
void begin_marking ();
/*! Must be called after a begin_marking() call, when the user finishes using the
marking methods. Note: There is no problem if end_marking() is called without
a previously call to begin_marking() */
void end_marking ();
/*! See if an element is marked (begin_marking() should be called first) */
bool marked ( SeElement* e );
/*! Unmark an element (begin_marking() should be called first) */
void unmark ( SeElement* e );
/*! Mark an element (begin_marking() should be called first) */
void mark ( SeElement* e );
/*! Indexing methods can be used only after a call to begin_indexing(), which permits
the user to associate any index to any element. Note however that after a call to
begin_indexing() the existant indices will have undefined values. This happens
because indices and markers share the same variables, so that both can not be used
at a same time. Method end_marking() must always be called after */
void begin_indexing ();
/*! To finish indexing mode, end_indexing() must be called. The method will do a global
normalization of the internal indices values, preparing them to be used for a later
marking or indexing session. It can be called without a previous begin_marking()
call, but note that it will always peform the global normalization. */
void end_indexing ();
/*! Retrieves the index of an element (begin_indexing() should be called first) */
semeshindex index ( SeElement* e );
/*! Sets the index of an element (begin_indexing() should be called first) */
void index ( SeEdge* e, semeshindex i );
public : // Operators Control ===========================================================================
/*! Get safe mode status. When it is true, error msgs are generated, but
operations become a little slower because some minor checkings are
performed. The default mode is true only for the
debug version of the library (compiled with _DEBUG macro defined).*/
bool safe_mode () { return _op_check_parms? true:false; }
/*! Change the safe mode status. The default mode is false. */
void safe_mode ( bool b ) { _op_check_parms=(char)b; }
/*! Say if error messages should be printed or not (using sr_out), default is false. */
void output_errors ( bool b ) { _output_op_errors=(char)b; }
/*! Whenever an operator returns null, an error message is generated and
can be retrieved here. Each time an operator is called, a new message
is generated. And whenever the operator finishes succesfully OpNoErrors
is generated. */
OpMsg last_op_msg () { return (OpMsg)_op_last_msg; }
/*! Get a string description of the given message. */
static const char *translate_op_msg ( OpMsg m );
/*! Makes a global consistency check, for debug purposes, should always return ChkOk. */
ChkMsg check_all () const;
private :
void _new_vtx(SeBase* s); void _new_edg(SeBase* s); void _new_fac(SeBase* s);
void _del_vtx(SeElement* e); void _del_edg(SeElement* e); void _del_fac(SeElement* e);
public : // Operators ==================================================================================
/*! Destroy all the mesh and associated data. */
void destroy ();
/*! Initialize the mesh. See also SeMeshBase documentation. */
SeBase* init ();
/*! Make edge and vertex operator. See also SeMeshBase documentation. */
SeBase* mev ( SeBase* s );
/*! Make edge and vertex operator, splitting a vertex loop. See also SeMeshBase documentation. */
SeBase* mev ( SeBase* s1, SeBase* s2 );
/*! Make edge and face operator. See also SeMeshBase documentation. */
SeBase* mef ( SeBase* s1, SeBase* s2 );
/*! Kill edge and vertex operator. See also SeMeshBase documentation. */
SeBase* kev ( SeBase* x );
/*! Kill edge and vertex operator that can join two vertex loops. See also SeMeshBase documentation. */
SeBase* kev ( SeBase* x, SeBase* *s );
/*! Kill edge and face operator. See also SeMeshBase documentation. */
SeBase* kef ( SeBase* x, SeBase* *s );
/*! Make genus by joining two face contours and deleting two faces,
vertices and edges of s2 face. s1 and s2 must be symmetrically
placed, each one on its contour to join. (not fully tested) */
SeBase* mg ( SeBase* s1, SeBase* s2 );
/*! Flip the edge of a face. See also SeMeshBase documentation. */
SeBase* flip ( SeBase* x );
/*! Edge collide operator. See also SeMeshBase documentation. */
SeBase* ecol ( SeBase* x, SeBase* *s );
/*! Vertex split operator. See also SeMeshBase documentation. */
SeBase* vsplit ( SeBase* s1, SeBase* s2 );
/*! Add vertex operator. See also SeMeshBase documentation. */
SeBase* addv ( SeBase* x );
/*! Delete vertex operator. See also SeMeshBase documentation. */
SeBase* delv ( SeBase* y );
private : // IO ========================================================================================
void _elemsave ( SrOutput& out, ElemType type, SeElement* first );
void _elemload ( SrInput& inp, SrArray<SeElement*>& e, const SrArray<SeBase*>& s, SrClassManagerBase* man );
public :
/*! Writes the mesh to the given output. save() will invoke the
virtual methods output() of the associated element managers.
Note: indexing is used during save(). */
bool save ( SrOutput& out );
/*! Reads the mesh from the given input. load() will invoke the
virtual methods input() of the associated element managers.
Note: indexing is used during load(). */
bool load ( SrInput& inp );
};
/*! This is the template version of the SeMeshBase class, that redefines some methods
of SeBase only for the purpose of including type casts to user defined classes.
All methods are implemented inline just calling the corresponding method of
the base class but correctly applying type casts to convert default types
to user types. It must be used together with SeTpl. */
template <class V, class E, class F> //, class VM, class EM, class FM>
class SeMesh : public SeMeshBase
{ public :
typedef Se<V,E,F> S;
typedef SrClassManager<V> VM;
typedef SrClassManager<E> EM;
typedef SrClassManager<F> FM;
SeMesh () : SeMeshBase ( new VM, new EM, new FM ) {}
S* first () const { return (S*)SeMeshBase::first(); }
S* init () { return (S*)SeMeshBase::init(); }
S* mev ( S* s ) { return (S*)SeMeshBase::mev(s); }
S* mev ( S* s1, S* s2 ) { return (S*)SeMeshBase::mev(s1,s2); }
S* mef ( S* s1, S* s2 ) { return (S*)SeMeshBase::mef(s1,s2); }
S* kev ( S* x ) { return (S*)SeMeshBase::kev(x); }
S* kev ( S* x, S* *s ) { return (S*)SeMeshBase::kev(x,(SeBase**)s); }
S* kef ( S* x, S* *s ) { return (S*)SeMeshBase::kef(x,(SeBase**)s); }
S* mg ( S* s1, S* s2 ) { return (S*)SeMeshBase::mg(s1,s2); }
S* flip ( S* x ) { return (S*)SeMeshBase::flip(x); }
S* ecol ( S* x, S* *s ) { return (S*)SeMeshBase::ecol(x,(SeBase**)s); }
S* vsplit ( S* s1, S* s2 ) { return (S*)SeMeshBase::vsplit(s1,s2); }
S* addv ( S* x ) { return (S*)SeMeshBase::addv(x); }
S* delv ( S* y ) { return (S*)SeMeshBase::delv(y); }
};
/*! \class SeMeshBase se_mesh.h
\brief manages topology and attached information of a symedge mesh.
SeMeshBase uses SeBase as argument for many methods, specially for the
topological operators. Each SeBase instance has only one vertex, edge
and face adjacent (or associated) and so it can be used to reference any
of these elements. SeMeshBase destructor calls destroy(), that will call also
each free() method of registered SeElementManagers in the mesh. To attach info
to a mesh, the user must derive SrClassManagerBase, suply the required virtual
methods, and push it in SeMeshBase with push_info() method.
Operators error handling is performed when the checking mode is true (the
default), all operators may then return a 0 (null) pointer when their
parameters are illegal. In such cases, a call to last_op_msg() will return
the error occured. Next is a schema explaining each operator: \code
*========================================================================
* Operator init()
*
* x=init() v1 o o v2 -> v1 o------o v2
* destroy() <-----
* destroy all the previous structure. x
*
*========================================================================
* Operator mev(s)
*
* s x
* <----- <-----
* x=mev(s) o------o o v -> o------o------o v
* s=kev(x) / | / |
* / | / |
* To kev(x), only o o o o
* one edge in v;
*
*========================================================================
* Operator mev(s1,s2)
* o o
* | \
* | s1 \
* | ----> \
* x=mev(s1,s2) o------o---------o -> o------o------o--o
* s1=kev(x,&s2) <---- | o | <--- v
* s2 | v | x
* To mev, s1 & s2 on o o
* the same vertex
* and s1!=s2
*
* To kev(x), more than one edge of x must be incident to v
*
*=========================================================================
* Operator mef(s1,s2)
*
* x=mef(s1,s2) o-------o-------o o-------o-------o
* s1=kef(x,&s2) | <---- | | | |
* | s1 | | | |
* | | | || |
* s1 & s2 on | | -> | e||x |
* same face | | | |V |
* | s2 | | | f |
* in kef(x), x->sym | ----> | | | |
* must be in a diff o-------o-------o o-------o-------o
* face than x
*
*========================================================================
* Operator flip(x)
*
* y=flip(x) o---o---o o---o---o
* / | | / |
* / | | / |
* x & x->sym must / || | / |
* be in diff faces o ||x o -> o---------------o
* and share the | |V / | <------ /
* same edge | | / | y /
* | | / | /
* o---o---o o---o---o
*
* This operator acts as an "edge rotation"; that in triangulations is the
* same as the well known flip (or swap) operator.
*
*========================================================================
* Operator ecol(x,&s2)
*
* s1=ecol(x,&s2) o o
* x=vsplit(s1,s2) / | s1|
* / | ^|
* \ / x | / \ || /
* x and x->sym must \ / --> |/ \ |/
* be in diff faces o---------o v -> o v
* and share the / \ |\ / |\
* same edge / \ | \ / | \
* / \ | / / |
* / \ | / /s2 |
* o V o
*
* In the process, 3 edges, 2 faces and 1 vertex are created/destroyed.
* This operator acts as an "edge collapse", and has
* the "vertex split" operator as inverse.
* The three destroyed edges are incident to x->vtx(), and not v.
*
*========================================================================
* Operator addv()
*
* y=addv(x) ----------- -----------
* x=delv(y) | <-- | |\ /|
* | x | | \ y^/ |
* | | | \ // |
* | | | \ / |
* | o | -> | o |
* | | | / \ |
* | | | / \ |
* | | | / \ |
* | | |/ \|
* ----------- -----------
*
*
\endcode */
//============================ End of File ===============================
# endif // SE_MESH_H