MeshKit  1.0
EdgeMesher.cpp
Go to the documentation of this file.
00001 #include "meshkit/EdgeMesher.hpp"
00002 #include "meshkit/Matrix.hpp"
00003 #include "meshkit/MKCore.hpp"
00004 #include "meshkit/ModelEnt.hpp"
00005 #include "meshkit/SizingFunction.hpp"
00006 #include "meshkit/RegisterMeshOp.hpp"
00007 #include "moab/ReadUtilIface.hpp"
00008 #include <vector>
00009 #include <math.h>
00010 
00011 namespace MeshKit
00012 {
00013 
00014 //---------------------------------------------------------------------------//
00015 //Entity Type initilization for edge meshing
00016 moab::EntityType EdgeMesher_tps[] = {moab::MBVERTEX, moab::MBEDGE, moab::MBMAXTYPE};
00017 const moab::EntityType* EdgeMesher::output_types()
00018   { return EdgeMesher_tps; }
00019 
00020 //---------------------------------------------------------------------------//
00021 // Construction Function for Edge Mesher
00022 EdgeMesher::EdgeMesher(MKCore *mk_core, const MEntVector &me_vec) 
00023         : MeshScheme(mk_core, me_vec), schemeType(EQUAL), ratio(1.2)
00024 {
00025 
00026 }
00027 #if 0
00028 //---------------------------------------------IBERRCHK(g_err, "Trouble get the adjacent geometric nodes on a surface.");------------------------------//
00029 // measure function: compute the distance between the parametric coordinate 
00030 // ustart and the parametric coordinate uend
00031 double EdgeMesher::measure(iGeom::EntityHandle ent, double ustart, double uend) const
00032 {
00033         double umin, umax;
00034 
00035         //get the minimal and maximal parametrical coordinates of the edge
00036         iGeom::Error err = mk_core()->igeom_instance()->getEntURange(ent, umin, umax);
00037         IBERRCHK(err, "Trouble getting parameter range for edge.");
00038 
00039         if (umin == umax) throw Error(MK_BAD_GEOMETRIC_EVALUATION, "Edge evaluated to same parameter umax and umin.");
00040 
00041         //compute the distance for edges
00042         double measure;
00043         err = mk_core()->igeom_instance()->measure(&ent, 1, &measure);
00044 
00045         IBERRCHK(err, "Trouble getting edge measure.");
00046 
00047         return measure * (uend - ustart) / (umax - umin);
00048 }
00049 #endif
00050 //---------------------------------------------------------------------------//
00051 // setup function: set up the number of intervals for edge meshing through the 
00052 // sizing function
00053 void EdgeMesher::setup_this()
00054 {
00055     //compute the number of intervals for the associated ModelEnts, from the size set on them
00056     //the sizing function they point to, or a default sizing function
00057   for (MEntSelection::iterator mit = mentSelection.begin(); mit != mentSelection.end(); mit++)
00058   {
00059     ModelEnt *me = mit->first;
00060 
00061       //first check to see whether entity is meshed
00062     if (me->get_meshed_state() >= COMPLETE_MESH || me->mesh_intervals() > 0)
00063       continue;
00064     
00065     SizingFunction *sf = mk_core()->sizing_function(me->sizing_function_index());
00066     if (!sf && me -> mesh_intervals() < 0 && me -> interval_firmness() == DEFAULT &&
00067         mk_core()->sizing_function(0))
00068     {
00069       sf = mk_core()->sizing_function(0);
00070       me->sizing_function_index(0);
00071     }
00072     
00073     if (!sf && me -> mesh_intervals() < 0 && me -> interval_firmness() == DEFAULT)
00074     {
00075         //no sizing set, just assume default #intervals as 4
00076       me->mesh_intervals(4);
00077       me->interval_firmness(DEFAULT);
00078     }
00079     else
00080     {
00081         //check # intervals first, then size, and just choose for now
00082       if (sf->intervals() > 0)
00083       {
00084         if (me->constrain_even() && sf->intervals()%2)
00085           me -> mesh_intervals(sf->intervals()+1);
00086         else
00087           me -> mesh_intervals(sf->intervals());
00088         me -> interval_firmness(HARD);
00089       }
00090       else if (sf->size()>0)
00091       {
00092         int intervals = me->measure()/sf->size();
00093         if (!intervals) intervals++;
00094         if (me->constrain_even() && intervals%2) intervals++;
00095         me->mesh_intervals(intervals);
00096         me->interval_firmness(SOFT);
00097       }
00098       else
00099         throw Error(MK_INCOMPLETE_MESH_SPECIFICATION,  "Sizing function for edge had neither positive size nor positive intervals.");
00100     }
00101   }
00102 
00103   // now call setup_boundary to treat vertices
00104    // Wrong!!!!!!!!!
00105   // setup_boundary();
00106   /* this is not enough to ensure that vertex mesher will be called before
00107     "this" edge mesher
00108     the case that fell through the cracks was if the end nodes were already setup
00109    then the this_op[0] would not be retrieved, and not inserted "before" the edge mesher MeshOp
00110   */
00111   int dim=0;
00112   MeshOp * vm = (MeshOp*) mk_core()->construct_meshop(dim);
00113 
00114   for (MEntSelection::iterator mit = mentSelection.begin(); mit != mentSelection.end(); mit++)
00115   {
00116     ModelEnt *me = mit->first;
00117     MEntVector children;
00118     me->get_adjacencies(0, children);
00119     for (unsigned int i=0; i<children.size(); i++)
00120       if (children[i]->is_meshops_list_empty())
00121       {
00122         vm->add_modelent(children[i]);
00123       }
00124   }
00125   // in any case, make sure that the vertex mesher is inserted before this edge mesher
00126   mk_core()->insert_node(vm, this, mk_core()->root_node());
00127 
00128 
00129 }
00130 
00131 //---------------------------------------------------------------------------//
00132 // execute function: Generate the mesh for edges
00133 void EdgeMesher::execute_this()
00134 {
00135   std::vector<double> coords;
00136   std::vector<moab::EntityHandle> nodes;
00137 
00138   for (MEntSelection::iterator mit = mentSelection.begin(); mit != mentSelection.end(); mit++)
00139   {
00140     ModelEnt *me = mit -> first;
00141     if (me->get_meshed_state() >= COMPLETE_MESH)
00142         continue;
00143     //resize the coords based on the interval setting
00144     int num_edges = me->mesh_intervals();
00145     coords.resize(3*(num_edges+1));
00146     nodes.clear();
00147     nodes.reserve(num_edges + 1);
00148 
00149     //get bounding mesh entities, use 1st 2 entries of nodes list temporarily
00150     //pick up the boundary end nodes
00151     me->boundary(0, nodes);
00152 
00153     bool periodic = (nodes.size() == 1);
00154     
00155     //get coords in list, then move one tuple to the last position
00156     moab::ErrorCode rval = mk_core()->moab_instance()->get_coords(&nodes[0], nodes.size(), &coords[0]);
00157     MBERRCHK(rval, mk_core()->moab_instance());
00158 
00159     //move the second node to the endmost position in the node list
00160     // if periodic, the last node coordinates are also at index 0 in coords array
00161     // there is only one node, coords[3+i] are not even initialized
00162     int index2 = (periodic) ? 0 : 3;
00163     for (int i = 0; i < 3; i++)
00164       coords[3*num_edges+i] = coords[index2+i];
00165 
00166     EdgeSchemeType scheme = schemeType;
00167     SizingFunction *sz = mk_core()->sizing_function(me->sizing_function_index());
00168     if (sz->variable())
00169       scheme = VARIABLE;
00170 
00171     //choose the scheme for edge mesher
00172     switch(scheme)
00173     {
00174       case EQUAL://equal meshing for edges
00175           EqualMeshing(me, num_edges, coords);
00176           break;
00177       case BIAS://bias meshing for edges
00178           BiasMeshing(me, num_edges, coords);
00179           break;
00180       case DUAL://dual bias meshing for edges
00181           DualBiasMeshing(me, num_edges, coords);
00182           break;
00183       case CURVATURE://curvature-based meshing for edges
00184           CurvatureMeshing(me, num_edges, coords);
00185           break;
00186       case VARIABLE: // use a var size from sizing function
00187           VariableMeshing(me, num_edges, coords);
00188           break;
00189       case EQUIGNOMONIC: // used to generate HOMME type meshes on a sphere
00190           EquiAngleGnomonic(me, num_edges, coords);
00191           break;
00192       default:
00193           break;                        
00194     }
00195     //the variable nodes should be resized, node size may be changed in the different scheme for edge meshing
00196     me->mesh_intervals(num_edges);
00197     nodes.resize(num_edges+1);
00198     
00199     //move the other nodes to the end of nodes' list
00200     if (periodic) nodes[num_edges] = nodes[0];
00201     else nodes[num_edges] = nodes[1];
00202 
00203     //create the vertices' entities on the edge
00204     if (num_edges > 1) {
00205       rval = mk_core()->moab_instance()->create_vertices(&coords[3], num_edges - 1, mit -> second);
00206       MBERRCHK(rval, mk_core()->moab_instance());
00207     }
00208     
00209     //distribute the nodes into vector
00210     int j = 1;
00211     for (moab::Range::iterator rit = mit -> second.begin(); rit != mit -> second.end(); rit++)
00212       nodes[j++] = *rit;
00213 
00214       //get the query interface, which we will use to create the edges directly 
00215     moab::ReadUtilIface *iface;
00216     rval = mk_core() -> moab_instance() -> query_interface(iface);
00217     MBERRCHK(rval, mk_core()->moab_instance());         
00218 
00219       //create the edges, get a direct ptr to connectivity
00220     moab::EntityHandle starth, *connect, *tmp_connect;
00221     rval = iface -> get_element_connect(num_edges, 2, moab::MBEDGE, 1, starth, connect);
00222     MBERRCHK(rval, mk_core()->moab_instance());
00223 
00224       //add edges to range for the MESelection
00225     mit -> second.insert(starth, starth + num_edges - 1);
00226 
00227       //now set the connectivity array from the nodes
00228     tmp_connect = &nodes[0];
00229     for (int i = 0; i < num_edges; i++)
00230     {
00231       connect[0] = tmp_connect[0];
00232       connect[1] = tmp_connect[1];
00233 
00234         //increment connectivity ptr by 2 to go to next edge
00235       connect += 2;
00236                         
00237         //increment tmp_connect by 1, to go to next node
00238       tmp_connect++;
00239     }
00240 
00241       //   ok, we are done, commit to ME
00242     me->commit_mesh(mit->second, COMPLETE_MESH);
00243    
00244         
00245   }
00246 
00247         
00248 }
00249 
00250 //---------------------------------------------------------------------------//
00251 // Deconstruction function
00252 EdgeMesher::~EdgeMesher()
00253 {
00254 
00255 }
00256 
00257 //---------------------------------------------------------------------------//
00258 // Create the mesh for edges with the equal distances
00259 void EdgeMesher::EqualMeshing(ModelEnt *ent, int num_edges, std::vector<double> &coords)
00260 {
00261   double umin, umax, measure;
00262   (void) measure;
00263     //get the u range for the edge
00264   iGeom::Error gerr =  ent->igeom_instance()->getEntURange(ent->geom_handle(), umin, umax);
00265   IBERRCHK(gerr, "Trouble get parameter range for edge.");
00266 
00267   if (umin == umax) throw Error(MK_BAD_GEOMETRIC_EVALUATION, "Edge evaluated to some parameter umax and umin.");
00268 
00269   //get the arc length
00270   measure = ent -> measure();
00271 
00272   double u, du;
00273   if (!num_edges) throw Error(MK_BAD_INPUT, "Trying to mesh edge with zero edges.");
00274   du = (umax - umin)/(double)num_edges;
00275         
00276   u = umin;
00277   //distribute the nodes with equal distances
00278   for (int i = 1; i < num_edges; i++)
00279   {
00280     u = umin + i*du;
00281     gerr = ent->igeom_instance()->getEntUtoXYZ(ent->geom_handle(), u, coords[3*i], coords[3*i+1], coords[3*i+2]);
00282     IBERRCHK(gerr, "Trouble getting U from XYZ along the edge.");
00283   }
00284 
00285 }
00286 
00287 //---------------------------------------------------------------------------//
00288 // Create the mesh for edges based on the curvatures
00289 void EdgeMesher::CurvatureMeshing(ModelEnt *ent, int &num_edges, std::vector<double> &coords)
00290 {
00291   double umin, umax, measure;
00292   (void) measure;
00293   //store the initial edge size, the edge size may be changed during meshing
00294   int initial_num_edges = num_edges;
00295 
00296   //get the u range for the edge
00297   iGeom::Error gerr = ent->igeom_instance() ->getEntURange(ent->geom_handle(), umin, umax);
00298   IBERRCHK(gerr, "Trouble get parameter range for edge.");
00299 
00300   if (umin == umax) throw Error(MK_BAD_GEOMETRIC_EVALUATION, "Edge evaluated to some parameter umax and umin.");
00301 
00302   //get the arc length
00303   measure = ent -> measure();
00304 
00305   int index = 0;
00306   double u, du, uMid;
00307   du = (umax - umin)/(double)num_edges;
00308         
00309   std::vector<double> NodeCoordinates;
00310   std::vector<double> TempNode;
00311   std::vector<double> URecord;          //record the value of U
00312 
00313   Point3D pts0, pts1, ptsMid;
00314   double tmp[3];
00315 
00316   NodeCoordinates.resize(3*(num_edges + 1));
00317 
00318   TempNode.resize(3*1);
00319   URecord.resize(1);    
00320 
00321   gerr = ent -> igeom_instance() -> getEntUtoXYZ(ent->geom_handle(), umin, TempNode[0], TempNode[1], TempNode[2]);
00322   IBERRCHK(gerr, "Trouble getting U from XYZ along the edge");
00323         
00324   NodeCoordinates[3*0] = TempNode[0];
00325   NodeCoordinates[3*0+1] = TempNode[1];
00326   NodeCoordinates[3*0+2] = TempNode[2];
00327 
00328   URecord[0] = umin;
00329 
00330   u = umin;
00331   //distribute the mesh nodes on the edge based on the curvature
00332   for (int i = 1; i < num_edges; i++)
00333   {
00334     //first distribute the nodes evenly
00335     u = umin + i*du;
00336     gerr = ent->igeom_instance()->getEntUtoXYZ(ent->geom_handle(), u, NodeCoordinates[3*i], NodeCoordinates[3*i+1], NodeCoordinates[3*i+2]);
00337     IBERRCHK(gerr, "Trouble getting U from XYZ along the edge.");
00338 
00339     //store the two adjacent mesh nodes on the edge
00340     pts0.px = NodeCoordinates[3*(i-1)];
00341     pts0.py = NodeCoordinates[3*(i-1)+1];
00342     pts0.pz = NodeCoordinates[3*(i-1)+2];
00343 
00344     pts1.px = NodeCoordinates[3*i];
00345     pts1.py = NodeCoordinates[3*i+1];
00346     pts1.pz = NodeCoordinates[3*i+2];
00347 
00348     //get the coordinates for mid point between two adjacent mesh nodes on the edge
00349     uMid = (u-du+u)/2;
00350     gerr = ent->igeom_instance()->getEntUtoXYZ(ent->geom_handle(), uMid, tmp[0], tmp[1], tmp[2]);
00351     ptsMid.px = tmp[0];
00352     ptsMid.py = tmp[1];
00353     ptsMid.pz = tmp[2];
00354 
00355     //calculate the error and check whether it requires further refinement based on the curvature
00356     if (!ErrorCalculate(ent, pts0, pts1, ptsMid))
00357     {
00358         DivideIntoMore(ent, pts0, ptsMid, pts1, u-du, u, uMid, index, TempNode, URecord);
00359     }
00360     
00361     // add the other end node to the array, get the next two adjacent mesh nodes
00362     index++;
00363     TempNode.resize(3*(index + 1));
00364     URecord.resize(index + 1);
00365     TempNode[3*index] = pts1.px;
00366     TempNode[3*index + 1] = pts1.py;
00367     TempNode[3*index + 2] = pts1.pz;
00368 
00369     URecord[index] = u; 
00370   }
00371 
00372   //sorting the parametrical coordinate data based on the value of u
00373   assert(TempNode.size()== (3*URecord.size()) );
00374         
00375   QuickSorting(TempNode, URecord, URecord.size());
00376   num_edges = URecord.size() - 1;
00377         
00378   //resize the variable coords
00379   coords.resize(3*(num_edges+1));       
00380 
00381   //move the other end node to the endmost of the list
00382   for (int i = 0; i < 3; i++)
00383     coords[3*num_edges+i] = coords[3*initial_num_edges+i];
00384 
00385   //return the mesh nodes       
00386   for (int i = 1; i < num_edges; i++)
00387   {
00388     coords[3*i] = TempNode[3*i];
00389     coords[3*i+1] = TempNode[3*i+1];
00390     coords[3*i+2] = TempNode[3*i+2];
00391   }
00392 
00393 }
00394 
00395 //---------------------------------------------------------------------------//
00396 // Create the mesh for edges with dual bias distances
00397 void EdgeMesher::DualBiasMeshing(ModelEnt *ent, int &num_edges, std::vector<double> &coords)
00398 {
00399   double umin, umax, measure;
00400 
00401     //get the u range for the edge
00402   iGeom::Error gerr = ent->igeom_instance()->getEntURange(ent->geom_handle(), umin, umax);
00403   IBERRCHK(gerr, "Trouble get parameter range for edge.");
00404 
00405   if (umin == umax) throw Error(MK_BAD_GEOMETRIC_EVALUATION, "Edge evaluated to some parameter umax and umin.");
00406 
00407   //get the arc length
00408   measure = ent -> measure();
00409 
00410   double u, L0, dist, u0, u1;
00411         
00412   //if the node # is odd, node # will increase by 1
00413   if ((num_edges%2)!=0)
00414   {
00415     num_edges++;
00416     coords.resize(3*(num_edges+1));
00417       //move the other end node's position because the variable coords has been resized.
00418     for (int k = 0; k < 3; k++)
00419       coords[3*num_edges + k] = coords[3*num_edges + k - 3];
00420   }
00421 
00422   //default bias ratio is 1.2
00423   double q = ratio;//
00424         
00425   //get the distance between the first two nodes
00426   L0 = 0.5 * measure * (1-q) / (1 - pow(q, num_edges/2));
00427                 
00428         
00429   u0 = umin;
00430   u1 = umax;
00431   //distribute the mesh nodes on the edge with dual-bias distances
00432   for (int i = 1; i < (num_edges/2 + 1); i++)
00433   {
00434       //distribute the mesh nodes on the one side               
00435     dist = L0*pow(q, i-1);
00436     u = u0 + (umax - umin) * dist/measure;
00437     u = getUCoord(ent, u0, dist, u, umin, umax);
00438     u0 = u;
00439     gerr = ent->igeom_instance()->getEntUtoXYZ(ent->geom_handle(), u, coords[3*i], coords[3*i+1], coords[3*i+2]);
00440     IBERRCHK(gerr, "Trouble getting U from XYZ along the edge.");
00441 
00442     //distribute the mesh nodes on the other side
00443     if (i < num_edges/2)
00444     {
00445       u = u1 - (umax-umin) * dist / measure;
00446       u = getUCoord(ent, u1, dist, u, umin, umax);
00447       u1 = u;
00448       gerr = ent->igeom_instance()->getEntUtoXYZ(ent->geom_handle(), u, coords[3*(num_edges-i)], coords[3*(num_edges-i)+1], coords[3*(num_edges-i)+2]);
00449       IBERRCHK(gerr, "Trouble getting U from XYZ along the edge");
00450     }
00451                 
00452   }
00453         
00454 }
00455 
00456 //---------------------------------------------------------------------------//
00457 // Create the mesh for edges with bias distances
00458 void EdgeMesher::BiasMeshing(ModelEnt *ent, int num_edges, std::vector<double> &coords)
00459 {
00460   double umin, umax, measure;
00461 
00462   //get the u range for the edge
00463   iGeom::Error gerr = ent->igeom_instance()->getEntURange(ent->geom_handle(), umin, umax);
00464   IBERRCHK(gerr, "Trouble get parameter range for edge.");
00465 
00466   if (umin == umax) throw Error(MK_BAD_GEOMETRIC_EVALUATION, "Edge evaluated to some parameter umax and umin.");
00467 
00468   //get the arc length
00469   measure = ent -> measure();
00470 
00471   double u, L0, dist = 0, u0;
00472         
00473   // the default bias ratio 1.2
00474   double q = ratio;
00475   L0 = measure * (1-q) / (1 - pow(q, num_edges));
00476                 
00477         
00478   u0 = umin;
00479   //distribute the mesh nodes on the edge with bias distances
00480   for (int i = 1; i < num_edges; i++)
00481   {
00482     dist = L0*pow(q, i-1);
00483     u = u0 + (umax - umin)*dist/measure;
00484     u = getUCoord(ent, u0, dist, u, umin, umax);
00485     u0 = u;
00486     gerr = ent->igeom_instance()->getEntUtoXYZ(ent->geom_handle(), u, coords[3*i], coords[3*i+1], coords[3*i+2]);
00487     IBERRCHK(gerr, "Trouble getting U from XYZ along the edge.");
00488   }
00489 }
00490 
00491 //---------------------------------------------------------------------------//
00492 // Mesh Refinement function based on the curvature: if the error is too big, refine the mesh on the edge
00493 void EdgeMesher::DivideIntoMore(ModelEnt *ent, Point3D p0, Point3D pMid, Point3D p1, double u0, double u1, double uMid, int &index, vector<double> &nodes, vector<double> &URecord)
00494 {
00495   //this is a recursive process, the process continues until the error is smaller than what is required.
00496   //first get two adjacent mesh nodes on the edge and coordinates for mid point between two adjacent nodes.
00497   //then check the left side and right side whether the error is too big nor not
00498   double uu0, uu1, uumid, tmp[3];
00499   Point3D pts0, pts1, ptsMid;
00500         
00501   index++;
00502   nodes.resize(3*(index+1));
00503   URecord.resize(index+1);
00504   nodes[3*index] = pMid.px;
00505   nodes[3*index+1] = pMid.py;
00506   nodes[3*index+2] = pMid.pz;
00507   URecord[index] = uMid;
00508         
00509   //check the left side
00510   uu0=u0;
00511   uu1=uMid;
00512   uumid=(uu0+uu1)/2;
00513   pts0=p0;
00514   pts1=pMid;
00515 
00516 
00517   iGeom::Error gerr = ent->igeom_instance()->getEntUtoXYZ(ent->geom_handle(), uumid, tmp[0], tmp[1], tmp[2]);
00518   IBERRCHK(gerr, "Trouble getting U from XYZ along the edge.");
00519   ptsMid.px = tmp[0];
00520   ptsMid.py = tmp[1];
00521   ptsMid.pz = tmp[2];
00522 
00523   //check the error
00524   if(!ErrorCalculate(ent, pts0, pts1, ptsMid))
00525   {
00526     //further refinement
00527     DivideIntoMore(ent, pts0, ptsMid, pts1, uu0, uu1, uumid, index, nodes, URecord);
00528   }
00529         
00530   //check the right side
00531   uu0 = uMid;
00532   uu1=u1;
00533   uumid=(uu0+uu1)/2;
00534   pts0=pMid;
00535   pts1=p1;
00536   //get the coorindinates for mid point 
00537   gerr = ent->igeom_instance()->getEntUtoXYZ(ent->geom_handle(), uumid, tmp[0], tmp[1], tmp[2]);
00538   IBERRCHK(gerr, "Trouble getting U from XYZ along the edge.");
00539   ptsMid.px = tmp[0];
00540   ptsMid.py = tmp[1];
00541   ptsMid.pz = tmp[2];
00542         
00543   //check the error
00544   if(!ErrorCalculate(ent, pts0, pts1, ptsMid))
00545   {
00546     //further refinement
00547     DivideIntoMore(ent, pts0, ptsMid, pts1, uu0, uu1, uumid, index, nodes, URecord);
00548   }
00549                         
00550 }
00551 
00552 //create the mesh for edges based on variable size from SizingFunction (var)
00553 void EdgeMesher::VariableMeshing(ModelEnt *ent, int &num_edges, std::vector<double> &coords)
00554 {
00555   double umin, umax, measure;
00556   (void) measure;
00557   // because of that, keep track of the first node position and last node position
00558   // first node position does not change, but the last node position do change
00559   // coords will contain all nodes, including umax in Urecord!
00560 
00561   SizingFunction *sf = mk_core()->sizing_function(ent->sizing_function_index());
00562   //get the u range for the edge
00563   iGeom::EntityHandle edge = ent->geom_handle();
00564   iGeom::Error gerr = ent->igeom_instance() ->getEntURange(edge, umin, umax);
00565   IBERRCHK(gerr, "Trouble get parameter range for edge.");
00566 
00567   if (umin == umax) throw Error(MK_BAD_GEOMETRIC_EVALUATION, "Edge evaluated to some parameter umax and umin.");
00568 
00569   //get the arc length
00570   measure = ent -> measure();
00571 
00572   // start advancing for each edge mesh, from the first point position
00573   double currentPar = umin;
00574   double currentPosition[3];
00575   gerr = ent->igeom_instance() ->getEntUtoXYZ(edge, umin, currentPosition[0],
00576       currentPosition[1], currentPosition[2] );
00577 
00578   double endPoint[3];
00579   gerr = ent->igeom_instance() ->getEntUtoXYZ(edge, umax, endPoint[0],
00580       endPoint[1], endPoint[2] );
00581   Vector<3> endpt(endPoint);
00582 
00583   double targetSize = sf->size(currentPosition);
00584   double startSize = targetSize;
00585 
00586   double endSize = sf->size(endPoint);
00587   // advance u such that the next point is at "currentSize" distance
00588   // or close to it
00589   // try first with a u that is coming from the (umax-umin)/number of edges
00590   double deltaU = (umax-umin)/num_edges;
00591   //coords.clear(); we do not want to clear, as the first node is still fine
00592   std::vector<double> URecord;    //record the values for u; we may have to adjust all
00593   // of them accordingly, and even add one more if we have some evenify problems.
00594   // keep in mind that size is just a suggestion, number of intervals is more important for
00595   // paver mesher
00596   Vector<3> pt(currentPosition);
00597 
00598   //bool notDone = true;
00599   double prevU = umin;
00600   while (currentPar + 1.1*deltaU < umax)
00601   {
00602     // do some binary search; actually, better, do Newton-Raphson, which should converge
00603     // faster
00604     //
00605     prevU = currentPar;
00606     currentPar += deltaU;
00607     // adjust current par, such that
00608     double point[3];
00609     gerr=ent->igeom_instance()->getEntUtoXYZ(edge, currentPar, point[0], point[1], point[2] );
00610     IBERRCHK(gerr, "Trouble getting position at parameter u.");
00611     Vector<3> ptCandidate(point);
00612     double compSize = length(ptCandidate-pt);
00613     int nit = 0;
00614 
00615     while ( (fabs(1.-compSize/targetSize)> 0.02 ) && (nit < 5))// 2% of the target size
00616     {
00617       // do Newton iteration
00618       double tangent[3];
00619       gerr=ent->igeom_instance() ->getEntTgntU(edge, currentPar, tangent[0], tangent[1], tangent[2] );
00620       IBERRCHK(gerr, "Trouble getting tangent at parameter u.");
00621       Vector<3> tang(tangent);
00622       double dldu = 1./compSize * ((ptCandidate-pt )%tang);
00623       nit++;// increase iteration count
00624       if (dldu!=0.)
00625       {
00626         double deu= (targetSize-compSize)/dldu;
00627         currentPar+=deu;
00628         if (prevU>currentPar)
00629         {
00630           break; // something is wrong
00631         }
00632         if (umax < currentPar)
00633         {
00634           currentPar = umax;
00635           break;
00636         }
00637         ent->igeom_instance()->getEntUtoXYZ(edge, currentPar, point[0], point[1], point[2]);
00638         Vector<3> newPt(point);
00639         compSize = length(newPt-pt);
00640         ptCandidate = newPt;
00641       }
00642 
00643     }
00644     // we have found an acceptable point/param
00645     URecord.push_back(currentPar);
00646     deltaU = currentPar-prevU;// should be greater than 0
00647     pt = ptCandidate;
00648     targetSize = sf->size(pt.data());// a new target size, at the current point
00649 
00650 
00651 
00652   }
00653   // when we are out of here, we need to adjust the URecords, to be more nicely
00654   // distributed; also, look at the evenify again
00655   int sizeU = (int)URecord.size();
00656   if ((sizeU%2==0) && ent->constrain_even() )
00657   {
00658     // add one more
00659     if (sizeU==0)
00660     {
00661       // just add one in the middle, and call it done
00662       URecord.push_back( (umin+umax)/2);
00663     }
00664     else
00665     {
00666       //at least 2 (maybe 4)
00667       double lastDelta = URecord[sizeU-1]-URecord[sizeU-2];
00668       URecord.push_back(URecord[sizeU-1]+lastDelta );
00669     }
00670   }
00671   // now, we have to redistribute, such as the last 2 deltas are about the same
00672   // so, we should have after a little work,
00673   // umin, umin+c*(URecord[0]-umin), ... umin+c*(URecord[size-1]-umin), umax
00674   // what we have now is
00675   // umin, URecord[0], ... ,URecord[size-1], and umax could be even outside or inside
00676   // keep the last sizes equal
00677   //  umin+c(UR[size-2]-umin) + umax = 2*( umin+c*(UR[size-1]-umin))
00678   //  c ( 2*(UR[size-1]-umin) -(UR[size-2]-umin) ) = umax - umin
00679   // c ( 2*UR[size-1] - UR[size-2] - umin ) = umax - umin
00680   // c = (umax-umin)/( 2*UR[size-1] - UR[size-2] - umin)
00681   sizeU = (int)URecord.size();// it may be bigger by one than the last time
00682   if (sizeU == 0)
00683   {
00684     // nothing to do, only one edge to generate
00685   }
00686   else if (sizeU == 1)
00687   {
00688     // put it according to the sizes at ends, and assume a nice variation for u
00689     // (u-umin) / (umax-u) = startSize / endSize
00690     // (u-umin)*endSize = (umax-u) * startSize
00691     // u(endSize+startSize)=(umax*startSize+umin*endSize)
00692     URecord[0] = (umax*startSize+umin*endSize)/(startSize+endSize);
00693 
00694   }
00695   else // sizeU>=2, so we can spread the param a little more, assuming nice
00696     // uniform mapping
00697   {
00698     double c =  (umax-umin)/( 2*URecord[sizeU-1] - URecord[sizeU-2] - umin);
00699     for (int i=0; i<sizeU; i++)
00700       URecord[i] = umin + c*(URecord[i] -umin);// some spreading out
00701   }
00702   // now, we can finally get the points for each U, U's should be spread out nicely
00703   URecord.push_back(umax); // just add the last u, for the end point
00704   //
00705   sizeU = (int) URecord.size(); // new size, after pushing the last u, umax
00706   num_edges = sizeU;// this is the new number of edges; the last one will be the end point
00707   // of the edge, corresponding to umax
00708   coords.resize(3*sizeU+3);
00709   // we already know that at i=0 is the first node, start vertex of edge
00710   // the rest will be computed from u
00711   // even the last one, which is an overkill
00712   for (int i = 1; i <= num_edges; i++)
00713   {
00714     double u = URecord[i-1];
00715     gerr = ent->igeom_instance()->getEntUtoXYZ(edge, u, coords[3*i], coords[3*i+1], coords[3*i+2]);
00716     IBERRCHK(gerr, "Trouble getting U from XYZ along the edge.");
00717   }
00718   return;
00719 
00720 }
00721 // number of edges is input here
00722 //  equal angles are formed at the center of the sphere/cube mesh
00723 // it is close to bias meshing, but not quite
00724 void EdgeMesher::EquiAngleGnomonic(ModelEnt *ent, int num_edges, std::vector<double> &coords)
00725 {
00726   const double MY_PI=3.14159265;
00727   double deltaAngle=MY_PI/num_edges/2;
00728  // double length=ent->measure();// this is an edge
00729   double umin, umax;
00730 
00731   //get the u range for the edge
00732   iGeom::Error gerr = ent->igeom_instance()->getEntURange(ent->geom_handle(), umin, umax);
00733   IBERRCHK(gerr, "Trouble get parameter range for edge.");
00734 
00735   if (umin == umax) throw Error(MK_BAD_GEOMETRIC_EVALUATION, "Edge evaluated to some parameter umax and umin.");
00736 
00737   // consider that the parametrization is very linear
00738   // most of the time u will be from 0 to length of edge, for a cube
00739   double deltau = umax - umin;
00740 
00741   double u = umin;// u will get different values,
00742   // start at u
00743   for (int i = 1; i < num_edges; i++)
00744     {
00745       double betak=i*deltaAngle;
00746       double alfak = MY_PI/4-betak;
00747       double tang_alfak = tan(alfak);
00748       u = umin+deltau/2*(1-tang_alfak);
00749 
00750       gerr = ent->igeom_instance()->getEntUtoXYZ(ent->geom_handle(), u, coords[3*i], coords[3*i+1], coords[3*i+2]);
00751       IBERRCHK(gerr, "Trouble getting U from XYZ along the edge.");
00752     }
00753   return;
00754 }
00755 //---------------------------------------------------------------------------//
00756 // Rapid sorting the mesh nodes on the edge based on the parametric coordinates. This is a recursive
00757 // process
00758 void EdgeMesher::RapidSorting(vector<double> &nodes, vector<double> &URecord, int left, int right)
00759 {
00760   int i, j;
00761   double middle, iTemp;
00762   Point3D TempData;
00763         
00764   middle=URecord[(left+right)/2];
00765   i=left;
00766   j=right;
00767         
00768   do
00769   {
00770       //search the values which are greater than the middle value from the left side            
00771     while((URecord[i] < middle)&&(i<right))
00772     {
00773       i++;
00774     }
00775       //search the values which are greater than the middle value from the right side
00776     while((URecord[j] > middle)&&(j > left))
00777     {
00778       j--;
00779     }
00780     if (i<=j)//find a pair of values
00781     {
00782       iTemp = URecord[i];
00783       URecord[i] = URecord[j];
00784       URecord[j]=iTemp;
00785                         
00786                         
00787       TempData.px = nodes[3*i];
00788       TempData.py = nodes[3*i+1];
00789       TempData.pz = nodes[3*i+2];
00790 
00791       nodes[3*i] = nodes[3*j];
00792       nodes[3*i+1] = nodes[3*j+1];
00793       nodes[3*i+2] = nodes[3*j+2];
00794       nodes[3*j] = TempData.px;
00795       nodes[3*j+1] = TempData.py;
00796       nodes[3*j+2] = TempData.pz;                       
00797                         
00798       i++;
00799       j--;
00800     }
00801   }while(i<=j);
00802   if (left < j)
00803     RapidSorting(nodes, URecord, left, j);
00804   if (right > i)
00805     RapidSorting(nodes, URecord, i, right);     
00806 }
00807 
00808 //---------------------------------------------------------------------------//
00809 // Quick Sorting: this function comes together with the function RapidSorting
00810 void EdgeMesher::QuickSorting(vector<double> &nodes, vector<double> &URecord, int count)
00811 {
00812   RapidSorting(nodes, URecord, 0, count-1);
00813 }
00814 
00815 
00816 //---------------------------------------------------------------------------//
00817 // return the x, y, z coordinates from the parametric coordinates
00818 EdgeMesher::Point3D EdgeMesher::getXYZCoords(ModelEnt *ent, double u) const
00819 {
00820   Point3D pts3D;
00821   double xyz[3];
00822 
00823 
00824   //get the coordinates in the physical space
00825   iGeom::Error gerr = ent->igeom_instance()->getEntUtoXYZ(ent->geom_handle(), u, xyz[0], xyz[1], xyz[2]);
00826   IBERRCHK(gerr, "Trouble getting U from XYZ along the edge."); 
00827 
00828   pts3D.px = xyz[0];
00829   pts3D.py = xyz[1];
00830   pts3D.pz = xyz[2];
00831   return pts3D;
00832 }
00833 
00834 //---------------------------------------------------------------------------//
00835 // get the parametric coordinate based on first parametric coordinate ustart and distance in the physical space
00836 double EdgeMesher::getUCoord(ModelEnt *ent, double ustart, double dist, double uguess, double umin, double umax) const
00837 {
00838 
00839   Point3D p0 = getXYZCoords(ent, ustart);
00840   Point3D p1 = getXYZCoords(ent, uguess);
00841 
00842 
00843   double dx, dy, dz, dl, u=uguess;
00844   double tol = 1.0E-7;
00845   int test=0;
00846 
00847   int ntrials=0;
00848   while(1)
00849   {
00850     dx = p1.px - p0.px;
00851     dy = p1.py - p0.py;
00852     dz = p1.pz - p0.pz;
00853     dl = sqrt(dx * dx + dy * dy + dz * dz);
00854     if ( fabs(dl-dist) < tol) break;
00855                 
00856     u = ustart + (u - ustart) * (dist/dl);
00857     if (u > umax)
00858     {
00859       u=umax;
00860       test++;
00861       if (test>10) break;
00862     }           
00863     if (u < umin)
00864     {           
00865       u=umin;
00866       test++;
00867       if (test>10) break;
00868     }           
00869     p1 = getXYZCoords(ent, u);
00870                 
00871 
00872     if (ntrials++ == 100000)
00873     {
00874       cout << " Warning: Searching for U failed " << endl;
00875     }
00876   }
00877   uguess = u;
00878   return uguess;
00879 }
00880 
00881 //---------------------------------------------------------------------------//
00882 // calculate the error: the distance between the mid point of two adjacent 
00883 // mesh nodes (on the mesh line segments) and mid point on the edge
00884 bool EdgeMesher::ErrorCalculate(ModelEnt *ent, Point3D p0, Point3D p1, Point3D pMid)
00885 {
00886   double lengtha, lengthb, lengthc;
00887   double deltax, deltay, deltaz;
00888   double angle, error, tol=1.0E-3, H;
00889   double cvtr_ijk[3], curvature;
00890   bool result;
00891 
00892   //calculate the distance between the first mesh node and mid point on the edge
00893   deltax = pMid.px-p0.px;
00894   deltay = pMid.py-p0.py;
00895   deltaz = pMid.pz-p0.pz;       
00896   lengtha = sqrt(deltax*deltax + deltay*deltay + deltaz*deltaz);
00897 
00898   //calculate the distance between two adjacent mesh nodes
00899   deltax = p1.px-p0.px;
00900   deltay = p1.py-p0.py;
00901   deltaz = p1.pz-p0.pz; 
00902   lengthb = sqrt(deltax*deltax + deltay*deltay + deltaz*deltaz);
00903 
00904   //calculate the distance between the second mesh node and mid point on the edge
00905   deltax = pMid.px-p1.px;
00906   deltay = pMid.py-p1.py;
00907   deltaz = pMid.pz-p1.pz;       
00908   lengthc = sqrt(deltax*deltax + deltay*deltay + deltaz*deltaz);
00909 
00910   //calculate the angle
00911   angle = acos((lengtha*lengtha + lengthb*lengthb - lengthc*lengthc)/(2*lengtha*lengthb));
00912   H = fabs(lengtha*sin(angle));
00913 
00914   //calculate the curvature     
00915   iGeom::Error gerr = ent->igeom_instance()->getEgCvtrXYZ(ent->geom_handle(), pMid.px, pMid.py, pMid.pz, cvtr_ijk[0], cvtr_ijk[1], cvtr_ijk[2]);
00916   IBERRCHK(gerr, "Trouble getting U from XYZ along the edge.");         
00917   curvature = sqrt(cvtr_ijk[0]*cvtr_ijk[0]+cvtr_ijk[1]*cvtr_ijk[1]+cvtr_ijk[2]*cvtr_ijk[2]);
00918   error= H*curvature;
00919         
00920         
00921   if (error > tol)
00922     result = false;
00923   else
00924     result = true;
00925   return result;                
00926 }
00927 
00928 }
00929 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines