HexahedralMeshTopologyKernel.hh 14.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*===========================================================================*\
 *                                                                           *
 *                            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 <http://www.gnu.org/licenses/>.                                      *
 *                                                                           *
\*===========================================================================*/

#ifndef HEXAHEDRALMESHTOPOLOGYKERNEL_HH
#define HEXAHEDRALMESHTOPOLOGYKERNEL_HH

38
39
40
#ifndef NDEBUG
#include <iostream>
#endif
41
42
#include <set>

43
#include "../Core/TopologyKernel.hh"
44
45
46
47
48
#include "HexahedralMeshIterators.hh"

namespace OpenVolumeMesh {

/**
Mike Kremer's avatar
Mike Kremer committed
49
50
51
 * \class HexahedralMeshTopologyKernel
 *
 * \brief A data structure basing on PolyhedralMesh with specializations for hexahedra.
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
 *
 * 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
 */

78
class HexahedralMeshTopologyKernel : public TopologyKernel {
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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
95
    HexahedralMeshTopologyKernel() = default;
96
97

    // Destructor
98
    ~HexahedralMeshTopologyKernel() override = default;
99
100

    // Overridden function
101
    FaceHandle add_face(const std::vector<HalfEdgeHandle>& _halfedges, bool _topologyCheck = false) override;
102
103

    // Overridden function
104
    FaceHandle add_face(const std::vector<VertexHandle>& _vertices) override;
105
106

    /// Overridden function
107
    CellHandle add_cell(const std::vector<HalfFaceHandle>& _halffaces, bool _topologyCheck = false) override;
108
109
110
111
112
113

private:

    bool check_halfface_ordering(const std::vector<HalfFaceHandle>& _hfs) const;

public:
114

115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
    /** \brief Add cell via incident vertices
     *
     * Test whether all required faces are already defined
     * and, if not, create them.
     * Give vertices in the following order:
     *
     *      5-------6
     *     /|      /|
     *    / |     / |
     *   3-------2  |
     *   |  4----|--7
     *   | /     | /
     *   |/      |/
     *   0-------1
     *
130
     * @param _vertices A list of vertices in the correct order
131
     * @param _topologyCheck Flag if a topology check should be performed before adding the cell
132
133
134
     *
     * @return The new hexahedron's cell handle
     */
135
    CellHandle add_cell(const std::vector<VertexHandle>& _vertices, bool _topologyCheck = false);
136

137
138
    // ======================= Specialized Iterators =============================

139
140
    friend class CellSheetCellIter;
    friend class HalfFaceSheetHalfFaceIter;
141
    friend class HexVertexIter;
142

143
144
    typedef class CellSheetCellIter CellSheetCellIter;
    typedef class HalfFaceSheetHalfFaceIter HalfFaceSheetHalfFaceIter;
145
    typedef class HexVertexIter HexVertexIter;
146

Max Lyon's avatar
Max Lyon committed
147
148
    CellSheetCellIter csc_iter(const CellHandle& _ref_h, const unsigned char _orthDir, int _max_laps = 1) const {
        return CellSheetCellIter(_ref_h, _orthDir, this, _max_laps);
149
150
    }

Max Lyon's avatar
Max Lyon committed
151
152
153
154
    std::pair<CellSheetCellIter,CellSheetCellIter> cell_sheet_cells(const CellHandle& _ref_h, const unsigned char _orthDir, int _max_laps = 1) const {
        CellSheetCellIter begin = csc_iter(_ref_h, _orthDir, _max_laps);
        CellSheetCellIter end   = make_end_circulator(begin);
        return std::make_pair(begin, end);
155
156
    }

Max Lyon's avatar
Max Lyon committed
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
    HalfFaceSheetHalfFaceIter hfshf_iter(const HalfFaceHandle& _ref_h, int _max_laps = 1) const {
        return HalfFaceSheetHalfFaceIter(_ref_h, this, _max_laps);
    }

    std::pair<HalfFaceSheetHalfFaceIter,HalfFaceSheetHalfFaceIter> halfface_sheet_halffaces(const HalfFaceHandle& _ref_h, int _max_laps = 1) const {
        HalfFaceSheetHalfFaceIter begin = hfshf_iter(_ref_h, _max_laps);
        HalfFaceSheetHalfFaceIter end   = make_end_circulator(begin);
        return std::make_pair(begin, end);
    }

    HexVertexIter hv_iter(const CellHandle& _ref_h, int _max_laps = 1) const {
        return HexVertexIter(_ref_h, this, _max_laps);
    }

    std::pair<HexVertexIter,HexVertexIter> hex_vertices(const CellHandle& _ref_h, int _max_laps = 1) const {
        HexVertexIter begin = hv_iter(_ref_h, _max_laps);
        HexVertexIter end   = make_end_circulator(begin);
        return std::make_pair(begin, end);
175
176
    }

177
178
    // ======================= Connectivity functions =============================

Mike Kremer's avatar
Mike Kremer committed
179
    inline HalfFaceHandle opposite_halfface_handle_in_cell(const HalfFaceHandle& _hfh, const CellHandle& _ch) const {
180

181
        assert((unsigned int)_ch.idx() < TopologyKernel::cells_.size());
182
183
184
185
186
187
188
189

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

190
        return TopologyKernel::InvalidHalfFaceHandle;
191
192
193
194
    }

