LCOV - code coverage report
Current view: top level - src/IntxMesh - IntxUtils.cpp (source / functions) Hit Total Coverage
Test: coverage_sk.info Lines: 528 889 59.4 %
Date: 2020-12-16 07:07:30 Functions: 26 37 70.3 %
Branches: 539 1967 27.4 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * IntxUtils.cpp
       3                 :            :  *
       4                 :            :  *  Created on: Oct 3, 2012
       5                 :            :  */
       6                 :            : 
       7                 :            : #ifdef WIN32               /* windows */
       8                 :            : #define _USE_MATH_DEFINES  // For M_PI
       9                 :            : #endif
      10                 :            : #include <cmath>
      11                 :            : #include <cassert>
      12                 :            : #include <iostream>
      13                 :            : // this is for sstream
      14                 :            : #include <sstream>
      15                 :            : 
      16                 :            : #include "moab/IntxMesh/IntxUtils.hpp"
      17                 :            : // this is from mbcoupler; maybe it should be moved somewhere in moab src
      18                 :            : // right now, add a dependency to mbcoupler
      19                 :            : // #include "ElemUtil.hpp"
      20                 :            : #include "moab/MergeMesh.hpp"
      21                 :            : #include "moab/ReadUtilIface.hpp"
      22                 :            : #include "MBTagConventions.hpp"
      23                 :            : #define CHECKNEGATIVEAREA
      24                 :            : 
      25                 :            : #ifdef CHECKNEGATIVEAREA
      26                 :            : #include <iomanip>
      27                 :            : #endif
      28                 :            : #include <queue>
      29                 :            : #include <map>
      30                 :            : 
      31                 :            : #ifdef MOAB_HAVE_TEMPESTREMAP
      32                 :            : #include "GridElements.h"
      33                 :            : #endif
      34                 :            : 
      35                 :            : namespace moab
      36                 :            : {
      37                 :            : 
      38                 :            : #define CORRTAGNAME "__correspondent"
      39                 :            : #define MAXEDGES    10
      40                 :            : 
      41                 :       9535 : int IntxUtils::borderPointsOfXinY2( double* X, int nX, double* Y, int nY, double* P, int* side, double epsilon_area )
      42                 :            : {
      43                 :            :     // 2 triangles, 3 corners, is the corner of X in Y?
      44                 :            :     // Y must have a positive area
      45                 :            :     /*
      46                 :            :      */
      47                 :       9535 :     int extraPoint = 0;
      48         [ +  + ]:      46957 :     for( int i = 0; i < nX; i++ )
      49                 :            :     {
      50                 :            :         // compute double the area of all nY triangles formed by a side of Y and a corner of X; if
      51                 :            :         // one is negative, stop (negative means it is outside; X and Y are all oriented such that
      52                 :            :         // they are positive oriented;
      53                 :            :         //  if one area is negative, it means it is outside the convex region, for sure)
      54                 :      37422 :         double* A = X + 2 * i;
      55                 :            : 
      56                 :      37422 :         int inside = 1;
      57         [ +  + ]:     107908 :         for( int j = 0; j < nY; j++ )
      58                 :            :         {
      59                 :      98911 :             double* B = Y + 2 * j;
      60                 :      98911 :             int j1    = ( j + 1 ) % nY;
      61                 :      98911 :             double* C = Y + 2 * j1;  // no copy of data
      62                 :            : 
      63                 :      98911 :             double area2 = ( B[0] - A[0] ) * ( C[1] - A[1] ) - ( C[0] - A[0] ) * ( B[1] - A[1] );
      64         [ +  + ]:      98911 :             if( area2 < -epsilon_area )
      65                 :            :             {
      66                 :      28425 :                 inside = 0;
      67                 :      28425 :                 break;
      68                 :            :             }
      69                 :            :         }
      70         [ +  + ]:      37422 :         if( inside )
      71                 :            :         {
      72                 :       8997 :             side[i] = 1;  // so vertex i of X is inside the convex region formed by Y
      73                 :            :             // so side has nX dimension (first array)
      74                 :       8997 :             P[extraPoint * 2]     = A[0];
      75                 :       8997 :             P[extraPoint * 2 + 1] = A[1];
      76                 :       8997 :             extraPoint++;
      77                 :            :         }
      78                 :            :     }
      79                 :       9535 :     return extraPoint;
      80                 :            : }
      81                 :            : 
      82                 :            : // used to order according to angle, so it can remove double easily
      83                 :            : struct angleAndIndex
      84                 :            : {
      85                 :            :     double angle;
      86                 :            :     int index;
      87                 :            : };
      88                 :            : 
      89                 :      57400 : bool angleCompare( angleAndIndex lhs, angleAndIndex rhs )
      90                 :            : {
      91                 :      57400 :     return lhs.angle < rhs.angle;
      92                 :            : }
      93                 :            : 
      94                 :            : // nP might be modified too, we will remove duplicates if found
      95                 :       8562 : int IntxUtils::SortAndRemoveDoubles2( double* P, int& nP, double epsilon_1 )
      96                 :            : {
      97         [ +  + ]:       8562 :     if( nP < 2 ) return 0;  // nothing to do
      98                 :            : 
      99                 :            :     // center of gravity for the points
     100                 :       8545 :     double c[2] = { 0., 0. };
     101                 :       8545 :     int k       = 0;
     102         [ +  + ]:      43700 :     for( k = 0; k < nP; k++ )
     103                 :            :     {
     104                 :      35155 :         c[0] += P[2 * k];
     105                 :      35155 :         c[1] += P[2 * k + 1];
     106                 :            :     }
     107                 :       8545 :     c[0] /= nP;
     108                 :       8545 :     c[1] /= nP;
     109                 :            : 
     110                 :            :     // how many? we dimensioned P at MAXEDGES*10; so we imply we could have at most 5*MAXEDGES
     111                 :            :     // intersection points
     112                 :            :     struct angleAndIndex pairAngleIndex[5 * MAXEDGES];
     113                 :            : 
     114         [ +  + ]:      43700 :     for( k = 0; k < nP; k++ )
     115                 :            :     {
     116                 :      35155 :         double x = P[2 * k] - c[0], y = P[2 * k + 1] - c[1];
     117 [ +  + ][ +  + ]:      35155 :         if( x != 0. || y != 0. ) { pairAngleIndex[k].angle = atan2( y, x ); }
     118                 :            :         else
     119                 :            :         {
     120                 :         63 :             pairAngleIndex[k].angle = 0;
     121                 :            :             // it would mean that the cells are touching at a vertex
     122                 :            :         }
     123                 :      35155 :         pairAngleIndex[k].index = k;
     124                 :            :     }
     125                 :            : 
     126                 :            :     // this should be faster than the bubble sort we had before
     127         [ +  - ]:       8545 :     std::sort( pairAngleIndex, pairAngleIndex + nP, angleCompare );
     128                 :            :     // copy now to a new double array
     129                 :            :     double PCopy[10 * MAXEDGES];  // the same dimension as P; very conservative, but faster than
     130                 :            :                                   // reallocate for a vector
     131         [ +  + ]:      43700 :     for( k = 0; k < nP; k++ )     // index will show where it should go now;
     132                 :            :     {
     133                 :      35155 :         int ck           = pairAngleIndex[k].index;
     134                 :      35155 :         PCopy[2 * k]     = P[2 * ck];
     135                 :      35155 :         PCopy[2 * k + 1] = P[2 * ck + 1];
     136                 :            :     }
     137                 :            :     // now copy from PCopy over original P location
     138         [ +  - ]:       8545 :     std::copy( PCopy, PCopy + 2 * nP, P );
     139                 :            : 
     140                 :            :     // eliminate duplicates, finally
     141                 :            : 
     142                 :       8545 :     int i = 0, j = 1;  // the next one; j may advance faster than i
     143                 :            :     // check the unit
     144                 :            :     // double epsilon_1 = 1.e-5; // these are cm; 2 points are the same if the distance is less
     145                 :            :     // than 1.e-5 cm
     146         [ +  + ]:      35155 :     while( j < nP )
     147                 :            :     {
     148         [ +  - ]:      26610 :         double d2 = dist2( &P[2 * i], &P[2 * j] );
     149         [ +  + ]:      26610 :         if( d2 > epsilon_1 )
     150                 :            :         {
     151                 :      22906 :             i++;
     152                 :      22906 :             P[2 * i]     = P[2 * j];
     153                 :      22906 :             P[2 * i + 1] = P[2 * j + 1];
     154                 :            :         }
     155                 :      26610 :         j++;
     156                 :            :     }
     157                 :            :     // test also the last point with the first one (index 0)
     158                 :            :     // the first one could be at -PI; last one could be at +PI, according to atan2 span
     159                 :            : 
     160         [ +  - ]:       8545 :     double d2 = dist2( P, &P[2 * i] );  // check the first and last points (ordered from -pi to +pi)
     161         [ +  + ]:       8545 :     if( d2 > epsilon_1 ) { nP = i + 1; }
     162                 :            :     else
     163                 :        326 :         nP = i;            // effectively delete the last point (that would have been the same with first)
     164         [ +  + ]:       8545 :     if( nP == 0 ) nP = 1;  // we should be left with at least one point we already tested if nP is 0 originally
     165                 :       8562 :     return 0;
     166                 :            : }
     167                 :            : 
     168                 :            : // the marks will show what edges of blue intersect the red
     169                 :            : 
     170                 :        973 : ErrorCode IntxUtils::EdgeIntersections2( double* blue, int nsBlue, double* red, int nsRed, int* markb, int* markr,
     171                 :            :                                          double* points, int& nPoints )
     172                 :            : {
     173                 :            :     /* EDGEINTERSECTIONS computes edge intersections of two elements
     174                 :            :      [P,n]=EdgeIntersections(X,Y) computes for the two given elements  * red
     175                 :            :      and blue ( stored column wise )
     176                 :            :      (point coordinates are stored column-wise, in counter clock
     177                 :            :      order) the points P where their edges intersect. In addition,
     178                 :            :      in n the indices of which neighbors of red  are also intersecting
     179                 :            :      with blue are given.
     180                 :            :      */
     181                 :            : 
     182                 :            :     // points is an array with enough slots   (24 * 2 doubles)
     183                 :        973 :     nPoints = 0;
     184         [ +  + ]:      10703 :     for( int i = 0; i < MAXEDGES; i++ )
     185                 :            :     {
     186                 :       9730 :         markb[i] = markr[i] = 0;
     187                 :            :     }
     188                 :            : 
     189         [ +  + ]:       4615 :     for( int i = 0; i < nsBlue; i++ )
     190                 :            :     {
     191         [ +  + ]:      17460 :         for( int j = 0; j < nsRed; j++ )
     192                 :            :         {
     193                 :            :             double b[2];
     194                 :            :             double a[2][2];  // 2*2
     195                 :      13818 :             int iPlus1 = ( i + 1 ) % nsBlue;
     196                 :      13818 :             int jPlus1 = ( j + 1 ) % nsRed;
     197         [ +  + ]:      41454 :             for( int k = 0; k < 2; k++ )
     198                 :            :             {
     199                 :      27636 :                 b[k] = red[2 * j + k] - blue[2 * i + k];
     200                 :            :                 // row k of a: a(k, 0), a(k, 1)
     201                 :      27636 :                 a[k][0] = blue[2 * iPlus1 + k] - blue[2 * i + k];
     202                 :      27636 :                 a[k][1] = red[2 * j + k] - red[2 * jPlus1 + k];
     203                 :            :             }
     204                 :      13818 :             double delta = a[0][0] * a[1][1] - a[0][1] * a[1][0];
     205         [ +  - ]:      13818 :             if( fabs( delta ) > 1.e-14 )  // this is close to machine epsilon
     206                 :            :             {
     207                 :            :                 // not parallel
     208                 :      13818 :                 double alfa = ( b[0] * a[1][1] - a[0][1] * b[1] ) / delta;
     209                 :      13818 :                 double beta = ( -b[0] * a[1][0] + b[1] * a[0][0] ) / delta;
     210 [ +  + ][ +  + ]:      13818 :                 if( 0 <= alfa && alfa <= 1. && 0 <= beta && beta <= 1. )
         [ +  + ][ +  + ]
     211                 :            :                 {
     212                 :            :                     // the intersection is good
     213         [ +  + ]:       6048 :                     for( int k = 0; k < 2; k++ )
     214                 :            :                     {
     215                 :       4032 :                         points[2 * nPoints + k] = blue[2 * i + k] + alfa * ( blue[2 * iPlus1 + k] - blue[2 * i + k] );
     216                 :            :                     }
     217                 :       2016 :                     markb[i] = 1;  // so neighbor number i of blue will be considered too.
     218                 :       2016 :                     markr[j] = 1;  // this will be used in advancing red around blue quad
     219                 :      13818 :                     nPoints++;
     220                 :            :                 }
     221                 :            :             }
     222                 :            :             // the case delta ~ 0. will be considered by the interior points logic
     223                 :            :         }
     224                 :            :     }
     225                 :        973 :     return MB_SUCCESS;
     226                 :            : }
     227                 :            : 
     228                 :            : // special one, for intersection between rll (constant latitude)  and cs quads
     229                 :       7589 : ErrorCode IntxUtils::EdgeIntxRllCs( double* blue, CartVect* bluec, int* blueEdgeType, int nsBlue, double* red,
     230                 :            :                                     CartVect* redc, int nsRed, int* markb, int* markr, int plane, double R,
     231                 :            :                                     double* points, int& nPoints )
     232                 :            : {
     233                 :            :     // if blue edge type is 1, intersect in 3d then project to 2d by gnomonic projection
     234                 :            :     // everything else the same (except if there are 2 points resulting, which is rare)
     235         [ +  + ]:      37945 :     for( int i = 0; i < 4; i++ )
     236                 :            :     {  // always at most 4 , so maybe don't bother
     237                 :      30356 :         markb[i] = markr[i] = 0;
     238                 :            :     }
     239                 :            : 
     240         [ +  + ]:      37727 :     for( int i = 0; i < nsBlue; i++ )
     241                 :            :     {
     242                 :      30138 :         int iPlus1 = ( i + 1 ) % nsBlue;
     243         [ +  + ]:      30138 :         if( blueEdgeType[i] == 0 )  // old style, just 2d
     244                 :            :         {
     245         [ +  + ]:      75890 :             for( int j = 0; j < nsRed; j++ )
     246                 :            :             {
     247                 :            :                 double b[2];
     248                 :            :                 double a[2][2];  // 2*2
     249                 :            : 
     250                 :      60712 :                 int jPlus1 = ( j + 1 ) % nsRed;
     251         [ +  + ]:     182136 :                 for( int k = 0; k < 2; k++ )
     252                 :            :                 {
     253                 :     121424 :                     b[k] = red[2 * j + k] - blue[2 * i + k];
     254                 :            :                     // row k of a: a(k, 0), a(k, 1)
     255                 :     121424 :                     a[k][0] = blue[2 * iPlus1 + k] - blue[2 * i + k];
     256                 :     121424 :                     a[k][1] = red[2 * j + k] - red[2 * jPlus1 + k];
     257                 :            :                 }
     258                 :      60712 :                 double delta = a[0][0] * a[1][1] - a[0][1] * a[1][0];
     259         [ +  + ]:      60712 :                 if( fabs( delta ) > 1.e-14 )
     260                 :            :                 {
     261                 :            :                     // not parallel
     262                 :      41362 :                     double alfa = ( b[0] * a[1][1] - a[0][1] * b[1] ) / delta;
     263                 :      41362 :                     double beta = ( -b[0] * a[1][0] + b[1] * a[0][0] ) / delta;
     264 [ +  + ][ +  + ]:      41362 :                     if( 0 <= alfa && alfa <= 1. && 0 <= beta && beta <= 1. )
         [ +  + ][ +  + ]
     265                 :            :                     {
     266                 :            :                         // the intersection is good
     267         [ +  + ]:      22143 :                         for( int k = 0; k < 2; k++ )
     268                 :            :                         {
     269                 :      14762 :                             points[2 * nPoints + k] =
     270                 :      14762 :                                 blue[2 * i + k] + alfa * ( blue[2 * iPlus1 + k] - blue[2 * i + k] );
     271                 :            :                         }
     272                 :       7381 :                         markb[i] = 1;  // so neighbor number i of blue will be considered too.
     273                 :       7381 :                         markr[j] = 1;  // this will be used in advancing red around blue quad
     274                 :      41362 :                         nPoints++;
     275                 :            :                     }
     276                 :            :                 }  // if the edges are too "parallel", skip them
     277                 :            :             }
     278                 :            :         }
     279                 :            :         else  // edge type is 1, so use 3d intersection
     280                 :            :         {
     281                 :      14960 :             CartVect& C = bluec[i];
     282                 :      14960 :             CartVect& D = bluec[iPlus1];
     283         [ +  + ]:      74800 :             for( int j = 0; j < nsRed; j++ )
     284                 :            :             {
     285                 :      59840 :                 int jPlus1  = ( j + 1 ) % nsRed;  // nsRed is just 4, forget about it, usually
     286                 :      59840 :                 CartVect& A = redc[j];
     287                 :      59840 :                 CartVect& B = redc[jPlus1];
     288                 :      59840 :                 int np      = 0;
     289                 :            :                 double E[9];
     290 [ +  - ][ +  - ]:      59840 :                 intersect_great_circle_arc_with_clat_arc( A.array(), B.array(), C.array(), D.array(), R, E, np );
         [ +  - ][ +  - ]
                 [ +  - ]
     291         [ +  + ]:      59840 :                 if( np == 0 ) continue;
     292 [ -  + ][ #  # ]:       7734 :                 if( np >= 2 ) { std::cout << "intersection with 2 points :" << A << B << C << D << "\n"; }
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     293         [ +  + ]:      15468 :                 for( int k = 0; k < np; k++ )
     294                 :            :                 {
     295                 :       7734 :                     gnomonic_projection( CartVect( E + k * 3 ), R, plane, points[2 * nPoints],
     296 [ +  - ][ +  - ]:       7734 :                                          points[2 * nPoints + 1] );
     297                 :       7734 :                     nPoints++;
     298                 :            :                 }
     299                 :       7734 :                 markb[i] = 1;  // so neighbor number i of blue will be considered too.
     300                 :       7734 :                 markr[j] = 1;  // this will be used in advancing red around blue quad
     301                 :            :             }
     302                 :            :         }
     303                 :            :     }
     304                 :       7589 :     return MB_SUCCESS;
     305                 :            : }
     306                 :            : 
     307                 :            : // vec utils related to gnomonic projection on a sphere
     308                 :            : 
     309                 :            : // vec utils
     310                 :            : 
     311                 :            : /*
     312                 :            :  *
     313                 :            :  * position on a sphere of radius R
     314                 :            :  * if plane specified, use it; if not, return the plane, and the point in the plane
     315                 :            :  * there are 6 planes, numbered 1 to 6
     316                 :            :  * plane 1: x=R, plane 2: y=R, 3: x=-R, 4: y=-R, 5: z=-R, 6: z=R
     317                 :            :  *
     318                 :            :  * projection on the plane will preserve the orientation, such that a triangle, quad pointing
     319                 :            :  * outside the sphere will have a positive orientation in the projection plane
     320                 :            :  */
     321                 :       3446 : void IntxUtils::decide_gnomonic_plane( const CartVect& pos, int& plane )
     322                 :            : {
     323                 :            :     // decide plane, based on max x, y, z
     324         [ +  + ]:       3446 :     if( fabs( pos[0] ) < fabs( pos[1] ) )
     325                 :            :     {
     326         [ +  + ]:       1645 :         if( fabs( pos[2] ) < fabs( pos[1] ) )
     327                 :            :         {
     328                 :            :             // pos[1] is biggest
     329         [ +  + ]:       1125 :             if( pos[1] > 0 )
     330                 :        558 :                 plane = 2;
     331                 :            :             else
     332                 :       1125 :                 plane = 4;
     333                 :            :         }
     334                 :            :         else
     335                 :            :         {
     336                 :            :             // pos[2] is biggest
     337         [ +  + ]:        520 :             if( pos[2] < 0 )
     338                 :        262 :                 plane = 5;
     339                 :            :             else
     340                 :       1645 :                 plane = 6;
     341                 :            :         }
     342                 :            :     }
     343                 :            :     else
     344                 :            :     {
     345         [ +  + ]:       1801 :         if( fabs( pos[2] ) < fabs( pos[0] ) )
     346                 :            :         {
     347                 :            :             // pos[0] is the greatest
     348         [ +  + ]:       1154 :             if( pos[0] > 0 )
     349                 :        572 :                 plane = 1;
     350                 :            :             else
     351                 :       1154 :                 plane = 3;
     352                 :            :         }
     353                 :            :         else
     354                 :            :         {
     355                 :            :             // pos[2] is biggest
     356         [ +  + ]:        647 :             if( pos[2] < 0 )
     357                 :        323 :                 plane = 5;
     358                 :            :             else
     359                 :        324 :                 plane = 6;
     360                 :            :         }
     361                 :            :     }
     362                 :       3446 :     return;
     363                 :            : }
     364                 :            : 
     365                 :            : // point on a sphere is projected on one of six planes, decided earlier
     366                 :      53678 : ErrorCode IntxUtils::gnomonic_projection( const CartVect& pos, double R, int plane, double& c1, double& c2 )
     367                 :            : {
     368                 :      53678 :     double alfa = 1.;  // the new point will be on line alfa*pos
     369                 :            : 
     370   [ +  +  +  +  :      53678 :     switch( plane )
                +  +  - ]
     371                 :            :     {
     372                 :            :         case 1: {
     373                 :            :             // the plane with x = R; x>y, x>z
     374                 :            :             // c1->y, c2->z
     375                 :       8611 :             alfa = R / pos[0];
     376                 :       8611 :             c1   = alfa * pos[1];
     377                 :       8611 :             c2   = alfa * pos[2];
     378                 :       8611 :             break;
     379                 :            :         }
     380                 :            :         case 2: {
     381                 :            :             // y = R -> zx
     382                 :       8749 :             alfa = R / pos[1];
     383                 :       8749 :             c1   = alfa * pos[2];
     384                 :       8749 :             c2   = alfa * pos[0];
     385                 :       8749 :             break;
     386                 :            :         }
     387                 :            :         case 3: {
     388                 :            :             // x=-R, -> yz
     389                 :       8475 :             alfa = -R / pos[0];
     390                 :       8475 :             c1   = -alfa * pos[1];  // the sign is to preserve orientation
     391                 :       8475 :             c2   = alfa * pos[2];
     392                 :       8475 :             break;
     393                 :            :         }
     394                 :            :         case 4: {
     395                 :            :             // y = -R
     396                 :       8369 :             alfa = -R / pos[1];
     397                 :       8369 :             c1   = -alfa * pos[2];  // the sign is to preserve orientation
     398                 :       8369 :             c2   = alfa * pos[0];
     399                 :       8369 :             break;
     400                 :            :         }
     401                 :            :         case 5: {
     402                 :            :             // z = -R
     403                 :       9735 :             alfa = -R / pos[2];
     404                 :       9735 :             c1   = -alfa * pos[0];  // the sign is to preserve orientation
     405                 :       9735 :             c2   = alfa * pos[1];
     406                 :       9735 :             break;
     407                 :            :         }
     408                 :            :         case 6: {
     409                 :       9739 :             alfa = R / pos[2];
     410                 :       9739 :             c1   = alfa * pos[0];
     411                 :       9739 :             c2   = alfa * pos[1];
     412                 :       9739 :             break;
     413                 :            :         }
     414                 :            :         default:
     415                 :          0 :             return MB_FAILURE;  // error
     416                 :            :     }
     417                 :            : 
     418                 :      53678 :     return MB_SUCCESS;  // no error
     419                 :            : }
     420                 :            : 
     421                 :            : // given the position on plane (one out of 6), find out the position on sphere
     422                 :      23466 : ErrorCode IntxUtils::reverse_gnomonic_projection( const double& c1, const double& c2, double R, int plane,
     423                 :            :                                                   CartVect& pos )
     424                 :            : {
     425                 :            : 
     426                 :            :     // the new point will be on line beta*pos
     427                 :      23466 :     double len  = sqrt( c1 * c1 + c2 * c2 + R * R );
     428                 :      23466 :     double beta = R / len;  // it is less than 1, in general
     429                 :            : 
     430   [ +  +  +  +  :      23466 :     switch( plane )
                +  +  - ]
     431                 :            :     {
     432                 :            :         case 1: {
     433                 :            :             // the plane with x = R; x>y, x>z
     434                 :            :             // c1->y, c2->z
     435                 :       3285 :             pos[0] = beta * R;
     436                 :       3285 :             pos[1] = c1 * beta;
     437                 :       3285 :             pos[2] = c2 * beta;
     438                 :       3285 :             break;
     439                 :            :         }
     440                 :            :         case 2: {
     441                 :            :             // y = R -> zx
     442                 :       3390 :             pos[1] = R * beta;
     443                 :       3390 :             pos[2] = c1 * beta;
     444                 :       3390 :             pos[0] = c2 * beta;
     445                 :       3390 :             break;
     446                 :            :         }
     447                 :            :         case 3: {
     448                 :            :             // x=-R, -> yz
     449                 :       3334 :             pos[0] = -R * beta;
     450                 :       3334 :             pos[1] = -c1 * beta;  // the sign is to preserve orientation
     451                 :       3334 :             pos[2] = c2 * beta;
     452                 :       3334 :             break;
     453                 :            :         }
     454                 :            :         case 4: {
     455                 :            :             // y = -R
     456                 :       3284 :             pos[1] = -R * beta;
     457                 :       3284 :             pos[2] = -c1 * beta;  // the sign is to preserve orientation
     458                 :       3284 :             pos[0] = c2 * beta;
     459                 :       3284 :             break;
     460                 :            :         }
     461                 :            :         case 5: {
     462                 :            :             // z = -R
     463                 :       5085 :             pos[2] = -R * beta;
     464                 :       5085 :             pos[0] = -c1 * beta;  // the sign is to preserve orientation
     465                 :       5085 :             pos[1] = c2 * beta;
     466                 :       5085 :             break;
     467                 :            :         }
     468                 :            :         case 6: {
     469                 :       5088 :             pos[2] = R * beta;
     470                 :       5088 :             pos[0] = c1 * beta;
     471                 :       5088 :             pos[1] = c2 * beta;
     472                 :       5088 :             break;
     473                 :            :         }
     474                 :            :         default:
     475                 :          0 :             return MB_FAILURE;  // error
     476                 :            :     }
     477                 :            : 
     478                 :      23466 :     return MB_SUCCESS;  // no error
     479                 :            : }
     480                 :            : 
     481                 :        294 : void IntxUtils::gnomonic_unroll( double& c1, double& c2, double R, int plane )
     482                 :            : {
     483                 :            :     double tmp;
     484   [ +  +  +  +  :        294 :     switch( plane )
                +  +  - ]
     485                 :            :     {
     486                 :            :         case 1:
     487                 :         49 :             break;  // nothing
     488                 :            :         case 2:     // rotate + 90
     489                 :         49 :             tmp = c1;
     490                 :         49 :             c1  = -c2;
     491                 :         49 :             c2  = tmp;
     492                 :         49 :             c1  = c1 + 2 * R;
     493                 :         49 :             break;
     494                 :            :         case 3:
     495                 :         49 :             c1 = c1 + 4 * R;
     496                 :         49 :             break;
     497                 :            :         case 4:  // rotate with -90 x-> -y; y -> x
     498                 :            : 
     499                 :         49 :             tmp = c1;
     500                 :         49 :             c1  = c2;
     501                 :         49 :             c2  = -tmp;
     502                 :         49 :             c1  = c1 - 2 * R;
     503                 :         49 :             break;
     504                 :            :         case 5:  // South Pole
     505                 :            :             // rotate 180 then move to (-2, -2)
     506                 :         49 :             c1 = -c1 - 2. * R;
     507                 :         49 :             c2 = -c2 - 2. * R;
     508                 :         49 :             break;
     509                 :            :             ;
     510                 :            :         case 6:  // North Pole
     511                 :         49 :             c1 = c1 - 2. * R;
     512                 :         49 :             c2 = c2 + 2. * R;
     513                 :         49 :             break;
     514                 :            :     }
     515                 :        294 :     return;
     516                 :            : }
     517                 :            : // given a mesh on the sphere, project all centers in 6 gnomonic planes, or project mesh too
     518                 :          1 : ErrorCode IntxUtils::global_gnomonic_projection( Interface* mb, EntityHandle inSet, double R, bool centers_only,
     519                 :            :                                                  EntityHandle& outSet )
     520                 :            : {
     521         [ +  - ]:          1 :     std::string parTagName( "PARALLEL_PARTITION" );
     522                 :            :     Tag part_tag;
     523         [ +  - ]:          2 :     Range partSets;
     524         [ +  - ]:          1 :     ErrorCode rval = mb->tag_get_handle( parTagName.c_str(), part_tag );
     525 [ -  + ][ #  # ]:          1 :     if( MB_SUCCESS == rval && part_tag != 0 )
     526                 :            :     {
     527 [ #  # ][ #  # ]:          0 :         rval = mb->get_entities_by_type_and_tag( inSet, MBENTITYSET, &part_tag, NULL, 1, partSets, Interface::UNION );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     528                 :            :     }
     529 [ +  - ][ -  + ]:          1 :     rval = ScaleToRadius( mb, inSet, 1.0 );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     530                 :            :     // Get all entities of dimension 2
     531         [ +  - ]:          2 :     Range inputRange;  // get
     532 [ +  - ][ -  + ]:          1 :     rval = mb->get_entities_by_dimension( inSet, 1, inputRange );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     533 [ +  - ][ -  + ]:          1 :     rval = mb->get_entities_by_dimension( inSet, 2, inputRange );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     534                 :            : 
     535         [ +  - ]:          2 :     std::map< EntityHandle, int > partsAssign;
     536         [ +  - ]:          2 :     std::map< int, EntityHandle > newPartSets;
     537 [ +  - ][ -  + ]:          1 :     if( !partSets.empty() )
     538                 :            :     {
     539                 :            :         // get all cells, and assign parts
     540 [ #  # ][ #  # ]:          0 :         for( Range::iterator setIt = partSets.begin(); setIt != partSets.end(); ++setIt )
         [ #  # ][ #  # ]
                 [ #  # ]
     541                 :            :         {
     542         [ #  # ]:          0 :             EntityHandle pSet = *setIt;
     543         [ #  # ]:          0 :             Range ents;
     544 [ #  # ][ #  # ]:          0 :             rval = mb->get_entities_by_handle( pSet, ents );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     545                 :            :             int val;
     546 [ #  # ][ #  # ]:          0 :             rval = mb->tag_get_data( part_tag, &pSet, 1, &val );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     547                 :            :             // create a new set with the same part id tag, in the outSet
     548                 :            :             EntityHandle newPartSet;
     549 [ #  # ][ #  # ]:          0 :             rval = mb->create_meshset( MESHSET_SET, newPartSet );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     550 [ #  # ][ #  # ]:          0 :             rval = mb->tag_set_data( part_tag, &newPartSet, 1, &val );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     551         [ #  # ]:          0 :             newPartSets[val] = newPartSet;
     552 [ #  # ][ #  # ]:          0 :             rval             = mb->add_entities( outSet, &newPartSet, 1 );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     553 [ #  # ][ #  # ]:          0 :             for( Range::iterator it = ents.begin(); it != ents.end(); ++it )
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     554                 :            :             {
     555 [ #  # ][ #  # ]:          0 :                 partsAssign[*it] = val;
     556                 :            :             }
     557                 :          0 :         }
     558                 :            :     }
     559                 :            : 
     560         [ -  + ]:          1 :     if( centers_only )
     561                 :            :     {
     562 [ #  # ][ #  # ]:          0 :         for( Range::iterator it = inputRange.begin(); it != inputRange.end(); ++it )
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     563                 :            :         {
     564         [ #  # ]:          0 :             CartVect center;
     565         [ #  # ]:          0 :             EntityHandle cell = *it;
     566 [ #  # ][ #  # ]:          0 :             rval              = mb->get_coords( &cell, 1, center.array() );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
                 [ #  # ]
     567                 :            :             int plane;
     568         [ #  # ]:          0 :             decide_gnomonic_plane( center, plane );
     569                 :            :             double c[3];
     570                 :          0 :             c[2] = 0.;
     571         [ #  # ]:          0 :             gnomonic_projection( center, R, plane, c[0], c[1] );
     572                 :            : 
     573         [ #  # ]:          0 :             gnomonic_unroll( c[0], c[1], R, plane );
     574                 :            : 
     575                 :            :             EntityHandle vertex;
     576 [ #  # ][ #  # ]:          0 :             rval = mb->create_vertex( c, vertex );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     577 [ #  # ][ #  # ]:          0 :             rval = mb->add_entities( outSet, &vertex, 1 );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     578                 :            :         }
     579                 :            :     }
     580                 :            :     else
     581                 :            :     {
     582                 :            :         // distribute the cells to 6 planes, based on the center
     583 [ +  - ][ +  + ]:         14 :         Range subranges[6];
           [ +  -  #  # ]
     584 [ +  - ][ +  - ]:        289 :         for( Range::iterator it = inputRange.begin(); it != inputRange.end(); ++it )
         [ +  - ][ +  - ]
                 [ +  + ]
     585                 :            :         {
     586         [ +  - ]:        288 :             CartVect center;
     587         [ +  - ]:        288 :             EntityHandle cell = *it;
     588 [ +  - ][ +  - ]:        288 :             rval              = mb->get_coords( &cell, 1, center.array() );MB_CHK_ERR( rval );
         [ -  + ][ #  # ]
                 [ #  # ]
     589                 :            :             int plane;
     590         [ +  - ]:        288 :             decide_gnomonic_plane( center, plane );
     591         [ +  - ]:        288 :             subranges[plane - 1].insert( cell );
     592                 :            :         }
     593 [ +  + ][ +  + ]:         13 :         for( int i = 1; i <= 6; i++ )
     594                 :            :         {
     595         [ +  - ]:          6 :             Range verts;
     596 [ +  - ][ -  + ]:          6 :             rval = mb->get_connectivity( subranges[i - 1], verts );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     597 [ +  - ][ +  - ]:         12 :             std::map< EntityHandle, EntityHandle > corr;
     598 [ +  - ][ +  - ]:        300 :             for( Range::iterator vt = verts.begin(); vt != verts.end(); ++vt )
         [ +  - ][ +  - ]
                 [ +  + ]
     599                 :            :             {
     600         [ +  - ]:        294 :                 CartVect vect;
     601         [ +  - ]:        294 :                 EntityHandle v = *vt;
     602 [ +  - ][ +  - ]:        294 :                 rval           = mb->get_coords( &v, 1, vect.array() );MB_CHK_ERR( rval );
         [ -  + ][ #  # ]
                 [ #  # ]
     603                 :            :                 double c[3];
     604                 :        294 :                 c[2] = 0.;
     605         [ +  - ]:        294 :                 gnomonic_projection( vect, R, i, c[0], c[1] );
     606         [ +  - ]:        294 :                 gnomonic_unroll( c[0], c[1], R, i );
     607                 :            :                 EntityHandle vertex;
     608 [ +  - ][ -  + ]:        294 :                 rval = mb->create_vertex( c, vertex );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     609         [ +  - ]:        294 :                 corr[v] = vertex;  // for new connectivity
     610                 :            :             }
     611                 :            :             EntityHandle new_conn[20];  // max edges in 2d ?
     612 [ +  - ][ +  - ]:        294 :             for( Range::iterator eit = subranges[i - 1].begin(); eit != subranges[i - 1].end(); ++eit )
         [ +  - ][ +  - ]
         [ +  + ][ +  - ]
     613                 :            :             {
     614         [ +  - ]:        288 :                 EntityHandle eh          = *eit;
     615                 :        288 :                 const EntityHandle* conn = NULL;
     616                 :            :                 int num_nodes;
     617 [ +  - ][ -  + ]:        288 :                 rval = mb->get_connectivity( eh, conn, num_nodes );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     618                 :            :                 // build a new vertex array
     619         [ +  + ]:       1296 :                 for( int i = 0; i < num_nodes; i++ )
     620         [ +  - ]:       1008 :                     new_conn[i] = corr[conn[i]];
     621         [ +  - ]:        288 :                 EntityType type = mb->type_from_handle( eh );
     622                 :            :                 EntityHandle newCell;
     623 [ +  - ][ -  + ]:        288 :                 rval = mb->create_element( type, new_conn, num_nodes, newCell );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     624 [ +  - ][ -  + ]:        288 :                 rval = mb->add_entities( outSet, &newCell, 1 );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     625         [ +  - ]:        288 :                 std::map< EntityHandle, int >::iterator mit = partsAssign.find( eh );
     626 [ +  - ][ -  + ]:        288 :                 if( mit != partsAssign.end() )
     627                 :            :                 {
     628         [ #  # ]:          0 :                     int val = mit->second;
     629 [ #  # ][ #  # ]:          0 :                     rval    = mb->add_entities( newPartSets[val], &newCell, 1 );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
                 [ #  # ]
     630                 :            :                 }
     631                 :            :             }
     632         [ #  # ]:          7 :         }
     633                 :            :     }
     634                 :            : 
     635                 :          2 :     return MB_SUCCESS;
     636                 :            : }
     637                 :          0 : void IntxUtils::transform_coordinates( double* avg_position, int projection_type )
     638                 :            : {
     639         [ #  # ]:          0 :     if( projection_type == 1 )
     640                 :            :     {
     641                 :            :         double R =
     642                 :          0 :             avg_position[0] * avg_position[0] + avg_position[1] * avg_position[1] + avg_position[2] * avg_position[2];
     643                 :          0 :         R               = sqrt( R );
     644                 :          0 :         double lat      = asin( avg_position[2] / R );
     645                 :          0 :         double lon      = atan2( avg_position[1], avg_position[0] );
     646                 :          0 :         avg_position[0] = lon;
     647                 :          0 :         avg_position[1] = lat;
     648                 :          0 :         avg_position[2] = R;
     649                 :            :     }
     650         [ #  # ]:          0 :     else if( projection_type == 2 )  // gnomonic projection
     651                 :            :     {
     652         [ #  # ]:          0 :         CartVect pos( avg_position );
     653                 :            :         int gplane;
     654         [ #  # ]:          0 :         IntxUtils::decide_gnomonic_plane( pos, gplane );
     655                 :            : 
     656         [ #  # ]:          0 :         IntxUtils::gnomonic_projection( pos, 1.0, gplane, avg_position[0], avg_position[1] );
     657                 :          0 :         avg_position[2] = 0;
     658         [ #  # ]:          0 :         IntxUtils::gnomonic_unroll( avg_position[0], avg_position[1], 1.0, gplane );
     659                 :            :     }
     660                 :          0 : }
     661                 :            : /*
     662                 :            :  *
     663                 :            :  use physical_constants, only : dd_pi
     664                 :            :  type(cartesian3D_t), intent(in) :: cart
     665                 :            :  type(spherical_polar_t)         :: sphere
     666                 :            : 
     667                 :            :  sphere%r=distance(cart)
     668                 :            :  sphere%lat=ASIN(cart%z/sphere%r)
     669                 :            :  sphere%lon=0
     670                 :            : 
     671                 :            :  ! ==========================================================
     672                 :            :  ! enforce three facts:
     673                 :            :  !
     674                 :            :  ! 1) lon at poles is defined to be zero
     675                 :            :  !
     676                 :            :  ! 2) Grid points must be separated by about .01 Meter (on earth)
     677                 :            :  !    from pole to be considered "not the pole".
     678                 :            :  !
     679                 :            :  ! 3) range of lon is { 0<= lon < 2*pi }
     680                 :            :  !
     681                 :            :  ! ==========================================================
     682                 :            : 
     683                 :            :  if (distance(cart) >= DIST_THRESHOLD) then
     684                 :            :  sphere%lon=ATAN2(cart%y,cart%x)
     685                 :            :  if (sphere%lon<0) then
     686                 :            :  sphere%lon=sphere%lon+2*DD_PI
     687                 :            :  end if
     688                 :            :  end if
     689                 :            : 
     690                 :            :  end function cart_to_spherical
     691                 :            :  */
     692                 :          0 : IntxUtils::SphereCoords IntxUtils::cart_to_spherical( CartVect& cart3d )
     693                 :            : {
     694                 :            :     SphereCoords res;
     695                 :          0 :     res.R = cart3d.length();
     696         [ #  # ]:          0 :     if( res.R < 0 )
     697                 :            :     {
     698                 :          0 :         res.lon = res.lat = 0.;
     699                 :          0 :         return res;
     700                 :            :     }
     701                 :          0 :     res.lat = asin( cart3d[2] / res.R );
     702                 :          0 :     res.lon = atan2( cart3d[1], cart3d[0] );
     703         [ #  # ]:          0 :     if( res.lon < 0 ) res.lon += 2 * M_PI;  // M_PI is defined in math.h? it seems to be true, although
     704                 :            :     // there are some defines it depends on :(
     705                 :            :     // #if defined __USE_BSD || defined __USE_XOPEN ???
     706                 :            : 
     707                 :          0 :     return res;
     708                 :            : }
     709                 :            : 
     710                 :            : /*
     711                 :            :  * ! ===================================================================
     712                 :            :  ! spherical_to_cart:
     713                 :            :  ! converts spherical polar {lon,lat}  to 3D cartesian {x,y,z}
     714                 :            :  ! on unit sphere
     715                 :            :  ! ===================================================================
     716                 :            : 
     717                 :            :  function spherical_to_cart(sphere) result (cart)
     718                 :            : 
     719                 :            :  type(spherical_polar_t), intent(in) :: sphere
     720                 :            :  type(cartesian3D_t)                 :: cart
     721                 :            : 
     722                 :            :  cart%x=sphere%r*COS(sphere%lat)*COS(sphere%lon)
     723                 :            :  cart%y=sphere%r*COS(sphere%lat)*SIN(sphere%lon)
     724                 :            :  cart%z=sphere%r*SIN(sphere%lat)
     725                 :            : 
     726                 :            :  end function spherical_to_cart
     727                 :            :  */
     728                 :          0 : CartVect IntxUtils::spherical_to_cart( IntxUtils::SphereCoords& sc )
     729                 :            : {
     730                 :          0 :     CartVect res;
     731                 :          0 :     res[0] = sc.R * cos( sc.lat ) * cos( sc.lon );  // x coordinate
     732                 :          0 :     res[1] = sc.R * cos( sc.lat ) * sin( sc.lon );  // y
     733                 :          0 :     res[2] = sc.R * sin( sc.lat );                  // z
     734                 :          0 :     return res;
     735                 :            : }
     736                 :            : 
     737                 :          3 : ErrorCode IntxUtils::ScaleToRadius( Interface* mb, EntityHandle set, double R )
     738                 :            : {
     739         [ +  - ]:          3 :     Range nodes;
     740         [ +  - ]:          3 :     ErrorCode rval = mb->get_entities_by_type( set, MBVERTEX, nodes, true );  // recursive
     741         [ -  + ]:          3 :     if( rval != moab::MB_SUCCESS ) return rval;
     742                 :            : 
     743                 :            :     // one by one, get the node and project it on the sphere, with a radius given
     744                 :            :     // the center of the sphere is at 0,0,0
     745 [ +  - ][ +  - ]:        495 :     for( Range::iterator nit = nodes.begin(); nit != nodes.end(); ++nit )
         [ +  - ][ +  - ]
                 [ +  + ]
     746                 :            :     {
     747         [ +  - ]:        492 :         EntityHandle nd = *nit;
     748         [ +  - ]:        492 :         CartVect pos;
     749 [ +  - ][ +  - ]:        492 :         rval = mb->get_coords( &nd, 1, (double*)&( pos[0] ) );
     750         [ -  + ]:        492 :         if( rval != moab::MB_SUCCESS ) return rval;
     751         [ +  - ]:        492 :         double len = pos.length();
     752         [ -  + ]:        492 :         if( len == 0. ) return MB_FAILURE;
     753         [ +  - ]:        492 :         pos  = R / len * pos;
     754 [ +  - ][ +  - ]:        492 :         rval = mb->set_coords( &nd, 1, (double*)&( pos[0] ) );
     755         [ -  + ]:        492 :         if( rval != moab::MB_SUCCESS ) return rval;
     756                 :            :     }
     757                 :          3 :     return MB_SUCCESS;
     758                 :            : }
     759                 :            : 
     760                 :            : // assume they are one the same sphere
     761                 :          0 : double IntxAreaUtils::spherical_angle( double* A, double* B, double* C, double Radius )
     762                 :            : {
     763                 :            :     // the angle by definition is between the planes OAB and OBC
     764         [ #  # ]:          0 :     CartVect a( A );
     765         [ #  # ]:          0 :     CartVect b( B );
     766         [ #  # ]:          0 :     CartVect c( C );
     767         [ #  # ]:          0 :     double err1 = a.length_squared() - Radius * Radius;
     768         [ #  # ]:          0 :     if( fabs( err1 ) > 0.0001 )
     769 [ #  # ][ #  # ]:          0 :     { std::cout << " error in input " << a << " radius: " << Radius << " error:" << err1 << "\n"; }
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     770         [ #  # ]:          0 :     CartVect normalOAB = a * b;
     771         [ #  # ]:          0 :     CartVect normalOCB = c * b;
     772         [ #  # ]:          0 :     return angle( normalOAB, normalOCB );
     773                 :            : }
     774                 :            : 
     775                 :            : // could be bigger than M_PI;
     776                 :            : // angle at B could be bigger than M_PI, if the orientation is such that ABC points toward the
     777                 :            : // interior
     778                 :        864 : double IntxUtils::oriented_spherical_angle( double* A, double* B, double* C )
     779                 :            : {
     780                 :            :     // assume the same radius, sphere at origin
     781 [ +  - ][ +  - ]:        864 :     CartVect a( A ), b( B ), c( C );
                 [ +  - ]
     782         [ +  - ]:        864 :     CartVect normalOAB = a * b;
     783         [ +  - ]:        864 :     CartVect normalOCB = c * b;
     784 [ +  - ][ +  - ]:        864 :     CartVect orient    = ( c - b ) * ( a - b );
                 [ +  - ]
     785         [ +  - ]:        864 :     double ang         = angle( normalOAB, normalOCB );  // this is between 0 and M_PI
     786         [ -  + ]:        864 :     if( ang != ang )
     787                 :            :     {
     788                 :            :         // signal of a nan
     789 [ #  # ][ #  # ]:          0 :         std::cout << a << " " << b << " " << c << "\n";
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     790 [ #  # ][ #  # ]:          0 :         std::cout << ang << "\n";
     791                 :            :     }
     792 [ +  - ][ -  + ]:        864 :     if( orient % b < 0 ) return ( 2 * M_PI - ang );  // the other angle, supplement
     793                 :            : 
     794                 :        864 :     return ang;
     795                 :            : }
     796                 :            : 
     797                 :          0 : double IntxAreaUtils::area_spherical_triangle( double* A, double* B, double* C, double Radius )
     798                 :            : {
     799         [ #  # ]:          0 :     switch( m_eAreaMethod )
     800                 :            :     {
     801                 :            :         case Girard:
     802                 :          0 :             return area_spherical_triangle_girard( A, B, C, Radius );
     803                 :            : #ifdef MOAB_HAVE_TEMPESTREMAP
     804                 :            :         case GaussQuadrature:
     805                 :            :             return area_spherical_triangle_GQ( A, B, C, Radius );
     806                 :            : #endif
     807                 :            :         case lHuiller:
     808                 :            :         default:
     809                 :          0 :             return area_spherical_triangle_lHuiller( A, B, C, Radius );
     810                 :            :     }
     811                 :            : }
     812                 :            : 
     813                 :       1154 : double IntxAreaUtils::area_spherical_polygon( double* A, int N, double Radius, int* sign )
     814                 :            : {
     815         [ +  + ]:       1154 :     switch( m_eAreaMethod )
     816                 :            :     {
     817                 :            :         case Girard:
     818                 :        216 :             return area_spherical_polygon_girard( A, N, Radius );
     819                 :            : #ifdef MOAB_HAVE_TEMPESTREMAP
     820                 :            :         case GaussQuadrature:
     821                 :            :             return area_spherical_polygon_GQ( A, N, Radius );
     822                 :            : #endif
     823                 :            :         case lHuiller:
     824                 :            :         default:
     825                 :        938 :             return area_spherical_polygon_lHuiller( A, N, Radius, sign );
     826                 :            :     }
     827                 :            : }
     828                 :            : 
     829                 :          0 : double IntxAreaUtils::area_spherical_triangle_girard( double* A, double* B, double* C, double Radius )
     830                 :            : {
     831 [ #  # ][ #  # ]:          0 :     double correction = spherical_angle( A, B, C, Radius ) + spherical_angle( B, C, A, Radius ) +
     832         [ #  # ]:          0 :                         spherical_angle( C, A, B, Radius ) - M_PI;
     833                 :          0 :     double area = Radius * Radius * correction;
     834                 :            :     // now, is it negative or positive? is it pointing toward the center or outward?
     835 [ #  # ][ #  # ]:          0 :     CartVect a( A ), b( B ), c( C );
                 [ #  # ]
     836 [ #  # ][ #  # ]:          0 :     CartVect abc = ( b - a ) * ( c - a );
                 [ #  # ]
     837 [ #  # ][ #  # ]:          0 :     if( abc % a > 0 )  // dot product positive, means ABC points out
     838                 :          0 :         return area;
     839                 :            :     else
     840                 :          0 :         return -area;
     841                 :            : }
     842                 :            : 
     843                 :        216 : double IntxAreaUtils::area_spherical_polygon_girard( double* A, int N, double Radius )
     844                 :            : {
     845                 :            :     // this should work for non-convex polygons too
     846                 :            :     // assume that the A, A+3, ..., A+3*(N-1) are the coordinates
     847                 :            :     //
     848         [ -  + ]:        216 :     if( N <= 2 ) return 0.;
     849                 :        216 :     double sum_angles = 0.;
     850         [ +  + ]:       1080 :     for( int i = 0; i < N; i++ )
     851                 :            :     {
     852                 :        864 :         int i1 = ( i + 1 ) % N;
     853                 :        864 :         int i2 = ( i + 2 ) % N;
     854                 :        864 :         sum_angles += IntxUtils::oriented_spherical_angle( A + 3 * i, A + 3 * i1, A + 3 * i2 );
     855                 :            :     }
     856                 :        216 :     double correction = sum_angles - ( N - 2 ) * M_PI;
     857                 :        216 :     return Radius * Radius * correction;
     858                 :            : }
     859                 :            : 
     860                 :       3488 : double IntxAreaUtils::area_spherical_polygon_lHuiller( double* A, int N, double Radius, int* sign )
     861                 :            : {
     862                 :            :     // This should work for non-convex polygons too
     863                 :            :     // In the input vector A, assume that the A, A+3, ..., A+3*(N-1) are the coordinates
     864                 :            :     // We also assume that the orientation is positive;
     865                 :            :     // If negative orientation, the area will be negative
     866         [ -  + ]:       3488 :     if( N <= 2 ) return 0.;
     867                 :            : 
     868                 :       3488 :     int lsign   = 1;  // assume positive orientain
     869                 :       3488 :     double area = 0.;
     870         [ +  + ]:      10392 :     for( int i = 1; i < N - 1; i++ )
     871                 :            :     {
     872                 :       6904 :         int i1              = i + 1;
     873                 :       6904 :         double areaTriangle = area_spherical_triangle_lHuiller( A, A + 3 * i, A + 3 * i1, Radius );
     874         [ +  + ]:       6904 :         if( areaTriangle < 0 )
     875                 :       5020 :             lsign = -1;  // signal that we have at least one triangle with negative orientation ;
     876                 :            :                          // possible nonconvex polygon
     877                 :       6904 :         area += areaTriangle;
     878                 :            :     }
     879         [ -  + ]:       3488 :     if( sign ) *sign = lsign;
     880                 :            : 
     881                 :       3488 :     return area;
     882                 :            : }
     883                 :            : 
     884                 :            : #ifdef MOAB_HAVE_TEMPESTREMAP
     885                 :            : double IntxAreaUtils::area_spherical_polygon_GQ( double* A, int N, double Radius )
     886                 :            : {
     887                 :            :     // this should work for non-convex polygons too
     888                 :            :     // In the input vector A, assume that the A, A+3, ..., A+3*(N-1) are the coordinates
     889                 :            :     // We also assume that the orientation is positive;
     890                 :            :     // If negative orientation, the area can be negative
     891                 :            :     if( N <= 2 ) return 0.;
     892                 :            : 
     893                 :            :     // assume positive orientain
     894                 :            :     double area = 0.;
     895                 :            :     for( int i = 1; i < N - 1; i++ )
     896                 :            :     {
     897                 :            :         int i1 = i + 1;
     898                 :            :         area += area_spherical_triangle_GQ( A, A + 3 * i, A + 3 * i1, Radius );
     899                 :            :     }
     900                 :            :     return area;
     901                 :            : }
     902                 :            : 
     903                 :            : /* compute the area by using Gauss-Quadratures; use TR interfaces directly */
     904                 :            : double IntxAreaUtils::area_spherical_triangle_GQ( double* ptA, double* ptB, double* ptC, double )
     905                 :            : {
     906                 :            :     Face face( 3 );
     907                 :            :     NodeVector nodes( 3 );
     908                 :            :     nodes[0] = Node( ptA[0], ptA[1], ptA[2] );
     909                 :            :     nodes[1] = Node( ptB[0], ptB[1], ptB[2] );
     910                 :            :     nodes[2] = Node( ptC[0], ptC[1], ptC[2] );
     911                 :            :     face.SetNode( 0, 0 );
     912                 :            :     face.SetNode( 1, 1 );
     913                 :            :     face.SetNode( 2, 2 );
     914                 :            :     return CalculateFaceArea( face, nodes );
     915                 :            : }
     916                 :            : #endif
     917                 :            : 
     918                 :            : /*
     919                 :            :  *  l'Huiller's formula for spherical triangle
     920                 :            :  *  http://williams.best.vwh.net/avform.htm
     921                 :            :  *  a, b, c are arc measures in radians, too
     922                 :            :  *  A, B, C are angles on the sphere, for which we already have formula
     923                 :            :  *               c
     924                 :            :  *         A -------B
     925                 :            :  *          \       |
     926                 :            :  *           \      |
     927                 :            :  *            \b    |a
     928                 :            :  *             \    |
     929                 :            :  *              \   |
     930                 :            :  *               \  |
     931                 :            :  *                \C|
     932                 :            :  *                 \|
     933                 :            :  *
     934                 :            :  *  (The angle at B is not necessarily a right angle)
     935                 :            :  *
     936                 :            :  *    sin(a)  sin(b)   sin(c)
     937                 :            :  *    ----- = ------ = ------
     938                 :            :  *    sin(A)  sin(B)   sin(C)
     939                 :            :  *
     940                 :            :  * In terms of the sides (this is excess, as before, but numerically stable)
     941                 :            :  *
     942                 :            :  *  E = 4*atan(sqrt(tan(s/2)*tan((s-a)/2)*tan((s-b)/2)*tan((s-c)/2)))
     943                 :            :  */
     944                 :       9454 : double IntxAreaUtils::area_spherical_triangle_lHuiller( double* ptA, double* ptB, double* ptC, double Radius )
     945                 :            : {
     946                 :            : 
     947                 :            :     // now, a is angle BOC, O is origin
     948 [ +  - ][ +  - ]:       9454 :     CartVect vA( ptA ), vB( ptB ), vC( ptC );
                 [ +  - ]
     949         [ +  - ]:       9454 :     double a = angle( vB, vC );
     950         [ +  - ]:       9454 :     double b = angle( vC, vA );
     951         [ +  - ]:       9454 :     double c = angle( vA, vB );
     952                 :       9454 :     int sign = 1;
     953 [ +  - ][ +  - ]:       9454 :     if( ( vA * vB ) % vC < 0 ) sign = -1;
                 [ +  + ]
     954                 :       9454 :     double s   = ( a + b + c ) / 2;
     955                 :       9454 :     double tmp = tan( s / 2 ) * tan( ( s - a ) / 2 ) * tan( ( s - b ) / 2 ) * tan( ( s - c ) / 2 );
     956         [ -  + ]:       9454 :     if( tmp < 0. ) tmp = 0.;
     957                 :            : 
     958                 :       9454 :     double E = 4 * atan( sqrt( tmp ) );
     959 [ -  + ][ #  # ]:       9454 :     if( E != E ) std::cout << " NaN at spherical triangle area \n";
     960                 :            : 
     961                 :       9454 :     double area = sign * E * Radius * Radius;
     962                 :            : 
     963                 :            : #ifdef CHECKNEGATIVEAREA
     964         [ +  + ]:       9454 :     if( area < 0 )
     965                 :            :     {
     966 [ +  - ][ +  - ]:       7570 :         std::cout << "negative area: " << area << "\n";
                 [ +  - ]
     967 [ +  - ][ +  - ]:       7570 :         std::cout << std::setprecision( 15 );
     968 [ +  - ][ +  - ]:       7570 :         std::cout << "vA: " << vA << "\n";
                 [ +  - ]
     969 [ +  - ][ +  - ]:       7570 :         std::cout << "vB: " << vB << "\n";
                 [ +  - ]
     970 [ +  - ][ +  - ]:       7570 :         std::cout << "vC: " << vC << "\n";
                 [ +  - ]
     971 [ +  - ][ +  - ]:       7570 :         std::cout << "sign: " << sign << "\n";
                 [ +  - ]
     972 [ +  - ][ +  - ]:       7570 :         std::cout << " a: " << a << "\n";
                 [ +  - ]
     973 [ +  - ][ +  - ]:       7570 :         std::cout << " b: " << b << "\n";
                 [ +  - ]
     974 [ +  - ][ +  - ]:       7570 :         std::cout << " c: " << c << "\n";
                 [ +  - ]
     975                 :            :     }
     976                 :            : #endif
     977                 :            : 
     978                 :       9454 :     return area;
     979                 :            : }
     980                 :            : #undef CHECKNEGATIVEAREA
     981                 :            : 
     982                 :          4 : double IntxAreaUtils::area_on_sphere( Interface* mb, EntityHandle set, double R )
     983                 :            : {
     984                 :            :     // Get all entities of dimension 2
     985         [ +  - ]:          4 :     Range inputRange;
     986 [ +  - ][ -  + ]:          4 :     ErrorCode rval = mb->get_entities_by_dimension( set, 2, inputRange );MB_CHK_ERR_RET_VAL( rval, -1.0 );
         [ #  # ][ #  # ]
     987                 :            : 
     988                 :            :     // Filter by elements that are owned by current process
     989 [ +  - ][ +  - ]:          8 :     std::vector< int > ownerinfo( inputRange.size(), -1 );
     990                 :            :     Tag intxOwnerTag;
     991         [ +  - ]:          4 :     rval = mb->tag_get_handle( "ORIG_PROC", intxOwnerTag );
     992         [ -  + ]:          4 :     if( MB_SUCCESS == rval )
     993                 :            :     {
     994 [ #  # ][ #  # ]:          0 :         rval = mb->tag_get_data( intxOwnerTag, inputRange, &ownerinfo[0] );MB_CHK_ERR_RET_VAL( rval, -1.0 );
         [ #  # ][ #  # ]
                 [ #  # ]
     995                 :            :     }
     996                 :            : 
     997                 :            :     // compare total area with 4*M_PI * R^2
     998                 :          4 :     int ie            = 0;
     999                 :          4 :     double total_area = 0.;
    1000 [ +  - ][ +  - ]:       1158 :     for( Range::iterator eit = inputRange.begin(); eit != inputRange.end(); ++eit )
         [ +  - ][ +  - ]
                 [ +  + ]
    1001                 :            :     {
    1002                 :            : 
    1003                 :            :         // All zero/positive owner data represents ghosted elems
    1004 [ +  - ][ -  + ]:       1154 :         if( ownerinfo[ie++] >= 0 ) continue;
    1005                 :            : 
    1006         [ +  - ]:       1154 :         EntityHandle eh        = *eit;
    1007         [ +  - ]:       1154 :         const double elem_area = this->area_spherical_element( mb, eh, R );
    1008                 :            : 
    1009                 :            :         // check whether the area of the spherical element is positive.
    1010         [ -  + ]:       1154 :         assert( elem_area > 0 );
    1011                 :            : 
    1012                 :            :         // sum up the contribution
    1013                 :       1154 :         total_area += elem_area;
    1014                 :            :     }
    1015                 :            : 
    1016                 :            :     // return total mesh area
    1017                 :          8 :     return total_area;
    1018                 :            : }
    1019                 :            : 
    1020                 :       1154 : double IntxAreaUtils::area_spherical_element( Interface* mb, EntityHandle elem, double R )
    1021                 :            : {
    1022                 :            :     // get the nodes, then the coordinates
    1023                 :            :     const EntityHandle* verts;
    1024                 :            :     int nsides;
    1025 [ +  - ][ -  + ]:       1154 :     ErrorCode rval = mb->get_connectivity( elem, verts, nsides );MB_CHK_ERR_RET_VAL( rval, -1.0 );
         [ #  # ][ #  # ]
    1026                 :            : 
    1027                 :            :     // account for possible padded polygons
    1028 [ -  + ][ #  # ]:       1154 :     while( verts[nsides - 2] == verts[nsides - 1] && nsides > 3 )
    1029                 :          0 :         nsides--;
    1030                 :            : 
    1031                 :            :     // get coordinates
    1032         [ +  - ]:       1154 :     std::vector< double > coords( 3 * nsides );
    1033 [ +  - ][ +  - ]:       1154 :     rval = mb->get_coords( verts, nsides, &coords[0] );MB_CHK_ERR_RET_VAL( rval, -1.0 );
         [ -  + ][ #  # ]
                 [ #  # ]
    1034                 :            : 
    1035                 :            :     // compute and return the area of the polygonal element
    1036 [ +  - ][ +  - ]:       1154 :     return area_spherical_polygon( &coords[0], nsides, R );
    1037                 :            : }
    1038                 :            : 
    1039                 :          0 : double IntxUtils::distance_on_great_circle( CartVect& p1, CartVect& p2 )
    1040                 :            : {
    1041         [ #  # ]:          0 :     SphereCoords sph1 = cart_to_spherical( p1 );
    1042         [ #  # ]:          0 :     SphereCoords sph2 = cart_to_spherical( p2 );
    1043                 :            :     // radius should be the same
    1044                 :          0 :     return sph1.R *
    1045                 :          0 :            acos( sin( sph1.lon ) * sin( sph2.lon ) + cos( sph1.lat ) * cos( sph2.lat ) * cos( sph2.lon - sph2.lon ) );
    1046                 :            : }
    1047                 :            : 
    1048                 :            : // break the nonconvex quads into triangles; remove the quad from the set? yes.
    1049                 :            : // maybe radius is not needed;
    1050                 :            : //
    1051                 :          0 : ErrorCode IntxUtils::enforce_convexity( Interface* mb, EntityHandle lset, int my_rank )
    1052                 :            : {
    1053                 :            :     // look at each polygon; compute all angles; if one is reflex, break that angle with
    1054                 :            :     // the next triangle; put the 2 new polys in the set;
    1055                 :            :     // still look at the next poly
    1056                 :            :     // replace it with 2 triangles, and remove from set;
    1057                 :            :     // it should work for all polygons / tested first for case 1, with dt 0.5 (too much deformation)
    1058                 :            :     // get all entities of dimension 2
    1059                 :            :     // then get the connectivity, etc
    1060                 :            : 
    1061         [ #  # ]:          0 :     Range inputRange;
    1062         [ #  # ]:          0 :     ErrorCode rval = mb->get_entities_by_dimension( lset, 2, inputRange );
    1063         [ #  # ]:          0 :     if( MB_SUCCESS != rval ) return rval;
    1064                 :            : 
    1065                 :          0 :     Tag corrTag       = 0;
    1066                 :          0 :     EntityHandle dumH = 0;
    1067         [ #  # ]:          0 :     rval              = mb->tag_get_handle( CORRTAGNAME, 1, MB_TYPE_HANDLE, corrTag, MB_TAG_DENSE, &dumH );
    1068         [ #  # ]:          0 :     if( rval == MB_TAG_NOT_FOUND ) corrTag = 0;
    1069                 :            : 
    1070                 :            :     Tag gidTag;
    1071         [ #  # ]:          0 :     rval = mb->tag_get_handle( "GLOBAL_ID", 1, MB_TYPE_INTEGER, gidTag, MB_TAG_DENSE );
    1072                 :            : 
    1073         [ #  # ]:          0 :     if( rval != MB_SUCCESS ) return rval;
    1074                 :            : 
    1075         [ #  # ]:          0 :     std::vector< double > coords;
    1076         [ #  # ]:          0 :     coords.resize( 3 * MAXEDGES );  // at most 10 vertices per polygon
    1077                 :            :     // we should create a queue with new polygons that need processing for reflex angles
    1078                 :            :     //  (obtuse)
    1079 [ #  # ][ #  # ]:          0 :     std::queue< EntityHandle > newPolys;
    1080                 :          0 :     int brokenPolys     = 0;
    1081         [ #  # ]:          0 :     Range::iterator eit = inputRange.begin();
    1082 [ #  # ][ #  # ]:          0 :     while( eit != inputRange.end() || !newPolys.empty() )
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
           [ #  #  #  # ]
    1083                 :            :     {
    1084                 :            :         EntityHandle eh;
    1085 [ #  # ][ #  # ]:          0 :         if( eit != inputRange.end() )
                 [ #  # ]
    1086                 :            :         {
    1087         [ #  # ]:          0 :             eh = *eit;
    1088         [ #  # ]:          0 :             ++eit;
    1089                 :            :         }
    1090                 :            :         else
    1091                 :            :         {
    1092         [ #  # ]:          0 :             eh = newPolys.front();
    1093         [ #  # ]:          0 :             newPolys.pop();
    1094                 :            :         }
    1095                 :            :         // get the nodes, then the coordinates
    1096                 :            :         const EntityHandle* verts;
    1097                 :            :         int num_nodes;
    1098         [ #  # ]:          0 :         rval = mb->get_connectivity( eh, verts, num_nodes );
    1099         [ #  # ]:          0 :         if( MB_SUCCESS != rval ) return rval;
    1100                 :          0 :         int nsides = num_nodes;
    1101                 :            :         // account for possible padded polygons
    1102 [ #  # ][ #  # ]:          0 :         while( verts[nsides - 2] == verts[nsides - 1] && nsides > 3 )
    1103                 :          0 :             nsides--;
    1104                 :          0 :         EntityHandle corrHandle = 0;
    1105         [ #  # ]:          0 :         if( corrTag )
    1106                 :            :         {
    1107         [ #  # ]:          0 :             rval = mb->tag_get_data( corrTag, &eh, 1, &corrHandle );
    1108         [ #  # ]:          0 :             if( MB_SUCCESS != rval ) return rval;
    1109                 :            :         }
    1110                 :          0 :         int gid = 0;
    1111         [ #  # ]:          0 :         rval    = mb->tag_get_data( gidTag, &eh, 1, &gid );
    1112         [ #  # ]:          0 :         if( MB_SUCCESS != rval ) return rval;
    1113         [ #  # ]:          0 :         coords.resize( 3 * nsides );
    1114         [ #  # ]:          0 :         if( nsides < 4 ) continue;  // if already triangles, don't bother
    1115                 :            :         // get coordinates
    1116 [ #  # ][ #  # ]:          0 :         rval = mb->get_coords( verts, nsides, &coords[0] );
    1117         [ #  # ]:          0 :         if( MB_SUCCESS != rval ) return rval;
    1118                 :            :         // compute each angle
    1119                 :          0 :         bool alreadyBroken = false;
    1120                 :            : 
    1121         [ #  # ]:          0 :         for( int i = 0; i < nsides; i++ )
    1122                 :            :         {
    1123         [ #  # ]:          0 :             double* A    = &coords[3 * i];
    1124         [ #  # ]:          0 :             double* B    = &coords[3 * ( ( i + 1 ) % nsides )];
    1125         [ #  # ]:          0 :             double* C    = &coords[3 * ( ( i + 2 ) % nsides )];
    1126         [ #  # ]:          0 :             double angle = IntxUtils::oriented_spherical_angle( A, B, C );
    1127         [ #  # ]:          0 :             if( angle - M_PI > 0. )  // even almost reflex is bad; break it!
    1128                 :            :             {
    1129         [ #  # ]:          0 :                 if( alreadyBroken )
    1130                 :            :                 {
    1131         [ #  # ]:          0 :                     mb->list_entities( &eh, 1 );
    1132         [ #  # ]:          0 :                     mb->list_entities( verts, nsides );
    1133         [ #  # ]:          0 :                     double* D = &coords[3 * ( ( i + 3 ) % nsides )];
    1134 [ #  # ][ #  # ]:          0 :                     std::cout << "ABC: " << angle << " \n";
                 [ #  # ]
    1135 [ #  # ][ #  # ]:          0 :                     std::cout << "BCD: " << IntxUtils::oriented_spherical_angle( B, C, D ) << " \n";
         [ #  # ][ #  # ]
    1136 [ #  # ][ #  # ]:          0 :                     std::cout << "CDA: " << IntxUtils::oriented_spherical_angle( C, D, A ) << " \n";
         [ #  # ][ #  # ]
    1137 [ #  # ][ #  # ]:          0 :                     std::cout << "DAB: " << IntxUtils::oriented_spherical_angle( D, A, B ) << " \n";
         [ #  # ][ #  # ]
    1138         [ #  # ]:          0 :                     std::cout << " this cell has at least 2 angles > 180, it has serious issues\n";
    1139                 :            : 
    1140                 :          0 :                     return MB_FAILURE;
    1141                 :            :                 }
    1142                 :            :                 // the bad angle is at i+1;
    1143                 :            :                 // create 1 triangle and one polygon; add the polygon to the input range, so
    1144                 :            :                 // it will be processed too
    1145                 :            :                 // also, add both to the set :) and remove the original polygon from the set
    1146                 :            :                 // break the next triangle, even though not optimal
    1147                 :            :                 // so create the triangle i+1, i+2, i+3; remove i+2 from original list
    1148                 :            :                 // even though not optimal in general, it is good enough.
    1149                 :          0 :                 EntityHandle conn3[3] = { verts[( i + 1 ) % nsides], verts[( i + 2 ) % nsides],
    1150                 :          0 :                                           verts[( i + 3 ) % nsides] };
    1151                 :            :                 // create a polygon with num_nodes-1 vertices, and connectivity
    1152                 :            :                 // verts[i+1], verts[i+3], (all except i+2)
    1153         [ #  # ]:          0 :                 std::vector< EntityHandle > conn( nsides - 1 );
    1154         [ #  # ]:          0 :                 for( int j = 1; j < nsides; j++ )
    1155                 :            :                 {
    1156         [ #  # ]:          0 :                     conn[j - 1] = verts[( i + j + 2 ) % nsides];
    1157                 :            :                 }
    1158                 :            :                 EntityHandle newElement;
    1159         [ #  # ]:          0 :                 rval = mb->create_element( MBTRI, conn3, 3, newElement );
    1160         [ #  # ]:          0 :                 if( MB_SUCCESS != rval ) return rval;
    1161                 :            : 
    1162         [ #  # ]:          0 :                 rval = mb->add_entities( lset, &newElement, 1 );
    1163         [ #  # ]:          0 :                 if( MB_SUCCESS != rval ) return rval;
    1164         [ #  # ]:          0 :                 if( corrTag )
    1165                 :            :                 {
    1166         [ #  # ]:          0 :                     rval = mb->tag_set_data( corrTag, &newElement, 1, &corrHandle );
    1167         [ #  # ]:          0 :                     if( MB_SUCCESS != rval ) return rval;
    1168                 :            :                 }
    1169         [ #  # ]:          0 :                 rval = mb->tag_set_data( gidTag, &newElement, 1, &gid );
    1170         [ #  # ]:          0 :                 if( MB_SUCCESS != rval ) return rval;
    1171         [ #  # ]:          0 :                 if( nsides == 4 )
    1172                 :            :                 {
    1173                 :            :                     // create another triangle
    1174 [ #  # ][ #  # ]:          0 :                     rval = mb->create_element( MBTRI, &conn[0], 3, newElement );
    1175         [ #  # ]:          0 :                     if( MB_SUCCESS != rval ) return rval;
    1176                 :            :                 }
    1177                 :            :                 else
    1178                 :            :                 {
    1179                 :            :                     // create another polygon, and add it to the inputRange
    1180 [ #  # ][ #  # ]:          0 :                     rval = mb->create_element( MBPOLYGON, &conn[0], nsides - 1, newElement );
    1181         [ #  # ]:          0 :                     if( MB_SUCCESS != rval ) return rval;
    1182         [ #  # ]:          0 :                     newPolys.push( newElement );  // because it has less number of edges, the
    1183                 :            :                     // reverse should work to find it.
    1184                 :            :                 }
    1185         [ #  # ]:          0 :                 rval = mb->add_entities( lset, &newElement, 1 );
    1186         [ #  # ]:          0 :                 if( MB_SUCCESS != rval ) return rval;
    1187         [ #  # ]:          0 :                 if( corrTag )
    1188                 :            :                 {
    1189         [ #  # ]:          0 :                     rval = mb->tag_set_data( corrTag, &newElement, 1, &corrHandle );
    1190         [ #  # ]:          0 :                     if( MB_SUCCESS != rval ) return rval;
    1191                 :            :                 }
    1192         [ #  # ]:          0 :                 rval = mb->tag_set_data( gidTag, &newElement, 1, &gid );
    1193         [ #  # ]:          0 :                 if( MB_SUCCESS != rval ) return rval;
    1194         [ #  # ]:          0 :                 mb->remove_entities( lset, &eh, 1 );
    1195                 :          0 :                 brokenPolys++;
    1196                 :            :                 /*std::cout<<"remove: " ;
    1197                 :            :                  mb->list_entities(&eh, 1);
    1198                 :            : 
    1199                 :            :                  std::stringstream fff;
    1200                 :            :                  fff << "file0" <<  brokenQuads<< ".vtk";
    1201                 :            :                  mb->write_file(fff.str().c_str(), 0, 0, &lset, 1);*/
    1202         [ #  # ]:          0 :                 alreadyBroken = true;  // get out of the loop, element is broken
    1203                 :            :             }
    1204                 :            :         }
    1205                 :            :     }
    1206 [ #  # ][ #  # ]:          0 :     std::cout << "on local process " << my_rank << " " << brokenPolys
         [ #  # ][ #  # ]
    1207         [ #  # ]:          0 :               << " concave polygons were decomposed in convex ones \n";
    1208                 :          0 :     return MB_SUCCESS;
    1209                 :            : }
    1210                 :            : 
    1211                 :            : // looking at quad connectivity, collapse to triangle if 2 nodes equal
    1212                 :            : // then delete the old quad
    1213                 :          1 : ErrorCode IntxUtils::fix_degenerate_quads( Interface* mb, EntityHandle set )
    1214                 :            : {
    1215         [ +  - ]:          1 :     Range quads;
    1216 [ +  - ][ -  + ]:          1 :     ErrorCode rval = mb->get_entities_by_type( set, MBQUAD, quads );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1217                 :            :     Tag gid;
    1218         [ +  - ]:          1 :     gid = mb->globalId_tag();
    1219 [ +  - ][ +  - ]:       1201 :     for( Range::iterator qit = quads.begin(); qit != quads.end(); ++qit )
         [ +  - ][ +  - ]
                 [ +  + ]
    1220                 :            :     {
    1221         [ +  - ]:       1200 :         EntityHandle quad         = *qit;
    1222                 :       1200 :         const EntityHandle* conn4 = NULL;
    1223                 :       1200 :         int num_nodes             = 0;
    1224 [ +  - ][ -  + ]:       1200 :         rval                      = mb->get_connectivity( quad, conn4, num_nodes );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1225         [ +  + ]:       6000 :         for( int i = 0; i < num_nodes; i++ )
    1226                 :            :         {
    1227                 :       4800 :             int next_node_index = ( i + 1 ) % num_nodes;
    1228         [ +  + ]:       4800 :             if( conn4[i] == conn4[next_node_index] )
    1229                 :            :             {
    1230                 :            :                 // form a triangle and delete the quad
    1231                 :            :                 // first get the global id, to set it on triangle later
    1232                 :         80 :                 int global_id = 0;
    1233 [ +  - ][ -  + ]:         80 :                 rval          = mb->tag_get_data( gid, &quad, 1, &global_id );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1234                 :         80 :                 int i2                = ( i + 2 ) % num_nodes;
    1235                 :         80 :                 int i3                = ( i + 3 ) % num_nodes;
    1236                 :         80 :                 EntityHandle conn3[3] = { conn4[i], conn4[i2], conn4[i3] };
    1237                 :            :                 EntityHandle tri;
    1238 [ +  - ][ -  + ]:         80 :                 rval = mb->create_element( MBTRI, conn3, 3, tri );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1239         [ +  - ]:         80 :                 mb->add_entities( set, &tri, 1 );
    1240         [ +  - ]:         80 :                 mb->remove_entities( set, &quad, 1 );
    1241         [ +  - ]:         80 :                 mb->delete_entities( &quad, 1 );
    1242 [ +  - ][ -  + ]:         80 :                 rval = mb->tag_set_data( gid, &tri, 1, &global_id );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1243                 :            :             }
    1244                 :            :         }
    1245                 :            :     }
    1246                 :          1 :     return MB_SUCCESS;
    1247                 :            : }
    1248                 :            : 
    1249                 :          4 : ErrorCode IntxAreaUtils::positive_orientation( Interface* mb, EntityHandle set, double R )
    1250                 :            : {
    1251         [ +  - ]:          4 :     Range cells2d;
    1252         [ +  - ]:          4 :     ErrorCode rval = mb->get_entities_by_dimension( set, 2, cells2d );
    1253         [ -  + ]:          4 :     if( MB_SUCCESS != rval ) return rval;
    1254 [ +  - ][ +  - ]:       2634 :     for( Range::iterator qit = cells2d.begin(); qit != cells2d.end(); ++qit )
         [ +  - ][ +  - ]
                 [ +  + ]
    1255                 :            :     {
    1256         [ +  - ]:       2630 :         EntityHandle cell        = *qit;
    1257                 :       2630 :         const EntityHandle* conn = NULL;
    1258                 :       2630 :         int num_nodes            = 0;
    1259         [ +  - ]:       2630 :         rval                     = mb->get_connectivity( cell, conn, num_nodes );
    1260         [ -  + ]:       2630 :         if( MB_SUCCESS != rval ) return rval;
    1261         [ -  + ]:       2630 :         if( num_nodes < 3 ) return MB_FAILURE;
    1262                 :            : 
    1263                 :            :         double coords[9];
    1264         [ +  - ]:       2630 :         rval = mb->get_coords( conn, 3, coords );
    1265         [ -  + ]:       2630 :         if( MB_SUCCESS != rval ) return rval;
    1266                 :            : 
    1267                 :            :         double area;
    1268         [ +  + ]:       2630 :         if( R > 0 )
    1269         [ +  - ]:       2550 :             area = area_spherical_triangle_lHuiller( coords, coords + 3, coords + 6, R );
    1270                 :            :         else
    1271         [ +  - ]:         80 :             area = IntxUtils::area2D( coords, coords + 3, coords + 6 );
    1272         [ +  + ]:       2630 :         if( area < 0 )
    1273                 :            :         {
    1274                 :            :             // compute all area, do not revert if total area is positive
    1275         [ +  - ]:       2550 :             std::vector< double > coords2( 3 * num_nodes );
    1276                 :            :             // get coordinates
    1277 [ +  - ][ +  - ]:       2550 :             rval = mb->get_coords( conn, num_nodes, &coords2[0] );
    1278         [ -  + ]:       2550 :             if( MB_SUCCESS != rval ) return MB_FAILURE;
    1279 [ +  - ][ +  - ]:       2550 :             double totArea = area_spherical_polygon_lHuiller( &coords2[0], num_nodes, R );
    1280         [ +  - ]:       2550 :             if( totArea < 0 )
    1281                 :            :             {
    1282         [ +  - ]:       2550 :                 std::vector< EntityHandle > newconn( num_nodes );
    1283         [ +  + ]:      12670 :                 for( int i = 0; i < num_nodes; i++ )
    1284                 :            :                 {
    1285         [ +  - ]:      10120 :                     newconn[num_nodes - 1 - i] = conn[i];
    1286                 :            :                 }
    1287 [ +  - ][ +  - ]:       2550 :                 rval = mb->set_connectivity( cell, &newconn[0], num_nodes );
    1288 [ -  + ][ +  - ]:       2550 :                 if( MB_SUCCESS != rval ) return rval;
    1289                 :            :             }
    1290                 :            :             else
    1291                 :            :             {
    1292 [ #  # ][ #  # ]:       2550 :                 std::cout << " nonconvex problem first area:" << area << " total area: " << totArea << std::endl;
         [ #  # ][ #  # ]
         [ #  # ][ +  - ]
    1293                 :       2550 :             }
    1294                 :            :         }
    1295                 :            :     }
    1296                 :          4 :     return MB_SUCCESS;
    1297                 :            : }
    1298                 :            : 
    1299                 :            : // distance along a great circle on a sphere of radius 1
    1300                 :            : // page 4
    1301                 :          0 : double IntxUtils::distance_on_sphere( double la1, double te1, double la2, double te2 )
    1302                 :            : {
    1303                 :          0 :     return acos( sin( te1 ) * sin( te2 ) + cos( te1 ) * cos( te2 ) * cos( la1 - la2 ) );
    1304                 :            : }
    1305                 :            : 
    1306                 :            : /*
    1307                 :            :  * given 2 great circle arcs, AB and CD, compute the unique intersection point, if it exists
    1308                 :            :  *  in between
    1309                 :            :  */
    1310                 :          2 : ErrorCode IntxUtils::intersect_great_circle_arcs( double* A, double* B, double* C, double* D, double R, double* E )
    1311                 :            : {
    1312                 :            :     // first verify A, B, C, D are on the same sphere
    1313                 :          2 :     double R2              = R * R;
    1314                 :          2 :     const double Tolerance = 1.e-12 * R2;
    1315                 :            : 
    1316 [ +  - ][ +  - ]:          2 :     CartVect a( A ), b( B ), c( C ), d( D );
         [ +  - ][ +  - ]
    1317                 :            : 
    1318 [ +  - ][ +  - ]:          4 :     if( fabs( a.length_squared() - R2 ) + fabs( b.length_squared() - R2 ) + fabs( c.length_squared() - R2 ) +
         [ +  - ][ -  + ]
    1319         [ +  - ]:          2 :             fabs( d.length_squared() - R2 ) >
    1320                 :          2 :         10 * Tolerance )
    1321                 :          0 :         return MB_FAILURE;
    1322                 :            : 
    1323         [ +  - ]:          2 :     CartVect n1 = a * b;
    1324 [ +  - ][ -  + ]:          2 :     if( n1.length_squared() < Tolerance ) return MB_FAILURE;
    1325                 :            : 
    1326         [ +  - ]:          2 :     CartVect n2 = c * d;
    1327 [ +  - ][ -  + ]:          2 :     if( n2.length_squared() < Tolerance ) return MB_FAILURE;
    1328         [ +  - ]:          2 :     CartVect n3 = n1 * n2;
    1329         [ +  - ]:          2 :     n3.normalize();
    1330                 :            : 
    1331         [ +  - ]:          2 :     n3 = R * n3;
    1332                 :            :     // the intersection is either n3 or -n3
    1333 [ +  - ][ +  - ]:          2 :     CartVect n4 = a * n3, n5 = n3 * b;
    1334 [ +  - ][ -  + ]:          2 :     if( n1 % n4 >= -Tolerance && n1 % n5 >= -Tolerance )
         [ #  # ][ #  # ]
                 [ -  + ]
    1335                 :            :     {
    1336                 :            :         // n3 is good for ab, see if it is good for cd
    1337         [ #  # ]:          0 :         n4 = c * n3;
    1338         [ #  # ]:          0 :         n5 = n3 * d;
    1339 [ #  # ][ #  # ]:          0 :         if( n2 % n4 >= -Tolerance && n2 % n5 >= -Tolerance )
         [ #  # ][ #  # ]
                 [ #  # ]
    1340                 :            :         {
    1341         [ #  # ]:          0 :             E[0] = n3[0];
    1342         [ #  # ]:          0 :             E[1] = n3[1];
    1343         [ #  # ]:          0 :             E[2] = n3[2];
    1344                 :            :         }
    1345                 :            :         else
    1346                 :          0 :             return MB_FAILURE;
    1347                 :            :     }
    1348                 :            :     else
    1349                 :            :     {
    1350                 :            :         // try -n3
    1351         [ +  - ]:          2 :         n3 = -n3;
    1352 [ +  - ][ +  - ]:          2 :         n4 = a * n3, n5 = n3 * b;
    1353 [ +  - ][ +  - ]:          2 :         if( n1 % n4 >= -Tolerance && n1 % n5 >= -Tolerance )
         [ +  - ][ +  + ]
                 [ +  + ]
    1354                 :            :         {
    1355                 :            :             // n3 is good for ab, see if it is good for cd
    1356         [ +  - ]:          1 :             n4 = c * n3;
    1357         [ +  - ]:          1 :             n5 = n3 * d;
    1358 [ +  - ][ +  - ]:          1 :             if( n2 % n4 >= -Tolerance && n2 % n5 >= -Tolerance )
         [ +  - ][ +  - ]
                 [ +  - ]
    1359                 :            :             {
    1360         [ +  - ]:          1 :                 E[0] = n3[0];
    1361         [ +  - ]:          1 :                 E[1] = n3[1];
    1362         [ +  - ]:          1 :                 E[2] = n3[2];
    1363                 :            :             }
    1364                 :            :             else
    1365                 :          0 :                 return MB_FAILURE;
    1366                 :            :         }
    1367                 :            :         else
    1368                 :          1 :             return MB_FAILURE;
    1369                 :            :     }
    1370                 :            : 
    1371                 :          2 :     return MB_SUCCESS;
    1372                 :            : }
    1373                 :            : 
    1374                 :            : // verify that result is in between a and b on a great circle arc, and between c and d on a constant
    1375                 :            : // latitude arc
    1376                 :      96448 : static bool verify( CartVect a, CartVect b, CartVect c, CartVect d, double x, double y, double z )
    1377                 :            : {
    1378                 :            :     // to check, the point has to be between a and b on a great arc, and between c and d on a const
    1379                 :            :     // lat circle
    1380         [ +  - ]:      96448 :     CartVect s( x, y, z );
    1381         [ +  - ]:      96448 :     CartVect n1 = a * b;
    1382         [ +  - ]:      96448 :     CartVect n2 = a * s;
    1383         [ +  - ]:      96448 :     CartVect n3 = s * b;
    1384 [ +  - ][ +  + ]:      96448 :     if( n1 % n2 < 0 || n1 % n3 < 0 ) return false;
         [ +  - ][ +  + ]
                 [ +  + ]
    1385                 :            : 
    1386                 :            :     // do the same for c, d, s, in plane z=0
    1387 [ +  - ][ +  - ]:      15716 :     c[2] = d[2] = s[2] = 0.;  // bring everything in the same plane, z=0;
                 [ +  - ]
    1388                 :            : 
    1389         [ +  - ]:      15716 :     n1 = c * d;
    1390         [ +  - ]:      15716 :     n2 = c * s;
    1391         [ +  - ]:      15716 :     n3 = s * d;
    1392 [ +  - ][ +  + ]:      15716 :     if( n1 % n2 < 0 || n1 % n3 < 0 ) return false;
         [ +  - ][ +  + ]
                 [ +  + ]
    1393                 :            : 
    1394                 :      96448 :     return true;
    1395                 :            : }
    1396                 :            : 
    1397                 :      59842 : ErrorCode IntxUtils::intersect_great_circle_arc_with_clat_arc( double* A, double* B, double* C, double* D, double R,
    1398                 :            :                                                                double* E, int& np )
    1399                 :            : {
    1400                 :      59842 :     const double distTol   = R * 1.e-6;
    1401                 :      59842 :     const double Tolerance = R * R * 1.e-12;  // radius should be 1, usually
    1402                 :      59842 :     np                     = 0;               // number of points in intersection
    1403 [ +  - ][ +  - ]:      59842 :     CartVect a( A ), b( B ), c( C ), d( D );
         [ +  - ][ +  - ]
    1404                 :            :     // check input first
    1405                 :      59842 :     double R2 = R * R;
    1406 [ +  - ][ +  - ]:     119684 :     if( fabs( a.length_squared() - R2 ) + fabs( b.length_squared() - R2 ) + fabs( c.length_squared() - R2 ) +
         [ +  - ][ -  + ]
    1407         [ +  - ]:      59842 :             fabs( d.length_squared() - R2 ) >
    1408                 :      59842 :         10 * Tolerance )
    1409                 :          0 :         return MB_FAILURE;
    1410                 :            : 
    1411 [ +  - ][ +  - ]:      59842 :     if( ( a - b ).length_squared() < Tolerance ) return MB_FAILURE;
                 [ -  + ]
    1412 [ +  - ][ +  - ]:      59842 :     if( ( c - d ).length_squared() < Tolerance )  // edges are too short
                 [ -  + ]
    1413                 :          0 :         return MB_FAILURE;
    1414                 :            : 
    1415                 :            :     // CD is the const latitude arc
    1416         [ -  + ]:      59842 :     if( fabs( C[2] - D[2] ) > distTol )  // cd is not on the same z (constant latitude)
    1417                 :          0 :         return MB_FAILURE;
    1418                 :            : 
    1419 [ +  - ][ -  + ]:      59842 :     if( fabs( R - C[2] ) < distTol || fabs( R + C[2] ) < distTol ) return MB_FAILURE;  // too close to the poles
    1420                 :            : 
    1421                 :            :     // find the points on the circle P(teta) = (r*sin(teta), r*cos(teta), C[2]) that are on the
    1422                 :            :     // great circle arc AB normal to the AB circle:
    1423         [ +  - ]:      59842 :     CartVect n1 = a * b;  // the normal to the great circle arc (circle)
    1424                 :            :     // solve the system of equations:
    1425                 :            :     /*
    1426                 :            :      *    n1%(x, y, z) = 0  // on the great circle
    1427                 :            :      *     z = C[2];
    1428                 :            :      *    x^2+y^2+z^2 = R^2
    1429                 :            :      */
    1430                 :      59842 :     double z = C[2];
    1431 [ +  - ][ +  - ]:      59842 :     if( fabs( n1[0] ) + fabs( n1[1] ) < 2 * Tolerance )
                 [ -  + ]
    1432                 :            :     {
    1433                 :            :         // it is the Equator; check if the const lat edge is Equator too
    1434         [ #  # ]:          0 :         if( fabs( C[2] ) > distTol )
    1435                 :            :         {
    1436                 :          0 :             return MB_FAILURE;  // no intx, too far from Eq
    1437                 :            :         }
    1438                 :            :         else
    1439                 :            :         {
    1440                 :            :             // all points are on the equator
    1441                 :            :             //
    1442         [ #  # ]:          0 :             CartVect cd = c * d;
    1443                 :            :             // by convention,  c<d, positive is from c to d
    1444                 :            :             // is a or b between c , d?
    1445         [ #  # ]:          0 :             CartVect ca = c * a;
    1446         [ #  # ]:          0 :             CartVect ad = a * d;
    1447         [ #  # ]:          0 :             CartVect cb = c * b;
    1448         [ #  # ]:          0 :             CartVect bd = b * d;
    1449         [ #  # ]:          0 :             bool agtc   = ( ca % cd >= -Tolerance );  // a>c?
    1450         [ #  # ]:          0 :             bool dgta   = ( ad % cd >= -Tolerance );  // d>a?
    1451         [ #  # ]:          0 :             bool bgtc   = ( cb % cd >= -Tolerance );  // b>c?
    1452         [ #  # ]:          0 :             bool dgtb   = ( bd % cd >= -Tolerance );  // d>b?
    1453         [ #  # ]:          0 :             if( agtc )
    1454                 :            :             {
    1455         [ #  # ]:          0 :                 if( dgta )
    1456                 :            :                 {
    1457                 :            :                     // a is for sure a point
    1458         [ #  # ]:          0 :                     E[0] = a[0];
    1459         [ #  # ]:          0 :                     E[1] = a[1];
    1460         [ #  # ]:          0 :                     E[2] = a[2];
    1461                 :          0 :                     np++;
    1462         [ #  # ]:          0 :                     if( bgtc )
    1463                 :            :                     {
    1464         [ #  # ]:          0 :                         if( dgtb )
    1465                 :            :                         {
    1466                 :            :                             // b is also in between c and d
    1467         [ #  # ]:          0 :                             E[3] = b[0];
    1468         [ #  # ]:          0 :                             E[4] = b[1];
    1469         [ #  # ]:          0 :                             E[5] = b[2];
    1470                 :          0 :                             np++;
    1471                 :            :                         }
    1472                 :            :                         else
    1473                 :            :                         {
    1474                 :            :                             // then order is c a d b, intx is ad
    1475         [ #  # ]:          0 :                             E[3] = d[0];
    1476         [ #  # ]:          0 :                             E[4] = d[1];
    1477         [ #  # ]:          0 :                             E[5] = d[2];
    1478                 :          0 :                             np++;
    1479                 :            :                         }
    1480                 :            :                     }
    1481                 :            :                     else
    1482                 :            :                     {
    1483                 :            :                         // b is less than c, so b c a d, intx is ac
    1484         [ #  # ]:          0 :                         E[3] = c[0];
    1485         [ #  # ]:          0 :                         E[4] = c[1];
    1486         [ #  # ]:          0 :                         E[5] = c[2];
    1487                 :          0 :                         np++;  // what if E[0] is E[3]?
    1488                 :            :                     }
    1489                 :            :                 }
    1490                 :            :                 else  // c < d < a
    1491                 :            :                 {
    1492         [ #  # ]:          0 :                     if( dgtb )  // d is for sure in
    1493                 :            :                     {
    1494         [ #  # ]:          0 :                         E[0] = d[0];
    1495         [ #  # ]:          0 :                         E[1] = d[1];
    1496         [ #  # ]:          0 :                         E[2] = d[2];
    1497                 :          0 :                         np++;
    1498         [ #  # ]:          0 :                         if( bgtc )  // c<b<d<a
    1499                 :            :                         {
    1500                 :            :                             // another point is b
    1501         [ #  # ]:          0 :                             E[3] = b[0];
    1502         [ #  # ]:          0 :                             E[4] = b[1];
    1503         [ #  # ]:          0 :                             E[5] = b[2];
    1504                 :          0 :                             np++;
    1505                 :            :                         }
    1506                 :            :                         else  // b<c<d<a
    1507                 :            :                         {
    1508                 :            :                             // another point is c
    1509         [ #  # ]:          0 :                             E[3] = c[0];
    1510         [ #  # ]:          0 :                             E[4] = c[1];
    1511         [ #  # ]:          0 :                             E[5] = c[2];
    1512                 :          0 :                             np++;
    1513                 :            :                         }
    1514                 :            :                     }
    1515                 :            :                     else
    1516                 :            :                     {
    1517                 :            :                         // nothing, order is c, d < a, b
    1518                 :            :                     }
    1519                 :            :                 }
    1520                 :            :             }
    1521                 :            :             else  // a < c < d
    1522                 :            :             {
    1523         [ #  # ]:          0 :                 if( bgtc )
    1524                 :            :                 {
    1525                 :            :                     // c is for sure in
    1526         [ #  # ]:          0 :                     E[0] = c[0];
    1527         [ #  # ]:          0 :                     E[1] = c[1];
    1528         [ #  # ]:          0 :                     E[2] = c[2];
    1529                 :          0 :                     np++;
    1530         [ #  # ]:          0 :                     if( dgtb )
    1531                 :            :                     {
    1532                 :            :                         // a < c < b < d; second point is b
    1533         [ #  # ]:          0 :                         E[3] = b[0];
    1534         [ #  # ]:          0 :                         E[4] = b[1];
    1535         [ #  # ]:          0 :                         E[5] = b[2];
    1536                 :          0 :                         np++;
    1537                 :            :                     }
    1538                 :            :                     else
    1539                 :            :                     {
    1540                 :            :                         // a < c < d < b; second point is d
    1541         [ #  # ]:          0 :                         E[3] = d[0];
    1542         [ #  # ]:          0 :                         E[4] = d[1];
    1543         [ #  # ]:          0 :                         E[5] = d[2];
    1544                 :          0 :                         np++;
    1545                 :            :                     }
    1546                 :            :                 }
    1547                 :            :                 else  // a, b < c < d
    1548                 :            :                 {
    1549                 :            :                     // nothing
    1550                 :            :                 }
    1551                 :            :             }
    1552                 :            :         }
    1553                 :            :         // for the 2 points selected, see if it is only one?
    1554                 :            :         // no problem, maybe it will be collapsed later anyway
    1555         [ #  # ]:          0 :         if( np > 0 ) return MB_SUCCESS;
    1556                 :          0 :         return MB_FAILURE;  // no intersection
    1557                 :            :     }
    1558                 :            :     {
    1559 [ +  - ][ +  - ]:      59842 :         if( fabs( n1[0] ) <= fabs( n1[1] ) )
                 [ +  + ]
    1560                 :            :         {
    1561                 :            :             // resolve eq in x:  n0 * x + n1 * y +n2*z = 0; y = -n2/n1*z -n0/n1*x
    1562                 :            :             //  (u+v*x)^2+x^2=R2-z^2
    1563                 :            :             //  (v^2+1)*x^2 + 2*u*v *x + u^2+z^2-R^2 = 0
    1564                 :            :             //  delta = 4*u^2*v^2 - 4*(v^2-1)(u^2+z^2-R^2)
    1565                 :            :             // x1,2 =
    1566 [ +  - ][ +  - ]:      30516 :             double u = -n1[2] / n1[1] * z, v = -n1[0] / n1[1];
         [ +  - ][ +  - ]
    1567                 :      30516 :             double a1 = v * v + 1, b1 = 2 * u * v, c1 = u * u + z * z - R2;
    1568                 :      30516 :             double delta = b1 * b1 - 4 * a1 * c1;
    1569         [ +  + ]:      30516 :             if( delta < -Tolerance ) return MB_FAILURE;  // no intersection
    1570         [ +  - ]:      24693 :             if( delta > Tolerance )                      // 2 solutions possible
    1571                 :            :             {
    1572                 :      24693 :                 double x1 = ( -b1 + sqrt( delta ) ) / 2 / a1;
    1573                 :      24693 :                 double x2 = ( -b1 - sqrt( delta ) ) / 2 / a1;
    1574                 :      24693 :                 double y1 = u + v * x1;
    1575                 :      24693 :                 double y2 = u + v * x2;
    1576 [ +  - ][ +  + ]:      24693 :                 if( verify( a, b, c, d, x1, y1, z ) )
    1577                 :            :                 {
    1578                 :       2004 :                     E[0] = x1;
    1579                 :       2004 :                     E[1] = y1;
    1580                 :       2004 :                     E[2] = z;
    1581                 :       2004 :                     np++;
    1582                 :            :                 }
    1583 [ +  - ][ +  + ]:      24693 :                 if( verify( a, b, c, d, x2, y2, z ) )
    1584                 :            :                 {
    1585                 :       2013 :                     E[3 * np + 0] = x2;
    1586                 :       2013 :                     E[3 * np + 1] = y2;
    1587                 :       2013 :                     E[3 * np + 2] = z;
    1588                 :      24693 :                     np++;
    1589                 :            :                 }
    1590                 :            :             }
    1591                 :            :             else
    1592                 :            :             {
    1593                 :            :                 // one solution
    1594                 :          0 :                 double x1 = -b1 / 2 / a1;
    1595                 :          0 :                 double y1 = u + v * x1;
    1596 [ #  # ][ #  # ]:          0 :                 if( verify( a, b, c, d, x1, y1, z ) )
    1597                 :            :                 {
    1598                 :          0 :                     E[0] = x1;
    1599                 :          0 :                     E[1] = y1;
    1600                 :          0 :                     E[2] = z;
    1601                 :      24693 :                     np++;
    1602                 :            :                 }
    1603                 :            :             }
    1604                 :            :         }
    1605                 :            :         else
    1606                 :            :         {
    1607                 :            :             // resolve eq in y, reverse
    1608                 :            :             //   n0 * x + n1 * y +n2*z = 0; x = -n2/n0*z -n1/n0*y = u+v*y
    1609                 :            :             //  (u+v*y)^2+y^2 -R2+z^2 =0
    1610                 :            :             //  (v^2+1)*y^2 + 2*u*v *y + u^2+z^2-R^2 = 0
    1611                 :            :             //
    1612                 :            :             // x1,2 =
    1613 [ +  - ][ +  - ]:      29326 :             double u = -n1[2] / n1[0] * z, v = -n1[1] / n1[0];
         [ +  - ][ +  - ]
    1614                 :      29326 :             double a1 = v * v + 1, b1 = 2 * u * v, c1 = u * u + z * z - R2;
    1615                 :      29326 :             double delta = b1 * b1 - 4 * a1 * c1;
    1616         [ +  + ]:      29326 :             if( delta < -Tolerance ) return MB_FAILURE;  // no intersection
    1617         [ +  - ]:      23531 :             if( delta > Tolerance )                      // 2 solutions possible
    1618                 :            :             {
    1619                 :      23531 :                 double y1 = ( -b1 + sqrt( delta ) ) / 2 / a1;
    1620                 :      23531 :                 double y2 = ( -b1 - sqrt( delta ) ) / 2 / a1;
    1621                 :      23531 :                 double x1 = u + v * y1;
    1622                 :      23531 :                 double x2 = u + v * y2;
    1623 [ +  - ][ +  + ]:      23531 :                 if( verify( a, b, c, d, x1, y1, z ) )
    1624                 :            :                 {
    1625                 :       1883 :                     E[0] = x1;
    1626                 :       1883 :                     E[1] = y1;
    1627                 :       1883 :                     E[2] = z;
    1628                 :       1883 :                     np++;
    1629                 :            :                 }
    1630 [ +  - ][ +  + ]:      23531 :                 if( verify( a, b, c, d, x2, y2, z ) )
    1631                 :            :                 {
    1632                 :       1835 :                     E[3 * np + 0] = x2;
    1633                 :       1835 :                     E[3 * np + 1] = y2;
    1634                 :       1835 :                     E[3 * np + 2] = z;
    1635                 :      23531 :                     np++;
    1636                 :            :                 }
    1637                 :            :             }
    1638                 :            :             else
    1639                 :            :             {
    1640                 :            :                 // one solution
    1641                 :          0 :                 double y1 = -b1 / 2 / a1;
    1642                 :          0 :                 double x1 = u + v * y1;
    1643 [ #  # ][ #  # ]:          0 :                 if( verify( a, b, c, d, x1, y1, z ) )
    1644                 :            :                 {
    1645                 :          0 :                     E[0] = x1;
    1646                 :          0 :                     E[1] = y1;
    1647                 :          0 :                     E[2] = z;
    1648                 :          0 :                     np++;
    1649                 :            :                 }
    1650                 :            :             }
    1651                 :            :         }
    1652                 :            :     }
    1653                 :            : 
    1654         [ +  + ]:      48224 :     if( np <= 0 ) return MB_FAILURE;
    1655                 :      59842 :     return MB_SUCCESS;
    1656                 :            : }
    1657                 :            : 
    1658                 :            : #if 0
    1659                 :            : ErrorCode set_edge_type_flag(Interface * mb, EntityHandle sf1)
    1660                 :            : {
    1661                 :            :   Range cells;
    1662                 :            :   ErrorCode rval = mb->get_entities_by_dimension(sf1, 2, cells);
    1663                 :            :   if (MB_SUCCESS!= rval)
    1664                 :            :   return rval;
    1665                 :            :   Range edges;
    1666                 :            :   rval = mb->get_adjacencies(cells, 1, true, edges, Interface::UNION);
    1667                 :            :   if (MB_SUCCESS!= rval)
    1668                 :            :   return rval;
    1669                 :            : 
    1670                 :            :   Tag edgeTypeTag;
    1671                 :            :   int default_int=0;
    1672                 :            :   rval = mb->tag_get_handle("edge_type", 1, MB_TYPE_INTEGER, edgeTypeTag,
    1673                 :            :       MB_TAG_DENSE | MB_TAG_CREAT, &default_int);
    1674                 :            :   if (MB_SUCCESS!= rval)
    1675                 :            :   return rval;
    1676                 :            :   // add edges to the set? not yet, maybe later
    1677                 :            :   // if edge horizontal, set value to 1
    1678                 :            :   int type_constant_lat=1;
    1679                 :            :   for (Range::iterator eit=edges.begin(); eit!=edges.end(); ++eit)
    1680                 :            :   {
    1681                 :            :     EntityHandle edge = *eit;
    1682                 :            :     const EntityHandle *conn=0;
    1683                 :            :     int num_n=0;
    1684                 :            :     rval = mb->get_connectivity(edge, conn, num_n );
    1685                 :            :     if (MB_SUCCESS!= rval)
    1686                 :            :     return rval;
    1687                 :            :     double coords[6];
    1688                 :            :     rval = mb->get_coords(conn, 2, coords);
    1689                 :            :     if (MB_SUCCESS!= rval)
    1690                 :            :     return rval;
    1691                 :            :     if (fabs( coords[2]-coords[5] )< 1.e-6 )
    1692                 :            :     {
    1693                 :            :       rval = mb->tag_set_data(edgeTypeTag, &edge, 1, &type_constant_lat);
    1694                 :            :       if (MB_SUCCESS!= rval)
    1695                 :            :       return rval;
    1696                 :            :     }
    1697                 :            :   }
    1698                 :            : 
    1699                 :            :   return MB_SUCCESS;
    1700                 :            : }
    1701                 :            : #endif
    1702                 :            : 
    1703                 :            : // decide in a different metric if the corners of CS quad are
    1704                 :            : // in the interior of an RLL quad
    1705                 :       7589 : int IntxUtils::borderPointsOfCSinRLL( CartVect* redc, double* red2dc, int nsRed, CartVect* bluec, int nsBlue,
    1706                 :            :                                       int* blueEdgeType, double* P, int* side, double epsil )
    1707                 :            : {
    1708                 :       7589 :     int extraPoints = 0;
    1709                 :            :     // first decide the blue z coordinates
    1710 [ +  - ][ +  - ]:       7589 :     CartVect A( 0. ), B( 0. ), C( 0. ), D( 0. );
         [ +  - ][ +  - ]
    1711         [ +  - ]:      22659 :     for( int i = 0; i < nsBlue; i++ )
    1712                 :            :     {
    1713         [ +  + ]:      22659 :         if( blueEdgeType[i] == 0 )
    1714                 :            :         {
    1715                 :      15070 :             int iP1 = ( i + 1 ) % nsBlue;
    1716 [ +  - ][ +  - ]:      15070 :             if( bluec[i][2] > bluec[iP1][2] )
                 [ +  + ]
    1717                 :            :             {
    1718                 :       7589 :                 A = bluec[i];
    1719                 :       7589 :                 B = bluec[iP1];
    1720                 :       7589 :                 C = bluec[( i + 2 ) % nsBlue];
    1721                 :       7589 :                 D = bluec[( i + 3 ) % nsBlue];  // it could be back to A, if triangle on top
    1722                 :      15070 :                 break;
    1723                 :            :             }
    1724                 :            :         }
    1725                 :            :     }
    1726 [ +  + ][ +  - ]:       7589 :     if( nsBlue == 3 && B[2] < 0 )
         [ +  + ][ +  + ]
    1727                 :            :     {
    1728                 :            :         // select D to be C
    1729                 :        108 :         D = C;
    1730                 :        108 :         C = B;  // B is the south pole then
    1731                 :            :     }
    1732                 :            :     // so we have A, B, C, D, with A at the top, b going down, then C, D, D > C, A > B
    1733                 :            :     // AB is const longitude, BC and DA constant latitude
    1734                 :            :     // check now each of the red points if they are inside this rectangle
    1735         [ +  + ]:      37945 :     for( int i = 0; i < nsRed; i++ )
    1736                 :            :     {
    1737                 :      30356 :         CartVect& X = redc[i];
    1738 [ +  - ][ +  - ]:      30356 :         if( X[2] > A[2] || X[2] < B[2] ) continue;  // it is above or below the rectangle
         [ +  + ][ +  - ]
         [ +  - ][ +  + ]
                 [ +  + ]
    1739                 :            :         // now decide if it is between the planes OAB and OCD
    1740 [ +  - ][ +  - ]:      15239 :         if( ( ( A * B ) % X >= -epsil ) && ( ( C * D ) % X >= -epsil ) )
         [ +  + ][ +  - ]
         [ +  - ][ +  + ]
         [ +  + ][ +  - ]
           [ +  +  #  #  
                   #  # ]
    1741                 :            :         {
    1742                 :       9043 :             side[i] = 1;  //
    1743                 :            :             // it means point X is in the rectangle that we want , on the sphere
    1744                 :            :             // pass the coords 2d
    1745                 :       9043 :             P[extraPoints * 2]     = red2dc[2 * i];
    1746                 :       9043 :             P[extraPoints * 2 + 1] = red2dc[2 * i + 1];
    1747                 :       9043 :             extraPoints++;
    1748                 :            :         }
    1749                 :            :     }
    1750                 :       7589 :     return extraPoints;
    1751                 :            : }
    1752                 :            : 
    1753                 :          0 : ErrorCode IntxUtils::deep_copy_set_with_quads( Interface* mb, EntityHandle source_set, EntityHandle dest_set )
    1754                 :            : {
    1755                 :            :     ReadUtilIface* read_iface;
    1756 [ #  # ][ #  # ]:          0 :     ErrorCode rval = mb->query_interface( read_iface );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1757                 :            :     // create the handle tag for the corresponding element / vertex
    1758                 :            : 
    1759                 :          0 :     EntityHandle dum = 0;
    1760                 :          0 :     Tag corrTag      = 0;  // it will be created here
    1761 [ #  # ][ #  # ]:          0 :     rval             = mb->tag_get_handle( CORRTAGNAME, 1, MB_TYPE_HANDLE, corrTag, MB_TAG_DENSE | MB_TAG_CREAT, &dum );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1762                 :            : 
    1763                 :            :     // give the same global id to new verts and cells created in the lagr(departure) mesh
    1764         [ #  # ]:          0 :     Tag gid = mb->globalId_tag();
    1765                 :            : 
    1766         [ #  # ]:          0 :     Range quads;
    1767 [ #  # ][ #  # ]:          0 :     rval = mb->get_entities_by_type( source_set, MBQUAD, quads );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1768                 :            : 
    1769         [ #  # ]:          0 :     Range connecVerts;
    1770 [ #  # ][ #  # ]:          0 :     rval = mb->get_connectivity( quads, connecVerts );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1771                 :            : 
    1772         [ #  # ]:          0 :     std::map< EntityHandle, EntityHandle > newNodes;
    1773                 :            : 
    1774         [ #  # ]:          0 :     std::vector< double* > coords;
    1775                 :            :     EntityHandle start_vert, start_elem, *connect;
    1776         [ #  # ]:          0 :     int num_verts = connecVerts.size();
    1777         [ #  # ]:          0 :     rval          = read_iface->get_node_coords( 3, num_verts, 0, start_vert, coords );
    1778         [ #  # ]:          0 :     if( MB_SUCCESS != rval ) return rval;
    1779                 :            :     // fill it up
    1780                 :          0 :     int i = 0;
    1781 [ #  # ][ #  # ]:          0 :     for( Range::iterator vit = connecVerts.begin(); vit != connecVerts.end(); ++vit, i++ )
         [ #  # ][ #  # ]
                 [ #  # ]
    1782                 :            :     {
    1783         [ #  # ]:          0 :         EntityHandle oldV = *vit;
    1784         [ #  # ]:          0 :         CartVect posi;
    1785 [ #  # ][ #  # ]:          0 :         rval = mb->get_coords( &oldV, 1, &( posi[0] ) );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
                 [ #  # ]
    1786                 :            : 
    1787                 :            :         int global_id;
    1788 [ #  # ][ #  # ]:          0 :         rval = mb->tag_get_data( gid, &oldV, 1, &global_id );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1789                 :          0 :         EntityHandle new_vert = start_vert + i;
    1790                 :            :         // Cppcheck warning (false positive): variable coords is assigned a value that is never used
    1791 [ #  # ][ #  # ]:          0 :         coords[0][i] = posi[0];
    1792 [ #  # ][ #  # ]:          0 :         coords[1][i] = posi[1];
    1793 [ #  # ][ #  # ]:          0 :         coords[2][i] = posi[2];
    1794                 :            : 
    1795         [ #  # ]:          0 :         newNodes[oldV] = new_vert;
    1796                 :            :         // set also the correspondent tag :)
    1797 [ #  # ][ #  # ]:          0 :         rval = mb->tag_set_data( corrTag, &oldV, 1, &new_vert );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1798                 :            : 
    1799                 :            :         // also the other side
    1800                 :            :         // need to check if we really need this; the new vertex will never need the old vertex
    1801                 :            :         // we have the global id which is the same
    1802 [ #  # ][ #  # ]:          0 :         rval = mb->tag_set_data( corrTag, &new_vert, 1, &oldV );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1803                 :            :         // set the global id on the corresponding vertex the same as the initial vertex
    1804 [ #  # ][ #  # ]:          0 :         rval = mb->tag_set_data( gid, &new_vert, 1, &global_id );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1805                 :            :     }
    1806                 :            :     // now create new quads in order (in a sequence)
    1807                 :            : 
    1808 [ #  # ][ #  # ]:          0 :     rval = read_iface->get_element_connect( quads.size(), 4, MBQUAD, 0, start_elem, connect );
    1809         [ #  # ]:          0 :     if( MB_SUCCESS != rval ) return rval;
    1810                 :          0 :     int ie = 0;
    1811 [ #  # ][ #  # ]:          0 :     for( Range::iterator it = quads.begin(); it != quads.end(); ++it, ie++ )
         [ #  # ][ #  # ]
                 [ #  # ]
    1812                 :            :     {
    1813         [ #  # ]:          0 :         EntityHandle q = *it;
    1814                 :            :         int nnodes;
    1815                 :            :         const EntityHandle* conn;
    1816 [ #  # ][ #  # ]:          0 :         rval = mb->get_connectivity( q, conn, nnodes );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1817                 :            :         int global_id;
    1818 [ #  # ][ #  # ]:          0 :         rval = mb->tag_get_data( gid, &q, 1, &global_id );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1819                 :            : 
    1820         [ #  # ]:          0 :         for( int ii = 0; ii < nnodes; ii++ )
    1821                 :            :         {
    1822                 :          0 :             EntityHandle v1      = conn[ii];
    1823         [ #  # ]:          0 :             connect[4 * ie + ii] = newNodes[v1];
    1824                 :            :         }
    1825                 :          0 :         EntityHandle newElement = start_elem + ie;
    1826                 :            : 
    1827                 :            :         // set the corresponding tag; not sure we need this one, from old to new
    1828 [ #  # ][ #  # ]:          0 :         rval = mb->tag_set_data( corrTag, &q, 1, &newElement );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1829 [ #  # ][ #  # ]:          0 :         rval = mb->tag_set_data( corrTag, &newElement, 1, &q );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1830                 :            : 
    1831                 :            :         // set the global id
    1832 [ #  # ][ #  # ]:          0 :         rval = mb->tag_set_data( gid, &newElement, 1, &global_id );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1833                 :            : 
    1834 [ #  # ][ #  # ]:          0 :         rval = mb->add_entities( dest_set, &newElement, 1 );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1835                 :            :     }
    1836                 :            : 
    1837 [ #  # ][ #  # ]:          0 :     rval = read_iface->update_adjacencies( start_elem, quads.size(), 4, connect );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
                 [ #  # ]
    1838                 :            : 
    1839                 :          0 :     return MB_SUCCESS;
    1840                 :            : }
    1841                 :            : 
    1842                 :          0 : ErrorCode IntxUtils::remove_duplicate_vertices( Interface* mb, EntityHandle file_set, double merge_tol,
    1843                 :            :                                                 std::vector< Tag >& tagList )
    1844                 :            : {
    1845         [ #  # ]:          0 :     Range verts;
    1846 [ #  # ][ #  # ]:          0 :     ErrorCode rval = mb->get_entities_by_dimension( file_set, 0, verts );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1847 [ #  # ][ #  # ]:          0 :     rval = mb->remove_entities( file_set, verts );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1848                 :            : 
    1849         [ #  # ]:          0 :     MergeMesh mm( mb );
    1850                 :            : 
    1851                 :            :     // remove the vertices from the set, before merging
    1852                 :            : 
    1853 [ #  # ][ #  # ]:          0 :     rval = mm.merge_all( file_set, merge_tol );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1854                 :            : 
    1855                 :            :     // now correct vertices that are repeated in polygons
    1856         [ #  # ]:          0 :     Range cells;
    1857 [ #  # ][ #  # ]:          0 :     rval = mb->get_entities_by_dimension( file_set, 2, cells );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1858                 :            : 
    1859         [ #  # ]:          0 :     verts.clear();
    1860 [ #  # ][ #  # ]:          0 :     rval = mb->get_connectivity( cells, verts );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1861                 :            : 
    1862         [ #  # ]:          0 :     Range modifiedCells;  // will be deleted at the end; keep the gid
    1863         [ #  # ]:          0 :     Range newCells;
    1864                 :            : 
    1865 [ #  # ][ #  # ]:          0 :     for( Range::iterator cit = cells.begin(); cit != cells.end(); ++cit )
         [ #  # ][ #  # ]
                 [ #  # ]
    1866                 :            :     {
    1867         [ #  # ]:          0 :         EntityHandle cell          = *cit;
    1868                 :          0 :         const EntityHandle* connec = NULL;
    1869                 :          0 :         int num_verts              = 0;
    1870 [ #  # ][ #  # ]:          0 :         rval                       = mb->get_connectivity( cell, connec, num_verts );MB_CHK_SET_ERR( rval, "Failed to get connectivity" );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1871                 :            : 
    1872         [ #  # ]:          0 :         std::vector< EntityHandle > newConnec;
    1873         [ #  # ]:          0 :         newConnec.push_back( connec[0] );  // at least one vertex
    1874                 :          0 :         int index    = 0;
    1875                 :          0 :         int new_size = 1;
    1876         [ #  # ]:          0 :         while( index < num_verts - 2 )
    1877                 :            :         {
    1878                 :          0 :             int next_index = ( index + 1 );
    1879 [ #  # ][ #  # ]:          0 :             if( connec[next_index] != newConnec[new_size - 1] )
    1880                 :            :             {
    1881         [ #  # ]:          0 :                 newConnec.push_back( connec[next_index] );
    1882                 :          0 :                 new_size++;
    1883                 :            :             }
    1884                 :          0 :             index++;
    1885                 :            :         }
    1886                 :            :         // add the last one only if different from previous and first node
    1887 [ #  # ][ #  # ]:          0 :         if( ( connec[num_verts - 1] != connec[num_verts - 2] ) && ( connec[num_verts - 1] != connec[0] ) )
    1888                 :            :         {
    1889         [ #  # ]:          0 :             newConnec.push_back( connec[num_verts - 1] );
    1890                 :          0 :             new_size++;
    1891                 :            :         }
    1892         [ #  # ]:          0 :         if( new_size < num_verts )
    1893                 :            :         {
    1894                 :            :             // cout << "new cell from " << cell << " has only " << new_size << " vertices \n";
    1895         [ #  # ]:          0 :             modifiedCells.insert( cell );
    1896                 :            :             // create a new cell with type triangle, quad or polygon
    1897                 :          0 :             EntityType type = MBTRI;
    1898         [ #  # ]:          0 :             if( new_size == 3 )
    1899                 :          0 :                 type = MBTRI;
    1900         [ #  # ]:          0 :             else if( new_size == 4 )
    1901                 :          0 :                 type = MBQUAD;
    1902         [ #  # ]:          0 :             else if( new_size > 4 )
    1903                 :          0 :                 type = MBPOLYGON;
    1904                 :            : 
    1905                 :            :             // create new cell
    1906                 :            :             EntityHandle newCell;
    1907 [ #  # ][ #  # ]:          0 :             rval = mb->create_element( type, &newConnec[0], new_size, newCell );MB_CHK_SET_ERR( rval, "Failed to create new cell" );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1908                 :            :             // set the old id to the new element
    1909         [ #  # ]:          0 :             newCells.insert( newCell );
    1910                 :            :             double value;  // use the same value to reset the tags, even if the tags are int (like Global ID)
    1911 [ #  # ][ #  # ]:          0 :             for( size_t i = 0; i < tagList.size(); i++ )
    1912                 :            :             {
    1913 [ #  # ][ #  # ]:          0 :                 rval = mb->tag_get_data( tagList[i], &cell, 1, (void*)( &value ) );MB_CHK_SET_ERR( rval, "Failed to get tag value" );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1914 [ #  # ][ #  # ]:          0 :                 rval = mb->tag_set_data( tagList[i], &newCell, 1, (void*)( &value ) );MB_CHK_SET_ERR( rval, "Failed to set tag value on new cell" );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1915                 :            :             }
    1916                 :            :         }
    1917                 :          0 :     }
    1918                 :            : 
    1919 [ #  # ][ #  # ]:          0 :     rval = mb->remove_entities( file_set, modifiedCells );MB_CHK_SET_ERR( rval, "Failed to remove old cells from file set" );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1920 [ #  # ][ #  # ]:          0 :     rval = mb->delete_entities( modifiedCells );MB_CHK_SET_ERR( rval, "Failed to delete old cells" );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1921 [ #  # ][ #  # ]:          0 :     rval = mb->add_entities( file_set, newCells );MB_CHK_SET_ERR( rval, "Failed to add new cells to file set" );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1922 [ #  # ][ #  # ]:          0 :     rval = mb->add_entities( file_set, verts );MB_CHK_SET_ERR( rval, "Failed to add verts to the file set" );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1923                 :            : 
    1924                 :          0 :     return MB_SUCCESS;
    1925                 :            : }
    1926                 :            : 
    1927 [ +  - ][ +  - ]:        228 : }  // namespace moab

Generated by: LCOV version 1.11