Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 /* 00002 * IntxUtils.cpp 00003 * 00004 * Created on: Oct 3, 2012 00005 */ 00006 #ifdef _MSC_VER /* windows */ 00007 #define _USE_MATH_DEFINES // For M_PI 00008 #endif 00009 00010 #ifdef WIN32 /* windows */ 00011 #define _USE_MATH_DEFINES // For M_PI 00012 #endif 00013 #include <cmath> 00014 #include <cassert> 00015 #include <iostream> 00016 // this is for sstream 00017 #include <sstream> 00018 00019 #include "moab/IntxMesh/IntxUtils.hpp" 00020 // this is from mbcoupler; maybe it should be moved somewhere in moab src 00021 // right now, add a dependency to mbcoupler 00022 // #include "ElemUtil.hpp" 00023 #include "moab/MergeMesh.hpp" 00024 #include "moab/ReadUtilIface.hpp" 00025 #include "MBTagConventions.hpp" 00026 #define CHECKNEGATIVEAREA 00027 00028 #ifdef CHECKNEGATIVEAREA 00029 #include <iomanip> 00030 #endif 00031 #include <queue> 00032 #include <map> 00033 00034 #ifdef MOAB_HAVE_TEMPESTREMAP 00035 #include "GridElements.h" 00036 #endif 00037 00038 namespace moab 00039 { 00040 00041 #define CORRTAGNAME "__correspondent" 00042 #define MAXEDGES 10 00043 00044 int IntxUtils::borderPointsOfXinY2( double* X, int nX, double* Y, int nY, double* P, int* side, double epsilon_area ) 00045 { 00046 // 2 triangles, 3 corners, is the corner of X in Y? 00047 // Y must have a positive area 00048 /* 00049 */ 00050 int extraPoint = 0; 00051 for( int i = 0; i < nX; i++ ) 00052 { 00053 // compute double the area of all nY triangles formed by a side of Y and a corner of X; if 00054 // one is negative, stop (negative means it is outside; X and Y are all oriented such that 00055 // they are positive oriented; 00056 // if one area is negative, it means it is outside the convex region, for sure) 00057 double* A = X + 2 * i; 00058 00059 int inside = 1; 00060 for( int j = 0; j < nY; j++ ) 00061 { 00062 double* B = Y + 2 * j; 00063 int j1 = ( j + 1 ) % nY; 00064 double* C = Y + 2 * j1; // no copy of data 00065 00066 double area2 = ( B[0] - A[0] ) * ( C[1] - A[1] ) - ( C[0] - A[0] ) * ( B[1] - A[1] ); 00067 if( area2 < -epsilon_area * 200 ) 00068 { 00069 inside = 0; 00070 break; 00071 } 00072 } 00073 if( inside ) 00074 { 00075 side[i] = 1; // so vertex i of X is inside the convex region formed by Y 00076 // so side has nX dimension (first array) 00077 P[extraPoint * 2] = A[0]; 00078 P[extraPoint * 2 + 1] = A[1]; 00079 extraPoint++; 00080 } 00081 } 00082 return extraPoint; 00083 } 00084 00085 // used to order according to angle, so it can remove double easily 00086 struct angleAndIndex 00087 { 00088 double angle; 00089 int index; 00090 }; 00091 00092 bool angleCompare( angleAndIndex lhs, angleAndIndex rhs ) 00093 { 00094 return lhs.angle < rhs.angle; 00095 } 00096 00097 // nP might be modified too, we will remove duplicates if found 00098 int IntxUtils::SortAndRemoveDoubles2( double* P, int& nP, double epsilon_1 ) 00099 { 00100 if( nP < 2 ) return 0; // nothing to do 00101 00102 // center of gravity for the points 00103 double c[2] = {0., 0.}; 00104 int k = 0; 00105 for( k = 0; k < nP; k++ ) 00106 { 00107 c[0] += P[2 * k]; 00108 c[1] += P[2 * k + 1]; 00109 } 00110 c[0] /= nP; 00111 c[1] /= nP; 00112 00113 // how many? we dimensioned P at MAXEDGES*10; so we imply we could have at most 5*MAXEDGES 00114 // intersection points 00115 struct angleAndIndex pairAngleIndex[5 * MAXEDGES]; 00116 00117 for( k = 0; k < nP; k++ ) 00118 { 00119 double x = P[2 * k] - c[0], y = P[2 * k + 1] - c[1]; 00120 if( x != 0. || y != 0. ) 00121 { 00122 pairAngleIndex[k].angle = atan2( y, x ); 00123 } 00124 else 00125 { 00126 pairAngleIndex[k].angle = 0; 00127 // it would mean that the cells are touching at a vertex 00128 } 00129 pairAngleIndex[k].index = k; 00130 } 00131 00132 // this should be faster than the bubble sort we had before 00133 std::sort( pairAngleIndex, pairAngleIndex + nP, angleCompare ); 00134 // copy now to a new double array 00135 double PCopy[10 * MAXEDGES]; // the same dimension as P; very conservative, but faster than 00136 // reallocate for a vector 00137 for( k = 0; k < nP; k++ ) // index will show where it should go now; 00138 { 00139 int ck = pairAngleIndex[k].index; 00140 PCopy[2 * k] = P[2 * ck]; 00141 PCopy[2 * k + 1] = P[2 * ck + 1]; 00142 } 00143 // now copy from PCopy over original P location 00144 std::copy( PCopy, PCopy + 2 * nP, P ); 00145 00146 // eliminate duplicates, finally 00147 00148 int i = 0, j = 1; // the next one; j may advance faster than i 00149 // check the unit 00150 // double epsilon_1 = 1.e-5; // these are cm; 2 points are the same if the distance is less 00151 // than 1.e-5 cm 00152 while( j < nP ) 00153 { 00154 double d2 = dist2( &P[2 * i], &P[2 * j] ); 00155 if( d2 > epsilon_1 ) 00156 { 00157 i++; 00158 P[2 * i] = P[2 * j]; 00159 P[2 * i + 1] = P[2 * j + 1]; 00160 } 00161 j++; 00162 } 00163 // test also the last point with the first one (index 0) 00164 // the first one could be at -PI; last one could be at +PI, according to atan2 span 00165 00166 double d2 = dist2( P, &P[2 * i] ); // check the first and last points (ordered from -pi to +pi) 00167 if( d2 > epsilon_1 ) 00168 { 00169 nP = i + 1; 00170 } 00171 else 00172 nP = i; // effectively delete the last point (that would have been the same with first) 00173 if( nP == 0 ) nP = 1; // we should be left with at least one point we already tested if nP is 0 originally 00174 return 0; 00175 } 00176 00177 // the marks will show what edges of blue intersect the red 00178 00179 ErrorCode IntxUtils::EdgeIntersections2( double* blue, 00180 int nsBlue, 00181 double* red, 00182 int nsRed, 00183 int* markb, 00184 int* markr, 00185 double* points, 00186 int& nPoints ) 00187 { 00188 /* EDGEINTERSECTIONS computes edge intersections of two elements 00189 [P,n]=EdgeIntersections(X,Y) computes for the two given elements * red 00190 and blue ( stored column wise ) 00191 (point coordinates are stored column-wise, in counter clock 00192 order) the points P where their edges intersect. In addition, 00193 in n the indices of which neighbors of red are also intersecting 00194 with blue are given. 00195 */ 00196 00197 // points is an array with enough slots (24 * 2 doubles) 00198 nPoints = 0; 00199 for( int i = 0; i < MAXEDGES; i++ ) 00200 { 00201 markb[i] = markr[i] = 0; 00202 } 00203 00204 for( int i = 0; i < nsBlue; i++ ) 00205 { 00206 for( int j = 0; j < nsRed; j++ ) 00207 { 00208 double b[2]; 00209 double a[2][2]; // 2*2 00210 int iPlus1 = ( i + 1 ) % nsBlue; 00211 int jPlus1 = ( j + 1 ) % nsRed; 00212 for( int k = 0; k < 2; k++ ) 00213 { 00214 b[k] = red[2 * j + k] - blue[2 * i + k]; 00215 // row k of a: a(k, 0), a(k, 1) 00216 a[k][0] = blue[2 * iPlus1 + k] - blue[2 * i + k]; 00217 a[k][1] = red[2 * j + k] - red[2 * jPlus1 + k]; 00218 } 00219 double delta = a[0][0] * a[1][1] - a[0][1] * a[1][0]; 00220 if( fabs( delta ) > 1.e-14 ) // this is close to machine epsilon 00221 { 00222 // not parallel 00223 double alfa = ( b[0] * a[1][1] - a[0][1] * b[1] ) / delta; 00224 double beta = ( -b[0] * a[1][0] + b[1] * a[0][0] ) / delta; 00225 if( 0 <= alfa && alfa <= 1. && 0 <= beta && beta <= 1. ) 00226 { 00227 // the intersection is good 00228 for( int k = 0; k < 2; k++ ) 00229 { 00230 points[2 * nPoints + k] = blue[2 * i + k] + alfa * ( blue[2 * iPlus1 + k] - blue[2 * i + k] ); 00231 } 00232 markb[i] = 1; // so neighbor number i of blue will be considered too. 00233 markr[j] = 1; // this will be used in advancing red around blue quad 00234 nPoints++; 00235 } 00236 } 00237 // the case delta ~ 0. will be considered by the interior points logic 00238 } 00239 } 00240 return MB_SUCCESS; 00241 } 00242 00243 // special one, for intersection between rll (constant latitude) and cs quads 00244 ErrorCode IntxUtils::EdgeIntxRllCs( double* blue, 00245 CartVect* bluec, 00246 int* blueEdgeType, 00247 int nsBlue, 00248 double* red, 00249 CartVect* redc, 00250 int nsRed, 00251 int* markb, 00252 int* markr, 00253 int plane, 00254 double R, 00255 double* points, 00256 int& nPoints ) 00257 { 00258 // if blue edge type is 1, intersect in 3d then project to 2d by gnomonic projection 00259 // everything else the same (except if there are 2 points resulting, which is rare) 00260 for( int i = 0; i < 4; i++ ) 00261 { // always at most 4 , so maybe don't bother 00262 markb[i] = markr[i] = 0; 00263 } 00264 00265 for( int i = 0; i < nsBlue; i++ ) 00266 { 00267 int iPlus1 = ( i + 1 ) % nsBlue; 00268 if( blueEdgeType[i] == 0 ) // old style, just 2d 00269 { 00270 for( int j = 0; j < nsRed; j++ ) 00271 { 00272 double b[2]; 00273 double a[2][2]; // 2*2 00274 00275 int jPlus1 = ( j + 1 ) % nsRed; 00276 for( int k = 0; k < 2; k++ ) 00277 { 00278 b[k] = red[2 * j + k] - blue[2 * i + k]; 00279 // row k of a: a(k, 0), a(k, 1) 00280 a[k][0] = blue[2 * iPlus1 + k] - blue[2 * i + k]; 00281 a[k][1] = red[2 * j + k] - red[2 * jPlus1 + k]; 00282 } 00283 double delta = a[0][0] * a[1][1] - a[0][1] * a[1][0]; 00284 if( fabs( delta ) > 1.e-14 ) 00285 { 00286 // not parallel 00287 double alfa = ( b[0] * a[1][1] - a[0][1] * b[1] ) / delta; 00288 double beta = ( -b[0] * a[1][0] + b[1] * a[0][0] ) / delta; 00289 if( 0 <= alfa && alfa <= 1. && 0 <= beta && beta <= 1. ) 00290 { 00291 // the intersection is good 00292 for( int k = 0; k < 2; k++ ) 00293 { 00294 points[2 * nPoints + k] = 00295 blue[2 * i + k] + alfa * ( blue[2 * iPlus1 + k] - blue[2 * i + k] ); 00296 } 00297 markb[i] = 1; // so neighbor number i of blue will be considered too. 00298 markr[j] = 1; // this will be used in advancing red around blue quad 00299 nPoints++; 00300 } 00301 } // if the edges are too "parallel", skip them 00302 } 00303 } 00304 else // edge type is 1, so use 3d intersection 00305 { 00306 CartVect& C = bluec[i]; 00307 CartVect& D = bluec[iPlus1]; 00308 for( int j = 0; j < nsRed; j++ ) 00309 { 00310 int jPlus1 = ( j + 1 ) % nsRed; // nsRed is just 4, forget about it, usually 00311 CartVect& A = redc[j]; 00312 CartVect& B = redc[jPlus1]; 00313 int np = 0; 00314 double E[9]; 00315 intersect_great_circle_arc_with_clat_arc( A.array(), B.array(), C.array(), D.array(), R, E, np ); 00316 if( np == 0 ) continue; 00317 if( np >= 2 ) 00318 { 00319 std::cout << "intersection with 2 points :" << A << B << C << D << "\n"; 00320 } 00321 for( int k = 0; k < np; k++ ) 00322 { 00323 gnomonic_projection( CartVect( E + k * 3 ), R, plane, points[2 * nPoints], 00324 points[2 * nPoints + 1] ); 00325 nPoints++; 00326 } 00327 markb[i] = 1; // so neighbor number i of blue will be considered too. 00328 markr[j] = 1; // this will be used in advancing red around blue quad 00329 } 00330 } 00331 } 00332 return MB_SUCCESS; 00333 } 00334 00335 // vec utils related to gnomonic projection on a sphere 00336 00337 // vec utils 00338 00339 /* 00340 * 00341 * position on a sphere of radius R 00342 * if plane specified, use it; if not, return the plane, and the point in the plane 00343 * there are 6 planes, numbered 1 to 6 00344 * plane 1: x=R, plane 2: y=R, 3: x=-R, 4: y=-R, 5: z=-R, 6: z=R 00345 * 00346 * projection on the plane will preserve the orientation, such that a triangle, quad pointing 00347 * outside the sphere will have a positive orientation in the projection plane 00348 */ 00349 void IntxUtils::decide_gnomonic_plane( const CartVect& pos, int& plane ) 00350 { 00351 // decide plane, based on max x, y, z 00352 if( fabs( pos[0] ) < fabs( pos[1] ) ) 00353 { 00354 if( fabs( pos[2] ) < fabs( pos[1] ) ) 00355 { 00356 // pos[1] is biggest 00357 if( pos[1] > 0 ) 00358 plane = 2; 00359 else 00360 plane = 4; 00361 } 00362 else 00363 { 00364 // pos[2] is biggest 00365 if( pos[2] < 0 ) 00366 plane = 5; 00367 else 00368 plane = 6; 00369 } 00370 } 00371 else 00372 { 00373 if( fabs( pos[2] ) < fabs( pos[0] ) ) 00374 { 00375 // pos[0] is the greatest 00376 if( pos[0] > 0 ) 00377 plane = 1; 00378 else 00379 plane = 3; 00380 } 00381 else 00382 { 00383 // pos[2] is biggest 00384 if( pos[2] < 0 ) 00385 plane = 5; 00386 else 00387 plane = 6; 00388 } 00389 } 00390 return; 00391 } 00392 00393 // point on a sphere is projected on one of six planes, decided earlier 00394 ErrorCode IntxUtils::gnomonic_projection( const CartVect& pos, double R, int plane, double& c1, double& c2 ) 00395 { 00396 double alfa = 1.; // the new point will be on line alfa*pos 00397 00398 switch( plane ) 00399 { 00400 case 1: { 00401 // the plane with x = R; x>y, x>z 00402 // c1->y, c2->z 00403 alfa = R / pos[0]; 00404 c1 = alfa * pos[1]; 00405 c2 = alfa * pos[2]; 00406 break; 00407 } 00408 case 2: { 00409 // y = R -> zx 00410 alfa = R / pos[1]; 00411 c1 = alfa * pos[2]; 00412 c2 = alfa * pos[0]; 00413 break; 00414 } 00415 case 3: { 00416 // x=-R, -> yz 00417 alfa = -R / pos[0]; 00418 c1 = -alfa * pos[1]; // the sign is to preserve orientation 00419 c2 = alfa * pos[2]; 00420 break; 00421 } 00422 case 4: { 00423 // y = -R 00424 alfa = -R / pos[1]; 00425 c1 = -alfa * pos[2]; // the sign is to preserve orientation 00426 c2 = alfa * pos[0]; 00427 break; 00428 } 00429 case 5: { 00430 // z = -R 00431 alfa = -R / pos[2]; 00432 c1 = -alfa * pos[0]; // the sign is to preserve orientation 00433 c2 = alfa * pos[1]; 00434 break; 00435 } 00436 case 6: { 00437 alfa = R / pos[2]; 00438 c1 = alfa * pos[0]; 00439 c2 = alfa * pos[1]; 00440 break; 00441 } 00442 default: 00443 return MB_FAILURE; // error 00444 } 00445 00446 return MB_SUCCESS; // no error 00447 } 00448 00449 // given the position on plane (one out of 6), find out the position on sphere 00450 ErrorCode IntxUtils::reverse_gnomonic_projection( const double& c1, 00451 const double& c2, 00452 double R, 00453 int plane, 00454 CartVect& pos ) 00455 { 00456 00457 // the new point will be on line beta*pos 00458 double len = sqrt( c1 * c1 + c2 * c2 + R * R ); 00459 double beta = R / len; // it is less than 1, in general 00460 00461 switch( plane ) 00462 { 00463 case 1: { 00464 // the plane with x = R; x>y, x>z 00465 // c1->y, c2->z 00466 pos[0] = beta * R; 00467 pos[1] = c1 * beta; 00468 pos[2] = c2 * beta; 00469 break; 00470 } 00471 case 2: { 00472 // y = R -> zx 00473 pos[1] = R * beta; 00474 pos[2] = c1 * beta; 00475 pos[0] = c2 * beta; 00476 break; 00477 } 00478 case 3: { 00479 // x=-R, -> yz 00480 pos[0] = -R * beta; 00481 pos[1] = -c1 * beta; // the sign is to preserve orientation 00482 pos[2] = c2 * beta; 00483 break; 00484 } 00485 case 4: { 00486 // y = -R 00487 pos[1] = -R * beta; 00488 pos[2] = -c1 * beta; // the sign is to preserve orientation 00489 pos[0] = c2 * beta; 00490 break; 00491 } 00492 case 5: { 00493 // z = -R 00494 pos[2] = -R * beta; 00495 pos[0] = -c1 * beta; // the sign is to preserve orientation 00496 pos[1] = c2 * beta; 00497 break; 00498 } 00499 case 6: { 00500 pos[2] = R * beta; 00501 pos[0] = c1 * beta; 00502 pos[1] = c2 * beta; 00503 break; 00504 } 00505 default: 00506 return MB_FAILURE; // error 00507 } 00508 00509 return MB_SUCCESS; // no error 00510 } 00511 00512 void IntxUtils::gnomonic_unroll( double& c1, double& c2, double R, int plane ) 00513 { 00514 double tmp; 00515 switch( plane ) 00516 { 00517 case 1: 00518 break; // nothing 00519 case 2: // rotate + 90 00520 tmp = c1; 00521 c1 = -c2; 00522 c2 = tmp; 00523 c1 = c1 + 2 * R; 00524 break; 00525 case 3: 00526 c1 = c1 + 4 * R; 00527 break; 00528 case 4: // rotate with -90 x-> -y; y -> x 00529 00530 tmp = c1; 00531 c1 = c2; 00532 c2 = -tmp; 00533 c1 = c1 - 2 * R; 00534 break; 00535 case 5: // South Pole 00536 // rotate 180 then move to (-2, -2) 00537 c1 = -c1 - 2. * R; 00538 c2 = -c2 - 2. * R; 00539 break; 00540 ; 00541 case 6: // North Pole 00542 c1 = c1 - 2. * R; 00543 c2 = c2 + 2. * R; 00544 break; 00545 } 00546 return; 00547 } 00548 // given a mesh on the sphere, project all centers in 6 gnomonic planes, or project mesh too 00549 ErrorCode IntxUtils::global_gnomonic_projection( Interface* mb, 00550 EntityHandle inSet, 00551 double R, 00552 bool centers_only, 00553 EntityHandle& outSet ) 00554 { 00555 std::string parTagName( "PARALLEL_PARTITION" ); 00556 Tag part_tag; 00557 Range partSets; 00558 ErrorCode rval = mb->tag_get_handle( parTagName.c_str(), part_tag ); 00559 if( MB_SUCCESS == rval && part_tag != 0 ) 00560 { 00561 rval = mb->get_entities_by_type_and_tag( inSet, MBENTITYSET, &part_tag, NULL, 1, partSets, Interface::UNION );MB_CHK_ERR( rval ); 00562 } 00563 rval = ScaleToRadius( mb, inSet, 1.0 );MB_CHK_ERR( rval ); 00564 // Get all entities of dimension 2 00565 Range inputRange; // get 00566 rval = mb->get_entities_by_dimension( inSet, 1, inputRange );MB_CHK_ERR( rval ); 00567 rval = mb->get_entities_by_dimension( inSet, 2, inputRange );MB_CHK_ERR( rval ); 00568 00569 std::map< EntityHandle, int > partsAssign; 00570 std::map< int, EntityHandle > newPartSets; 00571 if( !partSets.empty() ) 00572 { 00573 // get all cells, and assign parts 00574 for( Range::iterator setIt = partSets.begin(); setIt != partSets.end(); ++setIt ) 00575 { 00576 EntityHandle pSet = *setIt; 00577 Range ents; 00578 rval = mb->get_entities_by_handle( pSet, ents );MB_CHK_ERR( rval ); 00579 int val; 00580 rval = mb->tag_get_data( part_tag, &pSet, 1, &val );MB_CHK_ERR( rval ); 00581 // create a new set with the same part id tag, in the outSet 00582 EntityHandle newPartSet; 00583 rval = mb->create_meshset( MESHSET_SET, newPartSet );MB_CHK_ERR( rval ); 00584 rval = mb->tag_set_data( part_tag, &newPartSet, 1, &val );MB_CHK_ERR( rval ); 00585 newPartSets[val] = newPartSet; 00586 rval = mb->add_entities( outSet, &newPartSet, 1 );MB_CHK_ERR( rval ); 00587 for( Range::iterator it = ents.begin(); it != ents.end(); ++it ) 00588 { 00589 partsAssign[*it] = val; 00590 } 00591 } 00592 } 00593 00594 if( centers_only ) 00595 { 00596 for( Range::iterator it = inputRange.begin(); it != inputRange.end(); ++it ) 00597 { 00598 CartVect center; 00599 EntityHandle cell = *it; 00600 rval = mb->get_coords( &cell, 1, center.array() );MB_CHK_ERR( rval ); 00601 int plane; 00602 decide_gnomonic_plane( center, plane ); 00603 double c[3]; 00604 c[2] = 0.; 00605 gnomonic_projection( center, R, plane, c[0], c[1] ); 00606 00607 gnomonic_unroll( c[0], c[1], R, plane ); 00608 00609 EntityHandle vertex; 00610 rval = mb->create_vertex( c, vertex );MB_CHK_ERR( rval ); 00611 rval = mb->add_entities( outSet, &vertex, 1 );MB_CHK_ERR( rval ); 00612 } 00613 } 00614 else 00615 { 00616 // distribute the cells to 6 planes, based on the center 00617 Range subranges[6]; 00618 for( Range::iterator it = inputRange.begin(); it != inputRange.end(); ++it ) 00619 { 00620 CartVect center; 00621 EntityHandle cell = *it; 00622 rval = mb->get_coords( &cell, 1, center.array() );MB_CHK_ERR( rval ); 00623 int plane; 00624 decide_gnomonic_plane( center, plane ); 00625 subranges[plane - 1].insert( cell ); 00626 } 00627 for( int i = 1; i <= 6; i++ ) 00628 { 00629 Range verts; 00630 rval = mb->get_connectivity( subranges[i - 1], verts );MB_CHK_ERR( rval ); 00631 std::map< EntityHandle, EntityHandle > corr; 00632 for( Range::iterator vt = verts.begin(); vt != verts.end(); ++vt ) 00633 { 00634 CartVect vect; 00635 EntityHandle v = *vt; 00636 rval = mb->get_coords( &v, 1, vect.array() );MB_CHK_ERR( rval ); 00637 double c[3]; 00638 c[2] = 0.; 00639 gnomonic_projection( vect, R, i, c[0], c[1] ); 00640 gnomonic_unroll( c[0], c[1], R, i ); 00641 EntityHandle vertex; 00642 rval = mb->create_vertex( c, vertex );MB_CHK_ERR( rval ); 00643 corr[v] = vertex; // for new connectivity 00644 } 00645 EntityHandle new_conn[20]; // max edges in 2d ? 00646 for( Range::iterator eit = subranges[i - 1].begin(); eit != subranges[i - 1].end(); ++eit ) 00647 { 00648 EntityHandle eh = *eit; 00649 const EntityHandle* conn = NULL; 00650 int num_nodes; 00651 rval = mb->get_connectivity( eh, conn, num_nodes );MB_CHK_ERR( rval ); 00652 // build a new vertex array 00653 for( int j = 0; j < num_nodes; j++ ) 00654 new_conn[j] = corr[conn[j]]; 00655 EntityType type = mb->type_from_handle( eh ); 00656 EntityHandle newCell; 00657 rval = mb->create_element( type, new_conn, num_nodes, newCell );MB_CHK_ERR( rval ); 00658 rval = mb->add_entities( outSet, &newCell, 1 );MB_CHK_ERR( rval ); 00659 std::map< EntityHandle, int >::iterator mit = partsAssign.find( eh ); 00660 if( mit != partsAssign.end() ) 00661 { 00662 int val = mit->second; 00663 rval = mb->add_entities( newPartSets[val], &newCell, 1 );MB_CHK_ERR( rval ); 00664 } 00665 } 00666 } 00667 } 00668 00669 return MB_SUCCESS; 00670 } 00671 void IntxUtils::transform_coordinates( double* avg_position, int projection_type ) 00672 { 00673 if( projection_type == 1 ) 00674 { 00675 double R = 00676 avg_position[0] * avg_position[0] + avg_position[1] * avg_position[1] + avg_position[2] * avg_position[2]; 00677 R = sqrt( R ); 00678 double lat = asin( avg_position[2] / R ); 00679 double lon = atan2( avg_position[1], avg_position[0] ); 00680 avg_position[0] = lon; 00681 avg_position[1] = lat; 00682 avg_position[2] = R; 00683 } 00684 else if( projection_type == 2 ) // gnomonic projection 00685 { 00686 CartVect pos( avg_position ); 00687 int gplane; 00688 IntxUtils::decide_gnomonic_plane( pos, gplane ); 00689 00690 IntxUtils::gnomonic_projection( pos, 1.0, gplane, avg_position[0], avg_position[1] ); 00691 avg_position[2] = 0; 00692 IntxUtils::gnomonic_unroll( avg_position[0], avg_position[1], 1.0, gplane ); 00693 } 00694 } 00695 /* 00696 * 00697 use physical_constants, only : dd_pi 00698 type(cartesian3D_t), intent(in) :: cart 00699 type(spherical_polar_t) :: sphere 00700 00701 sphere%r=distance(cart) 00702 sphere%lat=ASIN(cart%z/sphere%r) 00703 sphere%lon=0 00704 00705 ! ========================================================== 00706 ! enforce three facts: 00707 ! 00708 ! 1) lon at poles is defined to be zero 00709 ! 00710 ! 2) Grid points must be separated by about .01 Meter (on earth) 00711 ! from pole to be considered "not the pole". 00712 ! 00713 ! 3) range of lon is { 0<= lon < 2*pi } 00714 ! 00715 ! ========================================================== 00716 00717 if (distance(cart) >= DIST_THRESHOLD) then 00718 sphere%lon=ATAN2(cart%y,cart%x) 00719 if (sphere%lon<0) then 00720 sphere%lon=sphere%lon+2*DD_PI 00721 end if 00722 end if 00723 00724 end function cart_to_spherical 00725 */ 00726 IntxUtils::SphereCoords IntxUtils::cart_to_spherical( CartVect& cart3d ) 00727 { 00728 SphereCoords res; 00729 res.R = cart3d.length(); 00730 if( res.R < 0 ) 00731 { 00732 res.lon = res.lat = 0.; 00733 return res; 00734 } 00735 res.lat = asin( cart3d[2] / res.R ); 00736 res.lon = atan2( cart3d[1], cart3d[0] ); 00737 if( res.lon < 0 ) res.lon += 2 * M_PI; // M_PI is defined in math.h? it seems to be true, although 00738 // there are some defines it depends on :( 00739 // #if defined __USE_BSD || defined __USE_XOPEN ??? 00740 00741 return res; 00742 } 00743 00744 /* 00745 * ! =================================================================== 00746 ! spherical_to_cart: 00747 ! converts spherical polar {lon,lat} to 3D cartesian {x,y,z} 00748 ! on unit sphere 00749 ! =================================================================== 00750 00751 function spherical_to_cart(sphere) result (cart) 00752 00753 type(spherical_polar_t), intent(in) :: sphere 00754 type(cartesian3D_t) :: cart 00755 00756 cart%x=sphere%r*COS(sphere%lat)*COS(sphere%lon) 00757 cart%y=sphere%r*COS(sphere%lat)*SIN(sphere%lon) 00758 cart%z=sphere%r*SIN(sphere%lat) 00759 00760 end function spherical_to_cart 00761 */ 00762 CartVect IntxUtils::spherical_to_cart( IntxUtils::SphereCoords& sc ) 00763 { 00764 CartVect res; 00765 res[0] = sc.R * cos( sc.lat ) * cos( sc.lon ); // x coordinate 00766 res[1] = sc.R * cos( sc.lat ) * sin( sc.lon ); // y 00767 res[2] = sc.R * sin( sc.lat ); // z 00768 return res; 00769 } 00770 00771 ErrorCode IntxUtils::ScaleToRadius( Interface* mb, EntityHandle set, double R ) 00772 { 00773 Range nodes; 00774 ErrorCode rval = mb->get_entities_by_type( set, MBVERTEX, nodes, true ); // recursive 00775 if( rval != moab::MB_SUCCESS ) return rval; 00776 00777 // one by one, get the node and project it on the sphere, with a radius given 00778 // the center of the sphere is at 0,0,0 00779 for( Range::iterator nit = nodes.begin(); nit != nodes.end(); ++nit ) 00780 { 00781 EntityHandle nd = *nit; 00782 CartVect pos; 00783 rval = mb->get_coords( &nd, 1, (double*)&( pos[0] ) ); 00784 if( rval != moab::MB_SUCCESS ) return rval; 00785 double len = pos.length(); 00786 if( len == 0. ) return MB_FAILURE; 00787 pos = R / len * pos; 00788 rval = mb->set_coords( &nd, 1, (double*)&( pos[0] ) ); 00789 if( rval != moab::MB_SUCCESS ) return rval; 00790 } 00791 return MB_SUCCESS; 00792 } 00793 00794 // assume they are one the same sphere 00795 double IntxAreaUtils::spherical_angle( double* A, double* B, double* C, double Radius ) 00796 { 00797 // the angle by definition is between the planes OAB and OBC 00798 CartVect a( A ); 00799 CartVect b( B ); 00800 CartVect c( C ); 00801 double err1 = a.length_squared() - Radius * Radius; 00802 if( fabs( err1 ) > 0.0001 ) 00803 { 00804 std::cout << " error in input " << a << " radius: " << Radius << " error:" << err1 << "\n"; 00805 } 00806 CartVect normalOAB = a * b; 00807 CartVect normalOCB = c * b; 00808 return angle( normalOAB, normalOCB ); 00809 } 00810 00811 // could be bigger than M_PI; 00812 // angle at B could be bigger than M_PI, if the orientation is such that ABC points toward the 00813 // interior 00814 double IntxUtils::oriented_spherical_angle( double* A, double* B, double* C ) 00815 { 00816 // assume the same radius, sphere at origin 00817 CartVect a( A ), b( B ), c( C ); 00818 CartVect normalOAB = a * b; 00819 CartVect normalOCB = c * b; 00820 CartVect orient = ( c - b ) * ( a - b ); 00821 double ang = angle( normalOAB, normalOCB ); // this is between 0 and M_PI 00822 if( ang != ang ) 00823 { 00824 // signal of a nan 00825 std::cout << a << " " << b << " " << c << "\n"; 00826 std::cout << ang << "\n"; 00827 } 00828 if( orient % b < 0 ) return ( 2 * M_PI - ang ); // the other angle, supplement 00829 00830 return ang; 00831 } 00832 00833 double IntxAreaUtils::area_spherical_triangle( double* A, double* B, double* C, double Radius, int rank ) 00834 { 00835 switch( m_eAreaMethod ) 00836 { 00837 case Girard: 00838 return area_spherical_triangle_girard( A, B, C, Radius ); 00839 #ifdef MOAB_HAVE_TEMPESTREMAP 00840 case GaussQuadrature: 00841 return area_spherical_triangle_GQ( A, B, C, Radius ); 00842 #endif 00843 case lHuiller: 00844 default: 00845 return area_spherical_triangle_lHuiller( A, B, C, Radius, rank ); 00846 } 00847 } 00848 00849 double IntxAreaUtils::area_spherical_polygon( double* A, int N, double Radius, int* sign, int rank ) 00850 { 00851 switch( m_eAreaMethod ) 00852 { 00853 case Girard: 00854 return area_spherical_polygon_girard( A, N, Radius ); 00855 #ifdef MOAB_HAVE_TEMPESTREMAP 00856 case GaussQuadrature: 00857 return area_spherical_polygon_GQ( A, N, Radius ); 00858 #endif 00859 case lHuiller: 00860 default: 00861 return area_spherical_polygon_lHuiller( A, N, Radius, sign, rank ); 00862 } 00863 } 00864 00865 double IntxAreaUtils::area_spherical_triangle_girard( double* A, double* B, double* C, double Radius ) 00866 { 00867 double correction = spherical_angle( A, B, C, Radius ) + spherical_angle( B, C, A, Radius ) + 00868 spherical_angle( C, A, B, Radius ) - M_PI; 00869 double area = Radius * Radius * correction; 00870 // now, is it negative or positive? is it pointing toward the center or outward? 00871 CartVect a( A ), b( B ), c( C ); 00872 CartVect abc = ( b - a ) * ( c - a ); 00873 if( abc % a > 0 ) // dot product positive, means ABC points out 00874 return area; 00875 else 00876 return -area; 00877 } 00878 00879 double IntxAreaUtils::area_spherical_polygon_girard( double* A, int N, double Radius ) 00880 { 00881 // this should work for non-convex polygons too 00882 // assume that the A, A+3, ..., A+3*(N-1) are the coordinates 00883 // 00884 if( N <= 2 ) return 0.; 00885 double sum_angles = 0.; 00886 for( int i = 0; i < N; i++ ) 00887 { 00888 int i1 = ( i + 1 ) % N; 00889 int i2 = ( i + 2 ) % N; 00890 sum_angles += IntxUtils::oriented_spherical_angle( A + 3 * i, A + 3 * i1, A + 3 * i2 ); 00891 } 00892 double correction = sum_angles - ( N - 2 ) * M_PI; 00893 return Radius * Radius * correction; 00894 } 00895 00896 double IntxAreaUtils::area_spherical_polygon_lHuiller( double* A, int N, double Radius, int* sign, int rank ) 00897 { 00898 // This should work for non-convex polygons too 00899 // In the input vector A, assume that the A, A+3, ..., A+3*(N-1) are the coordinates 00900 // We also assume that the orientation is positive; 00901 // If negative orientation, the area will be negative 00902 if( N <= 2 ) return 0.; 00903 00904 int lsign = 1; // assume positive orientation 00905 double area = 0.; 00906 for( int i = 1; i < N - 1; i++ ) 00907 { 00908 int i1 = i + 1; 00909 double areaTriangle = area_spherical_triangle_lHuiller( A, A + 3 * i, A + 3 * i1, Radius, rank ); 00910 if( areaTriangle < 0 ) 00911 lsign = -1; // signal that we have at least one triangle with negative orientation ; 00912 // possible nonconvex polygon 00913 area += areaTriangle; 00914 } 00915 if( sign ) *sign = lsign; 00916 00917 return area; 00918 } 00919 00920 #ifdef MOAB_HAVE_TEMPESTREMAP 00921 double IntxAreaUtils::area_spherical_polygon_GQ( double* A, int N, double Radius ) 00922 { 00923 // this should work for non-convex polygons too 00924 // In the input vector A, assume that the A, A+3, ..., A+3*(N-1) are the coordinates 00925 // We also assume that the orientation is positive; 00926 // If negative orientation, the area can be negative 00927 if( N <= 2 ) return 0.; 00928 00929 // assume positive orientain 00930 double area = 0.; 00931 for( int i = 1; i < N - 1; i++ ) 00932 { 00933 int i1 = i + 1; 00934 area += area_spherical_triangle_GQ( A, A + 3 * i, A + 3 * i1, Radius ); 00935 } 00936 return area; 00937 } 00938 00939 /* compute the area by using Gauss-Quadratures; use TR interfaces directly */ 00940 double IntxAreaUtils::area_spherical_triangle_GQ( double* ptA, double* ptB, double* ptC, double ) 00941 { 00942 Face face( 3 ); 00943 NodeVector nodes( 3 ); 00944 nodes[0] = Node( ptA[0], ptA[1], ptA[2] ); 00945 nodes[1] = Node( ptB[0], ptB[1], ptB[2] ); 00946 nodes[2] = Node( ptC[0], ptC[1], ptC[2] ); 00947 face.SetNode( 0, 0 ); 00948 face.SetNode( 1, 1 ); 00949 face.SetNode( 2, 2 ); 00950 return CalculateFaceArea( face, nodes ); 00951 } 00952 #endif 00953 00954 /* 00955 * l'Huiller's formula for spherical triangle 00956 * http://williams.best.vwh.net/avform.htm 00957 * a, b, c are arc measures in radians, too 00958 * A, B, C are angles on the sphere, for which we already have formula 00959 * c 00960 * A -------B 00961 * \ | 00962 * \ | 00963 * \b |a 00964 * \ | 00965 * \ | 00966 * \ | 00967 * \C| 00968 * \| 00969 * 00970 * (The angle at B is not necessarily a right angle) 00971 * 00972 * sin(a) sin(b) sin(c) 00973 * ----- = ------ = ------ 00974 * sin(A) sin(B) sin(C) 00975 * 00976 * In terms of the sides (this is excess, as before, but numerically stable) 00977 * 00978 * E = 4*atan(sqrt(tan(s/2)*tan((s-a)/2)*tan((s-b)/2)*tan((s-c)/2))) 00979 */ 00980 double IntxAreaUtils::area_spherical_triangle_lHuiller( double* ptA, double* ptB, double* ptC, double Radius, int rank ) 00981 { 00982 00983 // now, a is angle BOC, O is origin 00984 CartVect vA( ptA ), vB( ptB ), vC( ptC ); 00985 double a = angle( vB, vC ); 00986 double b = angle( vC, vA ); 00987 double c = angle( vA, vB ); 00988 int sign = 1; 00989 if( ( vA * vB ) % vC < 0 ) sign = -1; 00990 double s = ( a + b + c ) / 2; 00991 double tmp = tan( s / 2 ) * tan( ( s - a ) / 2 ) * tan( ( s - b ) / 2 ) * tan( ( s - c ) / 2 ); 00992 if( tmp < 0. ) tmp = 0.; 00993 00994 double E = 4 * atan( sqrt( tmp ) ); 00995 if( E != E ) std::cout << " NaN at spherical triangle area \n"; 00996 00997 double area = sign * E * Radius * Radius; 00998 00999 #ifdef CHECKNEGATIVEAREA 01000 if( area < 0 ) 01001 { 01002 std::cout << "negative area: " << area << " on task :" << rank << "\n"; 01003 std::cout << std::setprecision( 15 ); 01004 std::cout << "vA: " << vA << "\n"; 01005 std::cout << "vB: " << vB << "\n"; 01006 std::cout << "vC: " << vC << "\n"; 01007 std::cout << "sign: " << sign << "\n"; 01008 std::cout << " a: " << a << "\n"; 01009 std::cout << " b: " << b << "\n"; 01010 std::cout << " c: " << c << "\n"; 01011 } 01012 #endif 01013 01014 return area; 01015 } 01016 #undef CHECKNEGATIVEAREA 01017 01018 double IntxAreaUtils::area_on_sphere( Interface* mb, EntityHandle set, double R, int rank ) 01019 { 01020 // Get all entities of dimension 2 01021 Range inputRange; 01022 ErrorCode rval = mb->get_entities_by_dimension( set, 2, inputRange );MB_CHK_ERR_RET_VAL( rval, -1.0 ); 01023 01024 // Filter by elements that are owned by current process 01025 std::vector< int > ownerinfo( inputRange.size(), -1 ); 01026 Tag intxOwnerTag; 01027 rval = mb->tag_get_handle( "ORIG_PROC", intxOwnerTag ); 01028 if( MB_SUCCESS == rval ) 01029 { 01030 rval = mb->tag_get_data( intxOwnerTag, inputRange, &ownerinfo[0] );MB_CHK_ERR_RET_VAL( rval, -1.0 ); 01031 } 01032 01033 // compare total area with 4*M_PI * R^2 01034 int ie = 0; 01035 double total_area = 0.; 01036 for( Range::iterator eit = inputRange.begin(); eit != inputRange.end(); ++eit ) 01037 { 01038 01039 // All zero/positive owner data represents ghosted elems 01040 if( ownerinfo[ie++] >= 0 ) continue; 01041 01042 EntityHandle eh = *eit; 01043 const double elem_area = this->area_spherical_element( mb, eh, R, rank ); 01044 01045 // check whether the area of the spherical element is positive. 01046 assert( elem_area > 0 ); 01047 01048 // sum up the contribution 01049 total_area += elem_area; 01050 } 01051 01052 // return total mesh area 01053 return total_area; 01054 } 01055 01056 double IntxAreaUtils::area_spherical_element( Interface* mb, EntityHandle elem, double R, int rank ) 01057 { 01058 // get the nodes, then the coordinates 01059 const EntityHandle* verts; 01060 int nsides; 01061 ErrorCode rval = mb->get_connectivity( elem, verts, nsides );MB_CHK_ERR_RET_VAL( rval, -1.0 ); 01062 01063 // account for possible padded polygons 01064 while( verts[nsides - 2] == verts[nsides - 1] && nsides > 3 ) 01065 nsides--; 01066 01067 // get coordinates 01068 std::vector< double > coords( 3 * nsides ); 01069 rval = mb->get_coords( verts, nsides, &coords[0] );MB_CHK_ERR_RET_VAL( rval, -1.0 ); 01070 01071 // compute and return the area of the polygonal element 01072 int lsign = 1; 01073 double area = area_spherical_polygon( &coords[0], nsides, R, &lsign, rank ); 01074 { 01075 if( lsign < 0 ) 01076 { 01077 std::cout << " IntxAreaUtils::area_spherical_element : lsign :" << lsign << " area:" << area << " rank:" 01078 << rank << "\n"; 01079 mb->list_entity( elem ); 01080 } 01081 } 01082 return area; 01083 } 01084 01085 double IntxUtils::distance_on_great_circle( CartVect& p1, CartVect& p2 ) 01086 { 01087 SphereCoords sph1 = cart_to_spherical( p1 ); 01088 SphereCoords sph2 = cart_to_spherical( p2 ); 01089 // radius should be the same 01090 return sph1.R * 01091 acos( sin( sph1.lon ) * sin( sph2.lon ) + cos( sph1.lat ) * cos( sph2.lat ) * cos( sph2.lon - sph2.lon ) ); 01092 } 01093 01094 // break the nonconvex quads into triangles; remove the quad from the set? yes. 01095 // maybe radius is not needed; 01096 // 01097 ErrorCode IntxUtils::enforce_convexity( Interface* mb, EntityHandle lset, int my_rank ) 01098 { 01099 // look at each polygon; compute all angles; if one is reflex, break that angle with 01100 // the next triangle; put the 2 new polys in the set; 01101 // still look at the next poly 01102 // replace it with 2 triangles, and remove from set; 01103 // it should work for all polygons / tested first for case 1, with dt 0.5 (too much deformation) 01104 // get all entities of dimension 2 01105 // then get the connectivity, etc 01106 01107 Range inputRange; 01108 ErrorCode rval = mb->get_entities_by_dimension( lset, 2, inputRange );MB_CHK_ERR( rval ); 01109 01110 Tag corrTag = 0; 01111 EntityHandle dumH = 0; 01112 rval = mb->tag_get_handle( CORRTAGNAME, 1, MB_TYPE_HANDLE, corrTag, MB_TAG_DENSE, &dumH ); 01113 if( rval == MB_TAG_NOT_FOUND ) corrTag = 0; 01114 01115 Tag gidTag; 01116 rval = mb->tag_get_handle( "GLOBAL_ID", 1, MB_TYPE_INTEGER, gidTag, MB_TAG_DENSE );MB_CHK_ERR( rval ); 01117 01118 std::vector< double > coords; 01119 coords.resize( 3 * MAXEDGES ); // at most 10 vertices per polygon 01120 // we should create a queue with new polygons that need processing for reflex angles 01121 // (obtuse) 01122 std::queue< EntityHandle > newPolys; 01123 int brokenPolys = 0; 01124 Range::iterator eit = inputRange.begin(); 01125 while( eit != inputRange.end() || !newPolys.empty() ) 01126 { 01127 EntityHandle eh; 01128 if( eit != inputRange.end() ) 01129 { 01130 eh = *eit; 01131 ++eit; 01132 } 01133 else 01134 { 01135 eh = newPolys.front(); 01136 newPolys.pop(); 01137 } 01138 // get the nodes, then the coordinates 01139 const EntityHandle* verts; 01140 int num_nodes; 01141 rval = mb->get_connectivity( eh, verts, num_nodes );MB_CHK_ERR( rval ); 01142 int nsides = num_nodes; 01143 // account for possible padded polygons 01144 while( verts[nsides - 2] == verts[nsides - 1] && nsides > 3 ) 01145 nsides--; 01146 EntityHandle corrHandle = 0; 01147 if( corrTag ) 01148 { 01149 rval = mb->tag_get_data( corrTag, &eh, 1, &corrHandle );MB_CHK_ERR( rval ); 01150 } 01151 int gid = 0; 01152 rval = mb->tag_get_data( gidTag, &eh, 1, &gid );MB_CHK_ERR( rval ); 01153 coords.resize( 3 * nsides ); 01154 if( nsides < 4 ) continue; // if already triangles, don't bother 01155 // get coordinates 01156 rval = mb->get_coords( verts, nsides, &coords[0] );MB_CHK_ERR( rval ); 01157 // compute each angle 01158 bool alreadyBroken = false; 01159 01160 for( int i = 0; i < nsides; i++ ) 01161 { 01162 double* A = &coords[3 * i]; 01163 double* B = &coords[3 * ( ( i + 1 ) % nsides )]; 01164 double* C = &coords[3 * ( ( i + 2 ) % nsides )]; 01165 double angle = IntxUtils::oriented_spherical_angle( A, B, C ); 01166 if( angle - M_PI > 0. ) // even almost reflex is bad; break it! 01167 { 01168 if( alreadyBroken ) 01169 { 01170 mb->list_entities( &eh, 1 ); 01171 mb->list_entities( verts, nsides ); 01172 double* D = &coords[3 * ( ( i + 3 ) % nsides )]; 01173 std::cout << "ABC: " << angle << " \n"; 01174 std::cout << "BCD: " << IntxUtils::oriented_spherical_angle( B, C, D ) << " \n"; 01175 std::cout << "CDA: " << IntxUtils::oriented_spherical_angle( C, D, A ) << " \n"; 01176 std::cout << "DAB: " << IntxUtils::oriented_spherical_angle( D, A, B ) << " \n"; 01177 std::cout << " this cell has at least 2 angles > 180, it has serious issues\n"; 01178 01179 return MB_FAILURE; 01180 } 01181 // the bad angle is at i+1; 01182 // create 1 triangle and one polygon; add the polygon to the input range, so 01183 // it will be processed too 01184 // also, add both to the set :) and remove the original polygon from the set 01185 // break the next triangle, even though not optimal 01186 // so create the triangle i+1, i+2, i+3; remove i+2 from original list 01187 // even though not optimal in general, it is good enough. 01188 EntityHandle conn3[3] = {verts[( i + 1 ) % nsides], verts[( i + 2 ) % nsides], 01189 verts[( i + 3 ) % nsides]}; 01190 // create a polygon with num_nodes-1 vertices, and connectivity 01191 // verts[i+1], verts[i+3], (all except i+2) 01192 std::vector< EntityHandle > conn( nsides - 1 ); 01193 for( int j = 1; j < nsides; j++ ) 01194 { 01195 conn[j - 1] = verts[( i + j + 2 ) % nsides]; 01196 } 01197 EntityHandle newElement; 01198 rval = mb->create_element( MBTRI, conn3, 3, newElement );MB_CHK_ERR( rval ); 01199 01200 rval = mb->add_entities( lset, &newElement, 1 );MB_CHK_ERR( rval ); 01201 if( corrTag ) 01202 { 01203 rval = mb->tag_set_data( corrTag, &newElement, 1, &corrHandle );MB_CHK_ERR( rval ); 01204 } 01205 rval = mb->tag_set_data( gidTag, &newElement, 1, &gid );MB_CHK_ERR( rval ); 01206 if( nsides == 4 ) 01207 { 01208 // create another triangle 01209 rval = mb->create_element( MBTRI, &conn[0], 3, newElement );MB_CHK_ERR( rval ); 01210 } 01211 else 01212 { 01213 // create another polygon, and add it to the inputRange 01214 rval = mb->create_element( MBPOLYGON, &conn[0], nsides - 1, newElement );MB_CHK_ERR( rval ); 01215 newPolys.push( newElement ); // because it has less number of edges, the 01216 // reverse should work to find it. 01217 } 01218 rval = mb->add_entities( lset, &newElement, 1 );MB_CHK_ERR( rval ); 01219 if( corrTag ) 01220 { 01221 rval = mb->tag_set_data( corrTag, &newElement, 1, &corrHandle );MB_CHK_ERR( rval ); 01222 } 01223 rval = mb->tag_set_data( gidTag, &newElement, 1, &gid );MB_CHK_ERR( rval ); 01224 rval = mb->remove_entities( lset, &eh, 1 );MB_CHK_ERR( rval ); 01225 brokenPolys++; 01226 alreadyBroken = true; // get out of the loop, element is broken 01227 } 01228 } 01229 } 01230 if( brokenPolys > 0 ) 01231 { 01232 std::cout << "on local process " << my_rank << ", " << brokenPolys 01233 << " concave polygons were decomposed in convex ones \n"; 01234 #ifdef VERBOSE 01235 std::stringstream fff; 01236 fff << "file_set" << mb->id_from_handle( lset ) << "rk_" << my_rank << ".h5m"; 01237 rval = mb->write_file( fff.str().c_str(), 0, 0, &lset, 1 );MB_CHK_ERR( rval ); 01238 std::cout << "wrote new file set: " << fff.str() << "\n"; 01239 #endif 01240 } 01241 return MB_SUCCESS; 01242 } 01243 01244 // looking at quad connectivity, collapse to triangle if 2 nodes equal 01245 // then delete the old quad 01246 ErrorCode IntxUtils::fix_degenerate_quads( Interface* mb, EntityHandle set ) 01247 { 01248 Range quads; 01249 ErrorCode rval = mb->get_entities_by_type( set, MBQUAD, quads );MB_CHK_ERR( rval ); 01250 Tag gid; 01251 gid = mb->globalId_tag(); 01252 for( Range::iterator qit = quads.begin(); qit != quads.end(); ++qit ) 01253 { 01254 EntityHandle quad = *qit; 01255 const EntityHandle* conn4 = NULL; 01256 int num_nodes = 0; 01257 rval = mb->get_connectivity( quad, conn4, num_nodes );MB_CHK_ERR( rval ); 01258 for( int i = 0; i < num_nodes; i++ ) 01259 { 01260 int next_node_index = ( i + 1 ) % num_nodes; 01261 if( conn4[i] == conn4[next_node_index] ) 01262 { 01263 // form a triangle and delete the quad 01264 // first get the global id, to set it on triangle later 01265 int global_id = 0; 01266 rval = mb->tag_get_data( gid, &quad, 1, &global_id );MB_CHK_ERR( rval ); 01267 int i2 = ( i + 2 ) % num_nodes; 01268 int i3 = ( i + 3 ) % num_nodes; 01269 EntityHandle conn3[3] = {conn4[i], conn4[i2], conn4[i3]}; 01270 EntityHandle tri; 01271 rval = mb->create_element( MBTRI, conn3, 3, tri );MB_CHK_ERR( rval ); 01272 mb->add_entities( set, &tri, 1 ); 01273 mb->remove_entities( set, &quad, 1 ); 01274 mb->delete_entities( &quad, 1 ); 01275 rval = mb->tag_set_data( gid, &tri, 1, &global_id );MB_CHK_ERR( rval ); 01276 } 01277 } 01278 } 01279 return MB_SUCCESS; 01280 } 01281 01282 ErrorCode IntxAreaUtils::positive_orientation( Interface* mb, EntityHandle set, double R, int rank ) 01283 { 01284 Range cells2d; 01285 ErrorCode rval = mb->get_entities_by_dimension( set, 2, cells2d ); 01286 if( MB_SUCCESS != rval ) return rval; 01287 Tag gidTag = mb->globalId_tag(); 01288 for( Range::iterator qit = cells2d.begin(); qit != cells2d.end(); ++qit ) 01289 { 01290 EntityHandle cell = *qit; 01291 const EntityHandle* conn = NULL; 01292 int num_nodes = 0; 01293 rval = mb->get_connectivity( cell, conn, num_nodes ); 01294 if( MB_SUCCESS != rval ) return rval; 01295 if( num_nodes < 3 ) return MB_FAILURE; 01296 01297 double coords[9]; 01298 rval = mb->get_coords( conn, 3, coords ); 01299 if( MB_SUCCESS != rval ) return rval; 01300 01301 double area; 01302 if( R > 0 ) 01303 area = area_spherical_triangle_lHuiller( coords, coords + 3, coords + 6, R, rank ); 01304 else 01305 area = IntxUtils::area2D( coords, coords + 3, coords + 6 ); 01306 if( area < 0 ) 01307 { 01308 // compute all area, do not revert if total area is positive 01309 std::vector< double > coords2( 3 * num_nodes ); 01310 // get coordinates 01311 rval = mb->get_coords( conn, num_nodes, &coords2[0] ); 01312 if( MB_SUCCESS != rval ) return MB_FAILURE; 01313 int lsign; 01314 double totArea = area_spherical_polygon_lHuiller( &coords2[0], num_nodes, R, &lsign, rank ); 01315 if( totArea < 0 ) 01316 { 01317 std::vector< EntityHandle > newconn( num_nodes ); 01318 for( int i = 0; i < num_nodes; i++ ) 01319 { 01320 newconn[num_nodes - 1 - i] = conn[i]; 01321 } 01322 rval = mb->set_connectivity( cell, &newconn[0], num_nodes ); 01323 if( MB_SUCCESS != rval ) return rval; 01324 int gid; 01325 rval = mb->tag_get_data( gidTag, &cell, 1, &gid ); 01326 if( MB_SUCCESS != rval ) return rval; 01327 std::cout << " revert cell with global id:" << gid << " with num_nodes " << num_nodes << " on rank " 01328 << rank << "\n"; 01329 } 01330 else 01331 { 01332 std::cout << " nonconvex problem first area:" << area << " total area: " << totArea << std::endl; 01333 } 01334 } 01335 } 01336 return MB_SUCCESS; 01337 } 01338 01339 // distance along a great circle on a sphere of radius 1 01340 // page 4 01341 double IntxUtils::distance_on_sphere( double la1, double te1, double la2, double te2 ) 01342 { 01343 return acos( sin( te1 ) * sin( te2 ) + cos( te1 ) * cos( te2 ) * cos( la1 - la2 ) ); 01344 } 01345 01346 /* 01347 * given 2 great circle arcs, AB and CD, compute the unique intersection point, if it exists 01348 * in between 01349 */ 01350 ErrorCode IntxUtils::intersect_great_circle_arcs( double* A, double* B, double* C, double* D, double R, double* E ) 01351 { 01352 // first verify A, B, C, D are on the same sphere 01353 double R2 = R * R; 01354 const double Tolerance = 1.e-12 * R2; 01355 01356 CartVect a( A ), b( B ), c( C ), d( D ); 01357 01358 if( fabs( a.length_squared() - R2 ) + fabs( b.length_squared() - R2 ) + fabs( c.length_squared() - R2 ) + 01359 fabs( d.length_squared() - R2 ) > 01360 10 * Tolerance ) 01361 return MB_FAILURE; 01362 01363 CartVect n1 = a * b; 01364 if( n1.length_squared() < Tolerance ) return MB_FAILURE; 01365 01366 CartVect n2 = c * d; 01367 if( n2.length_squared() < Tolerance ) return MB_FAILURE; 01368 CartVect n3 = n1 * n2; 01369 n3.normalize(); 01370 01371 n3 = R * n3; 01372 // the intersection is either n3 or -n3 01373 CartVect n4 = a * n3, n5 = n3 * b; 01374 if( n1 % n4 >= -Tolerance && n1 % n5 >= -Tolerance ) 01375 { 01376 // n3 is good for ab, see if it is good for cd 01377 n4 = c * n3; 01378 n5 = n3 * d; 01379 if( n2 % n4 >= -Tolerance && n2 % n5 >= -Tolerance ) 01380 { 01381 E[0] = n3[0]; 01382 E[1] = n3[1]; 01383 E[2] = n3[2]; 01384 } 01385 else 01386 return MB_FAILURE; 01387 } 01388 else 01389 { 01390 // try -n3 01391 n3 = -n3; 01392 n4 = a * n3, n5 = n3 * b; 01393 if( n1 % n4 >= -Tolerance && n1 % n5 >= -Tolerance ) 01394 { 01395 // n3 is good for ab, see if it is good for cd 01396 n4 = c * n3; 01397 n5 = n3 * d; 01398 if( n2 % n4 >= -Tolerance && n2 % n5 >= -Tolerance ) 01399 { 01400 E[0] = n3[0]; 01401 E[1] = n3[1]; 01402 E[2] = n3[2]; 01403 } 01404 else 01405 return MB_FAILURE; 01406 } 01407 else 01408 return MB_FAILURE; 01409 } 01410 01411 return MB_SUCCESS; 01412 } 01413 01414 // verify that result is in between a and b on a great circle arc, and between c and d on a constant 01415 // latitude arc 01416 static bool verify( CartVect a, CartVect b, CartVect c, CartVect d, double x, double y, double z ) 01417 { 01418 // to check, the point has to be between a and b on a great arc, and between c and d on a const 01419 // lat circle 01420 CartVect s( x, y, z ); 01421 CartVect n1 = a * b; 01422 CartVect n2 = a * s; 01423 CartVect n3 = s * b; 01424 if( n1 % n2 < 0 || n1 % n3 < 0 ) return false; 01425 01426 // do the same for c, d, s, in plane z=0 01427 c[2] = d[2] = s[2] = 0.; // bring everything in the same plane, z=0; 01428 01429 n1 = c * d; 01430 n2 = c * s; 01431 n3 = s * d; 01432 if( n1 % n2 < 0 || n1 % n3 < 0 ) return false; 01433 01434 return true; 01435 } 01436 01437 ErrorCode IntxUtils::intersect_great_circle_arc_with_clat_arc( double* A, 01438 double* B, 01439 double* C, 01440 double* D, 01441 double R, 01442 double* E, 01443 int& np ) 01444 { 01445 const double distTol = R * 1.e-6; 01446 const double Tolerance = R * R * 1.e-12; // radius should be 1, usually 01447 np = 0; // number of points in intersection 01448 CartVect a( A ), b( B ), c( C ), d( D ); 01449 // check input first 01450 double R2 = R * R; 01451 if( fabs( a.length_squared() - R2 ) + fabs( b.length_squared() - R2 ) + fabs( c.length_squared() - R2 ) + 01452 fabs( d.length_squared() - R2 ) > 01453 10 * Tolerance ) 01454 return MB_FAILURE; 01455 01456 if( ( a - b ).length_squared() < Tolerance ) return MB_FAILURE; 01457 if( ( c - d ).length_squared() < Tolerance ) // edges are too short 01458 return MB_FAILURE; 01459 01460 // CD is the const latitude arc 01461 if( fabs( C[2] - D[2] ) > distTol ) // cd is not on the same z (constant latitude) 01462 return MB_FAILURE; 01463 01464 if( fabs( R - C[2] ) < distTol || fabs( R + C[2] ) < distTol ) return MB_FAILURE; // too close to the poles 01465 01466 // find the points on the circle P(teta) = (r*sin(teta), r*cos(teta), C[2]) that are on the 01467 // great circle arc AB normal to the AB circle: 01468 CartVect n1 = a * b; // the normal to the great circle arc (circle) 01469 // solve the system of equations: 01470 /* 01471 * n1%(x, y, z) = 0 // on the great circle 01472 * z = C[2]; 01473 * x^2+y^2+z^2 = R^2 01474 */ 01475 double z = C[2]; 01476 if( fabs( n1[0] ) + fabs( n1[1] ) < 2 * Tolerance ) 01477 { 01478 // it is the Equator; check if the const lat edge is Equator too 01479 if( fabs( C[2] ) > distTol ) 01480 { 01481 return MB_FAILURE; // no intx, too far from Eq 01482 } 01483 else 01484 { 01485 // all points are on the equator 01486 // 01487 CartVect cd = c * d; 01488 // by convention, c<d, positive is from c to d 01489 // is a or b between c , d? 01490 CartVect ca = c * a; 01491 CartVect ad = a * d; 01492 CartVect cb = c * b; 01493 CartVect bd = b * d; 01494 bool agtc = ( ca % cd >= -Tolerance ); // a>c? 01495 bool dgta = ( ad % cd >= -Tolerance ); // d>a? 01496 bool bgtc = ( cb % cd >= -Tolerance ); // b>c? 01497 bool dgtb = ( bd % cd >= -Tolerance ); // d>b? 01498 if( agtc ) 01499 { 01500 if( dgta ) 01501 { 01502 // a is for sure a point 01503 E[0] = a[0]; 01504 E[1] = a[1]; 01505 E[2] = a[2]; 01506 np++; 01507 if( bgtc ) 01508 { 01509 if( dgtb ) 01510 { 01511 // b is also in between c and d 01512 E[3] = b[0]; 01513 E[4] = b[1]; 01514 E[5] = b[2]; 01515 np++; 01516 } 01517 else 01518 { 01519 // then order is c a d b, intx is ad 01520 E[3] = d[0]; 01521 E[4] = d[1]; 01522 E[5] = d[2]; 01523 np++; 01524 } 01525 } 01526 else 01527 { 01528 // b is less than c, so b c a d, intx is ac 01529 E[3] = c[0]; 01530 E[4] = c[1]; 01531 E[5] = c[2]; 01532 np++; // what if E[0] is E[3]? 01533 } 01534 } 01535 else // c < d < a 01536 { 01537 if( dgtb ) // d is for sure in 01538 { 01539 E[0] = d[0]; 01540 E[1] = d[1]; 01541 E[2] = d[2]; 01542 np++; 01543 if( bgtc ) // c<b<d<a 01544 { 01545 // another point is b 01546 E[3] = b[0]; 01547 E[4] = b[1]; 01548 E[5] = b[2]; 01549 np++; 01550 } 01551 else // b<c<d<a 01552 { 01553 // another point is c 01554 E[3] = c[0]; 01555 E[4] = c[1]; 01556 E[5] = c[2]; 01557 np++; 01558 } 01559 } 01560 else 01561 { 01562 // nothing, order is c, d < a, b 01563 } 01564 } 01565 } 01566 else // a < c < d 01567 { 01568 if( bgtc ) 01569 { 01570 // c is for sure in 01571 E[0] = c[0]; 01572 E[1] = c[1]; 01573 E[2] = c[2]; 01574 np++; 01575 if( dgtb ) 01576 { 01577 // a < c < b < d; second point is b 01578 E[3] = b[0]; 01579 E[4] = b[1]; 01580 E[5] = b[2]; 01581 np++; 01582 } 01583 else 01584 { 01585 // a < c < d < b; second point is d 01586 E[3] = d[0]; 01587 E[4] = d[1]; 01588 E[5] = d[2]; 01589 np++; 01590 } 01591 } 01592 else // a, b < c < d 01593 { 01594 // nothing 01595 } 01596 } 01597 } 01598 // for the 2 points selected, see if it is only one? 01599 // no problem, maybe it will be collapsed later anyway 01600 if( np > 0 ) return MB_SUCCESS; 01601 return MB_FAILURE; // no intersection 01602 } 01603 { 01604 if( fabs( n1[0] ) <= fabs( n1[1] ) ) 01605 { 01606 // resolve eq in x: n0 * x + n1 * y +n2*z = 0; y = -n2/n1*z -n0/n1*x 01607 // (u+v*x)^2+x^2=R2-z^2 01608 // (v^2+1)*x^2 + 2*u*v *x + u^2+z^2-R^2 = 0 01609 // delta = 4*u^2*v^2 - 4*(v^2-1)(u^2+z^2-R^2) 01610 // x1,2 = 01611 double u = -n1[2] / n1[1] * z, v = -n1[0] / n1[1]; 01612 double a1 = v * v + 1, b1 = 2 * u * v, c1 = u * u + z * z - R2; 01613 double delta = b1 * b1 - 4 * a1 * c1; 01614 if( delta < -Tolerance ) return MB_FAILURE; // no intersection 01615 if( delta > Tolerance ) // 2 solutions possible 01616 { 01617 double x1 = ( -b1 + sqrt( delta ) ) / 2 / a1; 01618 double x2 = ( -b1 - sqrt( delta ) ) / 2 / a1; 01619 double y1 = u + v * x1; 01620 double y2 = u + v * x2; 01621 if( verify( a, b, c, d, x1, y1, z ) ) 01622 { 01623 E[0] = x1; 01624 E[1] = y1; 01625 E[2] = z; 01626 np++; 01627 } 01628 if( verify( a, b, c, d, x2, y2, z ) ) 01629 { 01630 E[3 * np + 0] = x2; 01631 E[3 * np + 1] = y2; 01632 E[3 * np + 2] = z; 01633 np++; 01634 } 01635 } 01636 else 01637 { 01638 // one solution 01639 double x1 = -b1 / 2 / a1; 01640 double y1 = u + v * x1; 01641 if( verify( a, b, c, d, x1, y1, z ) ) 01642 { 01643 E[0] = x1; 01644 E[1] = y1; 01645 E[2] = z; 01646 np++; 01647 } 01648 } 01649 } 01650 else 01651 { 01652 // resolve eq in y, reverse 01653 // n0 * x + n1 * y +n2*z = 0; x = -n2/n0*z -n1/n0*y = u+v*y 01654 // (u+v*y)^2+y^2 -R2+z^2 =0 01655 // (v^2+1)*y^2 + 2*u*v *y + u^2+z^2-R^2 = 0 01656 // 01657 // x1,2 = 01658 double u = -n1[2] / n1[0] * z, v = -n1[1] / n1[0]; 01659 double a1 = v * v + 1, b1 = 2 * u * v, c1 = u * u + z * z - R2; 01660 double delta = b1 * b1 - 4 * a1 * c1; 01661 if( delta < -Tolerance ) return MB_FAILURE; // no intersection 01662 if( delta > Tolerance ) // 2 solutions possible 01663 { 01664 double y1 = ( -b1 + sqrt( delta ) ) / 2 / a1; 01665 double y2 = ( -b1 - sqrt( delta ) ) / 2 / a1; 01666 double x1 = u + v * y1; 01667 double x2 = u + v * y2; 01668 if( verify( a, b, c, d, x1, y1, z ) ) 01669 { 01670 E[0] = x1; 01671 E[1] = y1; 01672 E[2] = z; 01673 np++; 01674 } 01675 if( verify( a, b, c, d, x2, y2, z ) ) 01676 { 01677 E[3 * np + 0] = x2; 01678 E[3 * np + 1] = y2; 01679 E[3 * np + 2] = z; 01680 np++; 01681 } 01682 } 01683 else 01684 { 01685 // one solution 01686 double y1 = -b1 / 2 / a1; 01687 double x1 = u + v * y1; 01688 if( verify( a, b, c, d, x1, y1, z ) ) 01689 { 01690 E[0] = x1; 01691 E[1] = y1; 01692 E[2] = z; 01693 np++; 01694 } 01695 } 01696 } 01697 } 01698 01699 if( np <= 0 ) return MB_FAILURE; 01700 return MB_SUCCESS; 01701 } 01702 01703 #if 0 01704 ErrorCode set_edge_type_flag(Interface * mb, EntityHandle sf1) 01705 { 01706 Range cells; 01707 ErrorCode rval = mb->get_entities_by_dimension(sf1, 2, cells); 01708 if (MB_SUCCESS!= rval) 01709 return rval; 01710 Range edges; 01711 rval = mb->get_adjacencies(cells, 1, true, edges, Interface::UNION); 01712 if (MB_SUCCESS!= rval) 01713 return rval; 01714 01715 Tag edgeTypeTag; 01716 int default_int=0; 01717 rval = mb->tag_get_handle("edge_type", 1, MB_TYPE_INTEGER, edgeTypeTag, 01718 MB_TAG_DENSE | MB_TAG_CREAT, &default_int); 01719 if (MB_SUCCESS!= rval) 01720 return rval; 01721 // add edges to the set? not yet, maybe later 01722 // if edge horizontal, set value to 1 01723 int type_constant_lat=1; 01724 for (Range::iterator eit=edges.begin(); eit!=edges.end(); ++eit) 01725 { 01726 EntityHandle edge = *eit; 01727 const EntityHandle *conn=0; 01728 int num_n=0; 01729 rval = mb->get_connectivity(edge, conn, num_n ); 01730 if (MB_SUCCESS!= rval) 01731 return rval; 01732 double coords[6]; 01733 rval = mb->get_coords(conn, 2, coords); 01734 if (MB_SUCCESS!= rval) 01735 return rval; 01736 if (fabs( coords[2]-coords[5] )< 1.e-6 ) 01737 { 01738 rval = mb->tag_set_data(edgeTypeTag, &edge, 1, &type_constant_lat); 01739 if (MB_SUCCESS!= rval) 01740 return rval; 01741 } 01742 } 01743 01744 return MB_SUCCESS; 01745 } 01746 #endif 01747 01748 // decide in a different metric if the corners of CS quad are 01749 // in the interior of an RLL quad 01750 int IntxUtils::borderPointsOfCSinRLL( CartVect* redc, 01751 double* red2dc, 01752 int nsRed, 01753 CartVect* bluec, 01754 int nsBlue, 01755 int* blueEdgeType, 01756 double* P, 01757 int* side, 01758 double epsil ) 01759 { 01760 int extraPoints = 0; 01761 // first decide the blue z coordinates 01762 CartVect A( 0. ), B( 0. ), C( 0. ), D( 0. ); 01763 for( int i = 0; i < nsBlue; i++ ) 01764 { 01765 if( blueEdgeType[i] == 0 ) 01766 { 01767 int iP1 = ( i + 1 ) % nsBlue; 01768 if( bluec[i][2] > bluec[iP1][2] ) 01769 { 01770 A = bluec[i]; 01771 B = bluec[iP1]; 01772 C = bluec[( i + 2 ) % nsBlue]; 01773 D = bluec[( i + 3 ) % nsBlue]; // it could be back to A, if triangle on top 01774 break; 01775 } 01776 } 01777 } 01778 if( nsBlue == 3 && B[2] < 0 ) 01779 { 01780 // select D to be C 01781 D = C; 01782 C = B; // B is the south pole then 01783 } 01784 // so we have A, B, C, D, with A at the top, b going down, then C, D, D > C, A > B 01785 // AB is const longitude, BC and DA constant latitude 01786 // check now each of the red points if they are inside this rectangle 01787 for( int i = 0; i < nsRed; i++ ) 01788 { 01789 CartVect& X = redc[i]; 01790 if( X[2] > A[2] || X[2] < B[2] ) continue; // it is above or below the rectangle 01791 // now decide if it is between the planes OAB and OCD 01792 if( ( ( A * B ) % X >= -epsil ) && ( ( C * D ) % X >= -epsil ) ) 01793 { 01794 side[i] = 1; // 01795 // it means point X is in the rectangle that we want , on the sphere 01796 // pass the coords 2d 01797 P[extraPoints * 2] = red2dc[2 * i]; 01798 P[extraPoints * 2 + 1] = red2dc[2 * i + 1]; 01799 extraPoints++; 01800 } 01801 } 01802 return extraPoints; 01803 } 01804 01805 ErrorCode IntxUtils::deep_copy_set_with_quads( Interface* mb, EntityHandle source_set, EntityHandle dest_set ) 01806 { 01807 ReadUtilIface* read_iface; 01808 ErrorCode rval = mb->query_interface( read_iface );MB_CHK_ERR( rval ); 01809 // create the handle tag for the corresponding element / vertex 01810 01811 EntityHandle dum = 0; 01812 Tag corrTag = 0; // it will be created here 01813 rval = mb->tag_get_handle( CORRTAGNAME, 1, MB_TYPE_HANDLE, corrTag, MB_TAG_DENSE | MB_TAG_CREAT, &dum );MB_CHK_ERR( rval ); 01814 01815 // give the same global id to new verts and cells created in the lagr(departure) mesh 01816 Tag gid = mb->globalId_tag(); 01817 01818 Range quads; 01819 rval = mb->get_entities_by_type( source_set, MBQUAD, quads );MB_CHK_ERR( rval ); 01820 01821 Range connecVerts; 01822 rval = mb->get_connectivity( quads, connecVerts );MB_CHK_ERR( rval ); 01823 01824 std::map< EntityHandle, EntityHandle > newNodes; 01825 01826 std::vector< double* > coords; 01827 EntityHandle start_vert, start_elem, *connect; 01828 int num_verts = connecVerts.size(); 01829 rval = read_iface->get_node_coords( 3, num_verts, 0, start_vert, coords ); 01830 if( MB_SUCCESS != rval ) return rval; 01831 // fill it up 01832 int i = 0; 01833 for( Range::iterator vit = connecVerts.begin(); vit != connecVerts.end(); ++vit, i++ ) 01834 { 01835 EntityHandle oldV = *vit; 01836 CartVect posi; 01837 rval = mb->get_coords( &oldV, 1, &( posi[0] ) );MB_CHK_ERR( rval ); 01838 01839 int global_id; 01840 rval = mb->tag_get_data( gid, &oldV, 1, &global_id );MB_CHK_ERR( rval ); 01841 EntityHandle new_vert = start_vert + i; 01842 // Cppcheck warning (false positive): variable coords is assigned a value that is never used 01843 coords[0][i] = posi[0]; 01844 coords[1][i] = posi[1]; 01845 coords[2][i] = posi[2]; 01846 01847 newNodes[oldV] = new_vert; 01848 // set also the correspondent tag :) 01849 rval = mb->tag_set_data( corrTag, &oldV, 1, &new_vert );MB_CHK_ERR( rval ); 01850 01851 // also the other side 01852 // need to check if we really need this; the new vertex will never need the old vertex 01853 // we have the global id which is the same 01854 rval = mb->tag_set_data( corrTag, &new_vert, 1, &oldV );MB_CHK_ERR( rval ); 01855 // set the global id on the corresponding vertex the same as the initial vertex 01856 rval = mb->tag_set_data( gid, &new_vert, 1, &global_id );MB_CHK_ERR( rval ); 01857 } 01858 // now create new quads in order (in a sequence) 01859 01860 rval = read_iface->get_element_connect( quads.size(), 4, MBQUAD, 0, start_elem, connect ); 01861 if( MB_SUCCESS != rval ) return rval; 01862 int ie = 0; 01863 for( Range::iterator it = quads.begin(); it != quads.end(); ++it, ie++ ) 01864 { 01865 EntityHandle q = *it; 01866 int nnodes; 01867 const EntityHandle* conn; 01868 rval = mb->get_connectivity( q, conn, nnodes );MB_CHK_ERR( rval ); 01869 int global_id; 01870 rval = mb->tag_get_data( gid, &q, 1, &global_id );MB_CHK_ERR( rval ); 01871 01872 for( int ii = 0; ii < nnodes; ii++ ) 01873 { 01874 EntityHandle v1 = conn[ii]; 01875 connect[4 * ie + ii] = newNodes[v1]; 01876 } 01877 EntityHandle newElement = start_elem + ie; 01878 01879 // set the corresponding tag; not sure we need this one, from old to new 01880 rval = mb->tag_set_data( corrTag, &q, 1, &newElement );MB_CHK_ERR( rval ); 01881 rval = mb->tag_set_data( corrTag, &newElement, 1, &q );MB_CHK_ERR( rval ); 01882 01883 // set the global id 01884 rval = mb->tag_set_data( gid, &newElement, 1, &global_id );MB_CHK_ERR( rval ); 01885 01886 rval = mb->add_entities( dest_set, &newElement, 1 );MB_CHK_ERR( rval ); 01887 } 01888 01889 rval = read_iface->update_adjacencies( start_elem, quads.size(), 4, connect );MB_CHK_ERR( rval ); 01890 01891 return MB_SUCCESS; 01892 } 01893 01894 ErrorCode IntxUtils::remove_duplicate_vertices( Interface* mb, 01895 EntityHandle file_set, 01896 double merge_tol, 01897 std::vector< Tag >& tagList ) 01898 { 01899 Range verts; 01900 ErrorCode rval = mb->get_entities_by_dimension( file_set, 0, verts );MB_CHK_ERR( rval ); 01901 rval = mb->remove_entities( file_set, verts );MB_CHK_ERR( rval ); 01902 01903 MergeMesh mm( mb ); 01904 01905 // remove the vertices from the set, before merging 01906 01907 rval = mm.merge_all( file_set, merge_tol );MB_CHK_ERR( rval ); 01908 01909 // now correct vertices that are repeated in polygons 01910 rval = remove_padded_vertices( mb, file_set, tagList ); 01911 return MB_SUCCESS; 01912 } 01913 01914 ErrorCode IntxUtils::remove_padded_vertices( Interface* mb, EntityHandle file_set, std::vector< Tag >& tagList ) 01915 { 01916 01917 // now correct vertices that are repeated in polygons 01918 Range cells; 01919 ErrorCode rval = mb->get_entities_by_dimension( file_set, 2, cells );MB_CHK_ERR( rval ); 01920 01921 Range verts; 01922 rval = mb->get_connectivity( cells, verts );MB_CHK_ERR( rval ); 01923 01924 Range modifiedCells; // will be deleted at the end; keep the gid 01925 Range newCells; 01926 01927 for( Range::iterator cit = cells.begin(); cit != cells.end(); ++cit ) 01928 { 01929 EntityHandle cell = *cit; 01930 const EntityHandle* connec = NULL; 01931 int num_verts = 0; 01932 rval = mb->get_connectivity( cell, connec, num_verts );MB_CHK_SET_ERR( rval, "Failed to get connectivity" ); 01933 01934 std::vector< EntityHandle > newConnec; 01935 newConnec.push_back( connec[0] ); // at least one vertex 01936 int index = 0; 01937 int new_size = 1; 01938 while( index < num_verts - 2 ) 01939 { 01940 int next_index = ( index + 1 ); 01941 if( connec[next_index] != newConnec[new_size - 1] ) 01942 { 01943 newConnec.push_back( connec[next_index] ); 01944 new_size++; 01945 } 01946 index++; 01947 } 01948 // add the last one only if different from previous and first node 01949 if( ( connec[num_verts - 1] != connec[num_verts - 2] ) && ( connec[num_verts - 1] != connec[0] ) ) 01950 { 01951 newConnec.push_back( connec[num_verts - 1] ); 01952 new_size++; 01953 } 01954 if( new_size < num_verts ) 01955 { 01956 // cout << "new cell from " << cell << " has only " << new_size << " vertices \n"; 01957 modifiedCells.insert( cell ); 01958 // create a new cell with type triangle, quad or polygon 01959 EntityType type = MBTRI; 01960 if( new_size == 3 ) 01961 type = MBTRI; 01962 else if( new_size == 4 ) 01963 type = MBQUAD; 01964 else if( new_size > 4 ) 01965 type = MBPOLYGON; 01966 01967 // create new cell 01968 EntityHandle newCell; 01969 rval = mb->create_element( type, &newConnec[0], new_size, newCell );MB_CHK_SET_ERR( rval, "Failed to create new cell" ); 01970 // set the old id to the new element 01971 newCells.insert( newCell ); 01972 double value; // use the same value to reset the tags, even if the tags are int (like Global ID) 01973 for( size_t i = 0; i < tagList.size(); i++ ) 01974 { 01975 rval = mb->tag_get_data( tagList[i], &cell, 1, (void*)( &value ) );MB_CHK_SET_ERR( rval, "Failed to get tag value" ); 01976 rval = mb->tag_set_data( tagList[i], &newCell, 1, (void*)( &value ) );MB_CHK_SET_ERR( rval, "Failed to set tag value on new cell" ); 01977 } 01978 } 01979 } 01980 01981 rval = mb->remove_entities( file_set, modifiedCells );MB_CHK_SET_ERR( rval, "Failed to remove old cells from file set" ); 01982 rval = mb->delete_entities( modifiedCells );MB_CHK_SET_ERR( rval, "Failed to delete old cells" ); 01983 rval = mb->add_entities( file_set, newCells );MB_CHK_SET_ERR( rval, "Failed to add new cells to file set" ); 01984 rval = mb->add_entities( file_set, verts );MB_CHK_SET_ERR( rval, "Failed to add verts to the file set" ); 01985 01986 return MB_SUCCESS; 01987 } 01988 01989 } // namespace moab