moab
SmoothCurve.cpp
Go to the documentation of this file.
00001 /*
00002  * SmoothCurve.cpp
00003  *
00004  */
00005 
00006 #include "SmoothCurve.hpp"
00007 //#include "SmoothVertex.hpp"
00008 #include "SmoothFace.hpp"
00009 #include "assert.h"
00010 #include <iostream>
00011 #include "moab/GeomTopoTool.hpp"
00012 
00013 namespace moab {
00014 
00015 SmoothCurve::SmoothCurve(Interface * mb, EntityHandle curve, GeomTopoTool * gTool ):
00016  _mb(mb), _set(curve), _gtt(gTool)
00017 {
00018   //_mbOut->create_meshset(MESHSET_ORDERED, _oSet);
00019   /*_cmlEdgeMesher = new CMLEdgeMesher (this, CML::STANDARD);
00020    _cmlEdgeMesher->set_sizing_function(CML::LINEAR_SIZING);*/
00021   _leng = 0; // not initialized
00022   _edgeTag = 0; // not initialized
00023 }
00024 SmoothCurve::~SmoothCurve()
00025 {
00026   // TODO Auto-generated destructor stub
00027 }
00028 
00029 double SmoothCurve::arc_length()
00030 {
00031 
00032   return _leng;
00033 }
00034 
00038 bool SmoothCurve::is_parametric()
00039 {
00040   return true;
00041 }
00042 
00048 bool SmoothCurve::is_periodic(double& period)
00049 {
00050   //assert(_ref_edge);
00051   //return _ref_edge->is_periodic(   period);
00052   Range vsets;
00053   _mb->get_child_meshsets(_set, vsets);// num_hops =1
00054   if (vsets.size() == 1)
00055   {
00056     period = _leng;
00057     return true;//  true , especially for ice sheet data
00058   }
00059   return false;
00060 }
00061 
00069 void SmoothCurve::get_param_range(double& u_start, double& u_end)
00070 {
00071   //assert(_ref_edge);
00072   u_start = 0;
00073   u_end = 1.;
00074 
00075   return;
00076 }
00077 
00091 double SmoothCurve::u_from_arc_length(double u_root, double arc_leng)
00092 {
00093 
00094   if (_leng <= 0)
00095     return 0;
00096   return u_root + arc_leng / _leng;
00097 }
00098 
00105 bool SmoothCurve::position_from_u(double u, double& x, double& y, double& z, double * tg)
00106 {
00107 
00108   // _fractions are increasing, so find the
00109   double * ptr = std::lower_bound(&_fractions[0],
00110       &_fractions[_fractions.size()], u);
00111   int index = ptr - &_fractions[0];
00112   double nextFraction = _fractions[index];
00113   double prevFraction = 0;
00114   if (index > 0)
00115   {
00116     prevFraction = _fractions[index - 1];
00117   }
00118   double t = (u - prevFraction) / (nextFraction - prevFraction);
00119 
00120   EntityHandle edge = _entities[index];
00121 
00122   CartVect position, tangent;
00123   ErrorCode rval = evaluate_smooth_edge(edge, t, position, tangent);
00124   if (MB_SUCCESS != rval) return false;
00125   assert(rval==MB_SUCCESS);
00126   x = position[0];
00127   y = position[1];
00128   z = position[2];
00129   if (tg)
00130   {
00131     // we need to do some scaling,
00132     double dtdu = 1/(nextFraction - prevFraction);
00133     tg[0] = tangent[0] * dtdu;
00134     tg[1] = tangent[1] * dtdu;
00135     tg[2] = tangent[2] * dtdu;
00136   }
00137 
00138   return true;
00139 
00140 }
00146 void SmoothCurve::move_to_curve(double& x, double& y, double& z)
00147 {
00148 
00149   // find closest point to the curve, and the parametric position
00150   // must be close by, but how close ???
00151   EntityHandle v;
00152   int edgeIndex;
00153   double u = u_from_position( x,  y,   z, v, edgeIndex);
00154   position_from_u(u, x, y, z);
00155 
00156   return;
00157 }
00158 
00167 double SmoothCurve::u_from_position(double x, double y, double z, EntityHandle & v,
00168     int & edgeIndex)
00169 {
00170   // this is an iterative process, expensive usually
00171   // get first all nodes , and their positions
00172   // find the closest node (and edge), and from there do some
00173   // iterations up to a point
00174   // do not exaggerate with convergence criteria
00175 
00176   v= 0; // we do not have a close by vertex yet
00177   CartVect initialPos(x, y, z);
00178   double u=0;
00179   int nbNodes = (int)_entities.size()*2;// the mesh edges are stored
00180   std::vector<EntityHandle> nodesConnec;
00181   nodesConnec.resize(nbNodes);
00182   ErrorCode rval = this->_mb->get_connectivity(&(_entities[0]), nbNodes/2, nodesConnec);
00183   if (MB_SUCCESS!=rval)
00184   {
00185     std::cout<<"error in getting connectivity\n";
00186     return 0;
00187   }
00188   // collapse nodesConnec, nodes should be in order
00189   for (int k=0; k<nbNodes/2; k++)
00190   {
00191     nodesConnec[k+1] = nodesConnec[2*k+1];
00192   }
00193   int numNodes = nbNodes/2+1;
00194   std::vector<CartVect> coordNodes;
00195   coordNodes.resize(numNodes);
00196 
00197   rval = _mb->get_coords(&(nodesConnec[0]), numNodes, (double*)&(coordNodes[0]));
00198   if (MB_SUCCESS!=rval)
00199   {
00200     std::cout<<"error in getting node positions\n";
00201     return 0;
00202   }
00203   // find the closest node, then find the closest edge, based on closest node
00204 
00205   int indexNode = 0;
00206   double minDist = 1.e30;
00207   // expensive linear search
00208   for (int i=0; i<numNodes; i++)
00209   {
00210     double d1 = (initialPos-coordNodes[i]).length();
00211     if (d1<minDist)
00212     {
00213       indexNode = i;
00214       minDist = d1;
00215     }
00216   }
00217   double tolerance = 0.00001; // what is the unit?
00218   // something reasonable
00219   if (minDist<tolerance)
00220   {
00221     v = nodesConnec[indexNode];
00222     // we are done, just return the proper u (from fractions)
00223     if (indexNode==0)
00224     {
00225       return 0; // first node has u = 0
00226     }
00227     else
00228       return _fractions[indexNode-1]; // fractions[0] > 0!!)
00229   }
00230   // find the mesh edge; could be previous or next edge
00231   edgeIndex = indexNode;// could be the previous one, though!!
00232   if (edgeIndex == numNodes-1)
00233     edgeIndex--;// we have one less edge, and do not worry about next edge
00234   else
00235   {
00236     if (edgeIndex>0)
00237     {
00238       // could be the previous; decide based on distance to the other
00239       // nodes of the 2 connected edges
00240       CartVect  prevNodePos = coordNodes[edgeIndex-1];
00241       CartVect  nextNodePos = coordNodes[edgeIndex+1];
00242       if ( (prevNodePos-initialPos).length_squared() <
00243            (nextNodePos-initialPos).length_squared() )
00244       {
00245         edgeIndex --;
00246       }
00247     }
00248   }
00249   // now, we know for sure that the closest point is somewhere on edgeIndex edge
00250   //
00251 
00252   // do newton iteration for local t between 0 and 1
00253 
00254   // copy from evaluation method
00255   CartVect P[2]; // P0 and P1
00256   CartVect controlPoints[3]; // edge control points
00257   double t4, t3, t2, one_minus_t, one_minus_t2, one_minus_t3, one_minus_t4;
00258 
00259   P[0] = coordNodes[edgeIndex];
00260   P[1] = coordNodes[edgeIndex+1];
00261 
00262   if (0 == _edgeTag)
00263   {
00264     rval = _mb->tag_get_handle("CONTROLEDGE", 9, MB_TYPE_DOUBLE, _edgeTag);
00265     if (rval != MB_SUCCESS)
00266       return 0;
00267   }
00268   rval = _mb->tag_get_data(_edgeTag, &(_entities[edgeIndex]), 1, (double*) &controlPoints[0]);
00269   if (rval != MB_SUCCESS)
00270     return rval;
00271 
00272   // starting point
00273   double tt = 0.5;// between the 2 ends of the edge
00274   int iterations=0;
00275   // find iteratively a better point
00276   int maxIterations = 10; // not too many
00277   CartVect outv;
00278   // we will solve minimize F = 0.5 * ( ini - r(t) )^2
00279   // so solve  F'(t) = 0
00280   // Iteration:  t_ -> t - F'(t)/F"(t)
00281   // F'(t) = r'(t) (ini-r(t) )
00282   // F"(t) = r"(t) (ini-r(t) ) - (r'(t))^2
00283   while (iterations<maxIterations)
00284   //
00285   {
00286     t2 = tt * tt;
00287     t3 = t2 * tt;
00288     t4 = t3 * tt;
00289     one_minus_t = 1. - tt;
00290     one_minus_t2 = one_minus_t * one_minus_t;
00291     one_minus_t3 = one_minus_t2 * one_minus_t;
00292     one_minus_t4 = one_minus_t3 * one_minus_t;
00293 
00294     outv = one_minus_t4 * P[0] + 4. * one_minus_t3 * tt * controlPoints[0] + 6.
00295         * one_minus_t2 * t2 * controlPoints[1] + 4. * one_minus_t * t3
00296         * controlPoints[2] + t4 * P[1];
00297 
00298     CartVect out_tangent = -4.*one_minus_t3*P[0] +
00299               4.*(one_minus_t3 -3.*tt*one_minus_t2)*controlPoints[0] +
00300               12.*(tt*one_minus_t2 - t2*one_minus_t)*controlPoints[1] +
00301               4.*(3.*t2*one_minus_t - t3)*controlPoints[2] +
00302               4.*t3*P[1];
00303 
00304     CartVect second_deriv = 12.*one_minus_t2 * P[0] +
00305         4.*( -3.*one_minus_t2 -3.*one_minus_t2 + 6.*tt * one_minus_t)*controlPoints[0] +
00306         12.*(one_minus_t2 - 4*tt*one_minus_t + t2)*controlPoints[1] +
00307         4.*(6.*tt - 12*t2)*controlPoints[2] +
00308         12.*t2*P[1];
00309     CartVect diff = outv - initialPos;
00310     double F_d =  out_tangent % diff;
00311     double F_dd = second_deriv % diff + out_tangent.length_squared();
00312 
00313     if (0==F_dd)
00314       break;// get out, we found minimum?
00315 
00316     double delta_t = - F_d/F_dd;
00317 
00318     if (fabs(delta_t) < 0.000001)
00319       break;
00320     tt = tt+delta_t;
00321     if (tt<0)
00322     {
00323       tt = 0.;
00324       v = nodesConnec[edgeIndex];// we are at end of mesh edge
00325       break;
00326     }
00327     if (tt>1)
00328     {
00329       tt = 1;
00330       v = nodesConnec[edgeIndex+1];// we are at one end
00331       break;
00332     }
00333     iterations++;
00334   }
00335   // so we have t on the segment, convert to u, which should
00336   // be between _fractions[edgeIndex] numbers
00337   double prevFraction = 0;
00338   if (edgeIndex>0)
00339     prevFraction = _fractions[edgeIndex-1];
00340 
00341   u =prevFraction + tt*(_fractions[edgeIndex] - prevFraction);
00342   return u;
00343 }
00344 
00350 void SmoothCurve::start_coordinates(double& x, double& y, double& z)
00351 {
00352 
00353   int nnodes;
00354   const EntityHandle * conn2;
00355   _mb->get_connectivity(_entities[0], conn2, nnodes);
00356   double c[3];
00357   _mb->get_coords(conn2, 1, c);
00358 
00359   x = c[0];
00360   y = c[1];
00361   z = c[2];
00362 
00363   return;
00364 }
00365 
00371 void SmoothCurve::end_coordinates(double& x, double& y, double& z)
00372 {
00373 
00374   int nnodes;
00375   const EntityHandle * conn2;
00376   _mb->get_connectivity(_entities[_entities.size() - 1], conn2, nnodes);
00377   double c[3];
00378   // careful, the second node here
00379   _mb->get_coords(&conn2[1], 1, c);
00380 
00381   x = c[0];
00382   y = c[1];
00383   z = c[2];
00384   return;
00385 }
00386 
00387 // this will recompute the 2 tangents for each edge, considering the geo edge they are into
00388 void SmoothCurve::compute_tangents_for_each_edge()
00389 {
00390   // will retrieve the edges in each set; they are retrieved in order they were put into, because
00391   // these sets are "MESHSET_ORDERED"
00392   // retrieve the tag handle for the tangents; it should have been created already
00393   // this tangents are computed for the chain of edges that form a geometric edge
00394   // some checks should be performed on the vertices, but we trust the correctness of the model completely
00395   // (like the vertices should match in the chain...)
00396   Tag tangentsTag;
00397   ErrorCode rval = _mb->tag_get_handle("TANGENTS", 6, MB_TYPE_DOUBLE, tangentsTag);
00398   if (rval != MB_SUCCESS)
00399     return; // some error should be thrown
00400   std::vector<EntityHandle> entities;
00401   _mb->get_entities_by_type(_set, MBEDGE, entities); // no recursion!!
00402   // basically, each tangent at a node will depend on previous tangent
00403   int nbEdges = entities.size();
00404   // now, we can advance in the loop
00405   // the only special problem is if the first node coincides with the last node, then we should
00406   // consider the closed loop; or maybe we should look at angles in that case too?
00407   // also, should we look at the 2 semi-circles case? How to decide if we need to continue the "tangents"
00408   // maybe we can do that later, and we can alter the tangents at the feature nodes, in the directions of the loops
00409   // again, do we need to decide the "closed" loop or not? Not yet...
00410   EntityHandle previousEdge = entities[0]; // this is the first edge in the chain
00411   CartVect TP[2]; // tangents for the previous edge
00412   rval = _mb->tag_get_data(tangentsTag, &previousEdge, 1, &TP[0]);// tangents for previous edge
00413   if (rval != MB_SUCCESS)
00414     return; // some error should be thrown
00415   CartVect TC[2]; // tangents for the current edge
00416   EntityHandle currentEdge;
00417   for (int i = 1; i < nbEdges; i++)
00418   {
00419     // current edge will start after first one
00420     currentEdge = entities[i];
00421     rval = _mb->tag_get_data(tangentsTag, &currentEdge, 1, &TC[0]);//
00422     // now compute the new tangent at common vertex; reset tangents for previous edge and current edge
00423     // a little bit of CPU and memory waste, but this is life
00424     CartVect T = 0.5 * TC[0] + 0.5 * TP[1]; //
00425     T.normalize();
00426     TP[1] = T;
00427     rval = _mb->tag_set_data(tangentsTag, &previousEdge, 1, &TP[0]);//
00428     TC[0] = T;
00429     rval = _mb->tag_set_data(tangentsTag, &currentEdge, 1, &TC[0]);//
00430     // now set the next edge
00431     previousEdge = currentEdge;
00432     TP[0] = TC[0];
00433     TP[1] = TC[1];
00434   }
00435   return;
00436 }
00437 
00438 void SmoothCurve::compute_control_points_on_boundary_edges(double ,
00439     std::map<EntityHandle, SmoothFace*> & mapSurfaces, Tag controlPointsTag,
00440     Tag markTag)
00441 {
00442   // these points really need the surfaces they belong to, because the control points on edges
00443   // depend on the normals on surfaces
00444   // the control points are averaged from different surfaces, by simple mean average
00445   // the surfaces have
00446   // do we really need min_dot here?
00447   // first of all, find out the SmoothFace for each surface set that is adjacent here
00448   //GeomTopoTool gTopoTool(_mb);
00449   std::vector<EntityHandle> faces;
00450   std::vector<int> senses;
00451   ErrorCode rval = _gtt->get_senses(_set, faces, senses);
00452   if (MB_SUCCESS != rval)
00453     return;
00454 
00455   // need to find the smooth face attached
00456   unsigned int numSurfacesAdjacent = faces.size();
00457   // get the edges, and then get the
00458   //std::vector<EntityHandle> entities;
00459   _mb->get_entities_by_type(_set, MBEDGE, _entities); // no recursion!!
00460   // each edge has the tangent computed already
00461   Tag tangentsTag;
00462   rval = _mb->tag_get_handle("TANGENTS", 6, MB_TYPE_DOUBLE, tangentsTag);
00463   if (rval != MB_SUCCESS)
00464     return; // some error should be thrown
00465 
00466   // we do not want to search every time
00467   std::vector<SmoothFace*> smoothFaceArray;
00468   unsigned int i = 0;
00469   for (i = 0; i < numSurfacesAdjacent; i++)
00470   {
00471     SmoothFace * sms = mapSurfaces[faces[i]];
00472     smoothFaceArray.push_back(sms);
00473   }
00474 
00475   unsigned int e = 0;
00476   for (e = 0; e < _entities.size(); e++)
00477   {
00478     CartVect zero(0.);
00479     CartVect ctrlP[3] = { zero, zero, zero };// null positions initially
00480     // the control points are averaged from connected faces
00481     EntityHandle edge = _entities[e]; // the edge in the chain
00482 
00483     int nnodes;
00484     const EntityHandle * conn2;
00485     rval = _mb->get_connectivity(edge, conn2, nnodes);
00486     if (rval != MB_SUCCESS || 2 != nnodes)
00487       return;// or continue or return error
00488 
00489     //double coords[6]; // store the coordinates for the nodes
00490     CartVect P[2];
00491     //ErrorCode rval = _mb->get_coords(conn2, 2, coords);
00492     rval = _mb->get_coords(conn2, 2, (double*) &P[0]);
00493     if (rval != MB_SUCCESS)
00494       return;
00495 
00496     CartVect chord = P[1] - P[0];
00497     _leng += chord.length();
00498     _fractions.push_back(_leng);
00499     CartVect N[2];
00500 
00501     //MBCartVect N0(&normalVec[0]);
00502     //MBCartVect N3(&normalVec[3]);
00503     CartVect T[2]; // T0, T3
00504     //if (edge->num_adj_facets() <= 1) {
00505     //stat = compute_curve_tangent(edge, min_dot, T0, T3);
00506     //  if (stat != CUBIT_SUCCESS)
00507     //  return stat;
00508     //} else {
00509     //}
00510     rval = _mb->tag_get_data(tangentsTag, &edge, 1, &T[0]);
00511     if (rval != MB_SUCCESS)
00512       return;
00513 
00514     for (i = 0; i < numSurfacesAdjacent; i++)
00515     {
00516       CartVect controlForEdge[3];
00517       rval = smoothFaceArray[i]->get_normals_for_vertices(conn2, N);
00518       if (rval != MB_SUCCESS)
00519         return;
00520 
00521       rval = smoothFaceArray[i]->init_edge_control_points(P[0], P[1], N[0],
00522           N[1], T[0], T[1], controlForEdge);
00523       if (rval != MB_SUCCESS)
00524         return;
00525 
00526       // accumulate those over faces!!!
00527       for (int j = 0; j < 3; j++)
00528       {
00529         ctrlP[j] += controlForEdge[j];
00530       }
00531     }
00532     // now divide them for the average position!
00533     for (int j = 0; j < 3; j++)
00534     {
00535       ctrlP[j] /= numSurfacesAdjacent;
00536     }
00537     // we are done, set the control points now!
00538     //edge->control_points(ctrl_pts, 4);
00539     rval = _mb->tag_set_data(controlPointsTag, &edge, 1, &ctrlP[0]);
00540     if (rval != MB_SUCCESS)
00541       return;
00542 
00543     this->_edgeTag = controlPointsTag;// this is a tag that will be stored with the edge
00544     // is that a waste of memory or not...
00545     // also mark the edge for later on
00546     unsigned char used = 1;
00547     _mb->tag_set_data(markTag, &edge, 1, &used);
00548   }
00549   // now divide fractions, to make them vary from 0 to 1
00550   assert(_leng>0.);
00551   for (e = 0; e < _entities.size(); e++)
00552     _fractions[e] /= _leng;
00553 
00554 }
00555 
00556 ErrorCode SmoothCurve::evaluate_smooth_edge(EntityHandle eh, double &tt,
00557     CartVect & outv, CartVect & out_tangent)
00558 {
00559   CartVect P[2]; // P0 and P1
00560   CartVect controlPoints[3]; // edge control points
00561   double t4, t3, t2, one_minus_t, one_minus_t2, one_minus_t3, one_minus_t4;
00562 
00563   // project the position to the linear edge
00564   // t is from 0 to 1 only!!
00565   //double tt = (t + 1) * 0.5;
00566   if (tt <= 0.0)
00567     tt = 0.0;
00568   if (tt >= 1.0)
00569     tt = 1.0;
00570 
00571   int nnodes;
00572   const EntityHandle * conn2;
00573   ErrorCode rval = _mb->get_connectivity(eh, conn2, nnodes);
00574   if (rval != MB_SUCCESS)
00575     return rval;
00576 
00577   rval = _mb->get_coords(conn2, 2, (double*) &P[0]);
00578   if (rval != MB_SUCCESS)
00579     return rval;
00580 
00581   if (0 == _edgeTag)
00582   {
00583     rval = _mb->tag_get_handle("CONTROLEDGE", 9, MB_TYPE_DOUBLE, _edgeTag);
00584     if (rval != MB_SUCCESS)
00585       return rval;
00586   }
00587   rval = _mb->tag_get_data(_edgeTag, &eh, 1, (double*) &controlPoints[0]);
00588   if (rval != MB_SUCCESS)
00589     return rval;
00590 
00591   t2 = tt * tt;
00592   t3 = t2 * tt;
00593   t4 = t3 * tt;
00594   one_minus_t = 1. - tt;
00595   one_minus_t2 = one_minus_t * one_minus_t;
00596   one_minus_t3 = one_minus_t2 * one_minus_t;
00597   one_minus_t4 = one_minus_t3 * one_minus_t;
00598 
00599   outv = one_minus_t4 * P[0] + 4. * one_minus_t3 * tt * controlPoints[0] + 6.
00600       * one_minus_t2 * t2 * controlPoints[1] + 4. * one_minus_t * t3
00601       * controlPoints[2] + t4 * P[1];
00602 
00603   out_tangent = -4.*one_minus_t3*P[0] +
00604             4.*(one_minus_t3 -3.*tt*one_minus_t2)*controlPoints[0] +
00605             12.*(tt*one_minus_t2 - t2*one_minus_t)*controlPoints[1] +
00606             4.*(3.*t2*one_minus_t - t3)*controlPoints[2] +
00607             4.*t3*P[1];
00608   return MB_SUCCESS;
00609 }
00610 } // namespace moab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines