![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 /*
00002 * MOAB, a Mesh-Oriented datABase, is a software component for creating,
00003 * storing and accessing finite element mesh data.
00004 *
00005 * Copyright 2004 Sandia Corporation. Under the terms of Contract
00006 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
00007 * retains certain rights in this software.
00008 *
00009 * This library is free software; you can redistribute it and/or
00010 * modify it under the terms of the GNU Lesser General Public
00011 * License as published by the Free Software Foundation; either
00012 * version 2.1 of the License, or (at your option) any later version.
00013 *
00014 */
00015
00016 /**\file BSPTree.hpp
00017 *\author Jason Kraftcheck (kraftche@cae.wisc.edu)
00018 *\date 2008-05-12
00019 */
00020
00021 #ifndef MOAB_BSP_TREE_HPP
00022 #define MOAB_BSP_TREE_HPP
00023
00024 #include "moab/Types.hpp"
00025 #include "moab/Interface.hpp"
00026
00027 #include
00028 #include
00029 #include
00030
00031 namespace moab
00032 {
00033
00034 class BSPTreeBoxIter;
00035 class BSPTreeIter;
00036 class Range;
00037 class BSPTreePoly;
00038
00039 /** \class BSPTree
00040 * \brief BSP tree, for sorting and searching entities spatially
00041 */
00042 class BSPTree
00043 {
00044 private:
00045 Interface* mbInstance;
00046 Tag planeTag, rootTag;
00047 unsigned meshSetFlags;
00048 bool cleanUpTrees;
00049 std::vector< EntityHandle > createdTrees;
00050
00051 ErrorCode init_tags( const char* tagname = 0 );
00052
00053 public:
00054 static double epsilon()
00055 {
00056 return 1e-6;
00057 }
00058
00059 BSPTree( Interface* iface, const char* tagname = 0, unsigned meshset_creation_flags = MESHSET_SET );
00060
00061 BSPTree( Interface* iface,
00062 bool destroy_created_trees,
00063 const char* tagname = 0,
00064 unsigned meshset_creation_flags = MESHSET_SET );
00065
00066 ~BSPTree();
00067
00068 //! Enumerate split plane directions
00069 enum Axis
00070 {
00071 X = 0,
00072 Y = 1,
00073 Z = 2
00074 };
00075
00076 /**\brief struct to store a plane
00077 *
00078 * If plane is defined as Ax+By+Cz+D=0, then
00079 * norm={A,B,C} and coeff=-D.
00080 */
00081 struct Plane
00082 {
00083 Plane() : coeff( 0.0 ) {}
00084 Plane( const double n[3], double d ) : coeff( d )
00085 {
00086 norm[0] = n[0];
00087 norm[1] = n[1];
00088 norm[2] = n[2];
00089 }
00090 /** a x + b y + c z + d = 0 */
00091 Plane( double a, double b, double c, double d ) : coeff( d )
00092 {
00093 norm[0] = a;
00094 norm[1] = b;
00095 norm[2] = c;
00096 }
00097 /** Create Y = 1 plane by doing Plane( Y, 1.0 ); */
00098 Plane( Axis normal, double point_on_axis ) : coeff( -point_on_axis )
00099 {
00100 norm[0] = norm[1] = norm[2] = 0;
00101 norm[normal] = 1.0;
00102 }
00103
00104 double norm[3]; //!< Unit normal of plane
00105 double coeff; //!< norm[0]*x + norm[1]*y + norm[2]*z + coeff = 0
00106
00107 /** Signed distance from point to plane:
00108 * absolute value is distance from point to plane
00109 * positive if 'above' plane, negative if 'below'
00110 * Note: assumes unit-length normal.
00111 */
00112 double signed_distance( const double point[3] ) const
00113 {
00114 return point[0] * norm[0] + point[1] * norm[1] + point[2] * norm[2] + coeff;
00115 }
00116
00117 /** return true if point is below the plane */
00118 bool below( const double point[3] ) const
00119 {
00120 return signed_distance( point ) <= 0.0;
00121 }
00122
00123 /** return true if point is above the plane */
00124 bool above( const double point[3] ) const
00125 {
00126 return signed_distance( point ) >= 0.0;
00127 }
00128
00129 double distance( const double point[3] ) const
00130 {
00131 return fabs( signed_distance( point ) );
00132 }
00133
00134 /** reverse plane normal */
00135 void flip()
00136 {
00137 norm[0] = -norm[0];
00138 norm[1] = -norm[1];
00139 norm[2] = -norm[2];
00140 coeff = -coeff;
00141 }
00142
00143 void set( const double normal[3], const double point[3] )
00144 {
00145 const double dot = normal[0] * point[0] + normal[1] * point[1] + normal[2] * point[2];
00146 *this = Plane( normal, -dot );
00147 }
00148
00149 void set( const double pt1[3], const double pt2[3], const double pt3[3] );
00150
00151 void set( double i, double j, double k, double cff )
00152 {
00153 *this = Plane( i, j, k, cff );
00154 }
00155
00156 /** Create Y = 1 plane by doing set( Y, 1.0 ); */
00157 void set( Axis normal, double point_on_axis )
00158 {
00159 coeff = -point_on_axis;
00160 norm[0] = norm[1] = norm[2] = 0;
00161 norm[normal] = 1.0;
00162 }
00163 };
00164
00165 //! Get split plane for tree node
00166 ErrorCode get_split_plane( EntityHandle node, Plane& plane )
00167 {
00168 return moab()->tag_get_data( planeTag, &node, 1, &plane );
00169 }
00170
00171 //! Set split plane for tree node
00172 ErrorCode set_split_plane( EntityHandle node, const Plane& plane );
00173
00174 //! Get bounding box for entire tree
00175 ErrorCode get_tree_box( EntityHandle root_node, double corner_coords[8][3] );
00176
00177 //! Get bounding box for entire tree
00178 ErrorCode get_tree_box( EntityHandle root_node, double corner_coords[24] );
00179
00180 //! Set bounding box for entire tree
00181 ErrorCode set_tree_box( EntityHandle root_node, const double box_min[3], const double box_max[3] );
00182 ErrorCode set_tree_box( EntityHandle root_node, const double corner_coords[8][3] );
00183
00184 //! Create tree root node
00185 ErrorCode create_tree( const double box_min[3], const double box_max[3], EntityHandle& root_handle );
00186 ErrorCode create_tree( const double corner_coords[8][3], EntityHandle& root_handle );
00187
00188 //! Create tree root node
00189 ErrorCode create_tree( EntityHandle& root_handle );
00190
00191 //! Find all tree roots
00192 ErrorCode find_all_trees( Range& results );
00193
00194 //! Destroy a tree
00195 ErrorCode delete_tree( EntityHandle root_handle );
00196
00197 Interface* moab()
00198 {
00199 return mbInstance;
00200 }
00201
00202 //! Get iterator for tree
00203 ErrorCode get_tree_iterator( EntityHandle tree_root, BSPTreeIter& result );
00204
00205 //! Get iterator at right-most ('last') leaf.
00206 ErrorCode get_tree_end_iterator( EntityHandle tree_root, BSPTreeIter& result );
00207
00208 //! Split leaf of tree
00209 //! Updates iterator location to point to first new leaf node.
00210 ErrorCode split_leaf( BSPTreeIter& leaf, Plane plane );
00211
00212 //! Split leaf of tree
00213 //! Updates iterator location to point to first new leaf node.
00214 ErrorCode split_leaf( BSPTreeIter& leaf, Plane plane, EntityHandle& left_child, EntityHandle& right_child );
00215
00216 //! Split leaf of tree
00217 //! Updates iterator location to point to first new leaf node.
00218 ErrorCode split_leaf( BSPTreeIter& leaf, Plane plane, const Range& left_entities, const Range& right_entities );
00219
00220 //! Split leaf of tree
00221 //! Updates iterator location to point to first new leaf node.
00222 ErrorCode split_leaf( BSPTreeIter& leaf,
00223 Plane plane,
00224 const std::vector< EntityHandle >& left_entities,
00225 const std::vector< EntityHandle >& right_entities );
00226
00227 //! Merge the leaf pointed to by the current iterator with it's
00228 //! sibling. If the sibling is not a leaf, multiple merges may
00229 //! be done.
00230 ErrorCode merge_leaf( BSPTreeIter& iter );
00231
00232 //! Get leaf containing input position.
00233 //!
00234 //! Does not take into account global bounding box of tree.
00235 //! - Therefore there is always one leaf containing the point.
00236 //! - If caller wants to account for global bounding box, then
00237 //! caller can test against that box and not call this method
00238 //! at all if the point is outside the box, as there is no leaf
00239 //! containing the point in that case.
00240 ErrorCode leaf_containing_point( EntityHandle tree_root, const double point[3], EntityHandle& leaf_out );
00241
00242 //! Get iterator at leaf containing input position.
00243 //!
00244 //! Returns MB_ENTITY_NOT_FOUND if point is not within
00245 //! bounding box of tree.
00246 ErrorCode leaf_containing_point( EntityHandle tree_root, const double xyz[3], BSPTreeIter& result );
00247 };
00248
00249 /** \class BSPTreeIter
00250 * \brief Iterate over leaves of a BSPTree
00251 */
00252 class BSPTreeIter
00253 {
00254 public:
00255 enum Direction
00256 {
00257 LEFT = 0,
00258 RIGHT = 1
00259 };
00260
00261 private:
00262 friend class BSPTree;
00263
00264 BSPTree* treeTool;
00265
00266 protected:
00267 std::vector< EntityHandle > mStack;
00268 mutable std::vector< EntityHandle > childVect;
00269
00270 virtual ErrorCode step_to_first_leaf( Direction direction );
00271
00272 virtual ErrorCode up();
00273 virtual ErrorCode down( const BSPTree::Plane& plane, Direction direction );
00274
00275 virtual ErrorCode initialize( BSPTree* tool, EntityHandle root, const double* point = 0 );
00276
00277 public:
00278 BSPTreeIter() : treeTool( 0 ), childVect( 2 ) {}
00279 virtual ~BSPTreeIter() {}
00280
00281 BSPTree* tool() const
00282 {
00283 return treeTool;
00284 }
00285
00286 //! Get handle for current leaf
00287 EntityHandle handle() const
00288 {
00289 return mStack.back();
00290 }
00291
00292 //! Get depth in tree. root is at depth of 1.
00293 unsigned depth() const
00294 {
00295 return mStack.size();
00296 }
00297
00298 //! Advance the iterator either left or right in the tree
00299 //! Note: stepping past the end of the tree will invalidate
00300 //! the iterator. It will *not* be work step the
00301 //! other direction.
00302 virtual ErrorCode step( Direction direction );
00303
00304 //! Advance to next leaf
00305 //! Returns MB_ENTITY_NOT_FOUND if at end.
00306 //! Note: stepping past the end of the tree will invalidate
00307 //! the iterator. Calling back() will not work.
00308 ErrorCode step()
00309 {
00310 return step( RIGHT );
00311 }
00312
00313 //! Move back to previous leaf
00314 //! Returns MB_ENTITY_NOT_FOUND if at beginning.
00315 //! Note: stepping past the start of the tree will invalidate
00316 //! the iterator. Calling step() will not work.
00317 ErrorCode back()
00318 {
00319 return step( LEFT );
00320 }
00321
00322 //! Get split plane that separates this node from its immediate sibling.
00323 ErrorCode get_parent_split_plane( BSPTree::Plane& plane ) const;
00324
00325 //! Get volume of leaf polyhedron
00326 virtual double volume() const;
00327
00328 //! Find range of overlap between ray and leaf.
00329 //!
00330 //!\param ray_point Coordinates of start point of ray
00331 //!\param ray_vect Directionion vector for ray such that
00332 //! the ray is defined by r(t) = ray_point + t * ray_vect
00333 //! for t > 0.
00334 //!\param t_enter Output: if return value is true, this value
00335 //! is the parameter location along the ray at which
00336 //! the ray entered the leaf. If return value is false,
00337 //! then this value is undefined.
00338 //!\param t_exit Output: if return value is true, this value
00339 //! is the parameter location along the ray at which
00340 //! the ray exited the leaf. If return value is false,
00341 //! then this value is undefined.
00342 //!\return true if ray intersects leaf, false otherwise.
00343 virtual bool intersect_ray( const double ray_point[3],
00344 const double ray_vect[3],
00345 double& t_enter,
00346 double& t_exit ) const;
00347
00348 //! Return true if thos node and the passed node share the
00349 //! same immediate parent.
00350 bool is_sibling( const BSPTreeIter& other_leaf ) const;
00351
00352 //! Return true if thos node and the passed node share the
00353 //! same immediate parent.
00354 bool is_sibling( EntityHandle other_leaf ) const;
00355
00356 //! Returns true if calling step() will advance to the
00357 //! immediate sibling of the current node. Returns false
00358 //! if current node is root or back() will move to the
00359 //! immediate sibling.
00360 bool sibling_is_forward() const;
00361
00362 //! Calculate the convex polyhedron bounding this leaf.
00363 virtual ErrorCode calculate_polyhedron( BSPTreePoly& polyhedron_out ) const;
00364 };
00365
00366 /** \class BSPTreeBoxIter
00367 * \brief Iterate over leaves of a BSPTree
00368 */
00369 class BSPTreeBoxIter : public BSPTreeIter
00370 {
00371 private:
00372 double leafCoords[8][3];
00373 struct Corners
00374 {
00375 double coords[4][3];
00376 };
00377 std::vector< Corners > stackData;
00378
00379 protected:
00380 virtual ErrorCode step_to_first_leaf( Direction direction );
00381
00382 virtual ErrorCode up();
00383 virtual ErrorCode down( const BSPTree::Plane& plane, Direction direction );
00384
00385 virtual ErrorCode initialize( BSPTree* tool, EntityHandle root, const double* point = 0 );
00386
00387 public:
00388 BSPTreeBoxIter() {}
00389 virtual ~BSPTreeBoxIter() {}
00390
00391 //! Faces of a hex : corner bitmap
00392 enum SideBits
00393 {
00394 B0154 = 0x33, //!< Face defined by corners {0,1,5,4}: 1st Exodus side
00395 B1265 = 0x66, //!< Face defined by corners {1,2,6,5}: 2nd Exodus side
00396 B2376 = 0xCC, //!< Face defined by corners {2,3,7,6}: 3rd Exodus side
00397 B3047 = 0x99, //!< Face defined by corners {3,0,4,7}: 4th Exodus side
00398 B3210 = 0x0F, //!< Face defined by corners {3,2,1,0}: 5th Exodus side
00399 B4567 = 0xF0 //!< Face defined by corners {4,5,6,7}: 6th Exodus side
00400 };
00401
00402 static SideBits side_above_plane( const double hex_coords[8][3], const BSPTree::Plane& plane );
00403
00404 static SideBits side_on_plane( const double hex_coords[8][3], const BSPTree::Plane& plane );
00405
00406 static SideBits opposite_face( const SideBits& bits )
00407 {
00408 return (SideBits)( ( ~bits ) & 0xFF );
00409 }
00410
00411 static ErrorCode face_corners( const SideBits face, const double hex_corners[8][3], double face_corners_out[4][3] );
00412
00413 //! Advance the iterator either left or right in the tree
00414 //! Note: stepping past the end of the tree will invalidate
00415 //! the iterator. It will *not* work to subsequently
00416 //! step the other direction.
00417 virtual ErrorCode step( Direction direction );
00418
00419 //! Advance to next leaf
00420 //! Returns MB_ENTITY_NOT_FOUND if at end.
00421 //! Note: stepping past the end of the tree will invalidate
00422 //! the iterator. Calling back() will not work.
00423 ErrorCode step()
00424 {
00425 return BSPTreeIter::step();
00426 }
00427
00428 //! Move back to previous leaf
00429 //! Returns MB_ENTITY_NOT_FOUND if at beginning.
00430 //! Note: stepping past the start of the tree will invalidate
00431 //! the iterator. Calling step() will not work.
00432 ErrorCode back()
00433 {
00434 return BSPTreeIter::back();
00435 }
00436
00437 //! Get coordinates of box corners, in Exodus II hexahedral ordering.
00438 ErrorCode get_box_corners( double coords[8][3] ) const;
00439
00440 //! Get volume of leaf box
00441 double volume() const;
00442
00443 //! test if a plane intersects the leaf box
00444 enum XSect
00445 {
00446 MISS = 0,
00447 SPLIT = 1,
00448 NONHEX = -1
00449 };
00450 XSect splits( const BSPTree::Plane& plane ) const;
00451
00452 //! test if a plane intersects the leaf box
00453 bool intersects( const BSPTree::Plane& plane ) const;
00454
00455 //! Find range of overlap between ray and leaf.
00456 //!
00457 //!\param ray_point Coordinates of start point of ray
00458 //!\param ray_vect Directionion vector for ray such that
00459 //! the ray is defined by r(t) = ray_point + t * ray_vect
00460 //! for t > 0.
00461 //!\param t_enter Output: if return value is true, this value
00462 //! is the parameter location along the ray at which
00463 //! the ray entered the leaf. If return value is false,
00464 //! then this value is undefined.
00465 //!\param t_exit Output: if return value is true, this value
00466 //! is the parameter location along the ray at which
00467 //! the ray exited the leaf. If return value is false,
00468 //! then this value is undefined.
00469 //!\return true if ray intersects leaf, false otherwise.
00470 bool intersect_ray( const double ray_point[3], const double ray_vect[3], double& t_enter, double& t_exit ) const;
00471
00472 //! Return the side of the box bounding this tree node
00473 //! that is shared with the immediately adjacent sibling
00474 //! (the tree node that shares a common parent node with
00475 //! this node in the binary tree.)
00476 //!
00477 //!\return MB_ENTITY_NOT FOUND if root node.
00478 //! MB_FAILURE if internal error.
00479 //! MB_SUCCESS otherwise.
00480 ErrorCode sibling_side( SideBits& side_out ) const;
00481
00482 //! Get adjacent leaf nodes on indicated side
00483 //!
00484 //!\param side Face of box for which to retrieve neighbors
00485 //!\param results List to which to append results. This function does
00486 //! *not* clear existing values in list.
00487 //!\param epsilon Tolerance on overlap. A positive value E will
00488 //! result in nodes that are separated by as much as E
00489 //! to be considered touching. A negative value -E will
00490 //! cause leaves that do not overlap by at least E to be
00491 //! considered non-overlapping. Amongst other things,
00492 //! this value can be used to control whether or not
00493 //! leaves adjacent at only their edges or corners are
00494 //! returned.
00495 ErrorCode get_neighbors( SideBits side, std::vector< BSPTreeBoxIter >& results, double epsilon = 0.0 ) const;
00496
00497 //! Calculate the convex polyhedron bounding this leaf.
00498 ErrorCode calculate_polyhedron( BSPTreePoly& polyhedron_out ) const;
00499 };
00500
00501 } // namespace moab
00502
00503 #endif