/*===========================================================================*\ * * * OpenVolumeMesh * * Copyright (C) 2011 by Computer Graphics Group, RWTH Aachen * * www.openvolumemesh.org * * * *---------------------------------------------------------------------------* * This file is part of OpenVolumeMesh. * * * * OpenVolumeMesh is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 3 of * * the License, or (at your option) any later version with the * * following exceptions: * * * * If other files instantiate templates or use macros * * or inline functions from this file, or you compile this file and * * link it with other files to produce an executable, this file does * * not by itself cause the resulting executable to be covered by the * * GNU Lesser General Public License. This exception does not however * * invalidate any other reasons why the executable file might be * * covered by the GNU Lesser General Public License. * * * * OpenVolumeMesh is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU LesserGeneral Public * * License along with OpenVolumeMesh. If not, * * see . * * * \*===========================================================================*/ /*===========================================================================*\ * * * $Revision$ * * $Date$ * * $LastChangedBy$ * * * \*===========================================================================*/ #ifndef TOPOLOGYKERNEL_HH_ #define TOPOLOGYKERNEL_HH_ #include #include #include #include #include "BaseEntities.hh" #include "OpenVolumeMeshHandle.hh" #include "ResourceManager.hh" #include "Iterators.hh" namespace OpenVolumeMesh { class TopologyKernel : public ResourceManager { public: TopologyKernel(); virtual ~TopologyKernel(); /* * Defines and constants */ static const VertexHandle InvalidVertexHandle; static const EdgeHandle InvalidEdgeHandle; static const FaceHandle InvalidFaceHandle; static const CellHandle InvalidCellHandle; static const HalfEdgeHandle InvalidHalfEdgeHandle; static const HalfFaceHandle InvalidHalfFaceHandle; typedef OpenVolumeMeshEdge Edge; typedef OpenVolumeMeshFace Face; typedef OpenVolumeMeshCell Cell; //===================================================================== // Iterators //===================================================================== friend class VertexOHalfEdgeIter; friend class HalfEdgeHalfFaceIter; friend class VertexCellIter; friend class HalfEdgeCellIter; friend class CellVertexIter; friend class CellCellIter; friend class HalfFaceVertexIter; friend class BoundaryFaceIter; friend class VertexIter; friend class EdgeIter; friend class HalfEdgeIter; friend class FaceIter; friend class HalfFaceIter; friend class CellIter; VertexOHalfEdgeIter voh_iter(const VertexHandle& _h) const { return VertexOHalfEdgeIter(_h, this); } HalfEdgeHalfFaceIter hehf_iter(const HalfEdgeHandle& _h) const { return HalfEdgeHalfFaceIter(_h, this); } VertexCellIter vc_iter(const VertexHandle& _h) const { return VertexCellIter(_h, this); } HalfEdgeCellIter hec_iter(const HalfEdgeHandle& _h) const { return HalfEdgeCellIter(_h, this); } CellVertexIter cv_iter(const CellHandle& _h) const { return CellVertexIter(_h, this); } CellCellIter cc_iter(const CellHandle& _h) const { return CellCellIter(_h, this); } HalfFaceVertexIter hfv_iter(const HalfFaceHandle& _h) const { return HalfFaceVertexIter(_h, this); } BoundaryFaceIter bf_iter() const { return BoundaryFaceIter(this); } VertexIter v_iter() const { return VertexIter(this); } VertexIter vertices_begin() const { return VertexIter(this, VertexHandle(0)); } VertexIter vertices_end() const { return VertexIter(this, VertexHandle(n_vertices())); } EdgeIter e_iter() const { return EdgeIter(this); } EdgeIter edges_begin() const { return EdgeIter(this, EdgeHandle(0)); } EdgeIter edges_end() const { return EdgeIter(this, EdgeHandle(edges_.size())); } HalfEdgeIter he_iter() const { return HalfEdgeIter(this); } HalfEdgeIter halfedges_begin() const { return HalfEdgeIter(this, HalfEdgeHandle(0)); } HalfEdgeIter halfedges_end() const { return HalfEdgeIter(this, HalfEdgeHandle(edges_.size() * 2)); } FaceIter f_iter() const { return FaceIter(this); } FaceIter faces_begin() const { return FaceIter(this, FaceHandle(0)); } FaceIter faces_end() const { return FaceIter(this, FaceHandle(faces_.size())); } HalfFaceIter hf_iter() const { return HalfFaceIter(this); } HalfFaceIter halffaces_begin() const { return HalfFaceIter(this, HalfFaceHandle(0)); } HalfFaceIter halffaces_end() const { return HalfFaceIter(this, HalfFaceHandle(faces_.size() * 2)); } CellIter c_iter() const { return CellIter(this); } CellIter cells_begin() const { return CellIter(this, CellHandle(0)); } CellIter cells_end() const { return CellIter(this, CellHandle(cells_.size())); } /* * Virtual functions with implementation */ /// Get number of vertices in mesh virtual unsigned int n_vertices() const { return n_vertices_; } /// Get number of edges in mesh virtual unsigned int n_edges() const { return n_edges_; } /// Get number of halfedges in mesh virtual unsigned int n_halfedges() const { return n_edges_ * 2u; } /// Get number of faces in mesh virtual unsigned int n_faces() const { return n_faces_; } /// Get number of halffaces in mesh virtual unsigned int n_halffaces() const { return n_faces_ * 2u; } /// Get number of cells in mesh virtual unsigned int n_cells() const { return n_cells_; } private: // Cache total entity numbers unsigned int n_vertices_; unsigned int n_edges_; unsigned int n_faces_; unsigned int n_cells_; public: /// Add abstract vertex virtual VertexHandle add_vertex(); //======================================================================= /// Add edge virtual EdgeHandle add_edge(const VertexHandle& _fromVertex, const VertexHandle& _toHandle, bool _allowDuplicates = false); /// Add face via incident edges virtual FaceHandle add_face(const std::vector& _halfedges, bool _topologyCheck = false); /// Add face via incident vertices virtual FaceHandle add_face(const std::vector& _vertices); /// Add cell via incident halffaces virtual CellHandle add_cell(const std::vector& _halffaces, bool _topologyCheck = false); /* * Non-virtual functions */ /// Get edge with handle _edgeHandle const Edge& edge(const EdgeHandle& _edgeHandle) const; /// Get face with handle _faceHandle const Face& face(const FaceHandle& _faceHandle) const; /// Get cell with handle _cellHandle const Cell& cell(const CellHandle& _cellHandle) const; /// Get edge with handle _edgeHandle Edge& edge(const EdgeHandle& _edgeHandle); /// Get face with handle _faceHandle Face& face(const FaceHandle& _faceHandle); /// Get cell with handle _cellHandle Cell& cell(const CellHandle& _cellHandle); /// Get edge that corresponds to halfedge with handle _halfEdgeHandle const Edge halfedge(const HalfEdgeHandle& _halfEdgeHandle) const; /// Get face that corresponds to halfface with handle _halfFaceHandle const Face halfface(const HalfFaceHandle& _halfFaceHandle) const; /// Get opposite halfedge that corresponds to halfedge with handle _halfEdgeHandle const Edge opposite_halfedge(const HalfEdgeHandle& _halfEdgeHandle) const; /// Get opposite halfface that corresponds to halfface with handle _halfFaceHandle const Face opposite_halfface(const HalfFaceHandle& _halfFaceHandle) const; // Get halfedge from vertex _vh1 to _vh2 const HalfEdgeHandle halfedge(const VertexHandle& _vh1, const VertexHandle& _vh2) const; // Get half-face from list of incident vertices (in connected order) // Note: Only the first three vertices are checked const HalfFaceHandle halfface(const std::vector& _vs) const; // Get half-face from list of incident half-edges // Note: Only the first two half-edges are checked const HalfFaceHandle halfface(const std::vector& _hes) const; /// Get next halfedge within a halfface const HalfEdgeHandle next_halfedge_in_halfface(const HalfEdgeHandle& _heh, const HalfFaceHandle& _hfh) const; /// Get previous halfedge within a halfface const HalfEdgeHandle prev_halfedge_in_halfface(const HalfEdgeHandle& _heh, const HalfFaceHandle& _hfh) const; /// Get valence of vertex (number of incident edges) inline unsigned int valence(const VertexHandle& _vh) const { if(!v_bottom_up_) { std::cerr << "Could not get vertex valence: No bottom-up adjacencies for vertices available!" << std::endl; return 0u; } assert((unsigned int)_vh.idx() < outgoing_hes_per_vertex_.size()); return outgoing_hes_per_vertex_[_vh.idx()].size(); } /// Get valence of edge (number of incident faces) inline unsigned int valence(const EdgeHandle& _eh) const { if(!e_bottom_up_) { std::cerr << "Could not get edge valence: No bottom-up adjacencies for edges available!" << std::endl; return 0u; } assert((unsigned int)halfedge_handle(_eh, 0).idx() < incident_hfs_per_he_.size()); return incident_hfs_per_he_[halfedge_handle(_eh, 0).idx()].size(); } /// Get valence of face (number of incident edges) inline unsigned int valence(const FaceHandle& _fh) const { assert((unsigned int)_fh.idx() < faces_.size()); return face(_fh).halfedges().size(); } /// Get valence of cell (number of incident faces) inline unsigned int valence(const CellHandle& _ch) const { assert((unsigned int)_ch.idx() < cells_.size()); return cell(_ch).halffaces().size(); } //===================================================================== // Delete entities //===================================================================== public: virtual VertexIter delete_vertex(const VertexHandle& _h); virtual EdgeIter delete_edge(const EdgeHandle& _h); virtual FaceIter delete_face(const FaceHandle& _h); virtual CellIter delete_cell(const CellHandle& _h); public: /// Clear whole mesh virtual void clear(bool _clearProps = true) { edges_.clear(); faces_.clear(); cells_.clear(); outgoing_hes_per_vertex_.clear(); incident_hfs_per_he_.clear(); incident_cell_per_hf_.clear(); n_vertices_ = 0; n_edges_ = 0; n_faces_ = 0; n_cells_ = 0; if(_clearProps) { // Delete all property data clear_vertex_props(); clear_edge_props(); clear_halfedge_props(); clear_face_props(); clear_halfface_props(); clear_cell_props(); clear_mesh_props(); } else { // Resize props resize_vprops(0u); resize_eprops(0u); resize_fprops(0u); resize_cprops(0u); } } //===================================================================== // Bottom-up Adjacencies //===================================================================== public: void enable_bottom_up_adjacencies(bool _enable) { enable_vertex_bottom_up_adjacencies(_enable); enable_edge_bottom_up_adjacencies(_enable); enable_face_bottom_up_adjacencies(_enable); } void enable_vertex_bottom_up_adjacencies(bool _enable) { if(_enable && !v_bottom_up_) { // Vertex bottom-up adjacencies have to be // recomputed for the whole mesh compute_vertex_bottom_up_adjacencies(); } if(!_enable) { outgoing_hes_per_vertex_.clear(); } v_bottom_up_ = _enable; } void enable_edge_bottom_up_adjacencies(bool _enable) { if(_enable && !e_bottom_up_) { // Edge bottom-up adjacencies have to be // recomputed for the whole mesh compute_edge_bottom_up_adjacencies(); if(f_bottom_up_) { std::for_each(edges_begin(), edges_end(), std::tr1::bind(&TopologyKernel::reorder_incident_halffaces, this, std::tr1::placeholders::_1)); } } if(!_enable) { incident_hfs_per_he_.clear(); } e_bottom_up_ = _enable; } void enable_face_bottom_up_adjacencies(bool _enable) { if(_enable && !f_bottom_up_) { // Face bottom-up adjacencies have to be // recomputed for the whole mesh compute_face_bottom_up_adjacencies(); if(e_bottom_up_) { std::for_each(edges_begin(), edges_end(), std::tr1::bind(&TopologyKernel::reorder_incident_halffaces, this, std::tr1::placeholders::_1)); } } if(!_enable) { incident_cell_per_hf_.clear(); } f_bottom_up_ = _enable; } bool has_full_bottom_up_adjacencies() const { return (has_vertex_bottom_up_adjacencies() && has_edge_bottom_up_adjacencies() && has_face_bottom_up_adjacencies()); } bool has_vertex_bottom_up_adjacencies() const { return v_bottom_up_; } bool has_edge_bottom_up_adjacencies() const { return e_bottom_up_; } bool has_face_bottom_up_adjacencies() const { return f_bottom_up_; } private: void compute_vertex_bottom_up_adjacencies(); void compute_edge_bottom_up_adjacencies(); void compute_face_bottom_up_adjacencies(); void reorder_incident_halffaces(const EdgeHandle& _eh); // Outgoing halfedges per vertex std::vector > outgoing_hes_per_vertex_; // Incident halffaces per (directed) halfedge std::vector > incident_hfs_per_he_; // Incident cell (at most one) per halfface std::vector incident_cell_per_hf_; bool v_bottom_up_; bool e_bottom_up_; bool f_bottom_up_; //===================================================================== // Connectivity //===================================================================== public: /// Get halfface that is adjacent (w.r.t. a common halfedge) within the same cell HalfFaceHandle adjacent_halfface_in_cell(const HalfFaceHandle& _halfFaceHandle, const HalfEdgeHandle& _halfEdgeHandle) const; /// Get cell that is incident to the given halfface CellHandle incident_cell(const HalfFaceHandle& _halfFaceHandle) const; bool is_boundary(const HalfFaceHandle& _halfFaceHandle) const { return _halfFaceHandle.idx() >= 0 && (unsigned int)_halfFaceHandle.idx() < incident_cell_per_hf_.size() && incident_cell_per_hf_[_halfFaceHandle.idx()] == InvalidCellHandle; } bool is_boundary(const FaceHandle& _faceHandle) const { return is_boundary(halfface_handle(_faceHandle, 0)) || is_boundary(halfface_handle(_faceHandle, 1)); } bool is_boundary(const EdgeHandle& _edgeHandle) const { if(!e_bottom_up_) { std::cerr << "Error: Function is_boundary() needs bottom-up adjacencies for edges!" << std::endl; return false; } for(HalfEdgeHalfFaceIter hehf_it = hehf_iter(halfedge_handle(_edgeHandle, 0)); hehf_it.valid(); ++hehf_it) { if(is_boundary(face_handle(*hehf_it))) { return true; } } return false; } bool is_boundary(const HalfEdgeHandle& _halfedgeHandle) const { if(!e_bottom_up_) { std::cerr << "Error: Function is_boundary() needs bottom-up adjacencies for edges!" << std::endl; return false; } for(HalfEdgeHalfFaceIter hehf_it = hehf_iter(_halfedgeHandle); hehf_it.valid(); ++hehf_it) { if(is_boundary(face_handle(*hehf_it))) { return true; } } return false; } bool is_boundary(const VertexHandle& _vertexHandle) const { if(!v_bottom_up_) { std::cerr << "Error: Function is_boundary() needs bottom-up adjacencies for vertices!" << std::endl; return false; } for(VertexOHalfEdgeIter voh_it = voh_iter(_vertexHandle); voh_it.valid(); ++voh_it) { if(is_boundary(*voh_it)) return true; } return false; } unsigned int n_vertices_in_cell(const CellHandle& _ch) const { std::set vertices; std::vector hfs = cell(_ch).halffaces(); for(std::vector::const_iterator hf_it = hfs.begin(); hf_it != hfs.end(); ++hf_it) { std::vector hes = halfface(*hf_it).halfedges(); for(std::vector::const_iterator he_it = hes.begin(); he_it != hes.end(); ++he_it) { vertices.insert(halfedge(*he_it).to_vertex()); } } return vertices.size(); } //========================================================================= /* * Non-virtual functions */ const Edge opposite_halfedge(const Edge& _edge) const { return Edge(_edge.to_vertex(), _edge.from_vertex()); } const Face opposite_halfface(const Face& _face) const { std::vector opp_halfedges; for(std::vector::const_iterator it = _face.halfedges().begin(); it != _face.halfedges().end(); ++it) { opp_halfedges.insert(opp_halfedges.begin(), opposite_halfedge_handle(*it)); } return Face(opp_halfedges); } /* * Static functions */ /// Conversion function static inline HalfEdgeHandle halfedge_handle(const EdgeHandle& _h, const unsigned char _subIdx) { // Is handle in range? if(_h.idx() < 0 || _subIdx > 1) return InvalidHalfEdgeHandle; return HalfEdgeHandle((2 * _h.idx()) + (_subIdx ? 1 : 0)); } /// Conversion function static inline HalfFaceHandle halfface_handle(const FaceHandle& _h, const unsigned char _subIdx) { // Is handle in range? if(_h.idx() < 0 || _subIdx > 1) return InvalidHalfFaceHandle; return HalfFaceHandle((2 * _h.idx()) + (_subIdx ? 1 : 0)); } /// Handle conversion static inline EdgeHandle edge_handle(const HalfEdgeHandle& _h) { // Is handle in range? if(_h.idx() < 0) return InvalidEdgeHandle; return EdgeHandle((int)(_h.idx() / 2)); } static inline FaceHandle face_handle(const HalfFaceHandle& _h) { // Is handle in range? if(_h.idx() < 0) return InvalidFaceHandle; return FaceHandle((int)(_h.idx() / 2)); } static inline HalfEdgeHandle opposite_halfedge_handle(const HalfEdgeHandle& _h) { // Is handle in range? if(_h.idx() < 0) return InvalidHalfEdgeHandle; // Is handle even? if(_h.idx() % 2 == 0) { return HalfEdgeHandle(_h.idx() + 1); } return HalfEdgeHandle(_h.idx() - 1); } static inline HalfFaceHandle opposite_halfface_handle(const HalfFaceHandle& _h) { // Is handle in range? if(_h.idx() < 0) return InvalidHalfFaceHandle; // Is handle even? if(_h.idx() % 2 == 0) { return HalfFaceHandle(_h.idx() + 1); } return HalfFaceHandle(_h.idx() - 1); } protected: // List of edges std::vector edges_; // List of faces std::vector faces_; // List of cells std::vector cells_; }; } #endif /* TOPOLOGYKERNEL_HH_ */