/*===========================================================================*\ * * * 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 HEXAHEDRALMESHTOPOLOGYKERNEL_HH #define HEXAHEDRALMESHTOPOLOGYKERNEL_HH #include #include "../Core/TopologyKernel.hh" #include "HexahedralMeshIterators.hh" namespace OpenVolumeMesh { /** * \class HexahedralMeshTopologyKernel * * \brief A data structure basing on PolyhedralMesh with specializations for hexahedra. * * The hexahedron has an induced "virtual" coordinate system. This supposes * the incident half-faces to be given in a specific order. * See the following figure for an illustration of the induced * coordinate system. * * \image html induced_coordsys.png * * The abbreviations XF, XB, etc. are short for * * \li \c XF: X-axis front face * \li \c XB: X-axis back face * \li \c YF: Y-axis front face * \li \c ... * * The axes refer to the intrinsic "virtual" axes of the hexahedron. * The incident half-faces have to be defined in the following order: * * \li \c 1. XF * \li \c 2. XB * \li \c 3. YF * \li \c 4. YB * \li \c 5. ZF * \li \c 6. ZB */ class HexahedralMeshTopologyKernel : public TopologyKernel { public: // Orientation constants static const unsigned char XF = 0; static const unsigned char XB = 1; static const unsigned char YF = 2; static const unsigned char YB = 3; static const unsigned char ZF = 4; static const unsigned char ZB = 5; static const unsigned char INVALID = 6; static inline unsigned char opposite_orientation(const unsigned char _d) { return (_d % 2 == 0 ? _d + 1 : _d - 1); } // Constructor HexahedralMeshTopologyKernel(); // Destructor ~HexahedralMeshTopologyKernel(); // Overridden function virtual FaceHandle add_face(const std::vector& _halfedges, bool _topologyCheck = true); // Overridden function virtual FaceHandle add_face(const std::vector& _vertices); /// Overridden function virtual CellHandle add_cell(const std::vector& _halffaces, bool _topologyCheck = true, bool _reorderFaces = false); // ======================= Specialized Iterators ============================= friend class CellSheetCellIter; friend class HalfFaceSheetHalfFaceIter; friend class OutsideNeighborHalfFaceIter; typedef class CellSheetCellIter CellSheetCellIter; typedef class HalfFaceSheetHalfFaceIter HalfFaceSheetHalfFaceIter; typedef class OutsideNeighborHalfFaceIter OutsideNeighborHalfFaceIter; CellSheetCellIter csc_iter(const CellHandle& _ref_h, const unsigned char _orthDir) const { return CellSheetCellIter(_ref_h, _orthDir, this); } HalfFaceSheetHalfFaceIter hfshf_iter(const HalfFaceHandle& _ref_h) const { return HalfFaceSheetHalfFaceIter(_ref_h, this); } OutsideNeighborHalfFaceIter onhf_iter(const HalfFaceHandle& _ref_h) const { return OutsideNeighborHalfFaceIter(_ref_h, this); } // ======================= Connectivity functions ============================= inline HalfFaceHandle opposite_halfface_handle_in_cell(const HalfFaceHandle& _hfh, const CellHandle& _ch) { assert((unsigned int)_ch < TopologyKernel::cells_.size()); if(orientation(_hfh, _ch) == XF) return xback_halfface(_ch); if(orientation(_hfh, _ch) == XB) return xfront_halfface(_ch); if(orientation(_hfh, _ch) == YF) return yback_halfface(_ch); if(orientation(_hfh, _ch) == YB) return yfront_halfface(_ch); if(orientation(_hfh, _ch) == ZF) return zback_halfface(_ch); if(orientation(_hfh, _ch) == ZB) return zfront_halfface(_ch); return TopologyKernel::InvalidHalfFaceHandle; } inline HalfFaceHandle xfront_halfface(const CellHandle& _ch) const { assert((unsigned int)_ch < TopologyKernel::cells_.size()); return TopologyKernel::cell(_ch).halffaces()[XF]; } inline HalfFaceHandle xback_halfface(const CellHandle& _ch) const { assert((unsigned int)_ch < TopologyKernel::cells_.size()); return TopologyKernel::cell(_ch).halffaces()[XB]; } inline HalfFaceHandle yfront_halfface(const CellHandle& _ch) const { assert((unsigned int)_ch < TopologyKernel::cells_.size()); return TopologyKernel::cell(_ch).halffaces()[YF]; } inline HalfFaceHandle yback_halfface(const CellHandle& _ch) const { assert((unsigned int)_ch < TopologyKernel::cells_.size()); return TopologyKernel::cell(_ch).halffaces()[YB]; } inline HalfFaceHandle zfront_halfface(const CellHandle& _ch) const { assert((unsigned int)_ch < TopologyKernel::cells_.size()); return TopologyKernel::cell(_ch).halffaces()[ZF]; } inline HalfFaceHandle zback_halfface(const CellHandle& _ch) const { assert((unsigned int)_ch < TopologyKernel::cells_.size()); return TopologyKernel::cell(_ch).halffaces()[ZB]; } unsigned char orientation(const HalfFaceHandle& _hfh, const CellHandle& _ch) const { assert((unsigned int)_ch < TopologyKernel::cells_.size()); std::vector halffaces = TopologyKernel::cell(_ch).halffaces(); for(unsigned int i = 0; i < halffaces.size(); ++i) { if(halffaces[i] == _hfh) return (unsigned char)i; } return INVALID; } static inline unsigned char orthogonal_orientation(const unsigned char _o1, const unsigned char _o2) { if(_o1 == XF && _o2 == YF) return ZF; if(_o1 == XF && _o2 == YB) return ZB; if(_o1 == XF && _o2 == ZF) return YB; if(_o1 == XF && _o2 == ZB) return YF; if(_o1 == XB && _o2 == YF) return ZB; if(_o1 == XB && _o2 == YB) return ZF; if(_o1 == XB && _o2 == ZF) return YF; if(_o1 == XB && _o2 == ZB) return YB; if(_o1 == YF && _o2 == XF) return ZB; if(_o1 == YF && _o2 == XB) return ZF; if(_o1 == YF && _o2 == ZF) return XF; if(_o1 == YF && _o2 == ZB) return XB; if(_o1 == YB && _o2 == XF) return ZF; if(_o1 == YB && _o2 == XB) return ZB; if(_o1 == YB && _o2 == ZF) return XB; if(_o1 == YB && _o2 == ZB) return XF; if(_o1 == ZF && _o2 == YF) return XB; if(_o1 == ZF && _o2 == YB) return XF; if(_o1 == ZF && _o2 == XF) return YF; if(_o1 == ZF && _o2 == XB) return YB; if(_o1 == ZB && _o2 == YF) return XF; if(_o1 == ZB && _o2 == YB) return XB; if(_o1 == ZB && _o2 == XF) return YB; if(_o1 == ZB && _o2 == XB) return YF; return INVALID; } inline HalfFaceHandle get_oriented_halfface(const unsigned char _o, const CellHandle& _ch) const { if(_o == XF) return xfront_halfface(_ch); if(_o == XB) return xback_halfface(_ch); if(_o == YF) return yfront_halfface(_ch); if(_o == YB) return yback_halfface(_ch); if(_o == ZF) return zfront_halfface(_ch); if(_o == ZB) return zback_halfface(_ch); return TopologyKernel::InvalidHalfFaceHandle; } HalfFaceHandle adjacent_halfface_on_sheet(const HalfFaceHandle& _hfh, const HalfEdgeHandle& _heh) const { if(!TopologyKernel::has_face_bottom_up_adjacencies()) { std::cerr << "No bottom-up adjacencies computed so far, could not get adjacent halfface on sheet!" << std::endl; return TopologyKernel::InvalidHalfFaceHandle; } HalfFaceHandle n_hf = _hfh; HalfEdgeHandle n_he = _heh; // Try the 1st way while(true) { n_hf = TopologyKernel::adjacent_halfface_in_cell(n_hf, n_he); if(n_hf == TopologyKernel::InvalidHalfFaceHandle) break; n_hf = TopologyKernel::opposite_halfface_handle(n_hf); if(n_hf == TopologyKernel::InvalidHalfFaceHandle) break; HalfEdgeHandle o_he = TopologyKernel::opposite_halfedge_handle(n_he); if(o_he == TopologyKernel::InvalidHalfEdgeHandle) break; n_hf = TopologyKernel::adjacent_halfface_in_cell(n_hf, o_he); if(n_hf == TopologyKernel::InvalidHalfFaceHandle) break; else return n_hf; } n_hf = TopologyKernel::opposite_halfface_handle(_hfh); n_he = TopologyKernel::opposite_halfedge_handle(_heh); // Try the 2nd way while(true) { n_hf = TopologyKernel::adjacent_halfface_in_cell(n_hf, n_he); if(n_hf == TopologyKernel::InvalidHalfFaceHandle) break; n_hf = TopologyKernel::opposite_halfface_handle(n_hf); if(n_hf == TopologyKernel::InvalidHalfFaceHandle) break; HalfEdgeHandle o_he = TopologyKernel::opposite_halfedge_handle(n_he); if(o_he == TopologyKernel::InvalidHalfEdgeHandle) break; n_hf = TopologyKernel::adjacent_halfface_in_cell(n_hf, o_he); if(n_hf == TopologyKernel::InvalidHalfFaceHandle) break; else return TopologyKernel::opposite_halfface_handle(n_hf); } return TopologyKernel::InvalidHalfFaceHandle; } HalfFaceHandle adjacent_halfface_on_surface(const HalfFaceHandle& _hfh, const HalfEdgeHandle& _heh) const { for(OpenVolumeMesh::HalfEdgeHalfFaceIter hehf_it = TopologyKernel::hehf_iter(_heh); hehf_it.valid(); ++hehf_it) { if(*hehf_it == _hfh) continue; if(TopologyKernel::is_boundary(*hehf_it)) { return *hehf_it; } if(TopologyKernel::is_boundary(TopologyKernel::opposite_halfface_handle(*hehf_it))) { return TopologyKernel::opposite_halfface_handle(*hehf_it); } } return TopologyKernel::InvalidHalfFaceHandle; } HalfFaceHandle neighboring_outside_halfface(const HalfFaceHandle& _hfh, const HalfEdgeHandle& _heh) const { if(!TopologyKernel::has_face_bottom_up_adjacencies()) { std::cerr << "No bottom-up adjacencies computed so far, could not get neighboring outside halfface!" << std::endl; return TopologyKernel::InvalidHalfFaceHandle; } for(OpenVolumeMesh::HalfEdgeHalfFaceIter hehf_it = TopologyKernel::hehf_iter(_heh); hehf_it; ++hehf_it) { if(*hehf_it == _hfh) continue; if(TopologyKernel::is_boundary(*hehf_it)) return *hehf_it; if(TopologyKernel::is_boundary(TopologyKernel::opposite_halfface_handle(*hehf_it))) return TopologyKernel::opposite_halfface_handle(*hehf_it); } return TopologyKernel::InvalidHalfFaceHandle; } private: const HalfFaceHandle& get_adjacent_halfface(const HalfFaceHandle& _hfh, const HalfEdgeHandle& _heh, const std::vector& _halffaces) const; }; } // Namespace OpenVolumeMesh #endif /* HEXAHEDRALMESHTOPOLOGYKERNEL_HH */