moab
FBEngine.cpp
Go to the documentation of this file.
00001 #include <iostream>
00002 #include <map>
00003 
00004 #include "moab/FBEngine.hpp"
00005 #include "moab/Interface.hpp"
00006 #include "moab/GeomTopoTool.hpp"
00007 #include "moab/OrientedBoxTreeTool.hpp"
00008 
00009 #include <stdlib.h>
00010 #include <cstring>
00011 #include <map>
00012 #include <set>
00013 #include <queue>
00014 #include <algorithm>
00015 #include "assert.h"
00016 
00017 #include "SmoothCurve.hpp"
00018 #include "SmoothFace.hpp"
00019 
00020 // this is just to replace MBI with moab interface, which is _mbImpl in this class
00021 #define MBI _mbImpl
00022 #define MBERRORR(rval, STR) { if (MB_SUCCESS != rval) { \
00023       std::cout<<STR<<std::endl;       \
00024       return rval; } }
00025 
00026 namespace moab {
00027 
00028 // some tolerances for ray tracing and geometry intersections
00029 // these are involved in ray tracing, at least
00030 
00031 unsigned min_tolerace_intersections = 1000;
00032 double tolerance = 0.01; // TODO: how is this used ????
00033 double tolerance_segment = 0.01; // for segments intersection, points collapse, area coordinates for triangles
00034 // it should be a relative, not an absolute value
00035 // as this splitting operation can create small edges, it should be relatively high
00036 // or, it should be coordinated with the decimation errors
00037 // we really just want to preserve the integrity of the mesh, we should avoid creating small edges or angles
00038 const bool Debug_surf_eval = false;
00039 bool debug_splits = false;
00040 
00041 // will compute intersection between a segment and slice of a plane
00042 // output is the intersection point
00043 bool intersect_segment_and_plane_slice(CartVect & from, CartVect & to,
00044     CartVect & p1, CartVect & p2, CartVect & , CartVect & normPlane,
00045     CartVect & intx_point, double & parPos)
00046 {
00047   //
00048   // plane eq is normPlane % r + d = 0, or normPlane % r - normPlane%p1 = 0
00049   double dd = -normPlane % p1;
00050   double valFrom = normPlane % from + dd;
00051   double valTo = normPlane % to + dd;
00052 
00053   if (fabs(valFrom) < tolerance_segment) {
00054     intx_point = from;
00055     parPos = 0.;
00056     double proj1 = (intx_point - p1) % (p2 - p1);
00057     double proj2 = (intx_point - p2) % (p1 - p2);
00058     if (proj1 <= -tolerance_segment || proj2 <= -tolerance_segment)
00059       return false;
00060     if (debug_splits)
00061       std::cout << "intx : " << intx_point << "\n";
00062     return true;
00063   }
00064   if (fabs(valTo) < tolerance_segment) {
00065     intx_point = to;
00066     parPos = 1;
00067     double proj1 = (intx_point - p1) % (p2 - p1);
00068     double proj2 = (intx_point - p2) % (p1 - p2);
00069     if (proj1 <= -tolerance_segment || proj2 <= -tolerance_segment)
00070       return false;
00071     if (debug_splits)
00072       std::cout << "intx : " << intx_point << "\n";
00073     return true;
00074   }
00075   if (valFrom * valTo > 0)
00076     return false; // no intersection, although it could be very close
00077   // else, it could intersect the plane; check for the slice too.
00078   parPos = valFrom / (valFrom - valTo);// this is 0 for valFrom 0, 1 for valTo 0
00079   intx_point = from + (to - from) * parPos;
00080   // now check if the intx_point is indeed between p1 and p2 in the slice.
00081   double proj1 = (intx_point - p1) % (p2 - p1);
00082   double proj2 = (intx_point - p2) % (p1 - p2);
00083   if (proj1 <= -tolerance_segment || proj2 <= -tolerance_segment)
00084     return false;
00085 
00086   if (debug_splits)
00087     std::cout << "intx : " << intx_point << "\n";
00088   return true;
00089 }
00090 
00091 ErrorCode area_coordinates(Interface * mbi, EntityHandle tri, CartVect & pnt,
00092     double * area_coord, EntityHandle & boundary_handle)
00093 {
00094 
00095   int nnodes;
00096   const EntityHandle * conn3;
00097   ErrorCode rval = mbi->get_connectivity(tri, conn3, nnodes);
00098   MBERRORR(rval, "Failed to get connectivity");
00099   assert(3 == nnodes);
00100   CartVect P[3];
00101   rval = mbi->get_coords(conn3, nnodes, (double*) &P[0]);
00102   MBERRORR(rval, "Failed to get coordinates");
00103 
00104   CartVect r0(P[0] - pnt);
00105   CartVect r1(P[1] - pnt);
00106   CartVect r2(P[2] - pnt);
00107   if (debug_splits)
00108   {
00109     std::cout << " nodes:" << conn3[0] << " "<<  conn3[1] << " " << conn3[2] <<"\n";
00110     std::cout << " distances: " << r0.length() << " " << r1.length() << " " << r2.length() << "\n";
00111   }
00112   if (r0.length() < tolerance_segment) {
00113     area_coord[0] = 1.;
00114     area_coord[1] = 0.;
00115     area_coord[2] = 0.;
00116     boundary_handle = conn3[0];
00117     return MB_SUCCESS;
00118   }
00119   if (r1.length() < tolerance_segment) {
00120     area_coord[0] = 0.;
00121     area_coord[1] = 1.;
00122     area_coord[2] = 0.;
00123     boundary_handle = conn3[1];
00124     return MB_SUCCESS;
00125   }
00126   if (r2.length() < tolerance_segment) {
00127     area_coord[0] = 0.;
00128     area_coord[1] = 0.;
00129     area_coord[2] = 1.;
00130     boundary_handle = conn3[2];
00131     return MB_SUCCESS;
00132   }
00133 
00134   CartVect v1(P[1] - P[0]);
00135   CartVect v2(P[2] - P[0]);
00136 
00137   double areaDouble = (v1 * v2).length();// the same for CartVect
00138   if (areaDouble < tolerance_segment * tolerance_segment) {
00139     MBERRORR(MB_FAILURE, "area of triangle too small");
00140   }
00141   area_coord[0] = (r1 * r2).length() / areaDouble;
00142   area_coord[1] = (r2 * r0).length() / areaDouble;
00143   area_coord[2] = (r0 * r1).length() / areaDouble;
00144 
00145   if (fabs(area_coord[0] + area_coord[1] + area_coord[2] - 1)
00146       > tolerance_segment) {
00147     MBERRORR(MB_FAILURE, "point outside triangle");
00148   }
00149   // the tolerance is used here for area coordinates (0 to 1), and in other
00150   // parts it is used as an absolute distance; pretty inconsistent.
00151   bool side0 = (area_coord[0] < tolerance_segment);
00152   bool side1 = (area_coord[1] < tolerance_segment);
00153   bool side2 = (area_coord[2] < tolerance_segment);
00154   if (!side0 && !side1 && !side2) 
00155     return MB_SUCCESS; // interior point
00156   // now, find out what boundary is in question
00157   // first, get all edges, in order
00158   std::vector<EntityHandle> edges;
00159   EntityHandle nn2[2];
00160   for (int i = 0; i < 3; i++) {
00161     nn2[0] = conn3[(i + 1) % 3];
00162     nn2[1] = conn3[(i + 2) % 3];
00163     std::vector<EntityHandle> adjacent;
00164     rval = mbi->get_adjacencies(nn2, 2, 1, false, adjacent,
00165         Interface::INTERSECT);
00166     MBERRORR(rval, "Failed to get edges");
00167     if (adjacent.size() != 1)
00168       MBERRORR(MB_FAILURE, "Failed to get adjacent edges");
00169     // should be only one edge here
00170     edges.push_back(adjacent[0]);
00171   }
00172 
00173   if (side0)
00174     boundary_handle = edges[0];
00175   if (side1)
00176     boundary_handle = edges[1];
00177   if (side2)
00178     boundary_handle = edges[2];
00179 
00180   return MB_SUCCESS;
00181 }
00182 
00183 FBEngine::FBEngine(Interface *impl, GeomTopoTool * topoTool, const bool smooth) :
00184   _mbImpl(impl), _my_geomTopoTool(topoTool), _t_created(false),
00185       _smooth(smooth), _initialized(false), _smthFace(NULL), _smthCurve(NULL)
00186 {
00187   if (!_my_geomTopoTool) {
00188     _my_geomTopoTool = new GeomTopoTool(_mbImpl);
00189     _t_created = true;
00190   }
00191   // should this be part of the constructor or not?
00192   //Init();
00193 }
00194 FBEngine::~FBEngine()
00195 {
00196   clean();
00197   _smooth = false;
00198 }
00199 
00200 void FBEngine::clean()
00201 {
00202   if (_smooth) {
00203     _faces.clear();
00204     _edges.clear();
00205     int size1 = _my_gsets[1].size();
00206     int i = 0;
00207     for (i = 0; i < size1; i++)
00208       delete _smthCurve[i];
00209     delete[] _smthCurve;
00210     _smthCurve = NULL;
00211     size1 = _my_gsets[2].size();
00212     for (i = 0; i < size1; i++)
00213       delete _smthFace[i];
00214     delete[] _smthFace;
00215     _smthFace = NULL;
00216     //_smooth = false;
00217   }
00218 
00219   for (int j = 0; j < 5; j++)
00220     _my_gsets[j].clear();
00221   if (_t_created)
00222     delete _my_geomTopoTool;
00223   _my_geomTopoTool = NULL;
00224   _t_created = false;
00225 }
00226 
00227 ErrorCode FBEngine::Init()
00228 {
00229   if (!_initialized) {
00230     if (!_my_geomTopoTool)
00231       return MB_FAILURE;
00232 
00233     ErrorCode rval = _my_geomTopoTool->find_geomsets(_my_gsets);
00234     assert(rval == MB_SUCCESS);
00235     if (MB_SUCCESS != rval){return rval;}
00236     
00237 
00238     rval = split_quads();
00239     assert (rval == MB_SUCCESS);
00240 
00241     rval = _my_geomTopoTool->construct_obb_trees();
00242     assert(rval == MB_SUCCESS);
00243 
00244     if (_smooth)
00245       rval = initializeSmoothing();
00246     assert(rval == MB_SUCCESS);
00247 
00248     _initialized = true;
00249   }
00250   return MB_SUCCESS;
00251 }
00252 ErrorCode FBEngine::initializeSmoothing()
00253 {
00254   //
00255   /*ErrorCode rval = Init();
00256    MBERRORR(rval, "failed initialize");*/
00257   // first of all, we need to retrieve all the surfaces from the (root) set
00258   // in icesheet_test we use iGeom, but maybe that is a stretch
00259   // get directly the sets with geom dim 2, and from there create the SmoothFace
00260   Tag geom_tag, gid_tag;
00261   ErrorCode rval = MBI->tag_get_handle(GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, geom_tag);
00262   MBERRORR(rval, "can't get geom tag");
00263   rval = MBI->tag_get_handle(GLOBAL_ID_TAG_NAME, 1, MB_TYPE_INTEGER, gid_tag);
00264   MBERRORR(rval, "can't get id tag");
00265   int numSurfaces = _my_gsets[2].size();
00266   //SmoothFace ** smthFace = new SmoothFace *[numSurfaces];
00267   _smthFace = new SmoothFace *[numSurfaces];
00268 
00269   // there should also be a map from surfaces to evaluators
00270   //std::map<MBEntityHandle, SmoothFace*> mapSurfaces;
00271 
00272   int i = 0;
00273   Range::iterator it;
00274   for (it = _my_gsets[2].begin(); it != _my_gsets[2].end(); it++, i++) {
00275     EntityHandle face = *it;
00276     _smthFace[i] = new SmoothFace(MBI, face, _my_geomTopoTool);// geom topo tool will be used for searching,
00277     // among other things; also for senses in edge sets...
00278     _faces[face] = _smthFace[i];
00279   }
00280 
00281   int numCurves = _my_gsets[1].size();//csets.size();
00282   //SmoothCurve ** smthCurve = new SmoothCurve *[numCurves];
00283   _smthCurve = new SmoothCurve *[numCurves];
00284   // there should also be a map from surfaces to evaluators
00285   //std::map<MBEntityHandle, SmoothCurve*> mapCurves;
00286 
00287   i = 0;
00288   for (it = _my_gsets[1].begin(); it != _my_gsets[1].end(); it++, i++) {
00289     EntityHandle curve = *it;
00290     _smthCurve[i] = new SmoothCurve(MBI, curve, _my_geomTopoTool);
00291     _edges[curve] = _smthCurve[i];
00292   }
00293 
00294   for (i = 0; i < numSurfaces; i++) {
00295     _smthFace[i]->init_gradient();// this will also retrieve the triangles in each surface
00296     _smthFace[i]->compute_tangents_for_each_edge();// this one will consider all edges internal, so the
00297     // tangents are all in the direction of the edge; a little bit of waste, as we store
00298     // one tangent for each edge node , even though they are equal here...
00299     // no loops are considered
00300   }
00301 
00302   // this will be used to mark boundary edges, so for them the control points are computed earlier
00303   unsigned char value = 0; // default value is "not used"=0 for the tag
00304   // unsigned char def_data_bit = 1;// valid by default
00305   // rval = mb->tag_create("valid", 1, MB_TAG_BIT, validTag, &def_data_bit);
00306   Tag markTag;
00307   rval = MBI->tag_get_handle("MARKER", 1, MB_TYPE_BIT, markTag, 
00308                              MB_TAG_EXCL|MB_TAG_BIT, &value); // default value : 0 = not computed yet
00309   // each feature edge will need to have a way to retrieve at every moment the surfaces it belongs to
00310   // from edge sets, using the sense tag, we can get faces, and from each face, using the map, we can get
00311   // the SmoothFace (surface evaluator), that has everything, including the normals!!!
00312   assert(rval==MB_SUCCESS);
00313 
00314   // create the tag also for control points on the edges
00315   double defCtrlPoints[9] = { 0., 0., 0., 0., 0., 0., 0., 0., 0. };
00316   Tag edgeCtrlTag;
00317   rval = MBI->tag_get_handle("CONTROLEDGE", 9, MB_TYPE_DOUBLE, edgeCtrlTag, 
00318                              MB_TAG_DENSE|MB_TAG_CREAT, &defCtrlPoints );
00319   assert(rval == MB_SUCCESS);
00320 
00321   Tag facetCtrlTag;
00322   double defControls[18] = { 0. };
00323   rval = MBI->tag_get_handle("CONTROLFACE", 18, MB_TYPE_DOUBLE, 
00324                              facetCtrlTag, MB_TAG_CREAT|MB_TAG_DENSE,
00325                              &defControls);
00326   assert(rval == MB_SUCCESS);
00327 
00328   Tag facetEdgeCtrlTag;
00329   double defControls2[27] = { 0. }; // corresponding to 9 control points on edges, in order from edge 0, 1, 2 ( 1-2, 2-0, 0-1 )
00330   rval = MBI->tag_get_handle("CONTROLEDGEFACE", 27, MB_TYPE_DOUBLE,
00331                               facetEdgeCtrlTag, MB_TAG_CREAT|MB_TAG_DENSE,
00332                               &defControls2);
00333   assert(rval == MB_SUCCESS);
00334   // if the
00335   double min_dot = -1.0; // depends on _angle, but now we ignore it, for the time being
00336   for (i = 0; i < numCurves; i++) {
00337     _smthCurve[i]->compute_tangents_for_each_edge();// do we need surfaces now? or just the chains?
00338     // the computed edges will be marked accordingly; later one, only internal edges to surfaces are left
00339     _smthCurve[i]->compute_control_points_on_boundary_edges(min_dot, _faces,
00340         edgeCtrlTag, markTag);
00341   }
00342 
00343   // when done with boundary edges, compute the control points on all edges in the surfaces
00344 
00345   for (i = 0; i < numSurfaces; i++) {
00346     // also pass the tags for
00347     _smthFace[i]->compute_control_points_on_edges(min_dot, edgeCtrlTag, markTag);
00348   }
00349 
00350   // now we should be able to compute the control points for the facets
00351 
00352   for (i = 0; i < numSurfaces; i++) {
00353     // also pass the tags for edge and facet control points
00354     _smthFace[i]->compute_internal_control_points_on_facets(min_dot,
00355         facetCtrlTag, facetEdgeCtrlTag);
00356   }
00357   // we will need to compute the tangents for all edges in the model
00358   // they will be needed for control points for each edge
00359   // the boundary edges and the feature edges are more complicated
00360   // the boundary edges need to consider their loops, but feature edges need to consider loops and the normals
00361   // on each connected surface
00362 
00363   // some control points
00364   if (Debug_surf_eval)
00365     for (i = 0; i < numSurfaces; i++)
00366       _smthFace[i]->DumpModelControlPoints();
00367 
00368   return MB_SUCCESS;
00369 }
00370 
00371 // clean up the smooth tags data if created, so the files will be smaller
00372 // if saved
00373 // also, recompute the tags if topology is modified
00374 void FBEngine::delete_smooth_tags()
00375 {
00376   // get all tags from database that are created for smooth data, and
00377   // delete them; it will delete all data associated with them
00378   // first tags from faces, edges:
00379   std::vector<Tag> smoothTags;
00380   int size1 = (int)_my_gsets[2].size();
00381 
00382   for (int i=0; i<size1; i++)
00383   {
00384     // these 2 will append gradient tag and plane tag
00385     _smthFace[i]->append_smooth_tags(smoothTags);
00386   }
00387   // then , get other tags:
00388   // "TANGENTS", "MARKER", "CONTROLEDGE", "CONTROLFACE", "CONTROLEDGEFACE"
00389   Tag tag_handle;
00390   ErrorCode rval = _mbImpl->tag_get_handle( "TANGENTS", 6, MB_TYPE_DOUBLE, tag_handle );
00391   if (rval != MB_TAG_NOT_FOUND)
00392     smoothTags.push_back(tag_handle);
00393 
00394   rval = _mbImpl->tag_get_handle( "MARKER", 1, MB_TYPE_BIT, tag_handle );
00395   if (rval != MB_TAG_NOT_FOUND)
00396     smoothTags.push_back(tag_handle);
00397 
00398   rval = _mbImpl->tag_get_handle( "CONTROLEDGE", 9, MB_TYPE_DOUBLE, tag_handle );
00399   if (rval != MB_TAG_NOT_FOUND)
00400     smoothTags.push_back(tag_handle);
00401 
00402   rval = _mbImpl->tag_get_handle( "CONTROLFACE", 18, MB_TYPE_DOUBLE, tag_handle );
00403   if (rval != MB_TAG_NOT_FOUND)
00404     smoothTags.push_back(tag_handle);
00405 
00406   rval = _mbImpl->tag_get_handle( "CONTROLEDGEFACE", 27, MB_TYPE_DOUBLE, tag_handle );
00407   if (rval != MB_TAG_NOT_FOUND)
00408     smoothTags.push_back(tag_handle);
00409 
00410   // a lot of tags, delete them
00411   for (unsigned int k = 0; k<smoothTags.size(); k++ )
00412   {
00413     // could be a lot of data
00414     _mbImpl->tag_delete(smoothTags[k]);
00415   }
00416 }
00417 /*
00418 #define COPY_RANGE(r, vec) {                      \
00419     EntityHandle *tmp_ptr = reinterpret_cast<EntityHandle*>(vec);   \
00420     std::copy(r.begin(), r.end(), tmp_ptr);}
00421 */
00422 
00423 /*static inline void
00424  ProcessError(const char* desc);*/
00425 
00426 ErrorCode FBEngine::getRootSet(EntityHandle * root_set)
00427 {
00428   *root_set =  _my_geomTopoTool-> get_root_model_set();
00429   return MB_SUCCESS;
00430 }
00431 
00432 ErrorCode FBEngine::getNumEntSets(EntityHandle set, int num_hops,
00433     int * all_sets)
00434 {
00435   ErrorCode rval = MBI->num_contained_meshsets(set, all_sets, num_hops + 1);
00436   return rval;
00437 }
00438 
00439 ErrorCode FBEngine::createEntSet(int isList, EntityHandle * pSet)
00440 {
00441   ErrorCode rval;
00442 
00443   if (isList)
00444     rval = MBI->create_meshset(MESHSET_ORDERED, *pSet);
00445   else
00446     rval = MBI->create_meshset(MESHSET_SET, *pSet);
00447 
00448   return rval;
00449 }
00450 
00451 ErrorCode FBEngine::getEntities(EntityHandle set_handle, int entity_type,
00452     Range & gentities)
00453 {
00454   int i;
00455   if (0 > entity_type || 4 < entity_type) {
00456     return MB_FAILURE;
00457   } else if (entity_type < 4) {// 4 means all entities
00458     gentities = _my_geomTopoTool->geoRanges()[entity_type];// all from root set!
00459   } else {
00460     gentities.clear();
00461     for (i = 0; i < 4; i++) {
00462       gentities.merge(_my_geomTopoTool->geoRanges()[i]);
00463     }
00464   }
00465   Range sets;
00466   // see now if they are in the set passed as input or not
00467   ErrorCode rval = MBI->get_entities_by_type(set_handle, MBENTITYSET, sets);
00468   MBERRORR(rval, "can't get sets in the initial set");
00469   gentities = intersect(gentities, sets);
00470 
00471   return MB_SUCCESS;
00472 }
00473 
00474 ErrorCode FBEngine::addEntArrToSet(Range entities, EntityHandle set)
00475 {
00476   return MBI->add_entities(set, entities);
00477 }
00478 
00479 ErrorCode FBEngine::addEntSet(EntityHandle entity_set_to_add,
00480     EntityHandle entity_set_handle)
00481 {
00482   return MBI->add_entities(entity_set_handle, &entity_set_to_add, 1);
00483 }
00484 
00485 ErrorCode FBEngine::getNumOfType(EntityHandle set, int ent_type, int * pNum)
00486 {
00487   if (0 > ent_type || 4 < ent_type) {
00488     std::cout << "Invalid type\n";
00489     return MB_FAILURE;
00490   }
00491   // get sets of geom dimension tag from here, and intersect with the gentities from goe
00492   // ranges
00493 
00494   // get the geom dimensions sets in the set (AKA gentities)
00495   Range geom_sets;
00496   Tag geom_tag;
00497   ErrorCode rval = _mbImpl->tag_get_handle(GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, geom_tag,
00498                                               MB_TAG_SPARSE|MB_TAG_CREAT);
00499   MBERRORR(rval, "Failed to get geom tag.");
00500   rval = _mbImpl->get_entities_by_type_and_tag(set, MBENTITYSET, &geom_tag, NULL, 1, geom_sets,
00501             Interface::UNION);
00502   MBERRORR(rval, "Failed to get gentities from set");
00503 
00504   if (ent_type==4)
00505   {
00506       *pNum=0;
00507       for (int k=0; k<=3; k++)
00508       {
00509         Range gEntsOfTypeK = intersect(geom_sets, _my_geomTopoTool->geoRanges()[k]);
00510         *pNum += (int)gEntsOfTypeK.size();
00511       }
00512   }
00513   else
00514   {
00515     Range gEntsOfType = intersect(geom_sets, _my_geomTopoTool->geoRanges()[ent_type]);
00516     *pNum = (int)gEntsOfType.size();
00517   }
00518   // we do not really check if it is in the set or not;
00519   // _my_gsets[i].find(gent) != _my_gsets[i].end()
00520   return MB_SUCCESS;
00521 }
00522 
00523 ErrorCode FBEngine::getEntType(EntityHandle gent, int * type)
00524 {
00525   for (int i = 0; i < 4; i++) {
00526     if (_my_geomTopoTool->geoRanges()[i].find(gent) != _my_geomTopoTool->geoRanges()[i].end()) {
00527       *type = i;
00528       return MB_SUCCESS;
00529     }
00530   }
00531   *type = -1; // failure
00532   return MB_FAILURE;
00533 }
00534 ErrorCode FBEngine::getEntBoundBox(EntityHandle gent, double* min_x,
00535     double* min_y, double* min_z, double* max_x, double* max_y, double* max_z)
00536 {
00537   ErrorCode rval;
00538   int type;
00539   rval = getEntType(gent, &type);
00540   MBERRORR(rval, "Failed to get entity type.");
00541 
00542   if (type == 0) {
00543     rval = getVtxCoord(gent, min_x, min_y, min_z);
00544     MBERRORR(rval, "Failed to get vertex coordinates.");
00545     max_x = min_x;
00546     max_y = min_y;
00547     max_z = min_z;
00548   } else if (type == 1) {
00549     rval = MB_FAILURE;
00550     MBERRORR(rval, "iGeom_getEntBoundBox is not supported for Edge entity type.");
00551   } else if (type == 2 || type == 3) {
00552 
00553     EntityHandle root;
00554     CartVect center, axis[3];
00555     rval = _my_geomTopoTool->get_root(gent, root);
00556     MBERRORR(rval, "Failed to get tree root in iGeom_getEntBoundBox.");
00557     rval = _my_geomTopoTool->obb_tree()->box(root, center.array(),
00558         axis[0].array(), axis[1].array(), axis[2].array());
00559     MBERRORR(rval, "Failed to get closest point in iGeom_getEntBoundBox.");
00560 
00561     CartVect absv[3];
00562     for (int i = 0; i < 3; i++) {
00563       absv[i] = CartVect(fabs(axis[i][0]), fabs(axis[i][1]), fabs(axis[i][2]));
00564     }
00565     CartVect min, max;
00566     min = center - absv[0] - absv[1] - absv[2];
00567     max = center + absv[0] + absv[1] + absv[2];
00568     *min_x = min[0];
00569     *min_y = min[1];
00570     *min_z = min[2];
00571     *max_x = max[0];
00572     *max_y = max[1];
00573     *max_z = max[2];
00574   } else
00575     return MB_FAILURE;
00576 
00577   return MB_SUCCESS;
00578 }
00579 ErrorCode FBEngine::getEntClosestPt(EntityHandle this_gent, double near_x,
00580     double near_y, double near_z, double* on_x, double* on_y, double* on_z)
00581 {
00582   ErrorCode rval;
00583   int type;
00584   rval = getEntType(this_gent, &type);
00585   MBERRORR(rval, "Failed to get entity type.");
00586 
00587   if (type == 0) {
00588     rval = getVtxCoord(this_gent, on_x, on_y, on_z);
00589     MBERRORR(rval, "Failed to get vertex coordinates.");
00590   } else if (_smooth && type == 1) {
00591     *on_x = near_x;
00592     *on_y = near_y;
00593     *on_z = near_z;
00594     SmoothCurve * smthcurve = _edges[this_gent];
00595     // call the new method from smooth edge
00596     smthcurve->move_to_curve( *on_x, *on_y, *on_z);
00597 
00598   } else if (type == 2 || type == 3) {
00599     double point[3] = { near_x, near_y, near_z };
00600     double point_out[3];
00601     EntityHandle root, facet_out;
00602     if (_smooth && 2 == type) {
00603       SmoothFace* smthFace = _faces[this_gent];
00604       *on_x = near_x;
00605       *on_y = near_y;
00606       *on_z = near_z;
00607       smthFace->move_to_surface(*on_x, *on_y, *on_z);
00608     } else {
00609       rval = _my_geomTopoTool->get_root(this_gent, root);
00610       MBERRORR(rval, "Failed to get tree root in iGeom_getEntClosestPt.");
00611       rval = _my_geomTopoTool->obb_tree()->closest_to_location(point, root,
00612           point_out, facet_out);
00613       MBERRORR(rval, "Failed to get closest point in iGeom_getEntClosestPt.");
00614 
00615       *on_x = point_out[0];
00616       *on_y = point_out[1];
00617       *on_z = point_out[2];
00618     }
00619   } else
00620     return MB_TYPE_OUT_OF_RANGE;
00621 
00622   return MB_SUCCESS;
00623 }
00624 
00625 ErrorCode FBEngine::getVtxCoord(EntityHandle vertex_handle, double * x0,
00626     double * y0, double * z0)
00627 {
00628   int type;
00629   ErrorCode rval = getEntType(vertex_handle, &type);
00630   MBERRORR(rval, "Failed to get entity type in getVtxCoord.");
00631 
00632   if (type != 0) {
00633     rval = MB_FAILURE;
00634     MBERRORR(rval, "Entity is not a vertex type.");
00635   }
00636 
00637   Range entities;
00638   rval = MBI->get_entities_by_type(vertex_handle, MBVERTEX, entities);
00639   MBERRORR(rval, "can't get nodes in vertex set.");
00640 
00641   if (entities.size() != 1) {
00642     MBERRORR(MB_FAILURE, "Vertex has multiple points.");
00643   }
00644   double coords[3];
00645   EntityHandle node = entities[0];
00646   rval = MBI->get_coords(&node, 1, coords);
00647   MBERRORR(rval, "can't get coordinates.");
00648   *x0 = coords[0];
00649   *y0 = coords[1];
00650   *z0 = coords[2];
00651 
00652   return MB_SUCCESS;
00653 }
00654 
00655 ErrorCode FBEngine::gsubtract(EntityHandle entity_set_1,
00656     EntityHandle entity_set_2, EntityHandle result_entity_set)
00657 {
00658   /*result_entity_set = subtract(entity_set_1, entity_set_2);*/
00659   Range ents1, ents2;
00660   ErrorCode rval = MBI->get_entities_by_type(entity_set_1, MBENTITYSET, ents1);
00661   MBERRORR(rval, "can't get entities from set 1.");
00662 
00663   rval = MBI->get_entities_by_type(entity_set_2, MBENTITYSET, ents2);
00664   MBERRORR(rval, "can't get entities from set 2.");
00665 
00666   ents1 = subtract(ents1, ents2);
00667   rval = MBI->clear_meshset(&result_entity_set, 1);
00668   MBERRORR(rval, "can't empty set.");
00669 
00670   rval = MBI->add_entities(result_entity_set, ents1);
00671   MBERRORR(rval, "can't add result to set.");
00672 
00673   return rval;
00674 }
00675 
00676 ErrorCode FBEngine::getEntNrmlXYZ(EntityHandle entity_handle, double x,
00677     double y, double z, double* nrml_i, double* nrml_j, double* nrml_k)
00678 {
00679   // just do for surface and volume
00680   int type;
00681   ErrorCode rval = getEntType(entity_handle, &type);
00682   MBERRORR(rval, "Failed to get entity type in iGeom_getEntNrmlXYZ.");
00683 
00684   if (type != 2 && type != 3) {
00685     MBERRORR(MB_FAILURE, "Entities passed into gentityNormal must be face or volume.");
00686   }
00687 
00688   if (_smooth && 2 == type) {
00689     SmoothFace* smthFace = _faces[entity_handle];
00690     //*on_x = near_x; *on_y = near_y; *on_z = near_z;
00691     smthFace-> normal_at(x, y, z, *nrml_i, *nrml_j, *nrml_k);
00692 
00693   } else {
00694     // get closest location and facet
00695     double point[3] = { x, y, z };
00696     double point_out[3];
00697     EntityHandle root, facet_out;
00698     _my_geomTopoTool->get_root(entity_handle, root);
00699     rval = _my_geomTopoTool->obb_tree()->closest_to_location(point, root,
00700         point_out, facet_out);
00701     MBERRORR(rval , "Failed to get closest location in iGeom_getEntNrmlXYZ.");
00702 
00703     // get facet normal
00704     const EntityHandle* conn;
00705     int len;
00706     CartVect coords[3], normal;
00707     rval = MBI->get_connectivity(facet_out, conn, len);
00708     MBERRORR(rval, "Failed to get triangle connectivity in iGeom_getEntNrmlXYZ.");
00709     if (len != 3)
00710       MBERRORR(MB_FAILURE, " not a triangle, error ");
00711 
00712     rval = MBI->get_coords(conn, len, coords[0].array());
00713     MBERRORR(rval, "Failed to get triangle coordinates in iGeom_getEntNrmlXYZ.");
00714 
00715     coords[1] -= coords[0];
00716     coords[2] -= coords[0];
00717     normal = coords[1] * coords[2];
00718     normal.normalize();
00719     *nrml_i = normal[0];
00720     *nrml_j = normal[1];
00721     *nrml_k = normal[2];
00722   }
00723   return MB_SUCCESS;
00724 }
00725 
00726 ErrorCode FBEngine::getPntRayIntsct(double x, double y, double z, double dir_x,
00727     double dir_y, double dir_z,
00728     std::vector<EntityHandle> &intersect_entity_handles,
00729     /* int storage_order,*/
00730     std::vector<double> & intersect_coords, std::vector<double> & param_coords)
00731 {
00732   // this is pretty cool
00733   // we will return only surfaces (gentities )
00734   //
00735   ErrorCode rval;
00736 
00737   unsigned int numfaces = _my_gsets[2].size();
00738   // do ray fire
00739   const double point[] = { x, y, z };
00740   const double dir[] = { dir_x, dir_y, dir_z };
00741   CartVect P(point);
00742   CartVect V(dir);
00743 
00744   //std::vector<double> distances;
00745   std::vector<EntityHandle> facets;
00746   //std::vector<EntityHandle> sets;
00747   unsigned int i;
00748   for (i = 0; i < numfaces; i++) {
00749     EntityHandle face = _my_gsets[2][i];
00750     EntityHandle rootForFace;
00751     rval = _my_geomTopoTool->get_root(face, rootForFace);
00752     MBERRORR(rval, "Failed to get root of face.");
00753     std::vector<double> distances_out;
00754     std::vector<EntityHandle> sets_out;
00755     std::vector<EntityHandle> facets_out;
00756     rval = _my_geomTopoTool->obb_tree()-> ray_intersect_sets(distances_out,
00757         sets_out, facets_out, rootForFace, tolerance,
00758         min_tolerace_intersections, point, dir);
00759     unsigned int j;
00760     for (j = 0; j < distances_out.size(); j++)
00761       param_coords.push_back(distances_out[j]);
00762     for (j = 0; j < sets_out.size(); j++)
00763       intersect_entity_handles.push_back(sets_out[j]);
00764     for (j = 0; j < facets_out.size(); j++)
00765       facets.push_back(facets_out[j]);
00766 
00767     MBERRORR(rval, "Failed to get ray intersections.");
00768   }
00769   // facets.size == distances.size()!!
00770   for (i = 0; i < param_coords.size(); i++) {
00771     CartVect intx = P + param_coords[i] * V;
00772     for (int j = 0; j < 3; j++)
00773       intersect_coords.push_back(intx[j]);
00774 
00775   }
00776   if (_smooth) {
00777     // correct the intersection point and the distance for smooth surfaces
00778     for (i = 0; i < intersect_entity_handles.size(); i++) {
00779       //EntityHandle geoSet = MBH_cast(sets[i]);
00780       SmoothFace* sFace = _faces[intersect_entity_handles[i]];
00781       // correct coordinates and distance from point
00782       /*moab::ErrorCode ray_intersection_correct(moab::EntityHandle facet, // (IN) the facet where the patch is defined
00783        moab::CartVect &pt, // (IN) shoot from
00784        moab::CartVect &ray, // (IN) ray direction
00785        moab::CartVect &eval_pt, // (INOUT) The intersection point
00786        double & distance, // (IN OUT) the new distance
00787        bool &outside);*/
00788       CartVect pos(&(intersect_coords[3 * i]));
00789       double dist = param_coords[i];
00790       bool outside = false;
00791       rval = sFace->ray_intersection_correct(facets[i], P, V, pos, dist,
00792           outside);
00793       MBERRORR(rval, "Failed to get better point on ray.");
00794       param_coords[i] = dist;
00795 
00796       for (int j = 0; j < 3; j++)
00797         intersect_coords[3 * i + j] = pos[j];
00798     }
00799   }
00800   return MB_SUCCESS;
00801 }
00802 
00803 ErrorCode FBEngine::getAdjacentEntities(const EntityHandle from,
00804     const int to_dim, Range &adjs)
00805 {
00806   int this_dim = -1;
00807   for (int i = 0; i < 4; i++) {
00808     if (_my_geomTopoTool->geoRanges()[i].find(from) != _my_geomTopoTool->geoRanges()[i].end()) {
00809       this_dim = i;
00810       break;
00811     }
00812   }
00813 
00814   // check target dimension
00815   if (-1 == this_dim) {
00816     //ProcessError(iBase_FAILURE, "Entity not a geometry entity.");
00817     return MB_FAILURE;
00818   } else if (0 > to_dim || 3 < to_dim) {
00819     //ProcessError(iBase_FAILURE, "To dimension must be between 0 and 3.");
00820     return MB_FAILURE;
00821   } else if (to_dim == this_dim) {
00822     //ProcessError(iBase_FAILURE,
00823     //      "To dimension must be different from entity dimension.");
00824     return MB_FAILURE;
00825   }
00826 
00827   ErrorCode rval = MB_SUCCESS;
00828   adjs.clear();
00829   if (to_dim > this_dim) {
00830     int diffDim = to_dim-this_dim;
00831     rval = MBI->get_parent_meshsets(from, adjs, diffDim);
00832     if (MB_SUCCESS != rval) return rval;
00833     if (diffDim>1)
00834     {
00835       // subtract the parents that come with diffDim-1 hops
00836       Range extra;
00837       rval = MBI->get_parent_meshsets(from, extra, diffDim-1);
00838       if (MB_SUCCESS != rval) return rval;
00839       adjs = subtract(adjs, extra);
00840     }
00841 
00842   } else {
00843     int diffDim = this_dim - to_dim;
00844     rval = MBI->get_child_meshsets(from, adjs, diffDim);
00845     if (MB_SUCCESS != rval) return rval;
00846     if (diffDim > 1)
00847     {
00848       // subtract the children that come with diffDim-1 hops
00849       Range extra;
00850       rval = MBI->get_child_meshsets(from, extra, diffDim-1);
00851       if (MB_SUCCESS != rval) return rval;
00852       adjs = subtract(adjs, extra);
00853     }
00854   }
00855 
00856   return rval;
00857 }
00858 
00859 // so far, this one is
00860 // used only for __MKModelEntityGeo tag
00861 
00862 ErrorCode FBEngine::createTag(const char* tag_name, int tag_size, int tag_type,
00863     Tag & tag_handle_out)
00864 {
00865   // this is copied from iMesh_MOAB.cpp; different name to not have trouble
00866   // with it
00867   // also, we do not want to depend on iMesh.h...
00868   // iMesh is more complicated, because of the options passed
00869 
00870   DataType mb_data_type_table2[] = { MB_TYPE_OPAQUE, MB_TYPE_INTEGER,
00871       MB_TYPE_DOUBLE, MB_TYPE_HANDLE, MB_TYPE_HANDLE };
00872   moab::TagType storage = MB_TAG_SPARSE;
00873   ErrorCode result;
00874 
00875   result = MBI->tag_get_handle(tag_name, tag_size,
00876       mb_data_type_table2[tag_type], tag_handle_out, storage | MB_TAG_EXCL);
00877 
00878   if (MB_SUCCESS != result) {
00879     std::string msg("iMesh_createTag: ");
00880     if (MB_ALREADY_ALLOCATED == result) {
00881       msg += "Tag already exists with name: \"";
00882       msg += tag_name;
00883       std::cout<<msg << "\n";
00884     }
00885     else
00886     {
00887       std::cout<< "Failed to create tag with name: " << tag_name << "\n";
00888       return MB_FAILURE;
00889     }
00890 
00891   }
00892 
00893   // end copy
00894   return MB_SUCCESS;
00895 }
00896 
00897 
00898 ErrorCode FBEngine::getArrData(const EntityHandle* entity_handles,
00899     int entity_handles_size, Tag tag_handle, void* tag_values_out)
00900 {
00901   // responsibility of the user to have tag_values_out properly allocated
00902   // only some types of Tags are possible (double, int, etc)
00903   return MBI->tag_get_data(tag_handle, entity_handles, entity_handles_size,
00904       tag_values_out);
00905 }
00906 
00907 ErrorCode FBEngine::setArrData(const EntityHandle* entity_handles,
00908     int entity_handles_size, Tag tag_handle, const void* tag_values)
00909 {
00910   // responsibility of the user to have tag_values_out properly allocated
00911   // only some types of Tags are possible (double, int, etc)
00912   return MBI->tag_set_data(tag_handle, entity_handles, entity_handles_size,
00913       tag_values);
00914 }
00915 
00916 ErrorCode FBEngine::getEntAdj(EntityHandle handle, int type_requested,
00917     Range & adjEnts)
00918 {
00919   return getAdjacentEntities(handle, type_requested, adjEnts);
00920 }
00921 
00922 ErrorCode FBEngine::getEgFcSense(EntityHandle mbedge, EntityHandle mbface,
00923     int & sense_out)
00924 {
00925 
00926   // this one is important, for establishing the orientation of the edges in faces
00927   // use senses
00928   std::vector<EntityHandle> faces;
00929   std::vector<int> senses; // 0 is forward and 1 is backward
00930   ErrorCode rval = _my_geomTopoTool->get_senses(mbedge, faces, senses);
00931   if (MB_SUCCESS != rval)
00932     return rval;
00933 
00934   for (unsigned int i = 0; i < faces.size(); i++) {
00935     if (faces[i] == mbface) {
00936       sense_out = senses[i];
00937       return MB_SUCCESS;
00938     }
00939   }
00940   return MB_FAILURE;
00941 
00942 }
00943 // we assume the measures array was allocated correctly
00944 ErrorCode FBEngine::measure(const EntityHandle * moab_entities,
00945     int entities_size, double * measures)
00946 {
00947   ErrorCode rval;
00948   for (int i = 0; i < entities_size; i++) {
00949     measures[i] = 0.;
00950 
00951     int type;
00952     EntityHandle gset = moab_entities[i];
00953     rval = getEntType(gset, &type);
00954     if (MB_SUCCESS != rval)
00955       return rval;
00956     if (type == 1) { // edge: get all edges part of the edge set
00957       Range entities;
00958       rval = MBI->get_entities_by_type(gset, MBEDGE, entities);
00959       if (MB_SUCCESS != rval)
00960         return rval;
00961 
00962       for (Range::iterator it = entities.begin(); it != entities.end(); it++) {
00963         EntityHandle edge = *it;
00964         CartVect vv[2];
00965         const EntityHandle *conn2 = NULL;
00966         int num_nodes;
00967         rval = MBI->get_connectivity(edge, conn2, num_nodes);
00968         if (MB_SUCCESS != rval || num_nodes != 2)
00969           return MB_FAILURE;
00970         rval = MBI->get_coords(conn2, 2, (double *) &(vv[0][0]));
00971         if (MB_SUCCESS != rval)
00972           return rval;
00973 
00974         vv[0] = vv[1] - vv[0];
00975         measures[i] += vv[0].length();
00976       }
00977     }
00978     if (type == 2) { // surface
00979       // get triangles in surface; TODO: quads!
00980       Range entities;
00981       rval = MBI->get_entities_by_type(gset, MBTRI, entities);
00982       if (MB_SUCCESS != rval)
00983         return rval;
00984 
00985       for (Range::iterator it = entities.begin(); it != entities.end(); it++) {
00986         EntityHandle tri = *it;
00987         CartVect vv[3];
00988         const EntityHandle *conn3 = NULL;
00989         int num_nodes;
00990         rval = MBI->get_connectivity(tri, conn3, num_nodes);
00991         if (MB_SUCCESS != rval || num_nodes != 3)
00992           return MB_FAILURE;
00993         rval = MBI->get_coords(conn3, 3, (double *) &(vv[0][0]));
00994         if (MB_SUCCESS != rval)
00995           return rval;
00996 
00997         vv[1] = vv[1] - vv[0];
00998         vv[2] = vv[2] - vv[0];
00999         vv[0] = vv[1] * vv[2];
01000         measures[i] += vv[0].length() / 2;// area of triangle
01001       }
01002 
01003     }
01004   }
01005   return MB_SUCCESS;
01006 }
01007 
01008 ErrorCode FBEngine::getEntNrmlSense(EntityHandle /*face*/, EntityHandle /*region*/,
01009                                     int& /*sense*/)
01010 {
01011   return MB_NOT_IMPLEMENTED; // not implemented
01012 }
01013 
01014 ErrorCode FBEngine::getEgEvalXYZ(EntityHandle /*edge*/, double /*x*/, double /*y*/,
01015                                  double /*z*/, double& /*on_x*/, double& /*on_y*/, double& /*on_z*/, double& /*tngt_i*/,
01016                                  double& /*tngt_j*/, double& /*tngt_k*/, double& /*cvtr_i*/, double& /*cvtr_j*/,
01017                                  double& /*cvtr_k*/)
01018 {
01019   return MB_NOT_IMPLEMENTED; // not implemented
01020 }
01021 ErrorCode FBEngine::getFcEvalXYZ(EntityHandle /*face*/, double /*x*/, double /*y*/,
01022                                  double /*z*/, double& /*on_x*/, double& /*on_y*/, double& /*on_z*/, double& /*nrml_i*/,
01023                                  double& /*nrml_j*/, double& /*nrml_k*/, double& /*cvtr1_i*/, double& /*cvtr1_j*/,
01024                                  double& /*cvtr1_k*/, double& /*cvtr2_i*/, double& /*cvtr2_j*/, double& /*cvtr2_k*/)
01025 {
01026   return MB_NOT_IMPLEMENTED; // not implemented
01027 }
01028 
01029 ErrorCode FBEngine::getEgVtxSense(EntityHandle edge, EntityHandle vtx1,
01030     EntityHandle vtx2, int& sense)
01031 {
01032   // need to decide first or second vertex
01033   // important for moab
01034   int type;
01035 
01036   EntityHandle v1, v2;
01037   ErrorCode rval = getEntType(vtx1, &type);
01038   if (MB_SUCCESS != rval || type != 0)
01039     return MB_FAILURE;
01040   // edge: get one vertex as part of the vertex set
01041   Range entities;
01042   rval = MBI->get_entities_by_type(vtx1, MBVERTEX, entities);
01043   if (MB_SUCCESS != rval)
01044     return rval;
01045   if (entities.size() < 1)
01046     return MB_FAILURE;
01047   v1 = entities[0]; // the first vertex
01048   entities.clear();
01049   rval = getEntType(vtx2, &type);
01050   if (MB_SUCCESS != rval || type != 0)
01051     return MB_FAILURE;
01052   rval = MBI->get_entities_by_type(vtx2, MBVERTEX, entities);
01053   if (MB_SUCCESS != rval)
01054     return rval;
01055   if (entities.size() < 1)
01056     return MB_FAILURE;
01057   v2 = entities[0]; // the first vertex
01058   entities.clear();
01059   // now get the edges, and get the first node and the last node in sequence of edges
01060   // the order is important...
01061   // these are ordered sets !!
01062   std::vector<EntityHandle> ents;
01063   rval = MBI->get_entities_by_type(edge, MBEDGE, ents);
01064   if (MB_SUCCESS != rval)
01065     return rval;
01066   if (ents.size() < 1)
01067     return MB_FAILURE;
01068 
01069   const EntityHandle* conn = NULL;
01070   int len;
01071   EntityHandle startNode, endNode;
01072   rval = MBI->get_connectivity(ents[0], conn, len);
01073   if (MB_SUCCESS != rval)
01074     return rval;
01075   startNode = conn[0];
01076   rval = MBI->get_connectivity(ents[ents.size() - 1], conn, len);
01077   if (MB_SUCCESS != rval)
01078     return rval;
01079 
01080   endNode = conn[1];
01081   sense = 1; //
01082   if ((startNode == endNode) && (v1 == startNode)) {
01083     sense = 0; // periodic
01084   }
01085   if ((startNode == v1) && (endNode == v2)) {
01086     sense = 1; // forward
01087   }
01088   if ((startNode == v2) && (endNode == v1)) {
01089     sense = -1; // reverse
01090   }
01091   return MB_SUCCESS;
01092 }
01093 
01094 ErrorCode FBEngine::getEntURange(EntityHandle edge, double& u_min,
01095     double& u_max)
01096 {
01097   SmoothCurve * smoothCurve = _edges[edge];// this is a map
01098   // now, call smoothCurve methods
01099   smoothCurve -> get_param_range(u_min, u_max);
01100   return MB_SUCCESS;
01101 }
01102 
01103 ErrorCode FBEngine::getEntUtoXYZ(EntityHandle edge, double u, double& x,
01104     double& y, double& z)
01105 {
01106   SmoothCurve * smoothCurve = _edges[edge];// this is a map
01107   // now, call smoothCurve methods
01108   smoothCurve -> position_from_u(u, x, y, z);
01109   return MB_SUCCESS;
01110 }
01111 
01112 ErrorCode FBEngine::getEntTgntU( EntityHandle edge,
01113                                     double u,
01114                                     double& i, double& j, double& k )
01115 {
01116   SmoothCurve * smoothCurve = _edges[edge];// this is a map
01117   // now, call smoothCurve methods
01118   double tg[3];
01119   double x, y, z;
01120   smoothCurve -> position_from_u(u, x, y, z, tg);
01121   i = tg[0];
01122   j = tg[1];
01123   k = tg[2];
01124   return MB_SUCCESS;
01125 }
01126 ErrorCode FBEngine::isEntAdj(EntityHandle entity1, EntityHandle entity2,
01127     bool& adjacent_out)
01128 {
01129   int type1, type2;
01130   ErrorCode rval = getEntType(entity1, &type1);
01131   if (MB_SUCCESS != rval)
01132     return rval;
01133   rval = getEntType(entity2, &type2);
01134   if (MB_SUCCESS != rval)
01135     return rval;
01136 
01137   Range adjs;
01138   if (type1 < type2) {
01139     rval = MBI->get_parent_meshsets(entity1, adjs, type2 - type1);
01140     if (MB_SUCCESS != rval)
01141       return rval;// MBERRORR("Failed to get parent meshsets in iGeom_isEntAdj.");
01142 
01143   } else {
01144     // note: if they ave the same type, they will not be adjacent, in our definition
01145     rval = MBI->get_child_meshsets(entity1, adjs, type1 - type2);
01146     if (MB_SUCCESS != rval)
01147       return rval;//MBERRORR("Failed to get child meshsets in iGeom_isEntAdj.");
01148   }
01149 
01150   //adjacent_out = adjs.find(entity2) != _my_gsets[type2].end();
01151   // hmmm, possible bug here; is this called?
01152   adjacent_out = adjs.find(entity2) != adjs.end();
01153 
01154 
01155   return MB_SUCCESS;
01156 }
01157 
01158 ErrorCode FBEngine::split_surface_with_direction(EntityHandle face, std::vector<double> & xyz, double * direction,
01159     int closed, double min_dot, EntityHandle & oNewFace )
01160 {
01161 
01162   // first of all, find all intersection points (piercing in the face along the direction)
01163   // assume it is robust; what if it is not sufficiently robust?
01164   // if the polyline is open, find the intersection with the boundary edges, of the
01165   // polyline extruded at ends
01166 
01167   ErrorCode rval;
01168 
01169   // then find the position
01170   int numIniPoints = (int) xyz.size() / 3;
01171   if (  (closed && numIniPoints < 3)  ||  (!closed && numIniPoints<2) )
01172     MBERRORR(MB_FAILURE, "not enough polyline points ");
01173   EntityHandle rootForFace;
01174 
01175   rval = _my_geomTopoTool->get_root(face, rootForFace);
01176   MBERRORR(rval, "Failed to get root of face.");
01177 
01178   const double dir[] = { direction[0], direction[1], direction[2] };
01179   std::vector<EntityHandle> nodes; // get the nodes closest to the ray traces of interest
01180 
01181   // these are nodes on the boundary of original face;
01182   // if the cutting line is not closed, the starting - ending vertices of the
01183   // polygonal line must come from this list
01184 
01185   std::vector<CartVect> b_pos;
01186   std::vector<EntityHandle> boundary_nodes;
01187   std::vector<EntityHandle> splittingNodes;
01188   Range boundary_mesh_edges;
01189   if (!closed)
01190   {
01191     rval = boundary_nodes_on_face(face, boundary_nodes);
01192     MBERRORR(rval, "Failed to get boundary nodes.");
01193     b_pos.resize(boundary_nodes.size());
01194     rval = _mbImpl->get_coords(&(boundary_nodes[0]), boundary_nodes.size(), (double *)(&b_pos[0][0]));
01195     MBERRORR(rval, "Failed to get coordinates for boundary nodes.");
01196     rval = boundary_mesh_edges_on_face(face, boundary_mesh_edges);
01197     MBERRORR(rval, "Failed to get mesh boundary edges for face.");
01198   }
01199   //
01200   int i = 0;
01201   CartVect dirct(direction);
01202   dirct.normalize(); // maybe an overkill?
01203   for (; i < numIniPoints; i++) {
01204 
01205     const double point[] = { xyz[3 * i], xyz[3 * i + 1], xyz[3 * i + 2] };// or even point( &(xyz[3*i]) ); //
01206     CartVect p1(point);
01207     if (!closed && ( (0==i) || (numIniPoints-1==i) ) )
01208     {
01209 
01210       // find the intersection point between a plane and boundary mesh edges
01211       // this will be the closest point on the boundary of face
01213       int i1 = i+1;
01214       if (i==numIniPoints-1) i1= i-1;// previous point if the last
01215       // the direction is from point to point1
01216       const double point1[] = { xyz[3 * i1], xyz[3 * i1 + 1], xyz[3 * i1 + 2] };
01217       CartVect p2(point1);
01218       CartVect normPlane=(p2-p1)*dirct;
01219       normPlane.normalize();
01220       //(roughly, from p1 to p2, perpendicular to dirct, in the "xy" plane
01221       // if the intx point is "outside" p1 - p2, skip if the intx point is closer to p2
01222       CartVect perpDir = dirct*normPlane;
01223       Range::iterator ite=boundary_mesh_edges.begin();
01224       // do a linear search for the best intersection point position (on a boundary edge)
01225       if (debug_splits)
01226       {
01227         std::cout << " p1:" << p1 <<"\n";
01228         std::cout << " p2:" << p2 <<"\n";
01229         std::cout << " perpDir:" << perpDir << "\n";
01230         std::cout<<" boundary edges size:" << boundary_mesh_edges.size() << "\n";
01231       }
01232       for ( ; ite!=boundary_mesh_edges.end(); ite++)
01233       {
01234         EntityHandle candidateEdge = *ite;
01235         const EntityHandle * conn2;
01236         int nno;
01237         rval= _mbImpl->get_connectivity(candidateEdge, conn2, nno);
01238         MBERRORR(rval, "Failed to get conn for boundary edge");
01239         CartVect pts[2];
01240         rval = _mbImpl->get_coords(conn2, 2, &(pts[0][0]));
01241         MBERRORR(rval, "Failed to get coords of nodes for boundary edge");
01242         CartVect intx_point;
01243         double parPos;
01244         bool intersect = intersect_segment_and_plane_slice(pts[0], pts[1],
01245             p1, p2, dirct, normPlane, intx_point,  parPos);
01246         if (debug_splits)
01247         {
01248           std::cout << "   Edge:" << _mbImpl->id_from_handle(candidateEdge)<<"\n";
01249           std::cout << "   Node 1:" << _mbImpl->id_from_handle(conn2[0]) << pts[0] <<"\n";
01250           std::cout << "   Node 2:" << _mbImpl->id_from_handle(conn2[1]) << pts[1] <<"\n";
01251           std::cout << "    Intersect bool:" << intersect << "\n";
01252         }
01253         if (intersect)
01254         {
01255           double proj1 = (intx_point-p1)%perpDir;
01256           double proj2 = (intx_point-p2)%perpDir;
01257           if (
01258                 ( fabs(proj1) > fabs(proj2) ) // this means it is closer to p2 than p1
01259               )
01260             continue; // basically, this means the intersection point is with a
01261                       //  boundary edge on the other side, closer to p2 than p1, so we skip it
01262           if (parPos==0)
01263           {
01264             //close to vertex 1, nothing to do
01265             nodes.push_back(conn2[0]);
01266             splittingNodes.push_back(conn2[0]);
01267           }
01268           else if (parPos ==1.)
01269           {
01270             //close to vertex 2, nothing to do
01271             nodes.push_back(conn2[1]);
01272             splittingNodes.push_back(conn2[1]);
01273           }
01274           else
01275           {
01276             // break the edge, create a new node at intersection point (will be smoothed out)
01277             EntityHandle newVertex;
01278             rval = _mbImpl->create_vertex(&(intx_point[0]), newVertex);
01279             MBERRORR(rval, "can't create vertex");
01280             nodes.push_back(newVertex);
01281             split_internal_edge(candidateEdge, newVertex);
01282             splittingNodes.push_back(newVertex);
01283             _brokenEdges[newVertex] = candidateEdge;
01284             _piercedEdges.insert(candidateEdge);
01285           }
01286           break; // break from the loop over boundary edges, we are interested in the first
01287                  //      split (hopefully, the only split)
01288         }
01289       }
01290       if (ite==boundary_mesh_edges.end())
01291         MBERRORR(MB_FAILURE, "Failed to find boundary intersection edge. Bail out");
01292 
01293     }
01294     else
01295     {
01296       std::vector<double> distances_out;
01297       std::vector<EntityHandle> sets_out;
01298       std::vector<EntityHandle> facets_out;
01299       rval = _my_geomTopoTool->obb_tree()-> ray_intersect_sets(distances_out,
01300           sets_out, facets_out, rootForFace, tolerance,
01301           min_tolerace_intersections, point, dir);
01302       MBERRORR(rval, "Failed to get ray intersections.");
01303       if (distances_out.size() < 1)
01304         MBERRORR(MB_FAILURE, "Failed to get one intersection point, bad direction.");
01305 
01306       if (distances_out.size() > 1) {
01307         std::cout
01308             << " too many intersection points. Only the first one considered\n";
01309       }
01310       std::vector<EntityHandle>::iterator pFace = std::find(sets_out.begin(), sets_out.end(), face);
01311 
01312       if (pFace == sets_out.end())
01313         MBERRORR(MB_FAILURE, "Failed to intersect given face, bad direction.");
01314       unsigned int index = pFace-sets_out.begin();
01315       // get the closest node of the triangle, and modify locally the triangle(s), so the
01316       // intersection point is at a new vertex, if needed
01317       CartVect P(point);
01318       CartVect Dir(dir);
01319       CartVect newPoint = P + distances_out[index] * Dir;
01320       // get the triangle coordinates
01321 
01322       double area_coord[3];
01323       EntityHandle  boundary_handle =0; // if 0, not on a boundary
01324       rval = area_coordinates(_mbImpl, facets_out[index], newPoint, area_coord, boundary_handle);
01325       MBERRORR(rval, "Failed to get area coordinates");
01326 
01327       if (debug_splits)
01328       {
01329         std::cout <<" int point:" << newPoint << " area coord " << area_coord[0] << " "
01330            <<  area_coord[1] << " " << area_coord[2] << "\n";
01331         std::cout << " triangle: " <<
01332             _mbImpl->id_from_handle(facets_out[index]) << " boundary:" <<  boundary_handle <<  "\n";
01333       }
01334       EntityType type;
01335       if (boundary_handle)
01336         type = _mbImpl->type_from_handle(boundary_handle);
01337       if (boundary_handle&& (type == MBVERTEX))
01338       {
01339         // nothing to do, we are happy
01340         nodes.push_back(boundary_handle);
01341       }
01342       else
01343       {
01344         // for an edge, we will split 2 triangles
01345         // for interior point, we will create 3 triangles out of one
01346         // create a new vertex
01347         EntityHandle newVertex;
01348         rval = _mbImpl->create_vertex(&(newPoint[0]), newVertex);
01349         if (boundary_handle)// this is edge
01350         {
01351           split_internal_edge(boundary_handle, newVertex);
01352           _piercedEdges.insert(boundary_handle);// to be removed at the end
01353         }
01354         else
01355           divide_triangle(facets_out[index], newVertex);
01356 
01357         nodes.push_back(newVertex);
01358       }
01359 
01360     }
01361   }
01362   // now, we have to find more intersection points, either interior to triangles, or on edges, or on vertices
01363   // use the same tolerance as before
01364   // starting from 2 points on 2 triangles, and having the direction, get more intersection points
01365   // between the plane formed by direction and those 2 points, and edges from triangulation (the triangles
01366   // involved will be part of the same gentity , original face ( moab set)
01367   //int closed = 1;// closed = 0 if the polyline is not closed
01368 
01369   CartVect Dir(direction);
01370   std::vector<EntityHandle>  chainedEdges;
01371 
01372   for (i = 0; i < numIniPoints - 1 + closed; i++) {
01373     int nextIndex = (i + 1) % numIniPoints;
01374     std::vector<EntityHandle> trianglesAlong;
01375     std::vector<CartVect> points;
01376       // otherwise to edges or even nodes
01377     std::vector<EntityHandle> entities;
01378     //start with initial points, intersect along the direction, find the facets
01379     rval = compute_intersection_points(face, nodes[i], nodes[nextIndex], Dir, points,
01380         entities, trianglesAlong);
01381     MBERRORR(rval, "can't get intersection points along a line");
01382     std::vector<EntityHandle> nodesAlongPolyline;
01383     // refactor code; move some edge creation for each 2 intersection points
01384     nodesAlongPolyline.push_back(entities[0]); // it is for sure a node
01385     int num_points = (int) points.size(); // it should be num_triangles + 1
01386     for (int j = 0; j < num_points-1; j++) {
01387       EntityHandle tri = trianglesAlong[j]; // this is happening in trianglesAlong i
01388       EntityHandle e1 = entities[j];
01389       EntityHandle e2 = entities[j + 1];
01390       EntityType et1 = _mbImpl->type_from_handle(e1);
01391       //EntityHandle vertex1 = nodesAlongPolyline[i];// irrespective of the entity type i,
01392       // we already have the vertex there
01393       EntityType et2 = _mbImpl->type_from_handle(e2);
01394       if (et2 == MBVERTEX) {
01395         nodesAlongPolyline.push_back(e2);
01396       }
01397       else // if (et2==MBEDGE)
01398       {
01399         CartVect coord_vert=points[j+1];
01400         EntityHandle newVertex;
01401         rval = _mbImpl->create_vertex((double*)&coord_vert, newVertex);
01402         MBERRORR(rval, "can't create vertex");
01403         nodesAlongPolyline.push_back(newVertex);
01404       }
01405       // if vertices, do not split anything, just get the edge for polyline
01406       if (et2 == MBVERTEX && et1 == MBVERTEX) {
01407         // nothing to do, just continue;
01408         continue; // continue the for loop
01409       }
01410 
01411       if (debug_splits)
01412       {
01413         std::cout <<"tri: type: " << _mbImpl->type_from_handle(tri) << " id:" <<
01414             _mbImpl->id_from_handle(tri) << "\n    e1:" << e1 << " id:" <<_mbImpl->id_from_handle(e1) <<
01415             "   e2:" << e2 << " id:" <<_mbImpl->id_from_handle(e2) <<"\n";
01416       }
01417       // here, at least one is an edge
01418       rval = BreakTriangle2( tri, e1, e2, nodesAlongPolyline[j], nodesAlongPolyline[j+1]);
01419       MBERRORR(rval, "can't break triangle 2");
01420       if (et2==MBEDGE)
01421         _piercedEdges.insert(e2);
01422       _piercedTriangles.insert(tri);
01423 
01424     }
01425     // nodesAlongPolyline will define a new geometric edge
01426     if (debug_splits)
01427     {
01428       std::cout<<"nodesAlongPolyline: " << nodesAlongPolyline.size() << "\n";
01429       std::cout << "points: " << num_points << "\n";
01430     }
01431     // if needed, create edges along polyline, or revert the existing ones, to
01432     // put them in a new edge set
01433     EntityHandle new_geo_edge;
01434     rval = create_new_gedge(nodesAlongPolyline, new_geo_edge);
01435     MBERRORR(rval, "can't create a new edge");
01436     chainedEdges.push_back(new_geo_edge);
01437     // end copy
01438   }
01439   // the segment between point_i and point_i+1 is in trianglesAlong_i
01440   // points_i is on entities_i
01441   // all these edges are oriented correctly
01442   rval = split_surface(face, chainedEdges, splittingNodes, oNewFace);
01443   MBERRORR(rval, "can't split surface");
01444   //
01445   rval = chain_edges(min_dot); // acos(0.8)~= 36 degrees
01446   MBERRORR(rval, "can't chain edges");
01447   return MB_SUCCESS;
01448 }
01455 ErrorCode FBEngine::split_surface(EntityHandle face,
01456      std::vector<EntityHandle> & chainedEdges,
01457      std::vector<EntityHandle> & splittingNodes, EntityHandle & newFace)
01458 {
01459   // use now the chained edges to create a new face (loop or clean split)
01460   // use a fill to determine the new sets, up to the polyline
01461   // points on the polyline will be moved to the closest point location, with some constraints
01462   // then the sets will be reset, geometry recomputed. new vertices, new edges, etc.
01463 
01464   Range iniTris;
01465   ErrorCode rval;
01466   rval = _mbImpl -> get_entities_by_type(face, MBTRI, iniTris);
01467   MBERRORR(rval, "can't get initial triangles");
01468 
01469   // start from a triangle that is not in the triangles to delete
01470   // flood fill 
01471 
01472   bool closed = splittingNodes.size()==0;
01473   if (!closed)
01474   {
01475     //
01476     if (splittingNodes.size()!=2)
01477       MBERRORR(MB_FAILURE, "need to have exactly 2 nodes for splitting");
01478     // we will have to split the boundary edges
01479     // first, find the actual boundary, and try to split with the 2 end points (nodes)
01480     // get the adjacent edges, and see which one has the end nodes
01481     rval = split_boundary(face, splittingNodes[0]);
01482     MBERRORR(rval, "can't split with first node");
01483     rval = split_boundary(face, splittingNodes[1]);
01484     MBERRORR(rval, "can't split with second node)");
01485   }
01486   // we will separate triangles to delete, unaffected, new_triangles,
01487   //  nodesAlongPolyline, 
01488   Range first, second;
01489   rval = separate (face, chainedEdges, first, second);
01490 
01491   // now, we are done with the computations;
01492   // we need to put the new nodes on the smooth surface
01493   if (this->_smooth)
01494   {
01495     rval = smooth_new_intx_points(face, chainedEdges);
01496     MBERRORR(rval, "can't smooth new points");
01497   }
01498 
01499   // create the new set
01500   rval = _mbImpl->create_meshset(MESHSET_SET, newFace);
01501   MBERRORR(rval, "can't create a new face");
01502 
01503   _my_geomTopoTool->add_geo_set(newFace, 2);
01504 
01505 
01506   // the new face will have the first set (positive sense triangles, to the left)
01507   rval = _mbImpl->add_entities(newFace, first);
01508   MBERRORR(rval, "can't add first range triangles to new face");
01509 
01510   for (unsigned int j=0; j<chainedEdges.size(); j++)
01511   {
01512     EntityHandle new_geo_edge = chainedEdges[j];
01513     // both faces will have the edge now
01514     rval = _mbImpl ->add_parent_child( face, new_geo_edge);
01515     MBERRORR(rval, "can't add parent child relations for new edge");
01516 
01517     rval = _mbImpl ->add_parent_child( newFace, new_geo_edge);
01518     MBERRORR(rval, "can't add parent child relations for new edge");
01519     // add senses
01520     // sense newFace is 1, old face is -1
01521     rval = _my_geomTopoTool-> set_sense( new_geo_edge, newFace, 1);
01522     MBERRORR(rval, "can't set sense for new edge");
01523 
01524     rval = _my_geomTopoTool-> set_sense( new_geo_edge, face, -1);
01525     MBERRORR(rval, "can't set sense for new edge in original face");
01526   }
01527 
01528   rval = set_neumann_tags(face, newFace);
01529   MBERRORR(rval, "can't set NEUMANN set tags");
01530 
01531   // now, we should remove from the original set all tris, and put the "second" range
01532   rval = _mbImpl->remove_entities(face, iniTris);
01533   MBERRORR(rval, "can't remove original tris from initial face set");
01534 
01535   rval = _mbImpl->add_entities(face, second);
01536   MBERRORR(rval, "can't add second range to the original set");
01537 
01538   if (!closed)
01539   {
01540     rval = redistribute_boundary_edges_to_faces(face, newFace, chainedEdges);
01541     MBERRORR(rval, "fail to reset the proper boundary faces");
01542   }
01543 
01544   /*if (_smooth)
01545     delete_smooth_tags();// they need to be recomputed, anyway
01546   // this will remove the extra smooth faces and edges
01547   clean();*/
01548   // also, these nodes need to be moved to the smooth surface, sometimes before deleting the old
01549   // triangles
01550   // remove the triangles from the set, then delete triangles (also some edges need to be deleted!)
01551   rval=_mbImpl->delete_entities( _piercedTriangles );
01552 
01553   MBERRORR(rval, "can't delete triangles");
01554   _piercedTriangles.clear();
01555   // delete edges that are broke up in 2
01556   rval=_mbImpl->delete_entities(_piercedEdges);
01557   MBERRORR(rval, "can't delete edges");
01558   _piercedEdges.clear();
01559 
01560   if (debug_splits)
01561   {
01562     _mbImpl->write_file("newFace.vtk", "vtk", 0, &newFace, 1);
01563     _mbImpl->write_file("leftoverFace.vtk", "vtk", 0, &face, 1);
01564   }
01565   return MB_SUCCESS;
01566 }
01567 
01568 ErrorCode FBEngine::smooth_new_intx_points(EntityHandle face,
01569       std::vector<EntityHandle> & chainedEdges)
01570 {
01571 
01572   // do not move nodes from the original face
01573   // first get all triangles, and then all nodes from those triangles
01574 
01575   Range tris;
01576   ErrorCode rval = _mbImpl->get_entities_by_type(face, MBTRI, tris);
01577   MBERRORR(rval, "can't get triangles");
01578 
01579   Range ini_nodes;
01580   rval = _mbImpl->get_connectivity( tris, ini_nodes);
01581   MBERRORR(rval, "can't get connectivities");
01582 
01583   SmoothFace* smthFace = _faces[face];
01584 
01585   // get all nodes from chained edges
01586   Range mesh_edges;
01587   for (unsigned int j= 0; j<chainedEdges.size(); j++)
01588   {
01589     // keep adding to the range of mesh edges
01590     rval = _mbImpl->get_entities_by_dimension(chainedEdges[j], 1, mesh_edges);
01591     MBERRORR(rval, "can't get mesh edges");
01592   }
01593   // nodes along polyline
01594   Range nodes_on_polyline;
01595   rval = _mbImpl->get_connectivity(mesh_edges, nodes_on_polyline, true); // corners only
01596   MBERRORR(rval, "can't get nodes on the polyline");
01597 
01598   Range new_intx_nodes = subtract(nodes_on_polyline, ini_nodes);
01599 
01600   std::vector<double> ini_coords;
01601   int num_points = (int)new_intx_nodes.size();
01602   ini_coords.resize(3*num_points);
01603   rval = _mbImpl->get_coords(new_intx_nodes, &(ini_coords[0]));
01604   MBERRORR(rval, "can't get coordinates");
01605 
01606   int i=0;
01607   for (Range::iterator it = new_intx_nodes.begin(); it != new_intx_nodes.end(); ++it)
01608   {
01609     /*EntityHandle node = *it;*/
01610     int i3=3*i;
01611     smthFace->move_to_surface(ini_coords[i3], ini_coords[i3+1], ini_coords[i3+2]);
01612     // reset the coordinates of this node
01613     ++i;
01614 
01615   }
01616   rval = _mbImpl->set_coords(new_intx_nodes, &(ini_coords[0]));
01617   MBERRORR(rval, "can't set smoothed coordinates for the new nodes");
01618 
01619   return MB_SUCCESS;
01620 }
01621 // we will use the fact that the splitting edge is oriented right now
01622 // to the left will be new face, to the right, old face
01623 // (to the left, positively oriented triangles)
01624 ErrorCode FBEngine::separate (EntityHandle face,
01625     std::vector<EntityHandle> & chainedEdges, Range & first,  Range & second)
01626 {
01627   //Range unaffectedTriangles = subtract(iniTriangles, _piercedTriangles);
01628   // insert in each
01629   // start with a new triangle, and flood to get the first range; what is left is the
01630   // second range
01631   // flood fill is considering edges adjacent to seed triangles; if there is
01632   //  an edge in the new_geo_edge, it is skipped; triangles in the
01633   // triangles to delete are not added
01634   // first, create all edges of the new triangles
01635 
01636   //
01637   // new face will have the new edge oriented positively
01638   // get mesh edges from geo edge (splitting gedge);
01639 
01640   Range mesh_edges;
01641   ErrorCode rval;
01642   // mesh_edges
01643   for(unsigned int j=0; j<chainedEdges.size(); j++)
01644   {
01645     // this will keep adding edges to the mesh_edges range
01646     // when we get out, the mesh_edges will be in this range, but not ordered
01647     rval = _mbImpl->get_entities_by_type(chainedEdges[j], MBEDGE, mesh_edges);
01648     MBERRORR(rval, "can't get new polyline edges");
01649     if (debug_splits)
01650     {
01651      std::cout << " At chained edge " << j << " " <<
01652          _mbImpl->id_from_handle(chainedEdges[j]) << " mesh_edges Range size:" << mesh_edges.size() << "\n";
01653     }
01654   }
01655 
01656   // get a positive triangle adjacent to mesh_edge[0]
01657   // add to first triangles to the left, second triangles to the right of the mesh_edges ;
01658 
01659   // create a temp tag, and when done, delete it
01660   // default value: 0
01661   // 3 to be deleted, pierced
01662   // 1 first set
01663   // 2 second set
01664   // create the tag also for control points on the edges
01665   int defVal = 0;
01666   Tag separateTag;
01667   rval = MBI->tag_get_handle("SEPARATE_TAG", 1, MB_TYPE_INTEGER, separateTag,
01668                                MB_TAG_DENSE|MB_TAG_CREAT, &defVal );
01669   MBERRORR(rval, "can't create temp tag for separation");
01670   // the deleted triangles will get a value 3, from start
01671   int delVal = 3;
01672   for (Range::iterator it1=this->_piercedTriangles.begin();
01673       it1!=_piercedTriangles.end(); it1++)
01674   {
01675     EntityHandle trToDelete= *it1;
01676     rval = _mbImpl->tag_set_data(separateTag, &trToDelete, 1, &delVal );
01677     MBERRORR(rval, "can't set delete tag value");
01678   }
01679 
01680   // find a triangle that will be in the first range, positively oriented about the splitting edge
01681   EntityHandle seed1=0;
01682   for (Range::iterator it = mesh_edges.begin(); it!=mesh_edges.end() && !seed1; it++)
01683   {
01684     EntityHandle meshEdge = *it;
01685     Range adj_tri;
01686     rval =  _mbImpl->get_adjacencies(&meshEdge, 1,
01687             2, false, adj_tri);
01688     MBERRORR(rval, "can't get adj_tris to mesh edge");
01689 
01690     for ( Range::iterator it2=adj_tri.begin(); it2!=adj_tri.end(); it2++)
01691     {
01692       EntityHandle tr=*it2;
01693       if (_piercedTriangles.find(tr)!=_piercedTriangles.end())
01694         continue;// do not attach pierced triangles, they are not good
01695       int num1, sense, offset;
01696       rval = _mbImpl->side_number(tr, meshEdge, num1, sense, offset);
01697       MBERRORR(rval, "edge not adjacent");
01698       if (sense==1)
01699       {
01700         //firstSet.insert(tr);
01701         if (!seed1)
01702         {
01703           seed1=tr;
01704           break;
01705         }
01706       }
01707     }
01708   }
01709 
01710   // flood fill first set, the rest will be in second set
01711   // the edges from new_geo_edge will not be crossed
01712 
01713   // get edges of face (adjacencies)
01714   // also get the old boundary edges, from face; they will be edges to not cross, too
01715   Range bound_edges;
01716   rval = getAdjacentEntities(face, 1, bound_edges);
01717   MBERRORR(rval, "can't get boundary edges");
01718 
01719   // add to the do not cross edges range, all edges from initial boundary
01720   Range initialBoundaryEdges;
01721   for (Range::iterator it= bound_edges.begin(); it!=bound_edges.end(); it++)
01722   {
01723     EntityHandle bound_edge=*it;
01724     rval = _mbImpl->get_entities_by_dimension(bound_edge, 1, initialBoundaryEdges);
01725   }
01726 
01727   Range doNotCrossEdges = unite(initialBoundaryEdges, mesh_edges);// add the splitting edges !
01728 
01729   // use a second method, with tags
01730   //
01731   std::queue<EntityHandle> queue1;
01732   queue1.push(seed1);
01733   std::vector<EntityHandle> arr1;
01734   while(!queue1.empty())
01735   {
01736     // start copy
01737     EntityHandle currentTriangle=queue1.front();
01738     queue1.pop();
01739     arr1.push_back(currentTriangle);
01740     // add new triangles that share an edge
01741     Range currentEdges;
01742     rval =  _mbImpl->get_adjacencies(&currentTriangle, 1,
01743         1, true, currentEdges, Interface::UNION);
01744     MBERRORR(rval, "can't get adjacencies");
01745     for (Range::iterator it=currentEdges.begin(); it!=currentEdges.end(); it++)
01746     {
01747       EntityHandle frontEdge= *it;
01748       if ( doNotCrossEdges.find(frontEdge)==doNotCrossEdges.end())
01749       {
01750         // this is an edge that can be crossed
01751         Range adj_tri;
01752         rval =  _mbImpl->get_adjacencies(&frontEdge, 1,
01753                 2, false, adj_tri, Interface::UNION);
01754         MBERRORR(rval, "can't get adj_tris");
01755         // if the triangle is not in first range, add it to the queue
01756         for (Range::iterator it2=adj_tri.begin(); it2!=adj_tri.end(); it2++)
01757         {
01758           EntityHandle tri2=*it2;
01759           int val =0;
01760           rval = _mbImpl->tag_get_data(separateTag, &tri2, 1, &val );
01761           MBERRORR(rval, "can't get tag value");
01762           if (val)
01763             continue;
01764           // else, set it to 1
01765           val =1;
01766           rval = _mbImpl->tag_set_data(separateTag, &tri2, 1, &val );
01767           MBERRORR(rval, "can't get tag value");
01768 
01769           queue1.push(tri2);
01770         }
01771       }// end edge do not cross
01772     }// end while
01773   }
01774 
01775   std::sort(arr1.begin(), arr1.end());
01776   //Range first1;
01777   std::copy(arr1.rbegin(), arr1.rend(), range_inserter(first));
01778 
01779   //std::cout<< "\n first1.size() " << first1.size() << " first.size(): " << first.size() << "\n";
01780   if (debug_splits)
01781   {
01782     EntityHandle tmpSet;
01783     _mbImpl->create_meshset(MESHSET_SET, tmpSet);
01784     _mbImpl->add_entities(tmpSet, first);
01785     _mbImpl->write_file("dbg1.vtk", "vtk", 0, &tmpSet, 1);
01786   }
01787   // now, decide the set 2:
01788   // first, get all ini tris
01789   Range initr;
01790   rval = _mbImpl -> get_entities_by_type(face, MBTRI, initr);
01791   MBERRORR(rval, "can't get tris ");
01792   second = unite(initr, _newTriangles);
01793   Range second2 = subtract(second, _piercedTriangles);
01794   second = subtract(second2, first);
01795   _newTriangles.clear();
01796   if (debug_splits)
01797   {
01798     std::cout<< "\n second.size() " << second.size() << " first.size(): " << first.size() << "\n";
01799     // debugging code
01800     EntityHandle tmpSet2;
01801     _mbImpl->create_meshset(MESHSET_SET, tmpSet2);
01802     _mbImpl->add_entities(tmpSet2, second);
01803     _mbImpl->write_file("dbg2.vtk", "vtk", 0, &tmpSet2, 1);
01804   }
01805   /*Range intex = intersect(first, second);
01806   if (!intex.empty() && debug_splits)
01807   {
01808     std::cout << "error, the sets should be disjoint\n";
01809     for (Range::iterator it1=intex.begin(); it1!=intex.end(); ++it1)
01810     {
01811       std::cout<<_mbImpl->id_from_handle(*it1) << "\n";
01812     }
01813   }*/
01814   rval = _mbImpl->tag_delete(separateTag);
01815   MBERRORR(rval, "can't delete tag ");
01816   return MB_SUCCESS;
01817 }
01818 // if there is an edge between 2 nodes, then check it's orientation, and revert it if needed
01819 ErrorCode  FBEngine::create_new_gedge(std::vector<EntityHandle> &nodesAlongPolyline, EntityHandle & new_geo_edge)
01820 {
01821 
01822   ErrorCode rval = _mbImpl->create_meshset(MESHSET_ORDERED, new_geo_edge);
01823   MBERRORR(rval, "can't create geo edge");
01824 
01825   // now, get the edges, or create if not existing
01826   std::vector<EntityHandle> mesh_edges;
01827   for (unsigned int i=0; i<nodesAlongPolyline.size()-1; i++)
01828   {
01829     EntityHandle n1 = nodesAlongPolyline[i], n2 = nodesAlongPolyline[i+1];
01830 
01831     EntityHandle nn2[2];
01832     nn2[0] = n1;
01833     nn2[1] = n2;
01834 
01835     std::vector<EntityHandle> adjacent;
01836     rval = _mbImpl->get_adjacencies(nn2, 2, 1, false, adjacent,
01837                 Interface::INTERSECT);
01838     // see if there is an edge between those 2 already, and if it is oriented as we like
01839     bool new_edge = true;
01840     if (adjacent.size()>=1)
01841     {
01842       // check the orientation
01843       const EntityHandle * conn2;
01844       int nnodes;
01845       rval = _mbImpl->get_connectivity(adjacent[0], conn2, nnodes);
01846       MBERRORR(rval, "can't get connectivity");
01847       if (conn2[0]==nn2[0] && conn2[1]==nn2[1])
01848       {
01849         // everything is fine
01850         mesh_edges.push_back(adjacent[0]);
01851         new_edge = false;// we found one that's good, no need to create a new one
01852       }
01853       else
01854       {
01855         _piercedEdges.insert(adjacent[0]);// we want to remove this one, it will be not needed
01856       }
01857     }
01858     if (new_edge)
01859     {
01860       // there is no edge between n1 and n2, create one
01861       EntityHandle mesh_edge;
01862       rval = _mbImpl->create_element(MBEDGE, nn2, 2, mesh_edge);
01863       MBERRORR(rval, "Failed to create a new edge");
01864       mesh_edges.push_back(mesh_edge);
01865     }
01866   }
01867 
01868   // add loops edges to the edge set
01869   rval = _mbImpl->add_entities(new_geo_edge, &mesh_edges[0], mesh_edges.size());// only one edge
01870   MBERRORR(rval, "can't add edges to new_geo_set");
01871   // check vertex sets for vertex 1 and vertex 2?
01872   // get all sets of dimension 0 from database, and see if our ends are here or not
01873 
01874   Range ends_geo_edge;
01875   ends_geo_edge.insert(nodesAlongPolyline[0]);
01876   ends_geo_edge.insert(nodesAlongPolyline[nodesAlongPolyline.size()-1]);
01877 
01878   for (unsigned int k = 0; k<ends_geo_edge.size(); k++ )
01879   {
01880     EntityHandle node = ends_geo_edge[k];
01881     EntityHandle nodeSet;
01882     bool found=find_vertex_set_for_node(node, nodeSet);
01883 
01884     if (!found)
01885     {
01886       // create a node set and add the node
01887 
01888       rval = _mbImpl->create_meshset(MESHSET_SET, nodeSet);
01889       MBERRORR(rval, "Failed to create a new vertex set");
01890 
01891       rval = _mbImpl->add_entities(nodeSet, &node, 1);
01892       MBERRORR(rval, "Failed to add the node to the set");
01893 
01894       rval = _my_geomTopoTool->add_geo_set(nodeSet, 0);//
01895       MBERRORR(rval, "Failed to commit the node set");
01896 
01897       if (debug_splits)
01898       {
01899         std::cout<<" create a vertex set " << _mbImpl->id_from_handle(nodeSet) << " global id:"<<
01900             this->_my_geomTopoTool->global_id(nodeSet) << " for node " << node <<  "\n";
01901       }
01902 
01903     }
01904 
01905     rval = _mbImpl ->add_parent_child( new_geo_edge, nodeSet);
01906     MBERRORR(rval, "Failed to add parent child relation");
01907   }
01908   // finally, put the edge in the range of edges
01909   _my_geomTopoTool->add_geo_set(new_geo_edge, 1);
01910 
01911 
01912   return rval;
01913 }
01914 
01915 void FBEngine::print_debug_triangle(EntityHandle t)
01916 {
01917   std::cout<< " triangle id:" << _mbImpl->id_from_handle(t) << "\n";
01918   const EntityHandle * conn3;
01919   int nnodes;
01920   _mbImpl->get_connectivity(t, conn3, nnodes);
01921   // get coords
01922   CartVect P[3];
01923   _mbImpl->get_coords(conn3, 3, (double*) &P[0]);
01924   std::cout <<"  nodes:" << conn3[0] << " " << conn3[1] << " " << conn3[2] << "\n";
01925   CartVect PP[3];
01926   PP[0] = P[1]-P[0];
01927   PP[1] = P[2]-P[1];
01928   PP[2] = P[0] - P[2];
01929 
01930   std::cout <<"  pos:" <<  P[0] << " " << P[1] << " " << P[2] << "\n";
01931   std::cout <<"   x,y diffs " <<  PP[0][0] <<" " << PP[0][1]  << ",  " << PP[1][0] <<" " << PP[1][1]
01932                    << ",  " << PP[2][0] <<" " << PP[2][1]  << "\n";
01933   return;
01934 }
01935 // actual breaking of triangles
01936 // case 1: n2 interior to triangle
01937 ErrorCode FBEngine::BreakTriangle(EntityHandle , EntityHandle , EntityHandle ,
01938     EntityHandle , EntityHandle , EntityHandle )
01939 {
01940   std::cout<< "FBEngine::BreakTriangle not implemented yet\n";
01941   return MB_FAILURE;
01942 }
01943 // case 2, n1 and n2 on boundary
01944 ErrorCode FBEngine::BreakTriangle2(EntityHandle tri, EntityHandle e1, EntityHandle e2, EntityHandle n1,
01945   EntityHandle n2)// nodesAlongPolyline are on entities!
01946 {
01947   // we have the nodes, we just need to reconnect to form new triangles
01948   ErrorCode rval;
01949   const EntityHandle * conn3;
01950   int nnodes;
01951   rval = _mbImpl->get_connectivity(tri, conn3, nnodes);
01952   MBERRORR(rval, "Failed to get connectivity");
01953   assert(3 == nnodes);
01954 
01955   EntityType et1= _mbImpl->type_from_handle(e1);
01956   EntityType et2= _mbImpl->type_from_handle(e2);
01957 
01958   if (MBVERTEX == et1)
01959   {
01960     // find the vertex in conn3, and form 2 other triangles
01961     int index =-1;
01962     for (index=0; index<3; index++)
01963     {
01964       if (conn3[index]==e1)// also n1
01965         break;
01966     }
01967     if (index==3)
01968       return MB_FAILURE;
01969     // 2 triangles: n1, index+1, n2, and n1, n2, index+2
01970     EntityHandle conn[6]={ n1, conn3[(index+1)%3], n2, n1, n2, conn3[(index+2)%3]};
01971     EntityHandle newTriangle;
01972     rval = _mbImpl->create_element(MBTRI, conn, 3, newTriangle);
01973     MBERRORR(rval, "Failed to create a new triangle");
01974     _newTriangles.insert(newTriangle);
01975     if (debug_splits)
01976       print_debug_triangle(newTriangle);
01977     rval = _mbImpl->create_element(MBTRI, conn+3, 3, newTriangle);// the second triangle
01978     MBERRORR(rval, "Failed to create a new triangle");
01979     _newTriangles.insert(newTriangle);
01980     if (debug_splits)
01981       print_debug_triangle(newTriangle);
01982     return MB_SUCCESS;
01983   }
01984   else if (MBVERTEX == et2)
01985   {
01986     int index =-1;
01987     for (index=0; index<3; index++)
01988     {
01989       if (conn3[index]==e2) // also n2
01990         break;
01991     }
01992     if (index==3)
01993       return MB_FAILURE;
01994     // 2 triangles: n1, index+1, n2, and n1, n2, index+2
01995     EntityHandle conn[6]={ n2, conn3[(index+1)%3], n1, n2, n1, conn3[(index+2)%3]};
01996     EntityHandle newTriangle;
01997     rval = _mbImpl->create_element(MBTRI, conn, 3, newTriangle);
01998     MBERRORR(rval, "Failed to create a new triangle");
01999     _newTriangles.insert(newTriangle);
02000     if (debug_splits)
02001           print_debug_triangle(newTriangle);
02002     rval = _mbImpl->create_element(MBTRI, conn+3, 3, newTriangle);// the second triangle
02003     MBERRORR(rval, "Failed to create a new triangle");
02004     _newTriangles.insert(newTriangle);
02005     if (debug_splits)
02006           print_debug_triangle(newTriangle);
02007     return MB_SUCCESS;
02008   }
02009   else
02010   {
02011     // both are edges adjacent to triangle tri
02012     // there are several configurations possible for n1, n2, between conn3 nodes.
02013     int num1, num2, sense, offset;
02014     rval = _mbImpl->side_number(tri, e1, num1, sense, offset);
02015     MBERRORR(rval, "edge not adjacent");
02016 
02017     rval = _mbImpl->side_number(tri, e2, num2, sense, offset);
02018     MBERRORR(rval, "edge not adjacent");
02019 
02020     const EntityHandle * conn12; // connectivity for edge 1
02021     const EntityHandle * conn22; // connectivity for edge 2
02022     //int nnodes;
02023     rval = _mbImpl->get_connectivity(e1, conn12, nnodes);
02024     MBERRORR(rval, "Failed to get connectivity of edge 1");
02025     assert(2 == nnodes);
02026     rval = _mbImpl->get_connectivity(e2, conn22, nnodes);
02027     MBERRORR(rval, "Failed to get connectivity of edge 2");
02028     assert(2 == nnodes);
02029     // now, having the side number, work through
02030     if (debug_splits)
02031     {
02032       std::cout << "tri conn3:" << conn3[0] << " "<< conn3[1] <<" " << conn3[2] << "\n";
02033       std::cout << " edge1: conn12:" << conn12[0] << " "<< conn12[1] <<"  side: " << num1 << "\n";
02034       std::cout << " edge2: conn22:" << conn22[0] << " "<< conn22[1] <<"  side: " << num2 << "\n";
02035     }
02036     int unaffectedSide = 3-num1-num2;
02037     int i3 = (unaffectedSide+2)%3;// to 0 is 2, to 1 is 0, to 2 is 1
02038     // triangles will be formed with triVertexIndex , n1, n2 (in what order?)
02039     EntityHandle v1, v2; // to hold the 2 nodes on edges
02040     if (num1==i3)
02041     {
02042       v1 = n1;
02043       v2 = n2;
02044     }
02045     else // if (num2==i3)
02046     {
02047       v1 = n2;
02048       v2 = n1;
02049     }
02050     // three triangles are formed
02051     int i1 = (i3+1)%3;
02052     int i2 = (i3+2)%3;
02053     // we could break the surface differently
02054     EntityHandle conn[9]={ conn3[i3], v1, v2, v1, conn3[i1], conn3[i2],
02055         v2, v1,  conn3[i2]};
02056     EntityHandle newTriangle;
02057     if (debug_splits)
02058        std::cout << "Split 2 edges :\n";
02059     rval = _mbImpl->create_element(MBTRI, conn, 3, newTriangle);
02060     MBERRORR(rval, "Failed to create a new triangle");
02061     _newTriangles.insert(newTriangle);
02062     if (debug_splits)
02063           print_debug_triangle(newTriangle);
02064     rval = _mbImpl->create_element(MBTRI, conn+3, 3, newTriangle);// the second triangle
02065     MBERRORR(rval, "Failed to create a new triangle");
02066     _newTriangles.insert(newTriangle);
02067     if (debug_splits)
02068           print_debug_triangle(newTriangle);
02069     rval = _mbImpl->create_element(MBTRI, conn+6, 3, newTriangle);// the second triangle
02070     MBERRORR(rval, "Failed to create a new triangle");
02071     _newTriangles.insert(newTriangle);
02072     if (debug_splits)
02073           print_debug_triangle(newTriangle);
02074     return MB_SUCCESS;
02075   }
02076 
02077   return MB_SUCCESS;
02078 }
02079 
02080 // build the list of intx points and entities from database involved
02081 // vertices, edges, triangles
02082 //it could be just a list of vertices (easiest case to handle after)
02083 
02084 ErrorCode FBEngine::compute_intersection_points(EntityHandle & ,
02085     EntityHandle from, EntityHandle to,
02086     CartVect & Dir, std::vector<CartVect> & points,
02087     std::vector<EntityHandle> & entities, std::vector<EntityHandle> & triangles)
02088 {
02089   // keep a stack of triangles to process, and do not add those already processed
02090   // either mark them, or maybe keep them in a local set?
02091   // from and to are now nodes, start from them
02092   CartVect p1, p2;// the position of from and to
02093   ErrorCode rval = _mbImpl->get_coords(&from, 1, (double *)&p1);
02094   MBERRORR(rval, "failed to get 'from' coordinates");
02095   rval = _mbImpl->get_coords(&to, 1, (double *)&p2);
02096   MBERRORR(rval, "failed to get 'from' coordinates");
02097 
02098   CartVect vect(p2 - p1);
02099   double dist2 = vect.length();
02100   if (dist2 < tolerance_segment) {
02101     // we are done, return
02102     return MB_SUCCESS;
02103   }
02104   CartVect normPlane = Dir * vect;
02105   normPlane.normalize();
02106   std::set<EntityHandle> visitedTriangles;
02107   CartVect currentPoint = p1;
02108   // push the current point if it is empty
02109   if (points.size() == 0) {
02110     points.push_back(p1);
02111     entities.push_back(from);// this is a node now
02112   }
02113 
02114   // these will be used in many loops
02115   CartVect intx = p1;// somewhere to start
02116   double param = -1.;
02117 
02118   // first intersection
02119   EntityHandle currentBoundary = from;// it is a node, in the beginning
02120 
02121   vect = p2 - currentPoint;
02122   while (vect.length() > 0.) {
02123     // advance towards "to" node, from boundary handle
02124     EntityType etype = _mbImpl->type_from_handle(currentBoundary);
02125     //if vertex, look for other triangles connected which intersect our plane (defined by p1, p2, dir)
02126     std::vector<EntityHandle> adj_tri;
02127     rval = _mbImpl->get_adjacencies(&currentBoundary, 1, 2, false, adj_tri);
02128     unsigned int j = 0;
02129     EntityHandle tri;
02130     for (; j < adj_tri.size(); j++) {
02131       tri = adj_tri[j];
02132       if (visitedTriangles.find(tri) != visitedTriangles.end())
02133         continue;// get another triangle, this one was already visited
02134       // check if it is one of the triangles that was pierced already
02135       if (_piercedTriangles.find(tri) != _piercedTriangles.end())
02136         continue;
02137       // if vertex, look for opposite edge
02138       // if edge, look for 2 opposite edges
02139       // get vertices
02140       int nnodes;
02141       const EntityHandle * conn3;
02142       rval = _mbImpl->get_connectivity(tri, conn3, nnodes);
02143       MBERRORR(rval, "Failed to get connectivity");
02144       // if one of the nodes is to, stop right there
02145       {
02146         if (conn3[0]==to || conn3[1]==to || conn3[2]==to)
02147         {
02148           visitedTriangles.insert(tri);
02149           triangles.push_back(tri);
02150           currentPoint = p2;
02151           points.push_back(p2);
02152           entities.push_back(to);// we are done
02153           break;// this is break from for loop, we still need to get out of while
02154           // we will get out, because vect will become 0, (p2-p2)
02155         }
02156       }
02157       EntityHandle nn2[2];
02158       if (MBVERTEX == etype) {
02159         nn2[0] = conn3[0];
02160         nn2[1] = conn3[1];
02161         if (nn2[0] == currentBoundary)
02162           nn2[0] = conn3[2];
02163         if (nn2[1] == currentBoundary)
02164           nn2[1] = conn3[2];
02165         // get coordinates
02166         CartVect Pt[2];
02167 
02168         rval = _mbImpl->get_coords(nn2, 2, (double*) &Pt[0]);
02169         MBERRORR(rval, "Failed to get coordinates");
02170         // see the intersection
02171         if (intersect_segment_and_plane_slice(Pt[0], Pt[1], currentPoint, p2,
02172             Dir, normPlane, intx, param)) {
02173           // we should stop for loop, and decide if it is edge or vertex
02174           if (param == 0.)
02175             currentBoundary = nn2[0];
02176           else {
02177             if (param == 1.)
02178               currentBoundary = nn2[1];
02179             else // param between 0 and 1, so edge
02180             {
02181               //find the edge between vertices
02182               std::vector<EntityHandle> edges1;
02183               // change the create flag to true, because that edge must exist in current triangle
02184               // if we want to advance; nn2 are 2 nodes in current triangle!!
02185               rval = _mbImpl->get_adjacencies(nn2, 2, 1, true, edges1,
02186                   Interface::INTERSECT);
02187               MBERRORR(rval, "Failed to get edges");
02188               if (edges1.size() != 1)
02189                 MBERRORR(MB_FAILURE, "Failed to get adjacent edges to 2 nodes");
02190               currentBoundary = edges1[0];
02191             }
02192           }
02193           visitedTriangles.insert(tri);
02194           currentPoint = intx;
02195           points.push_back(intx);
02196           entities.push_back(currentBoundary);
02197           triangles.push_back(tri);
02198           if (debug_splits)
02199             std::cout << "vtx new tri : " << _mbImpl->id_from_handle(tri)
02200                 << " type bdy:" << _mbImpl->type_from_handle(currentBoundary)
02201                 << "\n";
02202           break; // out of for loop over triangles
02203 
02204         }
02205       } else // this is MBEDGE, we have the other triangle to try out
02206       {
02207         //first find the nodes from existing boundary
02208         int nnodes2;
02209         const EntityHandle * conn2;
02210         rval = _mbImpl->get_connectivity(currentBoundary, conn2, nnodes2);
02211         MBERRORR(rval, "Failed to get connectivity");
02212         int thirdIndex = -1;
02213         for (int tj = 0; tj < 3; tj++) {
02214           if ((conn3[tj] != conn2[0]) && (conn3[tj] != conn2[1])) {
02215             thirdIndex = tj;
02216             break;
02217           }
02218         }
02219         if (-1 == thirdIndex)
02220           MBERRORR(MB_FAILURE, " can't get third node");
02221         CartVect Pt[3];
02222         rval = _mbImpl->get_coords(conn3, 3, (double*) &Pt[0]);
02223         MBERRORR(rval, "Failed to get coords");
02224         int indexFirst = (thirdIndex + 1) % 3;
02225         int indexSecond = (thirdIndex + 2) % 3;
02226         int index[2] = { indexFirst, indexSecond };
02227         for (int k = 0; k < 2; k++) {
02228           nn2[0] = conn3[index[k]], nn2[1] = conn3[thirdIndex];
02229           if (intersect_segment_and_plane_slice(Pt[index[k]], Pt[thirdIndex],
02230               currentPoint, p2, Dir, normPlane, intx, param)) {
02231             // we should stop for loop, and decide if it is edge or vertex
02232             if (param == 0.)
02233               currentBoundary = conn3[index[k]];//it is not really possible
02234             else {
02235               if (param == 1.)
02236                 currentBoundary = conn3[thirdIndex];
02237               else // param between 0 and 1, so edge is fine
02238               {
02239                 //find the edge between vertices
02240                 std::vector<EntityHandle> edges1;
02241                 // change the create flag to true, because that edge must exist in current triangle
02242                      // if we want to advance; nn2 are 2 nodes in current triangle!!
02243                 rval = _mbImpl->get_adjacencies(nn2, 2, 1, true, edges1,
02244                     Interface::INTERSECT);
02245                 MBERRORR(rval, "Failed to get edges");
02246                 if (edges1.size() != 1)
02247                   MBERRORR(MB_FAILURE, "Failed to get adjacent edges to 2 nodes");
02248                 currentBoundary = edges1[0];
02249               }
02250             }
02251             visitedTriangles.insert(tri);
02252             currentPoint = intx;
02253             points.push_back(intx);
02254             entities.push_back(currentBoundary);
02255             triangles.push_back(tri);
02256             if (debug_splits)
02257             {
02258               std::cout << "edge new tri : " << _mbImpl->id_from_handle(tri)
02259                   << "  type bdy: " << _mbImpl->type_from_handle(
02260                   currentBoundary) << " id: " << _mbImpl->id_from_handle(currentBoundary) << "\n";
02261               _mbImpl->list_entity(currentBoundary);
02262             }
02263             break; // out of for loop over triangles
02264 
02265           }
02266           // we should not reach here
02267         }
02268 
02269       }
02270 
02271     }
02272     /*if (j==adj_tri.size())
02273      {
02274      MBERRORR(MB_FAILURE, "did not advance");
02275      }*/
02276     vect = p2 - currentPoint;
02277 
02278   }
02279 
02280 
02281   if (debug_splits)
02282     std::cout << "nb entities: " << entities.size() <<  " triangles:" << triangles.size() <<
02283      " points.size(): " << points.size() <<  "\n";
02284 
02285   return MB_SUCCESS;
02286 }
02287 
02288 ErrorCode  FBEngine::split_edge_at_point(EntityHandle edge, CartVect & point,
02289     EntityHandle & new_edge)
02290 {
02291   //return MB_NOT_IMPLEMENTED;
02292   // first, we need to find the closest point on the smooth edge, then
02293   // split the smooth edge, then call the split_edge_at_mesh_node
02294   // or maybe just find the closest node??
02295   // first of all, we need to find a point on the smooth edge, close by
02296   // then split the mesh edge (if needed)
02297   // this would be quite a drama, as the new edge has to be inserted in
02298   // order for proper geo edge definition
02299 
02300   // first of all, find a closest point
02301   // usually called for
02302   if (debug_splits)
02303   {
02304     std::cout<<"Split edge " << _mbImpl->id_from_handle(edge) << " at point:" <<
02305         point << "\n";
02306   }
02307   int dim = _my_geomTopoTool->dimension(edge);
02308   if (dim !=1)
02309     return MB_FAILURE;
02310   if (!_smooth)
02311     return MB_FAILURE; // call it only for smooth option...
02312   // maybe we should do something for linear too
02313 
02314   SmoothCurve * curve = this->_edges[edge];
02315   EntityHandle closeNode;
02316   int edgeIndex;
02317   double u = curve-> u_from_position(point[0], point[1], point[2],
02318       closeNode, edgeIndex) ;
02319   if (0==closeNode)
02320   {
02321     // we really need to split an existing edge
02322     // do not do that yet
02323     // evaluate from u:
02324     /*double pos[3];
02325     curve->position_from_u(u,  pos[0], pos[1], pos[2] );*/
02326     // create a new node here, and split one edge
02327     // change also connectivity, create new triangles on both sides ...
02328     std::cout << "not found a close node,  u is: " << u << " edge index: " <<
02329         edgeIndex << "\n";
02330     return MB_FAILURE;// not implemented yet
02331   }
02332   return split_edge_at_mesh_node(edge, closeNode, new_edge);
02333 
02334 }
02335 
02336 ErrorCode FBEngine::split_edge_at_mesh_node(EntityHandle edge, EntityHandle node,
02337     EntityHandle & new_edge)
02338 {
02339   // the node should be in the list of nodes
02340 
02341   int dim = _my_geomTopoTool->dimension(edge);
02342   if (dim!=1)
02343     return MB_FAILURE; // not an edge
02344 
02345   if (debug_splits)
02346   {
02347     std::cout<<"Split edge " << _mbImpl->id_from_handle(edge) << " with global id: "<<
02348         _my_geomTopoTool->global_id(edge) << " at node:" <<
02349         _mbImpl->id_from_handle(node) << "\n";
02350   }
02351 
02352   // now get the edges
02353   // the order is important...
02354   // these are ordered sets !!
02355   std::vector<EntityHandle> ents;
02356   ErrorCode rval = _mbImpl->get_entities_by_type(edge, MBEDGE, ents);
02357   if (MB_SUCCESS != rval)
02358     return rval;
02359   if (ents.size() < 1)
02360     return MB_FAILURE; // no edges
02361 
02362   const EntityHandle* conn = NULL;
02363   int len;
02364   // find the edge connected to the splitting node
02365   int num_mesh_edges = (int)ents.size();
02366   int index_edge;
02367   EntityHandle firstNode = conn[0]; // will be used to decide vertex sets adjacencies
02368   for (index_edge = 0; index_edge<num_mesh_edges; index_edge++)
02369   {
02370     rval = MBI->get_connectivity(ents[index_edge], conn, len);
02371     if (MB_SUCCESS != rval)
02372       return rval;
02373     if (conn[0] == node)
02374     {
02375       if (index_edge==0)
02376       {
02377         new_edge = 0; // no need to split, it is the first node
02378         return MB_SUCCESS; // no split
02379       }
02380       else
02381         return MB_FAILURE; // we should have found the node already , wrong
02382                            // connectivity
02383     }
02384     else if (conn[1] == node)
02385     {
02386       // we found the index of interest
02387       break;
02388     }
02389   }
02390   if (index_edge==num_mesh_edges-1)
02391   {
02392     new_edge = 0; // no need to split, it is the last node
02393     return MB_SUCCESS; // no split
02394   }
02395 
02396   // here, we have 0 ... index_edge edges in the first set,
02397   // create a vertex set and add the node to it
02398 
02399   if (debug_splits)
02400   {
02401     std::cout<<"Split edge with " << num_mesh_edges << " mesh edges, at index (0 based) " <<
02402         index_edge << "\n";
02403   }
02404 
02405   // at this moment, the node set should have been already created in new_geo_edge
02406   EntityHandle nodeSet; // the node set that has the node (find it!)
02407   bool found=find_vertex_set_for_node(node, nodeSet);
02408 
02409   if (!found) {
02410     // create a node set and add the node
02411 
02412     // must be an error, but create one nevertheless
02413     rval = _mbImpl->create_meshset(MESHSET_SET, nodeSet);
02414     MBERRORR(rval, "Failed to create a new vertex set");
02415 
02416     rval = _mbImpl->add_entities(nodeSet, &node, 1);
02417     MBERRORR(rval, "Failed to add the node to the set");
02418 
02419     rval = _my_geomTopoTool->add_geo_set(nodeSet, 0);//
02420     MBERRORR(rval, "Failed to commit the node set");
02421 
02422     if (debug_splits)
02423     {
02424       std::cout<<" create a vertex set (this should have been created before!)" << _mbImpl->id_from_handle(nodeSet) << " global id:"<<
02425           this->_my_geomTopoTool->global_id(nodeSet) <<  "\n";
02426     }
02427   }
02428 
02429   // we need to remove the remaining mesh edges from first set, and add it
02430   // to the second set, in order
02431 
02432   rval = _mbImpl->create_meshset(MESHSET_ORDERED, new_edge);
02433   MBERRORR(rval, "can't create geo edge");
02434 
02435   int remaining= num_mesh_edges - 1 - index_edge;
02436 
02437   // add edges to the edge set
02438   rval = _mbImpl->add_entities(new_edge, &ents[index_edge+1], remaining);
02439   MBERRORR(rval, "can't add edges to the new edge");
02440 
02441   // also, remove the second node set from old edge
02442   // remove the edges index_edge+1 and up
02443 
02444   rval = _mbImpl->remove_entities(edge, &ents[index_edge+1], remaining);
02445   MBERRORR(rval, "can't remove edges from the old edge");
02446 
02447   // need to find the adjacent vertex sets
02448   Range vertexRange;
02449   rval = getAdjacentEntities(edge, 0, vertexRange);
02450 
02451   EntityHandle secondSet;
02452   if (vertexRange.size() == 1)
02453   {
02454     // initially a periodic edge, OK to add the new set to both edges, and the
02455     // second set
02456     secondSet = vertexRange[0];
02457   }
02458   else
02459   {
02460     if (vertexRange.size() > 2)
02461       return MB_FAILURE; // something must be wrong with too many vertices
02462     // find first node
02463     int k;
02464     for (k=0; k<2; k++)
02465     {
02466       Range verts;
02467       rval = _mbImpl->get_entities_by_type(vertexRange[k], MBVERTEX, verts);
02468 
02469       MBERRORR(rval, "can't get vertices from vertex set");
02470       if (verts.size()!=1)
02471          MBERRORR(MB_FAILURE, " node set not defined well");
02472       if (firstNode == verts[0])
02473       {
02474         secondSet = vertexRange[1-k]; // the other set; it is 1 or 0
02475         break;
02476       }
02477     }
02478     if (k>=2)
02479     {
02480       // it means we didn't find the right node set
02481       MBERRORR(MB_FAILURE, " can't find the right vertex");
02482     }
02483     // remove the second set from the connectivity with the
02484     //  edge (parent-child relation)
02485     //remove_parent_child( EntityHandle parent,
02486      //                                          EntityHandle child )
02487     rval = _mbImpl->remove_parent_child(edge, secondSet);
02488     MBERRORR(rval, " can't remove the second vertex from edge");
02489   }
02490   // at this point, we just need to add to both edges the new node set (vertex)
02491   rval = _mbImpl->add_parent_child(edge, nodeSet);
02492   MBERRORR(rval, " can't add new vertex to old edge");
02493 
02494   rval = _mbImpl->add_parent_child(new_edge, nodeSet);
02495   MBERRORR(rval, " can't add new vertex to new edge");
02496 
02497   // one thing that I forgot: add the secondSet as a child to new edge!!!
02498   // (so far, the new edge has only one end vertex!)
02499   rval = _mbImpl->add_parent_child(new_edge, secondSet);
02500   MBERRORR(rval, " can't add second vertex to new edge");
02501 
02502 // now, add the edge and vertex to geo tool
02503 
02504   rval = _my_geomTopoTool->add_geo_set(new_edge, 1);
02505   MBERRORR(rval, " can't add new edge");
02506 
02507   // next, get the adjacent faces to initial edge, and add them as parents
02508   // to the new edge
02509 
02510   // need to find the adjacent face sets
02511   Range faceRange;
02512   rval = getAdjacentEntities(edge, 2, faceRange);
02513 
02514   // these faces will be adjacent to the new edge too!
02515   // need to set the senses of new edge within faces
02516 
02517   for (Range::iterator it= faceRange.begin(); it!=faceRange.end(); it++)
02518   {
02519     EntityHandle face = *it;
02520     rval = _mbImpl->add_parent_child(face, new_edge);
02521     MBERRORR(rval, " can't add new edge - face parent relation");
02522     int sense;
02523     rval = _my_geomTopoTool->get_sense(edge, face, sense);
02524     MBERRORR(rval, " can't get initial sense of edge in the adjacent face");
02525     // keep the same sense for the new edge within the faces
02526     rval = _my_geomTopoTool->set_sense(new_edge, face, sense);
02527     MBERRORR(rval, " can't set sense of new edge in the adjacent face");
02528   }
02529 
02530   return MB_SUCCESS;
02531 }
02532 
02533 ErrorCode FBEngine::split_bedge_at_new_mesh_node(EntityHandle edge, EntityHandle node, EntityHandle brokenEdge,
02534       EntityHandle & new_edge)
02535 {
02536   // the node should be in the list of nodes
02537 
02538   int dim = _my_geomTopoTool->dimension(edge);
02539   if (dim != 1)
02540     return MB_FAILURE; // not an edge
02541 
02542   if (debug_splits) {
02543     std::cout << "Split edge " << _mbImpl->id_from_handle(edge)
02544         << " with global id: " << _my_geomTopoTool->global_id(edge)
02545         << " at new node:" << _mbImpl->id_from_handle(node) << "breaking mesh edge" <<
02546               _mbImpl->id_from_handle(brokenEdge)<< "\n";
02547   }
02548 
02549   // now get the edges
02550   // the order is important...
02551   // these are ordered sets !!
02552   std::vector<EntityHandle> ents;
02553   ErrorCode rval = _mbImpl->get_entities_by_type(edge, MBEDGE, ents);
02554   if (MB_SUCCESS != rval)
02555     return rval;
02556   if (ents.size() < 1)
02557     return MB_FAILURE; // no edges
02558 
02559   const EntityHandle* conn = NULL;
02560   int len;
02561   // the edge connected to the splitting node is brokenEdge
02562   // find the small edges it is broken into, which are connected to
02563   // new vertex (node) and its ends; also, if necessary, reorient these small edges
02564   // for proper orientation
02565   rval = _mbImpl->get_connectivity(brokenEdge, conn, len);
02566   MBERRORR(rval, "Failed to get connectivity of broken edge");
02567 
02568   // we already created the new edges, make sure they are oriented fine; if not, revert them
02569   EntityHandle conn02[]={conn[0], node}; // first node and new node
02570   // default, intersect
02571   std::vector<EntityHandle> adj_edges;
02572   rval = _mbImpl->get_adjacencies(conn02, 2, 1, false, adj_edges);
02573   if (adj_edges.size()<1 || rval !=MB_SUCCESS)
02574     MBERRORR(MB_FAILURE, " Can't find small split edge");
02575 
02576   // get this edge connectivity;
02577   EntityHandle firstEdge=adj_edges[0];
02578   const EntityHandle * connActual;
02579   rval = _mbImpl->get_connectivity(firstEdge, connActual, len);
02580   MBERRORR(rval, "Failed to get connectivity of first split edge");
02581   // if it is the same as conn02, we are happy
02582   if (conn02[0]!=connActual[0])
02583   {
02584     // reset connectivity of edge
02585     rval = _mbImpl->set_connectivity(firstEdge, conn02, 2);
02586     MBERRORR(rval, "Failed to reset connectivity of first split edge");
02587   }
02588   //  now treat the second edge
02589   adj_edges.clear(); //
02590   EntityHandle conn21[]={node, conn[1]}; //  new node and second node
02591   rval = _mbImpl->get_adjacencies(conn21, 2, 1, false, adj_edges);
02592   if (adj_edges.size()<1 || rval !=MB_SUCCESS)
02593     MBERRORR(MB_FAILURE, " Can't find second small split edge");
02594 
02595   // get this edge connectivity;
02596   EntityHandle secondEdge=adj_edges[0];
02597   rval = _mbImpl->get_connectivity(firstEdge, connActual, len);
02598   MBERRORR(rval, "Failed to get connectivity of first split edge");
02599   // if it is the same as conn21, we are happy
02600   if (conn21[0]!=connActual[0])
02601   {
02602     // reset connectivity of edge
02603     rval = _mbImpl->set_connectivity(secondEdge, conn21, 2);
02604     MBERRORR(rval, "Failed to reset connectivity of first split edge");
02605   }
02606 
02607   int num_mesh_edges = (int) ents.size();
02608   int index_edge;// this is the index of the edge that will be removed (because it is split)
02609   // the rest of edges will be put in order in the (remaining) edge and new edge
02610 
02611   for (index_edge = 0; index_edge < num_mesh_edges; index_edge++)
02612     if (brokenEdge==ents[index_edge])
02613       break;
02614   if (index_edge>=num_mesh_edges)
02615     MBERRORR(MB_FAILURE, "can't find the broken edge");
02616 
02617   //so the edges up to index_edge and firstEdge, will form the "old" edge
02618   // the edges secondEdge and from index_edge+1 to end will form the new_edge
02619 
02620   // here, we have 0 ... index_edge edges in the first set,
02621   // create a vertex set and add the node to it
02622 
02623   if (debug_splits) {
02624     std::cout << "Split edge with " << num_mesh_edges
02625         << " mesh edges, at index (0 based) " << index_edge << "\n";
02626   }
02627 
02628   // at this moment, the node set should have been already created in new_geo_edge
02629   EntityHandle nodeSet; // the node set that has the node (find it!)
02630   bool found = find_vertex_set_for_node(node, nodeSet);
02631 
02632   if (!found) {
02633     // create a node set and add the node
02634 
02635     // must be an error, but create one nevertheless
02636     rval = _mbImpl->create_meshset(MESHSET_SET, nodeSet);
02637     MBERRORR(rval, "Failed to create a new vertex set");
02638 
02639     rval = _mbImpl->add_entities(nodeSet, &node, 1);
02640     MBERRORR(rval, "Failed to add the node to the set");
02641 
02642     rval = _my_geomTopoTool->add_geo_set(nodeSet, 0);//
02643     MBERRORR(rval, "Failed to commit the node set");
02644 
02645     if (debug_splits) {
02646       std::cout
02647           << " create a vertex set (this should have been created before!)"
02648           << _mbImpl->id_from_handle(nodeSet) << " global id:"
02649           << this->_my_geomTopoTool->global_id(nodeSet) << "\n";
02650     }
02651   }
02652 
02653   // we need to remove the remaining mesh edges from first set, and add it
02654   // to the second set, in order
02655 
02656   rval = _mbImpl->create_meshset(MESHSET_ORDERED, new_edge);
02657   MBERRORR(rval, "can't create geo edge");
02658 
02659   int remaining = num_mesh_edges - 1 - index_edge;
02660 
02661   // add edges to the new edge set
02662   rval = _mbImpl->add_entities(new_edge, &secondEdge, 1); // add the second split edge to new edge
02663   MBERRORR(rval, "can't add second split edge to the new edge");
02664   // then add the rest
02665   rval = _mbImpl->add_entities(new_edge, &ents[index_edge + 1], remaining);
02666   MBERRORR(rval, "can't add edges to the new edge");
02667 
02668   // also, remove the second node set from old edge
02669   // remove the edges index_edge and up
02670 
02671   rval = _mbImpl->remove_entities(edge, &ents[index_edge], remaining+1);// include the
02672   MBERRORR(rval, "can't remove edges from the old edge");
02673   // add the firstEdge too
02674   rval = _mbImpl->add_entities(edge, &firstEdge, 1); // add the second split edge to new edge
02675   MBERRORR(rval, "can't add first split edge to the old edge");
02676 
02677   // need to find the adjacent vertex sets
02678   Range vertexRange;
02679   rval = getAdjacentEntities(edge, 0, vertexRange);
02680 
02681   EntityHandle secondSet;
02682   if (vertexRange.size() == 1) {
02683     // initially a periodic edge, OK to add the new set to both edges, and the
02684     // second set
02685     secondSet = vertexRange[0];
02686   } else {
02687     if (vertexRange.size() > 2)
02688       return MB_FAILURE; // something must be wrong with too many vertices
02689     // find first node
02690     EntityHandle firstNode;
02691 
02692     rval = MBI->get_connectivity(ents[0], conn, len);
02693     if (MB_SUCCESS != rval)
02694       return rval;
02695     firstNode = conn[0]; // this is the first node of the initial edge
02696                          // we will use it to identify the vertex set associated with it
02697     int k;
02698     for (k = 0; k < 2; k++) {
02699       Range verts;
02700       rval = _mbImpl->get_entities_by_type(vertexRange[k], MBVERTEX, verts);
02701 
02702       MBERRORR(rval, "can't get vertices from vertex set");
02703       if (verts.size() != 1)
02704         MBERRORR(MB_FAILURE, " node set not defined well");
02705       if (firstNode == verts[0]) {
02706         secondSet = vertexRange[1 - k]; // the other set; it is 1 or 0
02707         break;
02708       }
02709     }
02710     if (k >= 2) {
02711       // it means we didn't find the right node set
02712       MBERRORR(MB_FAILURE, " can't find the right vertex");
02713     }
02714     // remove the second set from the connectivity with the
02715     //  edge (parent-child relation)
02716     //remove_parent_child( EntityHandle parent,
02717     //                                          EntityHandle child )
02718     rval = _mbImpl->remove_parent_child(edge, secondSet);
02719     MBERRORR(rval, " can't remove the second vertex from edge");
02720   }
02721   // at this point, we just need to add to both edges the new node set (vertex)
02722   rval = _mbImpl->add_parent_child(edge, nodeSet);
02723   MBERRORR(rval, " can't add new vertex to old edge");
02724 
02725   rval = _mbImpl->add_parent_child(new_edge, nodeSet);
02726   MBERRORR(rval, " can't add new vertex to new edge");
02727 
02728   // one thing that I forgot: add the secondSet as a child to new edge!!!
02729   // (so far, the new edge has only one end vertex!)
02730   rval = _mbImpl->add_parent_child(new_edge, secondSet);
02731   MBERRORR(rval, " can't add second vertex to new edge");
02732 
02733   // now, add the edge and vertex to geo tool
02734 
02735   rval = _my_geomTopoTool->add_geo_set(new_edge, 1);
02736   MBERRORR(rval, " can't add new edge");
02737 
02738   // next, get the adjacent faces to initial edge, and add them as parents
02739   // to the new edge
02740 
02741   // need to find the adjacent face sets
02742   Range faceRange;
02743   rval = getAdjacentEntities(edge, 2, faceRange);
02744 
02745   // these faces will be adjacent to the new edge too!
02746   // need to set the senses of new edge within faces
02747 
02748   for (Range::iterator it = faceRange.begin(); it != faceRange.end(); it++) {
02749     EntityHandle face = *it;
02750     rval = _mbImpl->add_parent_child(face, new_edge);
02751     MBERRORR(rval, " can't add new edge - face parent relation");
02752     int sense;
02753     rval = _my_geomTopoTool->get_sense(edge, face, sense);
02754     MBERRORR(rval, " can't get initial sense of edge in the adjacent face");
02755     // keep the same sense for the new edge within the faces
02756     rval = _my_geomTopoTool->set_sense(new_edge, face, sense);
02757     MBERRORR(rval, " can't set sense of new edge in the adjacent face");
02758   }
02759 
02760   return MB_SUCCESS;
02761 }
02762 
02763 ErrorCode FBEngine::split_boundary(EntityHandle face, EntityHandle atNode)
02764 {
02765   // find the boundary edges, and split the one that we find it is a part of
02766   if (debug_splits)
02767   {
02768     std::cout<<"Split face " << _mbImpl->id_from_handle(face) << " at node:" <<
02769         _mbImpl->id_from_handle(atNode) << "\n";
02770   }
02771   Range bound_edges;
02772   ErrorCode rval = getAdjacentEntities(face, 1, bound_edges);
02773   MBERRORR(rval, " can't get boundary edges");
02774   bool brokEdge = _brokenEdges.find(atNode)!=_brokenEdges.end();
02775 
02776   for (Range::iterator it =bound_edges.begin(); it!=bound_edges.end(); it++ )
02777   {
02778     EntityHandle b_edge = *it;
02779     // get all edges in range
02780     Range mesh_edges;
02781     rval = _mbImpl->get_entities_by_dimension(b_edge, 1,
02782         mesh_edges);
02783     MBERRORR(rval, " can't get mesh edges");
02784     if (brokEdge)
02785     {
02786       EntityHandle brokenEdge = _brokenEdges[atNode];
02787       if (mesh_edges.find(brokenEdge)!=mesh_edges.end())
02788       {
02789         EntityHandle new_edge;
02790         rval = split_bedge_at_new_mesh_node(b_edge, atNode, brokenEdge, new_edge);
02791         return rval;
02792       }
02793     }
02794     else
02795     {
02796       Range nodes;
02797       rval = _mbImpl->get_connectivity(mesh_edges, nodes);
02798       MBERRORR(rval, " can't get nodes from mesh edges");
02799 
02800       if (nodes.find(atNode)!=nodes.end())
02801       {
02802         // we found our boundary edge candidate
02803         EntityHandle new_edge;
02804         rval = split_edge_at_mesh_node(b_edge, atNode, new_edge);
02805         return rval;
02806       }
02807     }
02808   }
02809   // if the node was not found in any "current" boundary, it broke an existing
02810   // boundary edge
02811   MBERRORR(MB_FAILURE, " we did not find an appropriate boundary edge"); ; //
02812   return MB_FAILURE; // needed to suppress compile warning
02813 }
02814 
02815 bool FBEngine::find_vertex_set_for_node(EntityHandle iNode, EntityHandle & oVertexSet)
02816 {
02817   bool found = false;
02818   Range vertex_sets;
02819 
02820   const int zero = 0;
02821   const void* const zero_val[] = { &zero };
02822   Tag geom_tag;
02823   ErrorCode rval = MBI->tag_get_handle(GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, geom_tag);
02824   if (MB_SUCCESS!=rval)
02825     return false;
02826   rval = _mbImpl->get_entities_by_type_and_tag(0, MBENTITYSET, &geom_tag,
02827         zero_val, 1, vertex_sets);
02828   if (MB_SUCCESS!=rval)
02829     return false;
02830   // local _gsets, as we might have not updated the local lists
02831   // see if ends of geo edge generated is in a geo set 0 or not
02832 
02833   for( Range::iterator vsit=vertex_sets.begin(); vsit!=vertex_sets.end(); vsit++)
02834   {
02835     EntityHandle vset=*vsit;
02836     // is the node part of this set?
02837     if (_mbImpl->contains_entities(vset, &iNode, 1))
02838     {
02839 
02840       found = true;
02841       oVertexSet = vset;
02842       break;
02843     }
02844   }
02845   return found;
02846 }
02847 ErrorCode FBEngine::redistribute_boundary_edges_to_faces(EntityHandle face, EntityHandle newFace,
02848       std::vector<EntityHandle> & chainedEdges)
02849 {
02850 
02851   // so far, original boundary edges are all parent/child relations for face
02852   // we should get them all, and see if they are truly adjacent to face or newFace
02853   // decide also on the orientation/sense with respect to the triangles
02854   Range r1; // range in old face
02855   Range r2; // range of tris in new face
02856   ErrorCode rval = _mbImpl->get_entities_by_dimension(face, 2, r1);
02857   MBERRORR(rval, " can't get triangles from old face");
02858   rval = _mbImpl->get_entities_by_dimension(newFace, 2, r2);
02859   MBERRORR(rval, " can't get triangles from new face");
02860   // right now, all boundary edges are children of face
02861   // we need to get them all, and verify if they indeed are adjacent to face
02862   Range children;
02863   rval = _mbImpl->get_child_meshsets(face, children);// only direct children are of interest
02864   MBERRORR(rval, " can't get children sets from face");
02865 
02866   for (Range::iterator it = children.begin(); it!=children.end(); it++)
02867   {
02868     EntityHandle edge=*it;
02869     if (std::find(chainedEdges.begin(), chainedEdges.end(), edge)!=chainedEdges.end())
02870       continue; // we already set this one fine
02871     // get one mesh edge from the edge; we have to get all of them!!
02872     if (_my_geomTopoTool->dimension(edge)!=1)
02873       continue; // not an edge
02874     Range mesh_edges;
02875     rval = _mbImpl->get_entities_by_handle(edge, mesh_edges);
02876     MBERRORR(rval, " can't get mesh edges from edge");
02877     if (mesh_edges.empty())
02878       MBERRORR(MB_FAILURE, " no mesh edges");
02879     EntityHandle mesh_edge = mesh_edges[0]; // first one is enough
02880     //get its triangles; see which one is in r1 or r2; it should not be in both
02881     Range triangles;
02882     rval = _mbImpl->get_adjacencies(&mesh_edge, 1, 2, false, triangles);
02883     MBERRORR(rval, " can't get adjacent triangles");
02884     Range intx1 = intersect(triangles, r1);
02885     Range intx2 = intersect(triangles, r2);
02886     if (!intx1.empty() && !intx2.empty())
02887       MBERRORR(MB_FAILURE, " at least one should be empty");
02888 
02889     if (intx2.empty())
02890     {
02891       // it means it is in the range r1; the sense should be fine, no need to reset
02892       // the sense should have been fine, also
02893       continue;
02894     }
02895     // so it must be a triangle in r2;
02896     EntityHandle triangle = intx2[0];// one triangle only
02897     // remove the edge from boundary of face, and add it to the boundary of newFace
02898     // remove_parent_child( EntityHandle parent,  EntityHandle child )
02899     rval = _mbImpl->remove_parent_child(face, edge);
02900     MBERRORR(rval, " can't remove parent child relation for edge");
02901     // add to the new face
02902     rval = _mbImpl->add_parent_child(newFace, edge);
02903     MBERRORR(rval, " can't add parent child relation for edge");
02904 
02905     // set some sense, based on the sense of the mesh_edge in triangle
02906     int num1, sense, offset;
02907     rval = _mbImpl->side_number(triangle, mesh_edge, num1, sense, offset);
02908     MBERRORR(rval, "mesh edge not adjacent to triangle");
02909 
02910     rval = this->_my_geomTopoTool->set_sense(edge, newFace, sense);
02911     MBERRORR(rval, "can't set proper sense of edge in face");
02912 
02913   }
02914 
02915   return MB_SUCCESS;
02916 }
02917 
02918 ErrorCode FBEngine::set_neumann_tags(EntityHandle face, EntityHandle newFace)
02919 {
02920   // these are for debugging purposes only
02921   // check the initial tag, then
02922   Tag ntag;
02923   ErrorCode rval = _mbImpl->tag_get_handle(NEUMANN_SET_TAG_NAME, 1, MB_TYPE_INTEGER, ntag);
02924   MBERRORR(rval, "can't get tag handle");
02925   // check the value for face
02926   int nval;
02927   rval = _mbImpl->tag_get_data(ntag, &face, 1, &nval);
02928   if (MB_SUCCESS == rval)
02929   {
02930     nval++;
02931   }
02932   else
02933   {
02934     nval = 1;
02935     rval = _mbImpl->tag_set_data(ntag, &face, 1, &nval);
02936     MBERRORR(rval, "can't set tag");
02937     nval = 2;
02938   }
02939   rval = _mbImpl->tag_set_data(ntag, &newFace, 1, &nval);
02940   MBERRORR(rval, "can't set tag");
02941 
02942   return MB_SUCCESS;
02943 }
02944 
02945 // split the quads if needed; it will create a new gtt, which will
02946 // contain triangles instead of quads
02947 ErrorCode FBEngine::split_quads()
02948 {
02949   // first see if we have any quads in the 2d faces
02950   //  _my_gsets[2] is a range of surfaces (moab sets of dimension 2)
02951   int num_quads=0;
02952   for (Range::iterator it=_my_gsets[2].begin(); it!=_my_gsets[2].end(); it++)
02953   {
02954     EntityHandle surface = *it;
02955     int num_q=0;
02956     _mbImpl->get_number_entities_by_type(surface, MBQUAD, num_q);
02957     num_quads+=num_q;
02958   }
02959 
02960   if (num_quads==0)
02961     return MB_SUCCESS; // nothing to do
02962 
02963   GeomTopoTool * new_gtt = NULL;
02964   ErrorCode rval = _my_geomTopoTool->duplicate_model(new_gtt);
02965   MBERRORR(rval, "can't duplicate model");
02966   if (this->_t_created)
02967     delete _my_geomTopoTool;
02968 
02969   _t_created = true; // this one is for sure created here, even if the original gtt was not
02970 
02971   // if we were using smart pointers, we would decrease the reference to the _my_geomTopoTool, at least
02972   _my_geomTopoTool = new_gtt;
02973 
02974   // replace the _my_gsets with the new ones, from the new set
02975   _my_geomTopoTool->find_geomsets(_my_gsets);
02976 
02977   // we have duplicated now the model, and the quads are part of the new _my_gsets[2]
02978   // we will split them now, by creating triangles along the smallest diagonal
02979   // maybe we will come up with a better criteria, but for the time being, it should be fine.
02980   // what we will do: we will remove all quads from the surface sets, and split them
02981 
02982   for (Range::iterator it2=_my_gsets[2].begin(); it2!=_my_gsets[2].end(); it2++)
02983   {
02984     EntityHandle surface = *it2;
02985     Range quads;
02986     rval = _mbImpl->get_entities_by_type(surface, MBQUAD, quads);
02987     MBERRORR(rval, "can't get quads from the surface set");
02988     rval = _mbImpl->remove_entities(surface, quads);
02989     MBERRORR(rval, "can't remove quads from the surface set"); // they are not deleted, just removed from the set
02990     for (Range::iterator it=quads.begin(); it!=quads.end(); it++)
02991     {
02992       EntityHandle quad = *it;
02993       int nnodes;
02994       const EntityHandle * conn;
02995       rval = _mbImpl->get_connectivity(quad, conn, nnodes);
02996       MBERRORR(rval, "can't get quad connectivity");
02997       // get all vertices position, to see which one is the shortest diagonal
02998       CartVect pos[4];
02999       rval = _mbImpl->get_coords(conn, 4, (double*) &pos[0]);
03000       MBERRORR(rval, "can't get node coordinates");
03001       bool diag1 = ( (pos[2]-pos[0]).length_squared() < (pos[3]-pos[1]).length_squared() );
03002       EntityHandle newTris[2];
03003       EntityHandle tri1[3]= { conn[0], conn[1], conn[2] };
03004       EntityHandle tri2[3]= { conn[0], conn[2], conn[3] };
03005       if (!diag1)
03006       {
03007         tri1[2] = conn[3];
03008         tri2[0] = conn[1];
03009       }
03010       rval = _mbImpl->create_element(MBTRI, tri1, 3, newTris[0]);
03011       MBERRORR(rval, "can't create triangle 1");
03012       rval = _mbImpl->create_element(MBTRI, tri2, 3, newTris[1]);
03013       MBERRORR(rval, "can't create triangle 2");
03014       rval = _mbImpl->add_entities(surface, newTris, 2);
03015       MBERRORR(rval, "can't add triangles to the set");
03016     }
03017     //
03018   }
03019   return MB_SUCCESS;
03020 }
03021 ErrorCode FBEngine::boundary_mesh_edges_on_face(EntityHandle face, Range & boundary_mesh_edges)
03022 {
03023   // this list is used only for finding the intersecting mesh edge for starting the
03024   // polygonal cutting line at boundary (if !closed)
03025   Range bound_edges;
03026   ErrorCode rval = getAdjacentEntities(face, 1, bound_edges);
03027   MBERRORR(rval, " can't get boundary edges");
03028   for (Range::iterator it =bound_edges.begin(); it!=bound_edges.end(); it++ )
03029   {
03030     EntityHandle b_edge = *it;
03031     // get all edges in range
03032     //Range mesh_edges;
03033     rval = _mbImpl->get_entities_by_dimension(b_edge, 1,
03034        boundary_mesh_edges);
03035     MBERRORR(rval, " can't get mesh edges");
03036   }
03037   return MB_SUCCESS;
03038 }
03039 ErrorCode FBEngine::boundary_nodes_on_face(EntityHandle face, std::vector<EntityHandle> & boundary_nodes)
03040 {
03041   // even if we repeat some nodes, it is OK
03042   // this list is used only for finding the closest boundary node for starting the
03043   // polygonal cutting line at boundary (if !closed)
03044   Range bound_edges;
03045   ErrorCode rval = getAdjacentEntities(face, 1, bound_edges);
03046   MBERRORR(rval, " can't get boundary edges");
03047   Range b_nodes;
03048   for (Range::iterator it =bound_edges.begin(); it!=bound_edges.end(); it++ )
03049   {
03050     EntityHandle b_edge = *it;
03051     // get all edges in range
03052     Range mesh_edges;
03053     rval = _mbImpl->get_entities_by_dimension(b_edge, 1,
03054         mesh_edges);
03055     MBERRORR(rval, " can't get mesh edges");
03056     rval = _mbImpl->get_connectivity(mesh_edges, b_nodes);
03057     MBERRORR(rval, " can't get nodes from mesh edges");
03058   }
03059   // create now a vector based on Range of nodes
03060   boundary_nodes.resize(b_nodes.size());
03061   std::copy(b_nodes.begin(), b_nodes.end(), boundary_nodes.begin());
03062   return MB_SUCCESS;
03063 }
03064 // used for splitting an edge
03065 ErrorCode FBEngine::split_internal_edge(EntityHandle & edge, EntityHandle & newVertex)
03066 {
03067   // split the edge, and form 4 new triangles and 2 edges
03068   // get 2 triangles adjacent to edge
03069   Range adj_tri;
03070   ErrorCode rval =  _mbImpl->get_adjacencies(&edge, 1,
03071                 2, false, adj_tri);
03072   MBERRORR(rval, "can't get adj_tris");
03073   adj_tri = subtract(adj_tri, _piercedTriangles);
03074   if (adj_tri.size()>=3)
03075   {
03076     std::cout<< "WARNING: non manifold geometry. Are you sure?";
03077   }
03078   for (Range::iterator it=adj_tri.begin(); it!=adj_tri.end(); ++it)
03079   {
03080     EntityHandle tri = *it;
03081     _piercedTriangles.insert(tri);
03082     const EntityHandle * conn3;
03083     int nnodes;
03084     rval = _mbImpl->get_connectivity(tri, conn3, nnodes); 
03085     MBERRORR(rval, "can't get nodes");
03086     int num1, sense, offset;
03087     rval = _mbImpl->side_number(tri, edge, num1, sense, offset);
03088     MBERRORR(rval, "can't get side number");
03089     // after we know the side number, we can split in 2 triangles
03090     // node i is opposite to edge i
03091     int num2 = (num1+1)%3;
03092     int num3 = (num2+1)%3;
03093     // the edge from num1 to num2 is split into 2 edges
03094     EntityHandle t1[]={conn3[num2], conn3[num3], newVertex};
03095     EntityHandle t2[]={conn3[num1], newVertex, conn3[num3]};
03096     EntityHandle newTriangle, newTriangle2;
03097     rval = _mbImpl->create_element(MBTRI, t1, 3, newTriangle);
03098     MBERRORR(rval, "can't create triangle");
03099     _newTriangles.insert(newTriangle);
03100     rval = _mbImpl->create_element(MBTRI, t2, 3, newTriangle2);
03101     MBERRORR(rval, "can't create triangle");
03102     _newTriangles.insert(newTriangle2);
03103     // create edges with this, indirectly
03104     std::vector<EntityHandle> edges0;
03105     rval = _mbImpl->get_adjacencies(&newTriangle, 1, 1, true, edges0);
03106     MBERRORR(rval, "can't get new edges");
03107     edges0.clear();
03108     rval = _mbImpl->get_adjacencies(&newTriangle2, 1, 1, true, edges0);
03109     MBERRORR(rval, "can't get new edges");
03110     if (debug_splits)
03111     {
03112       std::cout<<"2 (out of 4) triangles formed:\n";
03113       _mbImpl->list_entity(newTriangle);
03114       print_debug_triangle(newTriangle);
03115       _mbImpl->list_entity(newTriangle2);
03116       print_debug_triangle(newTriangle2);
03117     }
03118   }
03119   return MB_SUCCESS;
03120 }
03121   // triangle split
03122 ErrorCode FBEngine::divide_triangle(EntityHandle triangle, EntityHandle & newVertex)
03123 {
03124   // 
03125   _piercedTriangles.insert(triangle);
03126   int nnodes;
03127   const EntityHandle * conn3;
03128   ErrorCode  rval = _mbImpl->get_connectivity(triangle, conn3, nnodes); 
03129   MBERRORR(rval, "can't get nodes");
03130   EntityHandle t1[]={conn3[0], conn3[1], newVertex};
03131   EntityHandle t2[]={conn3[1], conn3[2], newVertex};
03132   EntityHandle t3[]={conn3[2], conn3[0], newVertex};
03133   EntityHandle newTriangle, newTriangle2, newTriangle3;
03134   rval = _mbImpl->create_element(MBTRI, t1, 3, newTriangle);
03135   MBERRORR(rval, "can't create triangle");
03136   _newTriangles.insert(newTriangle);
03137   rval = _mbImpl->create_element(MBTRI, t2, 3, newTriangle3);
03138   MBERRORR(rval, "can't create triangle");
03139   _newTriangles.insert(newTriangle3);
03140   rval = _mbImpl->create_element(MBTRI, t3, 3, newTriangle2);
03141   MBERRORR(rval, "can't create triangle");
03142   _newTriangles.insert(newTriangle2);
03143 
03144   // create all edges
03145   std::vector<EntityHandle> edges0;
03146   rval = _mbImpl->get_adjacencies(&newTriangle, 1, 1, true, edges0);
03147   MBERRORR(rval, "can't get new edges");
03148   edges0.clear();
03149   rval = _mbImpl->get_adjacencies(&newTriangle2, 1, 1, true, edges0);
03150   MBERRORR(rval, "can't get new edges");
03151   if (debug_splits)
03152   {
03153     std::cout<<"3 triangles formed:\n";
03154     _mbImpl->list_entity(newTriangle);
03155     print_debug_triangle(newTriangle);
03156     _mbImpl->list_entity(newTriangle3);
03157     print_debug_triangle(newTriangle3);
03158     _mbImpl->list_entity(newTriangle2);
03159     print_debug_triangle(newTriangle2);
03160     std::cout<<"original nodes in tri:\n";
03161     _mbImpl->list_entity(conn3[0]);
03162     _mbImpl->list_entity(conn3[1]);
03163     _mbImpl->list_entity(conn3[2]);
03164   }
03165   return MB_SUCCESS;
03166 }
03167 
03168 ErrorCode FBEngine::create_volume_with_direction(EntityHandle newFace1, EntityHandle newFace2, double * direction,
03169       EntityHandle & volume)
03170 {
03171 
03172   // MESHSET
03173   // ErrorCode rval = _mbImpl->create_meshset(MESHSET_ORDERED, new_geo_edge);
03174   ErrorCode rval = _mbImpl->create_meshset(MESHSET_SET, volume);
03175   MBERRORR(rval, "can't create volume");
03176 
03177   int volumeMatId = 1;// just give a mat id, for debugging, mostly
03178   Tag matTag;
03179   rval = _mbImpl->tag_get_handle(MATERIAL_SET_TAG_NAME, 1, MB_TYPE_INTEGER, matTag);
03180   MBERRORR(rval, "can't get material tag");
03181 
03182   rval=_mbImpl->tag_set_data(matTag, &volume, 1, &volumeMatId);
03183   MBERRORR(rval, "can't set material tag value on volume");
03184 
03185   // get the edges of those 2 faces, and get the vertices of those edges
03186   // in order, they should be created in the same order (?); check for that, anyway
03187   rval=_mbImpl->add_parent_child(volume, newFace1);
03188   MBERRORR(rval, "can't add first face to volume");
03189 
03190   rval=_mbImpl->add_parent_child(volume, newFace2);
03191   MBERRORR(rval, "can't add second face to volume");
03192 
03193   // first is bottom, so it is negatively oriented
03194   rval = _my_geomTopoTool->add_geo_set(volume, 3);
03195   MBERRORR(rval, "can't add volume to the gtt");
03196 
03197   // set senses
03198   // bottom face is negatively oriented, its normal is toward interior of the volume
03199   rval = _my_geomTopoTool->set_sense(newFace1, volume, -1);
03200   MBERRORR(rval, "can't set bottom face sense to the volume");
03201 
03202   // the top face is positively oriented
03203   rval = _my_geomTopoTool->set_sense(newFace2, volume, 1);
03204   MBERRORR(rval, "can't set top face sense to the volume");
03205 
03206   // the children should be in the same direction
03207   //   get the side edges of each face, and form lateral faces, along direction
03208   std::vector<EntityHandle> edges1;
03209   std::vector<EntityHandle> edges2;
03210 
03211   rval = _mbImpl->get_child_meshsets(newFace1, edges1); // no hops
03212   MBERRORR(rval, "can't get children edges or first face, bottom");
03213 
03214   rval = _mbImpl->get_child_meshsets(newFace2, edges2); // no hops
03215   MBERRORR(rval, "can't get children edges for second face, top");
03216 
03217   if (edges1.size()!=edges2.size())
03218     MBERRORR(MB_FAILURE, "wrong correspondence ");
03219 
03220   for (unsigned int i = 0; i < edges1.size(); ++i)
03221   {
03222     EntityHandle newLatFace;
03223     rval = weave_lateral_face_from_edges(edges1[i], edges2[i], direction, newLatFace);
03224     MBERRORR(rval, "can't weave lateral face");
03225     rval=_mbImpl->add_parent_child(volume, newLatFace);
03226     MBERRORR(rval, "can't add lateral face to volume");
03227 
03228     // set sense as positive
03229     rval = _my_geomTopoTool->set_sense(newLatFace, volume, 1);
03230     MBERRORR(rval, "can't set lateral face sense to the volume");
03231   }
03232 
03233   rval = set_default_neumann_tags();
03234   MBERRORR(rval, "can't set new neumann tags");
03235 
03236   return MB_SUCCESS;
03237 }
03238 
03239 ErrorCode  FBEngine::get_nodes_from_edge(EntityHandle gedge, std::vector<EntityHandle> & nodes)
03240 {
03241   std::vector<EntityHandle> ents;
03242   ErrorCode rval = _mbImpl->get_entities_by_type(gedge, MBEDGE, ents);
03243   if (MB_SUCCESS != rval)
03244     return rval;
03245   if (ents.size() < 1)
03246     return MB_FAILURE;
03247 
03248   nodes.resize(ents.size() +1);
03249   const EntityHandle* conn = NULL;
03250   int len;
03251   for (unsigned int i=0; i<ents.size(); ++i)
03252   {
03253     rval = _mbImpl->get_connectivity(ents[i], conn, len);
03254     MBERRORR(rval, "can't get edge connectivity");
03255     nodes[i] = conn[0];
03256   }
03257   // the last one is conn[1]
03258   nodes[ents.size()] = conn[1];
03259   return MB_SUCCESS;
03260 }
03261 ErrorCode  FBEngine::weave_lateral_face_from_edges(EntityHandle bEdge, EntityHandle tEdge,  double * direction,
03262       EntityHandle & newLatFace)
03263 {
03264   // in weird cases might need to create new vertices in the interior;
03265   // in most cases, it is OK
03266 
03267   ErrorCode rval = _mbImpl->create_meshset(MESHSET_SET, newLatFace);
03268   MBERRORR(rval, "can't create new lateral face");
03269 
03270   EntityHandle v[4]; // vertex sets
03271   // bot edge will be v1->v2
03272   // top edge will be v3->v4
03273   // we need to create edges from v1 to v3 and from v2 to v4
03274   std::vector<EntityHandle> adj;
03275   rval = _mbImpl->get_child_meshsets(bEdge, adj);
03276   MBERRORR(rval, "can't get children nodes");
03277   bool periodic = false;
03278   if (adj.size()==1)
03279   {
03280     v[0] = v[1] = adj[0];
03281     periodic = true;
03282   }
03283   else
03284   {
03285     v[0]=adj[0];
03286     v[1]=adj[1];
03287   }
03288   int senseB;
03289   rval = getEgVtxSense( bEdge, v[0], v[1],  senseB );
03290   MBERRORR(rval, "can't get bottom edge sense");
03291   if (-1==senseB)
03292   {
03293     v[1]=adj[0];// so , bEdge will be oriented from v[0] to v[1], and will start at nodes1, coords1..
03294     v[0]=adj[1];
03295   }
03296   adj.clear();
03297   rval = _mbImpl->get_child_meshsets(tEdge, adj);
03298   MBERRORR(rval, "can't get children nodes");
03299   if (adj.size()==1)
03300   {
03301     v[2]=v[3]=adj[0];
03302     if (!periodic)
03303       MBERRORR(MB_FAILURE, "top edge is periodic, but bottom edge is not");
03304   }
03305   else
03306   {
03307     v[2]=adj[0];
03308     v[3]=adj[1];
03309     if (periodic)
03310       MBERRORR(MB_FAILURE, "top edge is not periodic, but bottom edge is");
03311   }
03312 
03313   // now, using nodes on bottom edge and top edge, create triangles, oriented outwards the
03314   //  volume (sense positive on bottom edge)
03315   std::vector<EntityHandle> nodes1;
03316   rval = get_nodes_from_edge(bEdge, nodes1);
03317   MBERRORR(rval, "can't get nodes from bott edge");
03318 
03319   std::vector<EntityHandle> nodes2;
03320   rval = get_nodes_from_edge(tEdge, nodes2);
03321   MBERRORR(rval, "can't get nodes from top edge");
03322 
03323   std::vector<CartVect> coords1, coords2;
03324   coords1.resize(nodes1.size());
03325   coords2.resize(nodes2.size());
03326 
03327   int N1 = (int)nodes1.size();
03328   int N2 = (int)nodes2.size();
03329 
03330   rval = _mbImpl->get_coords(&(nodes1[0]), nodes1.size(), (double*) &(coords1[0]));
03331   MBERRORR(rval, "can't get coords of nodes from bott edge");
03332 
03333   rval = _mbImpl->get_coords(&(nodes2[0]), nodes2.size(), (double*) &(coords2[0]));
03334   MBERRORR(rval, "can't get coords of nodes from top edge");
03335   CartVect up(direction);
03336 
03337   // see if the start and end coordinates are matching, if not, reverse edge 2 nodes and coordinates
03338   CartVect v1 = (coords1[0]-coords2[0])*up;
03339   CartVect v2 = (coords1[0]-coords2[N2-1])*up;
03340   if (v1.length_squared()>v2.length_squared())
03341   {
03342     // we need to reverse coords2 and node2, as nodes are not above each other
03343     // the edges need to be found between v0 and v3, v1 and v2!
03344     for (unsigned int k=0 ; k<nodes2.size()/2; k++)
03345     {
03346       EntityHandle tmp=nodes2[k];
03347       nodes2[k] = nodes2[N2-1-k];
03348       nodes2[N2-1-k] = tmp;
03349       CartVect tv = coords2[k];
03350       coords2[k] = coords2[N2-1-k];
03351       coords2[N2-1-k]= tv;
03352     }
03353   }
03354   // make sure v[2] has nodes2[0], if not, reverse v[2] and v[3]
03355   if (!_mbImpl->contains_entities(v[2], &(nodes2[0]), 1))
03356   {
03357     //reverse v[2] and v[3], so v[2] will be above v[0]
03358     EntityHandle tmp = v[2];
03359     v[2] = v[3];
03360     v[3]= tmp;
03361   }
03362   // now we know that v[0]--v[3] will be vertex sets in the order we want
03363   EntityHandle nd[4]={nodes1[0], nodes1[N1-1], nodes2[0], nodes2[N2-1]};
03364 
03365   adj.clear();
03366   EntityHandle e1, e2;
03367   // find edge 1 between v[0] and v[2], and e2 between v[1] and v[3]
03368   rval=_mbImpl->get_parent_meshsets(v[0], adj);
03369   MBERRORR(rval, "can't get edges connected to vertex set 1");
03370   bool found = false;
03371   for (unsigned int j =0; j< adj.size(); j++)
03372   {
03373     EntityHandle ed=adj[j];
03374     Range vertices;
03375     rval = _mbImpl->get_child_meshsets(ed, vertices);
03376     if (vertices.find(v[2])!=vertices.end())
03377     {
03378       found = true;
03379       e1 = ed;
03380       break;
03381     }
03382   }
03383   if (!found)
03384   {
03385     // create an edge from v[0] to v[2]
03386     rval = _mbImpl->create_meshset(MESHSET_SET, e1);
03387     MBERRORR(rval, "can't create edge 1");
03388 
03389     rval=_mbImpl->add_parent_child(e1, v[0]);
03390     MBERRORR(rval, "can't add parent - child relation");
03391 
03392     rval=_mbImpl->add_parent_child(e1, v[2]);
03393     MBERRORR(rval, "can't add parent - child relation");
03394 
03395     EntityHandle nn2[2] = {nd[0], nd[2]};
03396     EntityHandle medge;
03397     rval = _mbImpl->create_element(MBEDGE, nn2, 2, medge);
03398     MBERRORR(rval, "can't create mesh edge");
03399 
03400     rval = _mbImpl->add_entities(e1, &medge, 1);
03401     MBERRORR(rval, "can't add mesh edge to geo edge");
03402 
03403     rval = this->_my_geomTopoTool->add_geo_set(e1, 1);
03404     MBERRORR(rval, "can't add edge to gtt");
03405   }
03406 
03407   // find the edge from v2 to v4 (if not, create one)
03408   rval=_mbImpl->get_parent_meshsets(v[1], adj);
03409   MBERRORR(rval, "can't get edges connected to vertex set 2");
03410   found = false;
03411   for (unsigned int i =0; i< adj.size(); i++)
03412   {
03413     EntityHandle ed=adj[i];
03414     Range vertices;
03415     rval = _mbImpl->get_child_meshsets(ed, vertices);
03416     if (vertices.find(v[3])!=vertices.end())
03417     {
03418       found = true;
03419       e2 = ed;
03420       break;
03421     }
03422   }
03423   if (!found)
03424   {
03425     // create an edge from v2 to v4
03426     rval = _mbImpl->create_meshset(MESHSET_SET, e2);
03427     MBERRORR(rval, "can't create edge 1");
03428 
03429     rval=_mbImpl->add_parent_child(e2, v[1]);
03430     MBERRORR(rval, "can't add parent - child relation");
03431 
03432     rval=_mbImpl->add_parent_child(e2, v[3]);
03433     MBERRORR(rval, "can't add parent - child relation");
03434 
03435     EntityHandle nn2[2] = {nd[1], nd[3]};
03436     EntityHandle medge;
03437     rval = _mbImpl->create_element(MBEDGE, nn2, 2, medge);
03438     MBERRORR(rval, "can't create mesh edge");
03439 
03440     rval = _mbImpl->add_entities(e2, &medge, 1);
03441     MBERRORR(rval, "can't add mesh edge to geo edge");
03442 
03443     rval =  _my_geomTopoTool->add_geo_set(e2, 1);
03444     MBERRORR(rval, "can't add edge to gtt");
03445   }
03446 
03447   // now we have the four edges, add them to the face, as children
03448 
03449   // add children to face
03450   rval=_mbImpl->add_parent_child(newLatFace, bEdge);
03451   MBERRORR(rval, "can't add parent - child relation");
03452 
03453   rval=_mbImpl->add_parent_child(newLatFace, tEdge);
03454   MBERRORR(rval, "can't add parent - child relation");
03455 
03456   rval=_mbImpl->add_parent_child(newLatFace, e1);
03457   MBERRORR(rval, "can't add parent - child relation");
03458 
03459   rval=_mbImpl->add_parent_child(newLatFace, e2);
03460   MBERRORR(rval, "can't add parent - child relation");
03461 
03462   rval =  _my_geomTopoTool->add_geo_set(newLatFace, 2);
03463   MBERRORR(rval, "can't add face to gtt");
03464   // add senses
03465   //
03466   rval = _my_geomTopoTool->set_sense(bEdge, newLatFace, 1);
03467   MBERRORR(rval, "can't set bottom edge sense to the lateral face");
03468 
03469   int Tsense;
03470   rval = getEgVtxSense( tEdge, v[3], v[2],  Tsense );
03471   MBERRORR(rval, "can't get top edge sense");
03472   // we need to see what sense has topEdge in face
03473   rval = _my_geomTopoTool->set_sense(tEdge, newLatFace, Tsense);
03474   MBERRORR(rval, "can't set top edge sense to the lateral face");
03475 
03476   rval = _my_geomTopoTool->set_sense(e1, newLatFace, -1);
03477   MBERRORR(rval, "can't set first vert edge sense");
03478 
03479   rval = _my_geomTopoTool->set_sense(e2, newLatFace, 1);
03480   MBERRORR(rval, "can't set second edge sense to the lateral face");
03481   // first, create edges along direction, for the
03482 
03483   int indexB=0, indexT=0;// indices of the current nodes in the weaving process
03484   // weaving is either up or down; the triangles are oriented positively either way
03485   // up is nodes1[indexB], nodes2[indexT+1], nodes2[indexT]
03486   // down is nodes1[indexB], nodes1[indexB+1], nodes2[indexT]
03487   // the decision to weave up or down is based on which one is closer to the direction normal
03488   /*
03489    *
03490    *     --------*------*-----------*                           ^
03491    *            /   .    \ .      .           ------> dir1      |  up
03492    *           /.         \   .  .                              |
03493    *     -----*------------*----*
03494    *
03495    */
03496   // we have to change the logic to account for cases when the curve in xy plane is not straight
03497   // (for example, when merging curves with a min_dot < -0.5, which means that the edges
03498   // could be even closed (periodic), with one vertex
03499   // the top and bottom curves should follow the same path in the "xy" plane (better to say
03500   // the plane perpendicular to the direction of weaving)
03501   // in this logic, the vector dir1 varies along the curve !!!
03502   CartVect dir1= coords1[1] - coords1[0];// we should have at least 2 nodes, N1>=2!!
03503 
03504   CartVect planeNormal = dir1*up;
03505   dir1 = up * planeNormal;
03506   dir1.normalize();
03507   // this direction will be updated constantly with the direction of last edge added
03508   bool weaveDown = true;
03509 
03510   CartVect startP = coords1[0]; // used for origin of comparisons
03511   while(1)
03512   {
03513     if ((indexB == N1-1) && (indexT == N2-1))
03514       break; // we cannot advance anymore
03515     if (indexB == N1-1)
03516     {
03517       weaveDown = false;
03518     }
03519     else if (indexT==N2-1)
03520     {
03521       weaveDown = true;
03522     }
03523     else
03524     {
03525       // none are at the end, we have to decide which way to go, based on which  index + 1 is closer
03526       double proj1 = (coords1[indexB+1]-startP)%dir1;
03527       double proj2 = (coords2[indexT+1]-startP)%dir1;
03528       if (proj1 < proj2)
03529         weaveDown = true;
03530       else
03531         weaveDown = false;
03532     }
03533     EntityHandle nTri[3] = { nodes1[indexB], nodes2[indexT+1], nodes2[indexT]};
03534     if (weaveDown)
03535     {
03536       nTri[1] = nodes1[indexB+1];
03537       nTri[2] = nodes2[indexT];
03538       indexB++;
03539     }
03540     else
03541       indexT++;
03542     EntityHandle triangle;
03543     rval = _mbImpl->create_element(MBTRI, nTri, 3, triangle);
03544     MBERRORR(rval, "can't create triangle");
03545 
03546     rval = _mbImpl->add_entities(newLatFace, &triangle, 1);
03547     MBERRORR(rval, "can't add triangle to face set");
03548     if (weaveDown)
03549     {
03550       // increase was from nodes1[indexB-1] to nodes1[indexb]
03551       dir1= coords1[indexB] - coords1[indexB-1];// we should have at least 2 nodes, N1>=2!!
03552     }
03553     else
03554     {
03555       dir1= coords2[indexT] - coords2[indexT-1];
03556     }
03557     dir1 = up * (dir1*up);
03558     dir1.normalize();
03559 
03560   }
03561   // we do not check yet if the triangles are inverted
03562   // if yes, we should correct them. HOW?
03563   // we probably need a better meshing strategy, one that can overcome really bad meshes.
03564   // again, these faces are not what we should use for geometry, maybe we should use the
03565   //  extruded quads, identified AFTER hexa are created.
03566   // right now, I see only a cosmetic use of these lateral faces
03567   // the whole idea of volume maybe is overrated
03568   // volume should be just quads extruded from bottom ?
03569   //
03570   return MB_SUCCESS;
03571 }
03572 // this will be used during creation of the volume, to set unique
03573 // tags on all surfaces
03574 // it is changing original tags, so do not use it if you want to preserve
03575 // initial neumann tags
03576 ErrorCode FBEngine::set_default_neumann_tags()
03577 {
03578   // these are for debugging purposes only
03579   // check the initial tag, then
03580   Tag ntag;
03581   ErrorCode rval = _mbImpl->tag_get_handle(NEUMANN_SET_TAG_NAME, 1, MB_TYPE_INTEGER, ntag);
03582   MBERRORR(rval, "can't get tag handle");
03583   // get all surfaces in the model now
03584   Range sets[5];
03585   rval = _my_geomTopoTool->find_geomsets(sets);
03586   MBERRORR(rval, "can't get geo sets");
03587   int nfaces = (int)sets[2].size();
03588   int * vals = new int [nfaces];
03589   for (int i=0; i<nfaces; i++)
03590   {
03591     vals[i] = i+1;
03592   }
03593   rval = _mbImpl->tag_set_data(ntag, sets[2], (void*)vals);
03594   MBERRORR(rval, "can't set tag values for neumann sets");
03595 
03596   delete [] vals;
03597 
03598   return MB_SUCCESS;
03599 }
03600 // a reverse operation for splitting an gedge at a mesh node
03601 ErrorCode FBEngine::chain_edges(double min_dot)
03602 {
03603   Range sets[5];
03604   ErrorCode rval;
03605   while (1)// break out only if no edges are chained
03606   {
03607     rval = _my_geomTopoTool->find_geomsets(sets);
03608     MBERRORR(rval, "can't get geo sets");
03609     // these gentities are "always" current, while the ones in this-> _my_gsets[0:4] are
03610     // the "originals" before FBEngine modifications
03611     int nedges=(int)sets[1].size();
03612     // as long as we have chainable edges, continue;
03613     bool chain=false;
03614     for (int i=0; i<nedges; i++)
03615     {
03616       EntityHandle edge=sets[1][i];
03617       EntityHandle next_edge;
03618       bool chainable=false;
03619       rval = chain_able_edge(edge, min_dot, next_edge, chainable);
03620       MBERRORR(rval, "can't determine chain-ability");
03621       if ( chainable )
03622       {
03623         rval = chain_two_edges(edge, next_edge);
03624         MBERRORR(rval, "can't chain 2 edges");
03625         chain = true;
03626         break; // interrupt for loop
03627       }
03628     }
03629     if (!chain)
03630     {
03631       break; // break out of while loop
03632     }
03633   }
03634   return MB_SUCCESS;
03635 }
03636 
03637 // determine if from the end of edge we can extend with another edge; return also the
03638 //  extension edge (next_edge)
03639 ErrorCode FBEngine::chain_able_edge(EntityHandle edge, double min_dot,
03640     EntityHandle & next_edge, bool & chainable)
03641 {
03642   // get the end, then get all parents of end
03643   // see if some are the starts of
03644   chainable = false;
03645   EntityHandle v1, v2;
03646   ErrorCode rval = get_vert_edges(edge, v1, v2);
03647   MBERRORR(rval, "can't get vertices");
03648   if (v1==v2)
03649     return MB_SUCCESS;// it is periodic, can't chain it with another edge!
03650 
03651   // v2 is a set, get its parents, which should be edges
03652   Range edges;
03653   rval = _mbImpl->get_parent_meshsets(v2, edges);
03654   MBERRORR(rval, "can't get parents of vertex set");
03655   // get parents of current edge (faces)
03656   Range faces;
03657   rval = _mbImpl->get_parent_meshsets(edge, faces);
03658   MBERRORR(rval, "can't get parents of edge set");
03659   // get also the last edge "tangent" at the vertex
03660   std::vector<EntityHandle> mesh_edges;
03661   rval = _mbImpl->get_entities_by_type(edge, MBEDGE, mesh_edges);
03662   MBERRORR(rval, "can't get mesh edges from edge set");
03663   EntityHandle lastMeshEdge= mesh_edges[mesh_edges.size()-1];
03664   const EntityHandle * conn2;
03665   int len;
03666   rval = _mbImpl->get_connectivity(lastMeshEdge, conn2, len);
03667   MBERRORR(rval, "can't connectivity of last mesh edge");
03668   // get the coordinates of last edge
03669   if (len!=2)
03670     MBERRORR(MB_FAILURE, "bad number of vertices");
03671   CartVect P[2];
03672   rval = _mbImpl->get_coords(conn2, len, (double*) &P[0]);
03673   MBERRORR(rval, "Failed to get coordinates");
03674 
03675   CartVect vec1(P[1] - P[0]);
03676   vec1.normalize();
03677   for (Range::iterator edgeIter = edges.begin(); edgeIter!=edges.end(); edgeIter++)
03678   {
03679     EntityHandle otherEdge = *edgeIter;
03680     if (edge==otherEdge)
03681       continue;
03682     // get faces parents of this edge
03683     Range faces2;
03684     rval = _mbImpl->get_parent_meshsets(otherEdge, faces2);
03685     MBERRORR(rval, "can't get parents of other edge set");
03686     if (faces!=faces2)
03687       continue;
03688     // now, if the first mesh edge is within given angle, we can go on
03689     std::vector<EntityHandle> mesh_edges2;
03690     rval = _mbImpl->get_entities_by_type(otherEdge, MBEDGE, mesh_edges2);
03691     MBERRORR(rval, "can't get mesh edges from other edge set");
03692     EntityHandle firstMeshEdge= mesh_edges2[0];
03693     const EntityHandle * conn22;
03694     int len2;
03695     rval = _mbImpl->get_connectivity(firstMeshEdge, conn22, len2);
03696     MBERRORR(rval, "can't connectivity of first mesh edge");
03697     if (len2!=2)
03698       MBERRORR(MB_FAILURE, "bad number of vertices");
03699     if (conn2[1]!=conn22[0])
03700       continue; // the mesh edges are not one after the other
03701     // get the coordinates of first edge
03702 
03703     //CartVect P2[2];
03704     rval = _mbImpl->get_coords(conn22, len, (double*) &P[0]);
03705     CartVect vec2(P[1] - P[0]);
03706     vec2.normalize();
03707     if (vec1%vec2 < min_dot)
03708       continue;
03709     // we found our edge, victory! we can get out
03710     next_edge = otherEdge;
03711     chainable = true;
03712     return MB_SUCCESS;
03713 
03714   }
03715 
03716 
03717   return MB_SUCCESS;// in general, hard to come by chain-able edges
03718 }
03719 ErrorCode FBEngine::chain_two_edges(EntityHandle edge, EntityHandle next_edge)
03720 {
03721   // the biggest thing is to see the sense tags; or maybe not...
03722   // they should be correct :)
03723   // get the vertex sets
03724   EntityHandle v11, v12, v21, v22;
03725   ErrorCode rval = get_vert_edges( edge,  v11, v12);
03726   MBERRORR(rval, "can't get vert sets");
03727   rval = get_vert_edges( next_edge,  v21, v22);
03728   MBERRORR(rval, "can't get vert sets");
03729   assert(v12==v21);
03730   std::vector<EntityHandle> mesh_edges;
03731   rval = MBI->get_entities_by_type(next_edge, MBEDGE, mesh_edges);
03732   MBERRORR(rval, "can't get mesh edges");
03733 
03734   rval = _mbImpl->add_entities(edge, &mesh_edges[0], (int)mesh_edges.size());
03735   MBERRORR(rval, "can't add new mesh edges");
03736   // remove the child - parent relation for second vertex of first edge
03737   rval = _mbImpl->remove_parent_child(edge, v12);
03738   MBERRORR(rval, "can't remove parent - child relation between first edge and middle vertex");
03739 
03740   if (v22!=v11) // the edge would become periodic, do not add again the relationship
03741   {
03742     rval = _mbImpl->add_parent_child(edge, v22);
03743     MBERRORR(rval, "can't add second vertex to edge ");
03744   }
03745   // we can now safely eliminate next_edge
03746   rval = _mbImpl->remove_parent_child(next_edge, v21);
03747   MBERRORR(rval, "can't remove child - parent relation ");
03748 
03749   rval = _mbImpl->remove_parent_child(next_edge, v22);
03750   MBERRORR(rval, "can't remove child - parent relation ");
03751 
03752   // remove the next_edge relation to the faces
03753   Range faces;
03754   rval = _mbImpl->get_parent_meshsets(next_edge, faces);
03755   MBERRORR(rval, "can't get parent faces ");
03756 
03757   for (Range::iterator it=faces.begin(); it!=faces.end(); it++)
03758   {
03759     EntityHandle ff=*it;
03760     rval = _mbImpl->remove_parent_child(ff, next_edge);
03761     MBERRORR(rval, "can't remove parent-edge rel ");
03762   }
03763 
03764   rval = _mbImpl->delete_entities(&next_edge, 1);
03765   MBERRORR(rval, "can't remove edge set ");
03766 
03767   // delete the vertex set that is idle now (v12 = v21)
03768   rval = _mbImpl->delete_entities(&v12, 1);
03769   MBERRORR(rval, "can't remove edge set ");
03770   return MB_SUCCESS;
03771 }
03772 ErrorCode FBEngine::get_vert_edges(EntityHandle edge, EntityHandle & v1, EntityHandle & v2)
03773 {
03774   // need to decide first or second vertex
03775   // important for moab
03776 
03777   Range children;
03778   //EntityHandle v1, v2;
03779   ErrorCode rval = _mbImpl->get_child_meshsets(edge, children);
03780   MBERRORR(rval, "can't get child meshsets");
03781   if (children.size()==1)
03782   {
03783     // this is periodic edge, get out early
03784     v1 = children[0];
03785     v2 = v1;
03786     return MB_SUCCESS;
03787   }
03788   else if (children.size()>2)
03789     MBERRORR(MB_FAILURE, "too many vertices in one edge");
03790   // edge: get one vertex as part of the vertex set
03791   Range entities;
03792   rval = MBI->get_entities_by_type(children[0], MBVERTEX, entities);
03793   MBERRORR(rval, "can't get entities from vertex set");
03794   if (entities.size() < 1)
03795     MBERRORR(MB_FAILURE, "no mesh nodes in vertex set");
03796   EntityHandle node0 = entities[0]; // the first vertex
03797   entities.clear();
03798 
03799   // now get the edges, and get the first node and the last node in sequence of edges
03800   // the order is important...
03801   // these are ordered sets !!
03802   std::vector<EntityHandle> ents;
03803   rval = MBI->get_entities_by_type(edge, MBEDGE, ents);
03804   MBERRORR(rval, "can't get mesh edges");
03805   if (ents.size() < 1)
03806     MBERRORR(MB_FAILURE, "no mesh edges in edge set");
03807 
03808   const EntityHandle* conn = NULL;
03809   int len;
03810   rval = MBI->get_connectivity(ents[0], conn, len);
03811   MBERRORR(rval, "can't connectivity of first mesh edge");
03812 
03813   if (conn[0]==node0)
03814   {
03815     v1 = children[0];
03816     v2 = children[1];
03817   }
03818   else // the other way around, although we should check (we are paranoid)
03819   {
03820     v2 = children[0];
03821     v1 = children[1];
03822   }
03823 
03824   return MB_SUCCESS;
03825 }
03826 } // namespace moab
03827 
03828 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines