Mesh Oriented datABase  (version 5.4.1)
Array-based unstructured mesh datastructure
IntxUtils.cpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines