moab
|
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, ¤tEdge, 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, ¤tEdge, 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