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
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 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
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
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
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
/**
 * MOAB, a Mesh-Oriented datABase, is a software component for creating,
 * storing and accessing finite element mesh data.
 *
 * Copyright 2004 Sandia Corporation.  Under the terms of Contract
 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
 * retains certain rights in this software.
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 *
 */

#ifndef MOAB_SKINNER_HPP
#define MOAB_SKINNER_HPP

#include "moab/Forward.hpp"
#include "moab/Range.hpp"
#include <vector>

namespace moab
{

class ScdBox;

/** \class Skinner
 * \brief Class for constructing and querying skin of a mesh
 * Class for constructing and querying skin of a mesh, defined as the outside lower-dimensional
 * boundary of a mesh or a given set of entities.  This class provides options for finding the
 * forward- and reverse-oriented members of the skin.  Several methods are available for computing
 * the skin, e.g. using geometric topology sets, vertex-entity adjacencies, or directly from
 * (n-1)-dimensional entities.
 */
class Skinner
{

    enum direction
    {
        FORWARD = 1,
        REVERSE = -1
    };

  protected:
    //! the MB instance that this works with
    Interface* thisMB;

    Tag mDeletableMBTag;
    Tag mAdjTag;
    int mTargetDim;

  public:
    //! constructor, takes mdb instance
    Skinner( Interface* mdb ) : thisMB( mdb ), mDeletableMBTag( 0 ), mAdjTag( 0 ), mTargetDim( 0 ) {}

    //! destructor
    ~Skinner();

    ErrorCode find_geometric_skin( const EntityHandle meshset, Range& forward_target_entities );

    /**\brief will accept entities all of one dimension and
     *        return entities of n-1 dimension; NOTE: get_vertices argument controls whether
     * vertices or entities of n-1 dimension are returned, and only one of these is allowed
     * (i.e. this function returns only vertices or (n-1)-dimensional entities, but not both)
     * \param entities The elements for which to find the skin
     * \param get_vertices If true, vertices on the skin are returned
     *        in the range, otherwise elements are returned
     * \param output_handles Range holding skin entities returned
     * \param output_reverse_handles Range holding entities on skin which
     *        are reversed wrt entities
     * \param create_vert_elem_adjs If true, this function will cause
     *        vertex-element adjacencies to be generated
     * \param create_skin_elements If true, this function will cause creation
     *        of skin entities, otherwise only skin entities already extant
     *        will be returned
     */
    ErrorCode find_skin( const EntityHandle meshset,
                         const Range& entities,
                         bool get_vertices,
                         Range& output_handles,
                         Range* output_reverse_handles = 0,
                         bool create_vert_elem_adjs    = false,
                         bool create_skin_elements     = true,
                         bool look_for_scd             = false );

    /**\brief will accept entities all of one dimension and
     *        return entities of n-1 dimension; NOTE: get_vertices argument controls whether
     * vertices or entities of n-1 dimension are returned, and only one of these is allowed
     * (i.e. this function returns only vertices or (n-1)-dimensional entities, but not both)
     * \param entities Pointer to elements for which to find the skin
     * \param num_entities Number of entities in vector
     * \param get_vertices If true, vertices on the skin are returned
     *        in the range, otherwise elements are returned
     * \param output_handles Range holding skin entities returned
     * \param output_reverse_handles Range holding entities on skin which
     *        are reversed wrt entities
     * \param create_vert_elem_adjs If true, this function will cause
     *        vertex-element adjacencies to be generated
     * \param create_skin_elements If true, this function will cause creation
     *        of skin entities, otherwise only skin entities already extant
     *        will be returned
     */
    ErrorCode find_skin( const EntityHandle this_set,
                         const EntityHandle* entities,
                         int num_entities,
                         bool get_vertices,
                         Range& output_handles,
                         Range* output_reverse_handles = 0,
                         bool create_vert_elem_adjs    = false,
                         bool create_skin_elements     = true,
                         bool look_for_scd             = false );

    /**\brief get skin entities of prescribed dimension
     * \param entities The elements for which to find the skin
     * \param dim Dimension of skin entities requested
     * \param skin_entities Range holding skin entities returned
     * \param create_vert_elem_adjs If true, this function will cause
     *        vertex-element adjacencies to be generated
     */
    ErrorCode find_skin( const EntityHandle this_set,
                         const Range& entities,
                         int dim,
                         Range& skin_entities,
                         bool create_vert_elem_adjs = false,
                         bool create_skin_elements  = true );

    ErrorCode classify_2d_boundary( const Range& boundary,
                                    const Range& bar_elements,
                                    EntityHandle boundary_edges,
                                    EntityHandle inferred_edges,
                                    EntityHandle non_manifold_edges,
                                    EntityHandle other_edges,
                                    int& number_boundary_nodes );

    //! given a skin of dimension 2, will classify and return edges
    //! as boundary, inferred, and non-manifold, and the rest (other)
    ErrorCode classify_2d_boundary( const Range& boundary,
                                    const Range& mesh_1d_elements,
                                    Range& boundary_edges,
                                    Range& inferred_edges,
                                    Range& non_manifold_edges,
                                    Range& other_edges,
                                    int& number_boundary_nodes );

  protected:
    ErrorCode initialize();

    ErrorCode deinitialize();

    ErrorCode find_skin_noadj( const Range& source_entities,
                               Range& forward_target_entities,
                               Range& reverse_target_entities );

    ErrorCode add_adjacency( EntityHandle entity );

    void add_adjacency( EntityHandle entity, const EntityHandle* conn, const int num_nodes );

    ErrorCode remove_adjacency( EntityHandle entity );

    bool entity_deletable( EntityHandle entity );

    void find_match( EntityType type,
                     const EntityHandle* conn,
                     const int num_nodes,
                     EntityHandle& match,
                     Skinner::direction& direct );

    bool connectivity_match( const EntityHandle* conn1,
                             const EntityHandle* conn2,
                             const int num_verts,
                             Skinner::direction& direct );

    void find_inferred_edges( Range& skin_boundary,
                              Range& candidate_edges,
                              Range& inferred_edges,
                              double reference_angle_degrees );

    bool has_larger_angle( EntityHandle& entity1, EntityHandle& entity2, double reference_angle_cosine );

    /**\brief Find vertices on the skin of a set of mesh entities.
     *\param entities The elements for which to find the skin.  Range
     *                may NOT contain vertices, polyhedra, or entity sets.
     *                All elements in range must be of the same dimension.
     *\param skin_verts Output: the vertices on the skin.
     *\param skin_elems Optional output: elements representing sides of entities
     *                    that are on the skin
     *\param create_if_missing If skin_elemts is non-null and this is true,
     *                    create new elements representing the sides of
     *                    entities on the skin.  If this is false, skin_elems
     *                    will contain only those skin elements that already
     *                    exist.
     */
    ErrorCode find_skin_vertices( const EntityHandle this_set,
                                  const Range& entities,
                                  Range* skin_verts      = 0,
                                  Range* skin_elems      = 0,
                                  Range* rev_elems       = 0,
                                  bool create_if_missing = true,
                                  bool corners_only      = false );

    /**\brief Skin edges
     *
     * Return any vertices adjacent to exactly one of the input edges.
     */
    ErrorCode find_skin_vertices_1D( Tag tag, const Range& edges, Range& skin_verts );

    /**\brief Skin faces
     *
     * For the set of face sides (logical edges), return
     * vertices on such sides and/or edges equivalent to such sides.
     *\param faces  Set of toplogically 2D entities to skin.
     *\param skin_verts If non-NULL, skin vertices will be added to this container.
     *\param skin_edges If non-NULL, skin edges will be added to this container
     *\param reverse_edges If skin_edges is not NULL and this is not NULL, then
     *                  any existing skin edges that are reversed with respect
     *                  to the skin side will be placed in this range instead of
     *                  skin_edges.  Note: this argument is ignored if skin_edges
     *                  is NULL.
     *\param create_edges If true, edges equivalent to face sides on the skin
     *                  that don't already exist will be created.  Note: this
     *                  parameter is honored regardless of whether or not skin
     *                  edges or vertices are returned.
     *\param corners_only If true, only skin vertices that correspond to the
     *                  corners of sides will be returned (i.e. no higher-order
     *                  nodes.)  This argument is ignored if skin_verts is NULL.
     */
    ErrorCode find_skin_vertices_2D( const EntityHandle this_set,
                                     Tag tag,
                                     const Range& faces,
                                     Range* skin_verts    = 0,
                                     Range* skin_edges    = 0,
                                     Range* reverse_edges = 0,
                                     bool create_edges    = false,
                                     bool corners_only    = false );

    /**\brief Skin volume mesh
     *
     * For the set of element sides (logical faces), return
     * vertices on such sides and/or faces equivalent to such sides.
     *\param entities  Set of toplogically 3D entities to skin.
     *\param skin_verts If non-NULL, skin vertices will be added to this container.
     *\param skin_faces If non-NULL, skin faces will be added to this container
     *\param reverse_faces If skin_faces is not NULL and this is not NULL, then
     *                  any existing skin faces that are reversed with respect
     *                  to the skin side will be placed in this range instead of
     *                  skin_faces.  Note: this argument is ignored if skin_faces
     *                  is NULL.
     *\param create_faces If true, face equivalent to sides on the skin
     *                  that don't already exist will be created.  Note: this
     *                  parameter is honored regardless of whether or not skin
     *                  faces or vertices are returned.
     *\param corners_only If true, only skin vertices that correspond to the
     *                  corners of sides will be returned (i.e. no higher-order
     *                  nodes.)  This argument is ignored if skin_verts is NULL.
     */
    ErrorCode find_skin_vertices_3D( const EntityHandle this_set,
                                     Tag tag,
                                     const Range& entities,
                                     Range* skin_verts    = 0,
                                     Range* skin_faces    = 0,
                                     Range* reverse_faces = 0,
                                     bool create_faces    = false,
                                     bool corners_only    = false );

    ErrorCode create_side( const EntityHandle this_set,
                           EntityHandle element,
                           EntityType side_type,
                           const EntityHandle* side_corners,
                           EntityHandle& side_elem_handle_out );

    bool edge_reversed( EntityHandle face, const EntityHandle edge_ends[2] );
    bool face_reversed( EntityHandle region, const EntityHandle* face_conn, EntityType face_type );

    //! look for structured box comprising source_entities, and if one is found use
    //! structured information to find the skin
    ErrorCode find_skin_scd( const Range& source_entities,
                             bool get_vertices,
                             Range& output_handles,
                             bool create_skin_elements );

    //! skin a structured box, taking advantage of structured information
    ErrorCode skin_box( ScdBox* box, bool get_vertices, Range& output_handles, bool create_skin_elements );
};

inline ErrorCode Skinner::find_skin( const EntityHandle this_set,
                                     const EntityHandle* entities,
                                     int num_entities,
                                     bool get_vertices,
                                     Range& output_handles,
                                     Range* output_reverse_handles,
                                     bool create_vert_elem_adjs,
                                     bool create_skin_elements,
                                     bool look_for_scd )
{
    Range ents;
    std::copy( entities, entities + num_entities, range_inserter( ents ) );
    return find_skin( this_set, ents, get_vertices, output_handles, output_reverse_handles, create_vert_elem_adjs,
                      create_skin_elements, look_for_scd );
}

}  // namespace moab

#endif