MeshKit
1.0
|
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