    inline HalfFaceHandle xfront_halfface(const CellHandle& _ch) const {

195
        assert((unsigned int)_ch.idx() < TopologyKernel::cells_.size());
196

197
        return TopologyKernel::cell(_ch).halffaces()[XF];
198
199
200
201
    }

    inline HalfFaceHandle xback_halfface(const CellHandle& _ch) const {

202
        assert((unsigned int)_ch.idx() < TopologyKernel::cells_.size());
203

204
        return TopologyKernel::cell(_ch).halffaces()[XB];
205
206
207
208
    }

    inline HalfFaceHandle yfront_halfface(const CellHandle& _ch) const {

209
        assert((unsigned int)_ch.idx() < TopologyKernel::cells_.size());
210

211
        return TopologyKernel::cell(_ch).halffaces()[YF];
212
213
214
215
    }

    inline HalfFaceHandle yback_halfface(const CellHandle& _ch) const {

216
        assert((unsigned int)_ch.idx() < TopologyKernel::cells_.size());
217

218
        return TopologyKernel::cell(_ch).halffaces()[YB];
219
220
221
222
    }

    inline HalfFaceHandle zfront_halfface(const CellHandle& _ch) const {

223
        assert((unsigned int)_ch.idx() < TopologyKernel::cells_.size());
224

225
        return TopologyKernel::cell(_ch).halffaces()[ZF];
226
227
228
229
    }

    inline HalfFaceHandle zback_halfface(const CellHandle& _ch) const {

230
        assert((unsigned int)_ch.idx() < TopologyKernel::cells_.size());
231

232
        return TopologyKernel::cell(_ch).halffaces()[ZB];
233
234
235
236
    }

    unsigned char orientation(const HalfFaceHandle& _hfh, const CellHandle& _ch) const {

237
        assert((unsigned int)_ch.idx() < TopologyKernel::cells_.size());
238

239
        std::vector<HalfFaceHandle> halffaces = TopologyKernel::cell(_ch).halffaces();
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
        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);
288
        return TopologyKernel::InvalidHalfFaceHandle;
289
290
291
292
    }

    HalfFaceHandle adjacent_halfface_on_sheet(const HalfFaceHandle& _hfh, const HalfEdgeHandle& _heh) const {

293
        if(!TopologyKernel::has_face_bottom_up_incidences()) {
294
#ifndef NDEBUG
295
            std::cerr << "No bottom-up incidences computed so far, could not get adjacent halfface on sheet!" << std::endl;
296
#endif
297
            return TopologyKernel::InvalidHalfFaceHandle;
298
299
300
301
302
303
304
        }

        HalfFaceHandle n_hf = _hfh;
        HalfEdgeHandle n_he = _heh;

        // Try the 1st way
        while(true) {
305
306
307
308
309
310
311
312
            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;
313
314
315
            else return n_hf;
        }

316
317
        n_hf = TopologyKernel::opposite_halfface_handle(_hfh);
        n_he = TopologyKernel::opposite_halfedge_handle(_heh);
318
319
320

        // Try the 2nd way
        while(true) {
321
322
323
324
325
326
327
328
329
            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);
330
331
        }

332
        return TopologyKernel::InvalidHalfFaceHandle;
333
334
335
336
    }

    HalfFaceHandle adjacent_halfface_on_surface(const HalfFaceHandle& _hfh, const HalfEdgeHandle& _heh) const {

337
        for(OpenVolumeMesh::HalfEdgeHalfFaceIter hehf_it = TopologyKernel::hehf_iter(_heh);
338
339
                hehf_it.valid(); ++hehf_it) {
            if(*hehf_it == _hfh) continue;
340
            if(TopologyKernel::is_boundary(*hehf_it)) {
341
342
                return *hehf_it;
            }
343
344
            if(TopologyKernel::is_boundary(TopologyKernel::opposite_halfface_handle(*hehf_it))) {
                return TopologyKernel::opposite_halfface_handle(*hehf_it);
345
346
            }
        }
347
        return TopologyKernel::InvalidHalfFaceHandle;
348
349
350
351
    }

    HalfFaceHandle neighboring_outside_halfface(const HalfFaceHandle& _hfh, const HalfEdgeHandle& _heh) const {

352
        if(!TopologyKernel::has_face_bottom_up_incidences()) {
353
#ifndef NDEBUG
354
            std::cerr << "No bottom-up incidences computed so far, could not get neighboring outside halfface!" << std::endl;
355
#endif
356
            return TopologyKernel::InvalidHalfFaceHandle;
357
358
        }

359
        for(OpenVolumeMesh::HalfEdgeHalfFaceIter hehf_it = TopologyKernel::hehf_iter(_heh);
360
361
                hehf_it; ++hehf_it) {
            if(*hehf_it == _hfh) continue;
362
363
364
            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);
365
366
        }

367
        return TopologyKernel::InvalidHalfFaceHandle;
368
369
370
371
372
373
374
375
376
377
378
379
    }

private:

    const HalfFaceHandle& get_adjacent_halfface(const HalfFaceHandle& _hfh, const HalfEdgeHandle& _heh,
            const std::vector<HalfFaceHandle>& _halffaces) const;

};

} // Namespace OpenVolumeMesh

#endif /* HEXAHEDRALMESHTOPOLOGYKERNEL_HH */