1
6 #if defined( _MSC_VER ) || defined( WIN32 )
7 #define _USE_MATH_DEFINES
8 #endif
9
10 #include <cmath>
11 #include <cassert>
12 #include <iostream>
13
14 #include "moab/IntxMesh/IntxUtils.hpp"
15
16
17
18 #include "moab/MergeMesh.hpp"
19 #include "moab/ReadUtilIface.hpp"
20 #include "MBTagConventions.hpp"
21
22 #define CHECKNEGATIVEAREA
23 #ifdef CHECKNEGATIVEAREA
24 #include <iomanip>
25 #endif
26 #include <queue>
27 #include <map>
28
29 #ifdef MOAB_HAVE_TEMPESTREMAP
30 #include "GridElements.h"
31 #endif
32
33 #ifdef MOAB_HAVE_EIGEN3
34 #define EIGEN_NO_DEBUG
35 #define EIGEN_MAX_CPP_VER 11
36 #include "Eigen/Dense"
37 #endif
38
39 namespace moab
40 {
41
51
52 #define CORRTAGNAME "__correspondent"
53 #define MAXEDGES 10
54
55
67 int IntxUtils::borderPointsOfXinY2( double* X, int nX, double* Y, int nY, double* P, int* side, double epsilon_area )
68 {
69
70
71
73 int extraPoint = 0;
74 for( int i = 0; i < nX; i++ )
75 {
76
77
78
79
80 double* A = X + 2 * i;
81
82 int inside = 1;
83 for( int j = 0; j < nY; j++ )
84 {
85 double* B = Y + 2 * j;
86 int j1 = ( j + 1 ) % nY;
87 double* C = Y + 2 * j1;
88
89 double area2 = ( B[0] - A[0] ) * ( C[1] - A[1] ) - ( C[0] - A[0] ) * ( B[1] - A[1] );
90 if( area2 < -epsilon_area )
91 {
92 inside = 0;
93 break;
94 }
95 }
96 if( inside )
97 {
98 side[i] = 1;
99
100 P[extraPoint * 2] = A[0];
101 P[extraPoint * 2 + 1] = A[1];
102 extraPoint++;
103 }
104 }
105 return extraPoint;
106 }
107
108
109 struct angleAndIndex
110 {
111 double angle;
112 int index;
113 };
114
115 bool angleCompare( angleAndIndex lhs, angleAndIndex rhs )
116 {
117 return lhs.angle < rhs.angle;
118 }
119
120
130 int IntxUtils::SortAndRemoveDoubles2( double* P, int& nP, double epsilon_1 )
131 {
132 if( nP < 2 ) return 0;
133
134
135 double c[2] = { 0., 0. };
136 int k = 0;
137 for( k = 0; k < nP; k++ )
138 {
139 c[0] += P[2 * k];
140 c[1] += P[2 * k + 1];
141 }
142 c[0] /= nP;
143 c[1] /= nP;
144
145
146
147 struct angleAndIndex pairAngleIndex[5 * MAXEDGES];
148
149 for( k = 0; k < nP; k++ )
150 {
151 double x = P[2 * k] - c[0], y = P[2 * k + 1] - c[1];
152 if( x != 0. || y != 0. )
153 {
154 pairAngleIndex[k].angle = atan2( y, x );
155 }
156 else
157 {
158 pairAngleIndex[k].angle = 0;
159
160 }
161 pairAngleIndex[k].index = k;
162 }
163
164
165 std::sort( pairAngleIndex, pairAngleIndex + nP, angleCompare );
166
167 double PCopy[10 * MAXEDGES];
168
169 for( k = 0; k < nP; k++ )
170 {
171 int ck = pairAngleIndex[k].index;
172 PCopy[2 * k] = P[2 * ck];
173 PCopy[2 * k + 1] = P[2 * ck + 1];
174 }
175
176 std::copy( PCopy, PCopy + 2 * nP, P );
177
178
179
180 int i = 0, j = 1;
181
182
183
184 while( j < nP )
185 {
186 double d2 = dist2( &P[2 * i], &P[2 * j] );
187 if( d2 > epsilon_1 )
188 {
189 i++;
190 P[2 * i] = P[2 * j];
191 P[2 * i + 1] = P[2 * j + 1];
192 }
193 j++;
194 }
195
196
197
198 double d2 = dist2( P, &P[2 * i] );
199 if( d2 > epsilon_1 )
200 {
201 nP = i + 1;
202 }
203 else
204 nP = i;
205 if( nP == 0 ) nP = 1;
206 return 0;
207 }
208
209
222 ErrorCode IntxUtils::EdgeIntersections2( double* blue,
223 int nsBlue,
224 double* red,
225 int nsRed,
226 int* markb,
227 int* markr,
228 double* points,
229 int& nPoints )
230 {
231
239
240
241 nPoints = 0;
242 for( int i = 0; i < MAXEDGES; i++ )
243 {
244 markb[i] = markr[i] = 0;
245 }
246
247 for( int i = 0; i < nsBlue; i++ )
248 {
249 for( int j = 0; j < nsRed; j++ )
250 {
251 double b[2];
252 double a[2][2];
253 int iPlus1 = ( i + 1 ) % nsBlue;
254 int jPlus1 = ( j + 1 ) % nsRed;
255 for( int k = 0; k < 2; k++ )
256 {
257 b[k] = red[2 * j + k] - blue[2 * i + k];
258
259 a[k][0] = blue[2 * iPlus1 + k] - blue[2 * i + k];
260 a[k][1] = red[2 * j + k] - red[2 * jPlus1 + k];
261 }
262 double delta = a[0][0] * a[1][1] - a[0][1] * a[1][0];
263 if( fabs( delta ) > 1.e-14 )
264 {
265
266 double alfa = ( b[0] * a[1][1] - a[0][1] * b[1] ) / delta;
267 double beta = ( -b[0] * a[1][0] + b[1] * a[0][0] ) / delta;
268 if( 0 <= alfa && alfa <= 1. && 0 <= beta && beta <= 1. )
269 {
270
271 for( int k = 0; k < 2; k++ )
272 {
273 points[2 * nPoints + k] = blue[2 * i + k] + alfa * ( blue[2 * iPlus1 + k] - blue[2 * i + k] );
274 }
275 markb[i] = 1;
276 markr[j] = 1;
277 nPoints++;
278 }
279 }
280
281 }
282 }
283 return MB_SUCCESS;
284 }
285
286
306 ErrorCode IntxUtils::EdgeIntxRllCs( double* blue,
307 CartVect* bluec,
308 int* blueEdgeType,
309 int nsBlue,
310 double* red,
311 CartVect* redc,
312 int nsRed,
313 int* markb,
314 int* markr,
315 int plane,
316 double R,
317 double* points,
318 int& nPoints )
319 {
320
321
322 for( int i = 0; i < 4; i++ )
323 {
324 markb[i] = markr[i] = 0;
325 }
326
327 for( int i = 0; i < nsBlue; i++ )
328 {
329 int iPlus1 = ( i + 1 ) % nsBlue;
330 if( blueEdgeType[i] == 0 )
331 {
332 for( int j = 0; j < nsRed; j++ )
333 {
334 double b[2];
335 double a[2][2];
336
337 int jPlus1 = ( j + 1 ) % nsRed;
338 for( int k = 0; k < 2; k++ )
339 {
340 b[k] = red[2 * j + k] - blue[2 * i + k];
341
342 a[k][0] = blue[2 * iPlus1 + k] - blue[2 * i + k];
343 a[k][1] = red[2 * j + k] - red[2 * jPlus1 + k];
344 }
345 double delta = a[0][0] * a[1][1] - a[0][1] * a[1][0];
346 if( fabs( delta ) > 1.e-14 )
347 {
348
349 double alfa = ( b[0] * a[1][1] - a[0][1] * b[1] ) / delta;
350 double beta = ( -b[0] * a[1][0] + b[1] * a[0][0] ) / delta;
351 if( 0 <= alfa && alfa <= 1. && 0 <= beta && beta <= 1. )
352 {
353
354 for( int k = 0; k < 2; k++ )
355 {
356 points[2 * nPoints + k] =
357 blue[2 * i + k] + alfa * ( blue[2 * iPlus1 + k] - blue[2 * i + k] );
358 }
359 markb[i] = 1;
360 markr[j] = 1;
361 nPoints++;
362 }
363 }
364 }
365 }
366 else
367 {
368 CartVect& C = bluec[i];
369 CartVect& D = bluec[iPlus1];
370 for( int j = 0; j < nsRed; j++ )
371 {
372 int jPlus1 = ( j + 1 ) % nsRed;
373 CartVect& A = redc[j];
374 CartVect& B = redc[jPlus1];
375 int np = 0;
376 double E[9];
377 intersect_great_circle_arc_with_clat_arc( A.array(), B.array(), C.array(), D.array(), R, E, np );
378 if( np == 0 ) continue;
379 if( np >= 2 )
380 {
381 std::cout << "intersection with 2 points :" << A << B << C << D << "\n";
382 }
383 for( int k = 0; k < np; k++ )
384 {
385 gnomonic_projection( CartVect( E + k * 3 ), R, plane, points[2 * nPoints],
386 points[2 * nPoints + 1] );
387 nPoints++;
388 }
389 markb[i] = 1;
390 markr[j] = 1;
391 }
392 }
393 }
394 return MB_SUCCESS;
395 }
396
397
398
399
400
401
411 void IntxUtils::decide_gnomonic_plane( const CartVect& pos, int& plane )
412 {
413
414 if( fabs( pos[0] ) < fabs( pos[1] ) )
415 {
416 if( fabs( pos[2] ) < fabs( pos[1] ) )
417 {
418
419 if( pos[1] > 0 )
420 plane = 2;
421 else
422 plane = 4;
423 }
424 else
425 {
426
427 if( pos[2] < 0 )
428 plane = 5;
429 else
430 plane = 6;
431 }
432 }
433 else
434 {
435 if( fabs( pos[2] ) < fabs( pos[0] ) )
436 {
437
438 if( pos[0] > 0 )
439 plane = 1;
440 else
441 plane = 3;
442 }
443 else
444 {
445
446 if( pos[2] < 0 )
447 plane = 5;
448 else
449 plane = 6;
450 }
451 }
452 return;
453 }
454
455
456 ErrorCode IntxUtils::gnomonic_projection( const CartVect& pos, double R, int plane, double& c1, double& c2 )
457 {
458 double alfa = 1.;
459
460 switch( plane )
461 {
462 case 1: {
463
464
465 alfa = R / pos[0];
466 c1 = alfa * pos[1];
467 c2 = alfa * pos[2];
468 break;
469 }
470 case 2: {
471
472 alfa = R / pos[1];
473 c1 = alfa * pos[2];
474 c2 = alfa * pos[0];
475 break;
476 }
477 case 3: {
478
479 alfa = -R / pos[0];
480 c1 = -alfa * pos[1];
481 c2 = alfa * pos[2];
482 break;
483 }
484 case 4: {
485
486 alfa = -R / pos[1];
487 c1 = -alfa * pos[2];
488 c2 = alfa * pos[0];
489 break;
490 }
491 case 5: {
492
493 alfa = -R / pos[2];
494 c1 = -alfa * pos[0];
495 c2 = alfa * pos[1];
496 break;
497 }
498 case 6: {
499 alfa = R / pos[2];
500 c1 = alfa * pos[0];
501 c2 = alfa * pos[1];
502 break;
503 }
504 default:
505 return MB_FAILURE;
506 }
507
508 return MB_SUCCESS;
509 }
510
511
512 ErrorCode IntxUtils::reverse_gnomonic_projection( const double& c1,
513 const double& c2,
514 double R,
515 int plane,
516 CartVect& pos )
517 {
518
519
520 double len = sqrt( c1 * c1 + c2 * c2 + R * R );
521 double beta = R / len;
522
523 switch( plane )
524 {
525 case 1: {
526
527
528 pos[0] = beta * R;
529 pos[1] = c1 * beta;
530 pos[2] = c2 * beta;
531 break;
532 }
533 case 2: {
534
535 pos[1] = R * beta;
536 pos[2] = c1 * beta;
537 pos[0] = c2 * beta;
538 break;
539 }
540 case 3: {
541
542 pos[0] = -R * beta;
543 pos[1] = -c1 * beta;
544 pos[2] = c2 * beta;
545 break;
546 }
547 case 4: {
548
549 pos[1] = -R * beta;
550 pos[2] = -c1 * beta;
551 pos[0] = c2 * beta;
552 break;
553 }
554 case 5: {
555
556 pos[2] = -R * beta;
557 pos[0] = -c1 * beta;
558 pos[1] = c2 * beta;
559 break;
560 }
561 case 6: {
562 pos[2] = R * beta;
563 pos[0] = c1 * beta;
564 pos[1] = c2 * beta;
565 break;
566 }
567 default:
568 return MB_FAILURE;
569 }
570
571 return MB_SUCCESS;
572 }
573
574 void IntxUtils::gnomonic_unroll( double& c1, double& c2, double R, int plane )
575 {
576 double tmp;
577 switch( plane )
578 {
579 case 1:
580 break;
581 case 2:
582 tmp = c1;
583 c1 = -c2;
584 c2 = tmp;
585 c1 = c1 + 2 * R;
586 break;
587 case 3:
588 c1 = c1 + 4 * R;
589 break;
590 case 4:
591
592 tmp = c1;
593 c1 = c2;
594 c2 = -tmp;
595 c1 = c1 - 2 * R;
596 break;
597 case 5:
598
599 c1 = -c1 - 2. * R;
600 c2 = -c2 - 2. * R;
601 break;
602 ;
603 case 6:
604 c1 = c1 - 2. * R;
605 c2 = c2 + 2. * R;
606 break;
607 }
608 return;
609 }
610
611 ErrorCode IntxUtils::global_gnomonic_projection( Interface* mb,
612 EntityHandle inSet,
613 double R,
614 bool centers_only,
615 EntityHandle& outSet )
616 {
617 std::string parTagName( "PARALLEL_PARTITION" );
618 Tag part_tag;
619 Range partSets;
620 ErrorCode rval = mb->tag_get_handle( parTagName.c_str(), part_tag );
621 if( MB_SUCCESS == rval && part_tag != 0 )
622 {
623 rval = mb->get_entities_by_type_and_tag( inSet, MBENTITYSET, &part_tag, NULL, 1, partSets, Interface::UNION );MB_CHK_ERR( rval );
624 }
625 rval = ScaleToRadius( mb, inSet, 1.0 );MB_CHK_ERR( rval );
626
627 Range inputRange;
628 rval = mb->get_entities_by_dimension( inSet, 1, inputRange );MB_CHK_ERR( rval );
629 rval = mb->get_entities_by_dimension( inSet, 2, inputRange );MB_CHK_ERR( rval );
630
631 std::map< EntityHandle, int > partsAssign;
632 std::map< int, EntityHandle > newPartSets;
633 if( !partSets.empty() )
634 {
635
636 for( Range::iterator setIt = partSets.begin(); setIt != partSets.end(); ++setIt )
637 {
638 EntityHandle pSet = *setIt;
639 Range ents;
640 rval = mb->get_entities_by_handle( pSet, ents );MB_CHK_ERR( rval );
641 int val;
642 rval = mb->tag_get_data( part_tag, &pSet, 1, &val );MB_CHK_ERR( rval );
643
644 EntityHandle newPartSet;
645 rval = mb->create_meshset( MESHSET_SET, newPartSet );MB_CHK_ERR( rval );
646 rval = mb->tag_set_data( part_tag, &newPartSet, 1, &val );MB_CHK_ERR( rval );
647 newPartSets[val] = newPartSet;
648 rval = mb->add_entities( outSet, &newPartSet, 1 );MB_CHK_ERR( rval );
649 for( Range::iterator it = ents.begin(); it != ents.end(); ++it )
650 {
651 partsAssign[*it] = val;
652 }
653 }
654 }
655
656 if( centers_only )
657 {
658 for( Range::iterator it = inputRange.begin(); it != inputRange.end(); ++it )
659 {
660 CartVect center;
661 EntityHandle cell = *it;
662 rval = mb->get_coords( &cell, 1, center.array() );MB_CHK_ERR( rval );
663 int plane;
664 decide_gnomonic_plane( center, plane );
665 double c[3];
666 c[2] = 0.;
667 gnomonic_projection( center, R, plane, c[0], c[1] );
668
669 gnomonic_unroll( c[0], c[1], R, plane );
670
671 EntityHandle vertex;
672 rval = mb->create_vertex( c, vertex );MB_CHK_ERR( rval );
673 rval = mb->add_entities( outSet, &vertex, 1 );MB_CHK_ERR( rval );
674 }
675 }
676 else
677 {
678
679 Range subranges[6];
680 for( Range::iterator it = inputRange.begin(); it != inputRange.end(); ++it )
681 {
682 CartVect center;
683 EntityHandle cell = *it;
684 rval = mb->get_coords( &cell, 1, center.array() );MB_CHK_ERR( rval );
685 int plane;
686 decide_gnomonic_plane( center, plane );
687 subranges[plane - 1].insert( cell );
688 }
689 for( int i = 1; i <= 6; i++ )
690 {
691 Range verts;
692 rval = mb->get_connectivity( subranges[i - 1], verts );MB_CHK_ERR( rval );
693 std::map< EntityHandle, EntityHandle > corr;
694 for( Range::iterator vt = verts.begin(); vt != verts.end(); ++vt )
695 {
696 CartVect vect;
697 EntityHandle v = *vt;
698 rval = mb->get_coords( &v, 1, vect.array() );MB_CHK_ERR( rval );
699 double c[3];
700 c[2] = 0.;
701 gnomonic_projection( vect, R, i, c[0], c[1] );
702 gnomonic_unroll( c[0], c[1], R, i );
703 EntityHandle vertex;
704 rval = mb->create_vertex( c, vertex );MB_CHK_ERR( rval );
705 corr[v] = vertex;
706 }
707 EntityHandle new_conn[20];
708 for( Range::iterator eit = subranges[i - 1].begin(); eit != subranges[i - 1].end(); ++eit )
709 {
710 EntityHandle eh = *eit;
711 const EntityHandle* conn = NULL;
712 int num_nodes;
713 rval = mb->get_connectivity( eh, conn, num_nodes );MB_CHK_ERR( rval );
714
715 for( int j = 0; j < num_nodes; j++ )
716 new_conn[j] = corr[conn[j]];
717 EntityType type = mb->type_from_handle( eh );
718 EntityHandle newCell;
719 rval = mb->create_element( type, new_conn, num_nodes, newCell );MB_CHK_ERR( rval );
720 rval = mb->add_entities( outSet, &newCell, 1 );MB_CHK_ERR( rval );
721 std::map< EntityHandle, int >::iterator mit = partsAssign.find( eh );
722 if( mit != partsAssign.end() )
723 {
724 int val = mit->second;
725 rval = mb->add_entities( newPartSets[val], &newCell, 1 );MB_CHK_ERR( rval );
726 }
727 }
728 }
729 }
730
731 return MB_SUCCESS;
732 }
733 void IntxUtils::transform_coordinates( double* avg_position, int projection_type )
734 {
735 if( projection_type == 1 )
736 {
737 double R =
738 avg_position[0] * avg_position[0] + avg_position[1] * avg_position[1] + avg_position[2] * avg_position[2];
739 R = sqrt( R );
740 double lat = asin( avg_position[2] / R );
741 double lon = atan2( avg_position[1], avg_position[0] );
742 avg_position[0] = lon;
743 avg_position[1] = lat;
744 avg_position[2] = R;
745 }
746 else if( projection_type == 2 )
747 {
748 CartVect pos( avg_position );
749 int gplane;
750 IntxUtils::decide_gnomonic_plane( pos, gplane );
751
752 IntxUtils::gnomonic_projection( pos, 1.0, gplane, avg_position[0], avg_position[1] );
753 avg_position[2] = 0;
754 IntxUtils::gnomonic_unroll( avg_position[0], avg_position[1], 1.0, gplane );
755 }
756 }
757
788 IntxUtils::SphereCoords IntxUtils::cart_to_spherical( CartVect& cart3d )
789 {
790 SphereCoords res;
791 res.R = cart3d.length();
792 if( res.R < 0 )
793 {
794 res.lon = res.lat = 0.;
795 return res;
796 }
797 res.lat = asin( cart3d[2] / res.R );
798 res.lon = atan2( cart3d[1], cart3d[0] );
799 if( res.lon < 0 ) res.lon += 2 * M_PI;
800
801
802
803 return res;
804 }
805
806
824 CartVect IntxUtils::spherical_to_cart( IntxUtils::SphereCoords& sc )
825 {
826 CartVect res;
827 res[0] = sc.R * cos( sc.lat ) * cos( sc.lon );
828 res[1] = sc.R * cos( sc.lat ) * sin( sc.lon );
829 res[2] = sc.R * sin( sc.lat );
830 return res;
831 }
832
833 ErrorCode IntxUtils::ScaleToRadius( Interface* mb, EntityHandle set, double R )
834 {
835 Range nodes;
836 ErrorCode rval = mb->get_entities_by_type( set, MBVERTEX, nodes, true );
837 if( rval != moab::MB_SUCCESS ) return rval;
838
839
840
841 for( Range::iterator nit = nodes.begin(); nit != nodes.end(); ++nit )
842 {
843 EntityHandle nd = *nit;
844 CartVect pos;
845 rval = mb->get_coords( &nd, 1, (double*)&( pos[0] ) );
846 if( rval != moab::MB_SUCCESS ) return rval;
847 double len = pos.length();
848 if( len == 0. ) return MB_FAILURE;
849 pos = R / len * pos;
850 rval = mb->set_coords( &nd, 1, (double*)&( pos[0] ) );
851 if( rval != moab::MB_SUCCESS ) return rval;
852 }
853 return MB_SUCCESS;
854 }
855
856
857 double IntxAreaUtils::spherical_angle( const double* A, const double* B, const double* C, double Radius )
858 {
859
860 CartVect a( A );
861 CartVect b( B );
862 CartVect c( C );
863 double err1 = a.length_squared() - Radius * Radius;
864 if( fabs( err1 ) > 0.0001 )
865 {
866 std::cout << " error in input " << a << " radius: " << Radius << " error:" << err1 << "\n";
867 }
868 CartVect normalOAB = a * b;
869 CartVect normalOCB = c * b;
870 return angle( normalOAB, normalOCB );
871 }
872
873
874
875
876 double IntxUtils::oriented_spherical_angle( const double* A, const double* B, const double* C )
877 {
878
879 CartVect a( A ), b( B ), c( C );
880 CartVect normalOAB = a * b;
881 CartVect normalOCB = c * b;
882 CartVect orient = ( c - b ) * ( a - b );
883 double ang = angle( normalOAB, normalOCB );
884 if( ang != ang )
885 {
886
887 std::cout << a << " " << b << " " << c << "\n";
888 std::cout << ang << "\n";
889 }
890 if( orient % b < 0 ) return ( 2 * M_PI - ang );
891
892 return ang;
893 }
894
895 double IntxAreaUtils::area_spherical_triangle( const double* A, const double* B, const double* C, double Radius )
896 {
897 switch( m_eAreaMethod )
898 {
899 case Girard:
900 return area_spherical_triangle_girard( A, B, C, Radius );
901 #ifdef MOAB_HAVE_TEMPESTREMAP
902 case GaussQuadrature:
903 return area_spherical_triangle_GQ( A, B, C );
904 #endif
905 case lHuiller:
906 default:
907 return area_spherical_triangle_lHuiller( A, B, C, Radius );
908 }
909 }
910
911 double IntxAreaUtils::area_spherical_polygon( const double* A, int N, double Radius, int* sign )
912 {
913 switch( m_eAreaMethod )
914 {
915 case Girard:
916 return area_spherical_polygon_girard( A, N, Radius );
917 #ifdef MOAB_HAVE_TEMPESTREMAP
918 case GaussQuadrature:
919 return area_spherical_polygon_GQ( A, N ) * Radius * Radius;
920 #endif
921 case lHuiller:
922 default:
923 return area_spherical_polygon_lHuiller( A, N, Radius, sign );
924 }
925 }
926
927 double IntxAreaUtils::area_spherical_triangle_girard( const double* A, const double* B, const double* C, double Radius )
928 {
929 double correction = spherical_angle( A, B, C, Radius ) + spherical_angle( B, C, A, Radius ) +
930 spherical_angle( C, A, B, Radius ) - M_PI;
931 double area = Radius * Radius * correction;
932
933 CartVect a( A ), b( B ), c( C );
934 CartVect abc = ( b - a ) * ( c - a );
935 if( abc % a > 0 )
936 return area;
937 else
938 return -area;
939 }
940
941 double IntxAreaUtils::area_spherical_polygon_girard( const double* A, int N, double Radius )
942 {
943
944
945
946 if( N <= 2 ) return 0.;
947 double sum_angles = 0.;
948 for( int i = 0; i < N; i++ )
949 {
950 int i1 = ( i + 1 ) % N;
951 int i2 = ( i + 2 ) % N;
952 sum_angles += IntxUtils::oriented_spherical_angle( A + 3 * i, A + 3 * i1, A + 3 * i2 );
953 }
954 double correction = sum_angles - ( N - 2 ) * M_PI;
955 return Radius * Radius * correction;
956 }
957
958 double IntxAreaUtils::area_spherical_polygon_lHuiller( const double* A, int N, double Radius, int* sign )
959 {
960
961
962
963
964 if( N <= 2 ) return 0.;
965
966 int lsign = 1;
967 double area = 0.;
968 for( int i = 1; i < N - 1; i++ )
969 {
970 int i1 = i + 1;
971 double areaTriangle = area_spherical_triangle_lHuiller( A, A + 3 * i, A + 3 * i1, Radius );
972 if( areaTriangle < 0 )
973 lsign = -1;
974
975 area += areaTriangle;
976 }
977 if( sign ) *sign = lsign;
978
979 return area;
980 }
981
982 #ifdef MOAB_HAVE_TEMPESTREMAP
983
984 double IntxAreaUtils::area_spherical_polygon_GQ( const double* A, int N )
985 {
986
987
988
989
990 if( N <= 2 ) return 0.;
991
992
993 double area = 0.;
994 for( int i = 1; i < N - 1; i++ )
995 {
996 area += area_spherical_triangle_GQ( A, A + 3 * i, A + 3 * ( i + 1 ) );
997 }
998 return area;
999 }
1000
1001 template < typename Derived >
1002 Eigen::Array< typename Derived::Scalar, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime > shift(
1003 const Eigen::ArrayBase< Derived >& array,
1004 int positions )
1005 {
1006 Eigen::Array< typename Derived::Scalar, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime > result = array;
1007 if( positions > 0 )
1008 {
1009 result.segment( positions, array.size() - positions ) = array.head( array.size() - positions );
1010 result.head( positions ).setZero();
1011 }
1012 else if( positions < 0 )
1013 {
1014 result.head( array.size() + positions ) = array.tail( array.size() + positions );
1015 result.tail( -positions ).setZero();
1016 }
1017 return result;
1018 }
1019
1020 double IntxAreaUtils::area_spherical_triangle_GQ( const double* inode1, const double* inode2, const double* inode3 )
1021 {
1022 #if defined( MOAB_HAVE_EIGEN3 )
1023 typedef Eigen::Map< const Eigen::Vector3d > V3d;
1024 const V3d node1( inode1 );
1025 const V3d node2( inode2 );
1026 const V3d node3( inode3 );
1027 const int nOrder = 6;
1028
1029
1030 const double dG[6] = { 0.03376524289842397, 0.1693953067668678, 0.3806904069584016,
1031 0.6193095930415985, 0.8306046932331322, 0.966234757101576 };
1032 const double dW[6] = { 0.08566224618958521, 0.1803807865240693, 0.2339569672863455,
1033 0.2339569672863455, 0.1803807865240693, 0.08566224618958521 };
1034
1035 double dFaceArea = 0.0;
1036 Eigen::Vector3d dF, dF2, dDaF, dDbF, dDaG, dDbG;
1037 double nodeCross[3];
1038
1039
1040 for( int p = 0; p < nOrder; p++ )
1041 {
1042 for( int q = 0; q < nOrder; q++ )
1043 {
1044
1045 const double dA = dG[p];
1046 const double dB = dG[q];
1047
1048
1049 dF = ( ( ( 1.0 - dB ) * ( 1.0 - dA ) ) * node1 ) + ( ( ( 1.0 - dB ) * dA ) * node2 ) + ( dB * node3 );
1050 dF2 = dF.array().square();
1051
1052 dDaF = ( node1 - node2 );
1053
1054
1055 dDbF = ( node3 - node1 ) + dA * dDaF;
1056 dDaF *= ( dB - 1.0 );
1057
1058 const double dDenomTerm = std::pow( dF.norm(), -3.0 );
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076 dDaG( 0 ) = dDaF( 0 ) * ( dF2( 1 ) + dF2( 2 ) ) - dF( 0 ) * ( dDaF( 1 ) * dF( 1 ) + dDaF( 2 ) * dF( 2 ) );
1077 dDaG( 1 ) = dDaF( 1 ) * ( dF2( 0 ) + dF2( 2 ) ) - dF( 1 ) * ( dDaF( 0 ) * dF( 0 ) + dDaF( 2 ) * dF( 2 ) );
1078 dDaG( 2 ) = dDaF( 2 ) * ( dF2( 0 ) + dF2( 1 ) ) - dF( 2 ) * ( dDaF( 0 ) * dF( 0 ) + dDaF( 1 ) * dF( 1 ) );
1079
1080
1081 dDbG( 0 ) = dDbF( 0 ) * ( dF2( 1 ) + dF2( 2 ) ) - dF( 0 ) * ( dDbF( 1 ) * dF( 1 ) + dDbF( 2 ) * dF( 2 ) );
1082 dDbG( 1 ) = dDbF( 1 ) * ( dF2( 0 ) + dF2( 2 ) ) - dF( 1 ) * ( dDbF( 0 ) * dF( 0 ) + dDbF( 2 ) * dF( 2 ) );
1083 dDbG( 2 ) = dDbF( 2 ) * ( dF2( 0 ) + dF2( 1 ) ) - dF( 2 ) * ( dDbF( 0 ) * dF( 0 ) + dDbF( 1 ) * dF( 1 ) );
1084
1085
1086 dDaG *= dDenomTerm;
1087 dDbG *= dDenomTerm;
1088
1089
1090 nodeCross[0] = dDaG( 1 ) * dDbG( 2 ) - dDaG( 2 ) * dDbG( 1 );
1091 nodeCross[1] = dDaG( 2 ) * dDbG( 0 ) - dDaG( 0 ) * dDbG( 2 );
1092 nodeCross[2] = dDaG( 0 ) * dDbG( 1 ) - dDaG( 1 ) * dDbG( 0 );
1093
1094 const double dJacobian =
1095 std::sqrt( nodeCross[0] * nodeCross[0] + nodeCross[1] * nodeCross[1] + nodeCross[2] * nodeCross[2] );
1096
1097
1098 dFaceArea += dW[p] * dW[q] * dJacobian;
1099 }
1100 }
1101
1102 return dFaceArea;
1103 #else
1104
1105 Face face( 3 );
1106 NodeVector nodes( 3 );
1107 nodes[0] = Node( inode1[0], inode1[1], inode1[2] );
1108 nodes[1] = Node( inode2[0], inode2[1], inode2[2] );
1109 nodes[2] = Node( inode3[0], inode3[1], inode3[2] );
1110 face.SetNode( 0, 0 );
1111 face.SetNode( 1, 1 );
1112 face.SetNode( 2, 2 );
1113 return CalculateFaceArea( face, nodes );
1114 #endif
1115 }
1116
1117 #endif
1118
1119
1145 double IntxAreaUtils::area_spherical_triangle_lHuiller( const double* ptA,
1146 const double* ptB,
1147 const double* ptC,
1148 double Radius )
1149 {
1150
1151
1152 CartVect vA( ptA ), vB( ptB ), vC( ptC );
1153 double a = angle_robust( vB, vC );
1154 double b = angle_robust( vC, vA );
1155 double c = angle_robust( vA, vB );
1156 int sign = 1;
1157
1158 if( ( vA * vB ) % vC < 0 ) sign = -1;
1159 double s = ( a + b + c ) / 2;
1160 double a1 = ( s - a ) / 2;
1161 double b1 = ( s - b ) / 2;
1162 double c1 = ( s - c ) / 2;
1163 #ifdef MOAB_HAVE_TEMPESTREMAP
1164 if( fabs( a1 ) < 1.e-14 || fabs( b1 ) < 1.e-14 || fabs( c1 ) < 1.e-14 )
1165 {
1166 double area = area_spherical_triangle_GQ( ptA, ptB, ptC ) * sign;
1167 #ifdef VERBOSE
1168 std::cout << " very obtuse angle, use TR to compute area " << " a1:" << a1 << " b1:" << b1 << " c1:" << c1
1169 << "\n";
1170 std::cout << " area with TR: " << area << "\n";
1171 #endif
1172 return area;
1173 }
1174 #endif
1175 double tmp = tan( s / 2 ) * tan( a1 ) * tan( b1 ) * tan( c1 );
1176 if( tmp < 0. ) tmp = 0.;
1177
1178 double E = 4 * atan( sqrt( tmp ) );
1179 if( E != E ) std::cout << " NaN at spherical triangle area \n";
1180
1181 double area = sign * E * Radius * Radius;
1182
1183 #ifdef CHECKNEGATIVEAREA
1184 if( area < 0 )
1185 {
1186 std::cout << "negative area: " << area << "\n";
1187 std::cout << std::setprecision( 15 );
1188 std::cout << "vA: " << vA << "\n";
1189 std::cout << "vB: " << vB << "\n";
1190 std::cout << "vC: " << vC << "\n";
1191 std::cout << "sign: " << sign << "\n";
1192 std::cout << " a: " << a << "\n";
1193 std::cout << " b: " << b << "\n";
1194 std::cout << " c: " << c << "\n";
1195 }
1196 #endif
1197
1198 return area;
1199 }
1200
1201 double IntxAreaUtils::area_on_sphere( Interface* mb, EntityHandle set, double R )
1202 {
1203
1204 Range inputRange;
1205 ErrorCode rval = mb->get_entities_by_dimension( set, 2, inputRange );MB_CHK_ERR_RET_VAL( rval, -1.0 );
1206
1207
1208 std::vector< int > ownerinfo( inputRange.size(), -1 );
1209 Tag intxOwnerTag;
1210 rval = mb->tag_get_handle( "ORIG_PROC", intxOwnerTag );
1211 if( MB_SUCCESS == rval )
1212 {
1213 rval = mb->tag_get_data( intxOwnerTag, inputRange, &ownerinfo[0] );MB_CHK_ERR_RET_VAL( rval, -1.0 );
1214 }
1215
1216
1217 int ie = 0;
1218 double total_area = 0.;
1219 for( Range::iterator eit = inputRange.begin(); eit != inputRange.end(); ++eit )
1220 {
1221
1222
1223 if( ownerinfo[ie++] >= 0 ) continue;
1224
1225 EntityHandle eh = *eit;
1226 const double elem_area = this->area_spherical_element( mb, eh, R );
1227
1228
1229 if( elem_area <= 0 )
1230 {
1231 std::cout << "Area of element " << mb->id_from_handle( eh ) << " is = " << elem_area << "\n";
1232 mb->list_entity( eh );
1233 }
1234 assert( elem_area > 0 );
1235
1236
1237 total_area += elem_area;
1238 }
1239
1240
1241 return total_area;
1242 }
1243
1244 double IntxAreaUtils::area_spherical_element( Interface* mb, EntityHandle elem, double R )
1245 {
1246
1247 const EntityHandle* verts;
1248 int nsides;
1249 ErrorCode rval = mb->get_connectivity( elem, verts, nsides );MB_CHK_ERR_RET_VAL( rval, -1.0 );
1250
1251
1252 while( verts[nsides - 2] == verts[nsides - 1] && nsides > 3 )
1253 nsides--;
1254
1255
1256 std::vector< double > coords( 3 * nsides );
1257 rval = mb->get_coords( verts, nsides, &coords[0] );MB_CHK_ERR_RET_VAL( rval, -1.0 );
1258
1259
1260 return area_spherical_polygon( &coords[0], nsides, R );
1261 }
1262
1263 double IntxUtils::distance_on_great_circle( CartVect& p1, CartVect& p2 )
1264 {
1265 SphereCoords sph1 = cart_to_spherical( p1 );
1266 SphereCoords sph2 = cart_to_spherical( p2 );
1267
1268 return sph1.R *
1269 acos( sin( sph1.lon ) * sin( sph2.lon ) + cos( sph1.lat ) * cos( sph2.lat ) * cos( sph2.lon - sph2.lon ) );
1270 }
1271
1272
1273
1285 ErrorCode IntxUtils::enforce_convexity( Interface* mb, EntityHandle lset, int my_rank )
1286 {
1287 Range inputRange;
1288 ErrorCode rval = mb->get_entities_by_dimension( lset, 2, inputRange );MB_CHK_ERR( rval );
1289
1290 Tag corrTag = 0;
1291 EntityHandle dumH = 0;
1292 rval = mb->tag_get_handle( CORRTAGNAME, 1, MB_TYPE_HANDLE, corrTag, MB_TAG_DENSE, &dumH );
1293 if( rval == MB_TAG_NOT_FOUND ) corrTag = 0;
1294
1295 Tag gidTag;
1296 rval = mb->tag_get_handle( "GLOBAL_ID", 1, MB_TYPE_INTEGER, gidTag, MB_TAG_DENSE );MB_CHK_ERR( rval );
1297
1298 std::vector< double > coords;
1299 coords.resize( 3 * MAXEDGES );
1300
1301
1302 std::queue< EntityHandle > newPolys;
1303 int brokenPolys = 0;
1304 Range::iterator eit = inputRange.begin();
1305 while( eit != inputRange.end() || !newPolys.empty() )
1306 {
1307 EntityHandle eh;
1308 if( eit != inputRange.end() )
1309 {
1310 eh = *eit;
1311 ++eit;
1312 }
1313 else
1314 {
1315 eh = newPolys.front();
1316 newPolys.pop();
1317 }
1318
1319 const EntityHandle* verts;
1320 int num_nodes;
1321 rval = mb->get_connectivity( eh, verts, num_nodes );MB_CHK_ERR( rval );
1322 int nsides = num_nodes;
1323
1324 while( verts[nsides - 2] == verts[nsides - 1] && nsides > 3 )
1325 nsides--;
1326 EntityHandle corrHandle = 0;
1327 if( corrTag )
1328 {
1329 rval = mb->tag_get_data( corrTag, &eh, 1, &corrHandle );MB_CHK_ERR( rval );
1330 }
1331 int gid = 0;
1332 rval = mb->tag_get_data( gidTag, &eh, 1, &gid );MB_CHK_ERR( rval );
1333 coords.resize( 3 * nsides );
1334 if( nsides < 4 ) continue;
1335
1336 rval = mb->get_coords( verts, nsides, &coords[0] );MB_CHK_ERR( rval );
1337
1338 bool alreadyBroken = false;
1339
1340 for( int i = 0; i < nsides; i++ )
1341 {
1342 double* A = &coords[3 * i];
1343 double* B = &coords[3 * ( ( i + 1 ) % nsides )];
1344 double* C = &coords[3 * ( ( i + 2 ) % nsides )];
1345 double angle = IntxUtils::oriented_spherical_angle( A, B, C );
1346 if( angle - M_PI > 0. )
1347 {
1348 if( alreadyBroken )
1349 {
1350 mb->list_entities( &eh, 1 );
1351 mb->list_entities( verts, nsides );
1352 double* D = &coords[3 * ( ( i + 3 ) % nsides )];
1353 std::cout << "ABC: " << angle << " \n";
1354 std::cout << "BCD: " << IntxUtils::oriented_spherical_angle( B, C, D ) << " \n";
1355 std::cout << "CDA: " << IntxUtils::oriented_spherical_angle( C, D, A ) << " \n";
1356 std::cout << "DAB: " << IntxUtils::oriented_spherical_angle( D, A, B ) << " \n";
1357 std::cout << " this cell has at least 2 angles > 180, it has serious issues\n";
1358
1359 return MB_FAILURE;
1360 }
1361
1362
1363
1364
1365
1366
1367
1368 EntityHandle conn3[3] = { verts[( i + 1 ) % nsides], verts[( i + 2 ) % nsides],
1369 verts[( i + 3 ) % nsides] };
1370
1371
1372 std::vector< EntityHandle > conn( nsides - 1 );
1373 for( int j = 1; j < nsides; j++ )
1374 {
1375 conn[j - 1] = verts[( i + j + 2 ) % nsides];
1376 }
1377 EntityHandle newElement;
1378 rval = mb->create_element( MBTRI, conn3, 3, newElement );MB_CHK_ERR( rval );
1379
1380 rval = mb->add_entities( lset, &newElement, 1 );MB_CHK_ERR( rval );
1381 if( corrTag )
1382 {
1383 rval = mb->tag_set_data( corrTag, &newElement, 1, &corrHandle );MB_CHK_ERR( rval );
1384 }
1385 rval = mb->tag_set_data( gidTag, &newElement, 1, &gid );MB_CHK_ERR( rval );
1386 if( nsides == 4 )
1387 {
1388
1389 rval = mb->create_element( MBTRI, &conn[0], 3, newElement );MB_CHK_ERR( rval );
1390 }
1391 else
1392 {
1393
1394 rval = mb->create_element( MBPOLYGON, &conn[0], nsides - 1, newElement );MB_CHK_ERR( rval );
1395 newPolys.push( newElement );
1396
1397 }
1398 rval = mb->add_entities( lset, &newElement, 1 );MB_CHK_ERR( rval );
1399 if( corrTag )
1400 {
1401 rval = mb->tag_set_data( corrTag, &newElement, 1, &corrHandle );MB_CHK_ERR( rval );
1402 }
1403 rval = mb->tag_set_data( gidTag, &newElement, 1, &gid );MB_CHK_ERR( rval );
1404 rval = mb->remove_entities( lset, &eh, 1 );MB_CHK_ERR( rval );
1405 brokenPolys++;
1406 alreadyBroken = true;
1407 }
1408 }
1409 }
1410 if( brokenPolys > 0 )
1411 {
1412 std::cout << "on local process " << my_rank << ", " << brokenPolys
1413 << " concave polygons were decomposed in convex ones \n";
1414 #ifdef VERBOSE
1415 std::stringstream fff;
1416 fff << "file_set" << mb->id_from_handle( lset ) << "rk_" << my_rank << ".h5m";
1417 rval = mb->write_file( fff.str().c_str(), 0, 0, &lset, 1 );MB_CHK_ERR( rval );
1418 std::cout << "wrote new file set: " << fff.str() << "\n";
1419 #endif
1420 }
1421 return MB_SUCCESS;
1422 }
1423
1424
1425
1426 ErrorCode IntxUtils::fix_degenerate_quads( Interface* mb, EntityHandle set )
1427 {
1428 Range quads;
1429 ErrorCode rval = mb->get_entities_by_type( set, MBQUAD, quads );MB_CHK_ERR( rval );
1430 Tag gid;
1431 gid = mb->globalId_tag();
1432 for( Range::iterator qit = quads.begin(); qit != quads.end(); ++qit )
1433 {
1434 EntityHandle quad = *qit;
1435 const EntityHandle* conn4 = NULL;
1436 int num_nodes = 0;
1437 rval = mb->get_connectivity( quad, conn4, num_nodes );MB_CHK_ERR( rval );
1438 for( int i = 0; i < num_nodes; i++ )
1439 {
1440 int next_node_index = ( i + 1 ) % num_nodes;
1441 if( conn4[i] == conn4[next_node_index] )
1442 {
1443
1444
1445 int global_id = 0;
1446 rval = mb->tag_get_data( gid, &quad, 1, &global_id );MB_CHK_ERR( rval );
1447 int i2 = ( i + 2 ) % num_nodes;
1448 int i3 = ( i + 3 ) % num_nodes;
1449 EntityHandle conn3[3] = { conn4[i], conn4[i2], conn4[i3] };
1450 EntityHandle tri;
1451 rval = mb->create_element( MBTRI, conn3, 3, tri );MB_CHK_ERR( rval );
1452 mb->add_entities( set, &tri, 1 );
1453 mb->remove_entities( set, &quad, 1 );
1454 mb->delete_entities( &quad, 1 );
1455 rval = mb->tag_set_data( gid, &tri, 1, &global_id );MB_CHK_ERR( rval );
1456 }
1457 }
1458 }
1459 return MB_SUCCESS;
1460 }
1461
1462 ErrorCode IntxAreaUtils::positive_orientation( Interface* mb, EntityHandle set, double R )
1463 {
1464 Range cells2d;
1465 ErrorCode rval = mb->get_entities_by_dimension( set, 2, cells2d );MB_CHK_ERR( rval );
1466 for( Range::iterator qit = cells2d.begin(); qit != cells2d.end(); ++qit )
1467 {
1468 EntityHandle cell = *qit;
1469 const EntityHandle* conn = NULL;
1470 int num_nodes = 0;
1471 rval = mb->get_connectivity( cell, conn, num_nodes );MB_CHK_ERR( rval );
1472 if( num_nodes < 3 ) return MB_FAILURE;
1473
1474 double coords[9];
1475 rval = mb->get_coords( conn, 3, coords );MB_CHK_ERR( rval );
1476
1477 double area;
1478 if( R > 0 )
1479 area = area_spherical_triangle_lHuiller( coords, coords + 3, coords + 6, R );
1480 else
1481 area = IntxUtils::area2D( coords, coords + 3, coords + 6 );
1482 if( area < 0 )
1483 {
1484
1485 std::vector< double > coords2( 3 * num_nodes );
1486
1487 rval = mb->get_coords( conn, num_nodes, &coords2[0] );MB_CHK_ERR( rval );
1488 double totArea = area_spherical_polygon_lHuiller( &coords2[0], num_nodes, R );
1489 if( totArea < 0 )
1490 {
1491 std::vector< EntityHandle > newconn( num_nodes );
1492 for( int i = 0; i < num_nodes; i++ )
1493 {
1494 newconn[num_nodes - 1 - i] = conn[i];
1495 }
1496 rval = mb->set_connectivity( cell, &newconn[0], num_nodes );MB_CHK_ERR( rval );
1497 }
1498 else
1499 {
1500 std::cout << " nonconvex problem first area:" << area << " total area: " << totArea << std::endl;
1501 }
1502 }
1503 }
1504 return MB_SUCCESS;
1505 }
1506
1507
1508
1509 double IntxUtils::distance_on_sphere( double la1, double te1, double la2, double te2 )
1510 {
1511 return acos( sin( te1 ) * sin( te2 ) + cos( te1 ) * cos( te2 ) * cos( la1 - la2 ) );
1512 }
1513
1514
1518 ErrorCode IntxUtils::intersect_great_circle_arcs( double* A, double* B, double* C, double* D, double R, double* E )
1519 {
1520
1521 double R2 = R * R;
1522 const double Tolerance = 1.e-12 * R2;
1523
1524 CartVect a( A ), b( B ), c( C ), d( D );
1525
1526 if( fabs( a.length_squared() - R2 ) + fabs( b.length_squared() - R2 ) + fabs( c.length_squared() - R2 ) +
1527 fabs( d.length_squared() - R2 ) >
1528 10 * Tolerance )
1529 return MB_FAILURE;
1530
1531 CartVect n1 = a * b;
1532 if( n1.length_squared() < Tolerance ) return MB_FAILURE;
1533
1534 CartVect n2 = c * d;
1535 if( n2.length_squared() < Tolerance ) return MB_FAILURE;
1536 CartVect n3 = n1 * n2;
1537 n3.normalize();
1538
1539 n3 = R * n3;
1540
1541 CartVect n4 = a * n3, n5 = n3 * b;
1542 if( n1 % n4 >= -Tolerance && n1 % n5 >= -Tolerance )
1543 {
1544
1545 n4 = c * n3;
1546 n5 = n3 * d;
1547 if( n2 % n4 >= -Tolerance && n2 % n5 >= -Tolerance )
1548 {
1549 E[0] = n3[0];
1550 E[1] = n3[1];
1551 E[2] = n3[2];
1552 }
1553 else
1554 return MB_FAILURE;
1555 }
1556 else
1557 {
1558
1559 n3 = -n3;
1560 n4 = a * n3, n5 = n3 * b;
1561 if( n1 % n4 >= -Tolerance && n1 % n5 >= -Tolerance )
1562 {
1563
1564 n4 = c * n3;
1565 n5 = n3 * d;
1566 if( n2 % n4 >= -Tolerance && n2 % n5 >= -Tolerance )
1567 {
1568 E[0] = n3[0];
1569 E[1] = n3[1];
1570 E[2] = n3[2];
1571 }
1572 else
1573 return MB_FAILURE;
1574 }
1575 else
1576 return MB_FAILURE;
1577 }
1578
1579 return MB_SUCCESS;
1580 }
1581
1582
1583
1584 static bool verify( CartVect a, CartVect b, CartVect c, CartVect d, double x, double y, double z )
1585 {
1586
1587
1588 CartVect s( x, y, z );
1589 CartVect n1 = a * b;
1590 CartVect n2 = a * s;
1591 CartVect n3 = s * b;
1592 if( n1 % n2 < 0 || n1 % n3 < 0 ) return false;
1593
1594
1595 c[2] = d[2] = s[2] = 0.;
1596
1597 n1 = c * d;
1598 n2 = c * s;
1599 n3 = s * d;
1600 if( n1 % n2 < 0 || n1 % n3 < 0 ) return false;
1601
1602 return true;
1603 }
1604
1605 ErrorCode IntxUtils::intersect_great_circle_arc_with_clat_arc( double* A,
1606 double* B,
1607 double* C,
1608 double* D,
1609 double R,
1610 double* E,
1611 int& np )
1612 {
1613 const double distTol = R * 1.e-6;
1614 const double Tolerance = R * R * 1.e-12;
1615 np = 0;
1616 CartVect a( A ), b( B ), c( C ), d( D );
1617
1618 double R2 = R * R;
1619 if( fabs( a.length_squared() - R2 ) + fabs( b.length_squared() - R2 ) + fabs( c.length_squared() - R2 ) +
1620 fabs( d.length_squared() - R2 ) >
1621 10 * Tolerance )
1622 return MB_FAILURE;
1623
1624 if( ( a - b ).length_squared() < Tolerance ) return MB_FAILURE;
1625 if( ( c - d ).length_squared() < Tolerance )
1626 return MB_FAILURE;
1627
1628
1629 if( fabs( C[2] - D[2] ) > distTol )
1630 return MB_FAILURE;
1631
1632 if( fabs( R - C[2] ) < distTol || fabs( R + C[2] ) < distTol ) return MB_FAILURE;
1633
1634
1635
1636 CartVect n1 = a * b;
1637
1638
1643 double z = C[2];
1644 if( fabs( n1[0] ) + fabs( n1[1] ) < 2 * Tolerance )
1645 {
1646
1647 if( fabs( C[2] ) > distTol )
1648 {
1649 return MB_FAILURE;
1650 }
1651 else
1652 {
1653
1654
1655 CartVect cd = c * d;
1656
1657
1658 CartVect ca = c * a;
1659 CartVect ad = a * d;
1660 CartVect cb = c * b;
1661 CartVect bd = b * d;
1662 bool agtc = ( ca % cd >= -Tolerance );
1663 bool dgta = ( ad % cd >= -Tolerance );
1664 bool bgtc = ( cb % cd >= -Tolerance );
1665 bool dgtb = ( bd % cd >= -Tolerance );
1666 if( agtc )
1667 {
1668 if( dgta )
1669 {
1670
1671 E[0] = a[0];
1672 E[1] = a[1];
1673 E[2] = a[2];
1674 np++;
1675 if( bgtc )
1676 {
1677 if( dgtb )
1678 {
1679
1680 E[3] = b[0];
1681 E[4] = b[1];
1682 E[5] = b[2];
1683 np++;
1684 }
1685 else
1686 {
1687
1688 E[3] = d[0];
1689 E[4] = d[1];
1690 E[5] = d[2];
1691 np++;
1692 }
1693 }
1694 else
1695 {
1696
1697 E[3] = c[0];
1698 E[4] = c[1];
1699 E[5] = c[2];
1700 np++;
1701 }
1702 }
1703 else
1704 {
1705 if( dgtb )
1706 {
1707 E[0] = d[0];
1708 E[1] = d[1];
1709 E[2] = d[2];
1710 np++;
1711 if( bgtc )
1712 {
1713
1714 E[3] = b[0];
1715 E[4] = b[1];
1716 E[5] = b[2];
1717 np++;
1718 }
1719 else
1720 {
1721
1722 E[3] = c[0];
1723 E[4] = c[1];
1724 E[5] = c[2];
1725 np++;
1726 }
1727 }
1728 else
1729 {
1730
1731 }
1732 }
1733 }
1734 else
1735 {
1736 if( bgtc )
1737 {
1738
1739 E[0] = c[0];
1740 E[1] = c[1];
1741 E[2] = c[2];
1742 np++;
1743 if( dgtb )
1744 {
1745
1746 E[3] = b[0];
1747 E[4] = b[1];
1748 E[5] = b[2];
1749 np++;
1750 }
1751 else
1752 {
1753
1754 E[3] = d[0];
1755 E[4] = d[1];
1756 E[5] = d[2];
1757 np++;
1758 }
1759 }
1760 else
1761 {
1762
1763 }
1764 }
1765 }
1766
1767
1768 if( np > 0 ) return MB_SUCCESS;
1769 return MB_FAILURE;
1770 }
1771 {
1772 if( fabs( n1[0] ) <= fabs( n1[1] ) )
1773 {
1774
1775
1776
1777
1778
1779 double u = -n1[2] / n1[1] * z, v = -n1[0] / n1[1];
1780 double a1 = v * v + 1, b1 = 2 * u * v, c1 = u * u + z * z - R2;
1781 double delta = b1 * b1 - 4 * a1 * c1;
1782 if( delta < -Tolerance ) return MB_FAILURE;
1783 if( delta > Tolerance )
1784 {
1785 double x1 = ( -b1 + sqrt( delta ) ) / 2 / a1;
1786 double x2 = ( -b1 - sqrt( delta ) ) / 2 / a1;
1787 double y1 = u + v * x1;
1788 double y2 = u + v * x2;
1789 if( verify( a, b, c, d, x1, y1, z ) )
1790 {
1791 E[0] = x1;
1792 E[1] = y1;
1793 E[2] = z;
1794 np++;
1795 }
1796 if( verify( a, b, c, d, x2, y2, z ) )
1797 {
1798 E[3 * np + 0] = x2;
1799 E[3 * np + 1] = y2;
1800 E[3 * np + 2] = z;
1801 np++;
1802 }
1803 }
1804 else
1805 {
1806
1807 double x1 = -b1 / 2 / a1;
1808 double y1 = u + v * x1;
1809 if( verify( a, b, c, d, x1, y1, z ) )
1810 {
1811 E[0] = x1;
1812 E[1] = y1;
1813 E[2] = z;
1814 np++;
1815 }
1816 }
1817 }
1818 else
1819 {
1820
1821
1822
1823
1824
1825
1826 double u = -n1[2] / n1[0] * z, v = -n1[1] / n1[0];
1827 double a1 = v * v + 1, b1 = 2 * u * v, c1 = u * u + z * z - R2;
1828 double delta = b1 * b1 - 4 * a1 * c1;
1829 if( delta < -Tolerance ) return MB_FAILURE;
1830 if( delta > Tolerance )
1831 {
1832 double y1 = ( -b1 + sqrt( delta ) ) / 2 / a1;
1833 double y2 = ( -b1 - sqrt( delta ) ) / 2 / a1;
1834 double x1 = u + v * y1;
1835 double x2 = u + v * y2;
1836 if( verify( a, b, c, d, x1, y1, z ) )
1837 {
1838 E[0] = x1;
1839 E[1] = y1;
1840 E[2] = z;
1841 np++;
1842 }
1843 if( verify( a, b, c, d, x2, y2, z ) )
1844 {
1845 E[3 * np + 0] = x2;
1846 E[3 * np + 1] = y2;
1847 E[3 * np + 2] = z;
1848 np++;
1849 }
1850 }
1851 else
1852 {
1853
1854 double y1 = -b1 / 2 / a1;
1855 double x1 = u + v * y1;
1856 if( verify( a, b, c, d, x1, y1, z ) )
1857 {
1858 E[0] = x1;
1859 E[1] = y1;
1860 E[2] = z;
1861 np++;
1862 }
1863 }
1864 }
1865 }
1866
1867 if( np <= 0 ) return MB_FAILURE;
1868 return MB_SUCCESS;
1869 }
1870
1871 #if 0
1872 ErrorCode set_edge_type_flag(Interface * mb, EntityHandle sf1)
1873 {
1874 Range cells;
1875 ErrorCode rval = mb->get_entities_by_dimension(sf1, 2, cells);
1876 if (MB_SUCCESS!= rval)
1877 return rval;
1878 Range edges;
1879 rval = mb->get_adjacencies(cells, 1, true, edges, Interface::UNION);
1880 if (MB_SUCCESS!= rval)
1881 return rval;
1882
1883 Tag edgeTypeTag;
1884 int default_int=0;
1885 rval = mb->tag_get_handle("edge_type", 1, MB_TYPE_INTEGER, edgeTypeTag,
1886 MB_TAG_DENSE | MB_TAG_CREAT, &default_int);
1887 if (MB_SUCCESS!= rval)
1888 return rval;
1889
1890
1891 int type_constant_lat=1;
1892 for (Range::iterator eit=edges.begin(); eit!=edges.end(); ++eit)
1893 {
1894 EntityHandle edge = *eit;
1895 const EntityHandle *conn=0;
1896 int num_n=0;
1897 rval = mb->get_connectivity(edge, conn, num_n );
1898 if (MB_SUCCESS!= rval)
1899 return rval;
1900 double coords[6];
1901 rval = mb->get_coords(conn, 2, coords);
1902 if (MB_SUCCESS!= rval)
1903 return rval;
1904 if (fabs( coords[2]-coords[5] )< 1.e-6 )
1905 {
1906 rval = mb->tag_set_data(edgeTypeTag, &edge, 1, &type_constant_lat);
1907 if (MB_SUCCESS!= rval)
1908 return rval;
1909 }
1910 }
1911
1912 return MB_SUCCESS;
1913 }
1914 #endif
1915
1916
1917
1918 int IntxUtils::borderPointsOfCSinRLL( CartVect* redc,
1919 double* red2dc,
1920 int nsRed,
1921 CartVect* bluec,
1922 int nsBlue,
1923 int* blueEdgeType,
1924 double* P,
1925 int* side,
1926 double epsil )
1927 {
1928 int extraPoints = 0;
1929
1930 CartVect A( 0. ), B( 0. ), C( 0. ), D( 0. );
1931 for( int i = 0; i < nsBlue; i++ )
1932 {
1933 if( blueEdgeType[i] == 0 )
1934 {
1935 int iP1 = ( i + 1 ) % nsBlue;
1936 if( bluec[i][2] > bluec[iP1][2] )
1937 {
1938 A = bluec[i];
1939 B = bluec[iP1];
1940 C = bluec[( i + 2 ) % nsBlue];
1941 D = bluec[( i + 3 ) % nsBlue];
1942 break;
1943 }
1944 }
1945 }
1946 if( nsBlue == 3 && B[2] < 0 )
1947 {
1948
1949 D = C;
1950 C = B;
1951 }
1952
1953
1954
1955 for( int i = 0; i < nsRed; i++ )
1956 {
1957 CartVect& X = redc[i];
1958 if( X[2] > A[2] || X[2] < B[2] ) continue;
1959
1960 if( ( ( A * B ) % X >= -epsil ) && ( ( C * D ) % X >= -epsil ) )
1961 {
1962 side[i] = 1;
1963
1964
1965 P[extraPoints * 2] = red2dc[2 * i];
1966 P[extraPoints * 2 + 1] = red2dc[2 * i + 1];
1967 extraPoints++;
1968 }
1969 }
1970 return extraPoints;
1971 }
1972
1973 ErrorCode IntxUtils::deep_copy_set_with_quads( Interface* mb, EntityHandle source_set, EntityHandle dest_set )
1974 {
1975 ReadUtilIface* read_iface;
1976 ErrorCode rval = mb->query_interface( read_iface );MB_CHK_ERR( rval );
1977
1978
1979 EntityHandle dum = 0;
1980 Tag corrTag = 0;
1981 rval = mb->tag_get_handle( CORRTAGNAME, 1, MB_TYPE_HANDLE, corrTag, MB_TAG_DENSE | MB_TAG_CREAT, &dum );MB_CHK_ERR( rval );
1982
1983
1984 Tag gid = mb->globalId_tag();
1985
1986 Range quads;
1987 rval = mb->get_entities_by_type( source_set, MBQUAD, quads );MB_CHK_ERR( rval );
1988
1989 Range connecVerts;
1990 rval = mb->get_connectivity( quads, connecVerts );MB_CHK_ERR( rval );
1991
1992 std::map< EntityHandle, EntityHandle > newNodes;
1993
1994 std::vector< double* > coords;
1995 EntityHandle start_vert, start_elem, *connect;
1996 int num_verts = connecVerts.size();
1997 rval = read_iface->get_node_coords( 3, num_verts, 0, start_vert, coords );
1998 if( MB_SUCCESS != rval ) return rval;
1999
2000 int i = 0;
2001 for( Range::iterator vit = connecVerts.begin(); vit != connecVerts.end(); ++vit, i++ )
2002 {
2003 EntityHandle oldV = *vit;
2004 CartVect posi;
2005 rval = mb->get_coords( &oldV, 1, &( posi[0] ) );MB_CHK_ERR( rval );
2006
2007 int global_id;
2008 rval = mb->tag_get_data( gid, &oldV, 1, &global_id );MB_CHK_ERR( rval );
2009 EntityHandle new_vert = start_vert + i;
2010
2011 coords[0][i] = posi[0];
2012 coords[1][i] = posi[1];
2013 coords[2][i] = posi[2];
2014
2015 newNodes[oldV] = new_vert;
2016
2017 rval = mb->tag_set_data( corrTag, &oldV, 1, &new_vert );MB_CHK_ERR( rval );
2018
2019
2020
2021
2022 rval = mb->tag_set_data( corrTag, &new_vert, 1, &oldV );MB_CHK_ERR( rval );
2023
2024 rval = mb->tag_set_data( gid, &new_vert, 1, &global_id );MB_CHK_ERR( rval );
2025 }
2026
2027
2028 rval = read_iface->get_element_connect( quads.size(), 4, MBQUAD, 0, start_elem, connect );
2029 if( MB_SUCCESS != rval ) return rval;
2030 int ie = 0;
2031 for( Range::iterator it = quads.begin(); it != quads.end(); ++it, ie++ )
2032 {
2033 EntityHandle q = *it;
2034 int nnodes;
2035 const EntityHandle* conn;
2036 rval = mb->get_connectivity( q, conn, nnodes );MB_CHK_ERR( rval );
2037 int global_id;
2038 rval = mb->tag_get_data( gid, &q, 1, &global_id );MB_CHK_ERR( rval );
2039
2040 for( int ii = 0; ii < nnodes; ii++ )
2041 {
2042 EntityHandle v1 = conn[ii];
2043 connect[4 * ie + ii] = newNodes[v1];
2044 }
2045 EntityHandle newElement = start_elem + ie;
2046
2047
2048 rval = mb->tag_set_data( corrTag, &q, 1, &newElement );MB_CHK_ERR( rval );
2049 rval = mb->tag_set_data( corrTag, &newElement, 1, &q );MB_CHK_ERR( rval );
2050
2051
2052 rval = mb->tag_set_data( gid, &newElement, 1, &global_id );MB_CHK_ERR( rval );
2053
2054 rval = mb->add_entities( dest_set, &newElement, 1 );MB_CHK_ERR( rval );
2055 }
2056
2057 rval = read_iface->update_adjacencies( start_elem, quads.size(), 4, connect );MB_CHK_ERR( rval );
2058
2059 return MB_SUCCESS;
2060 }
2061
2062 ErrorCode IntxUtils::remove_duplicate_vertices( Interface* mb,
2063 EntityHandle file_set,
2064 double merge_tol,
2065 std::vector< Tag >& tagList )
2066 {
2067 Range verts;
2068 ErrorCode rval = mb->get_entities_by_dimension( file_set, 0, verts );MB_CHK_ERR( rval );
2069 rval = mb->remove_entities( file_set, verts );MB_CHK_ERR( rval );
2070
2071 MergeMesh mm( mb );
2072
2073
2074
2075 rval = mm.merge_all( file_set, merge_tol );MB_CHK_ERR( rval );
2076
2077
2078 rval = remove_padded_vertices( mb, file_set, tagList );
2079 return MB_SUCCESS;
2080 }
2081
2082 ErrorCode IntxUtils::remove_padded_vertices( Interface* mb, EntityHandle file_set, std::vector< Tag >& tagList )
2083 {
2084
2085
2086 Range cells;
2087 ErrorCode rval = mb->get_entities_by_dimension( file_set, 2, cells );MB_CHK_ERR( rval );
2088
2089 Range verts;
2090 rval = mb->get_connectivity( cells, verts );MB_CHK_ERR( rval );
2091
2092 Range modifiedCells;
2093 Range newCells;
2094
2095 for( Range::iterator cit = cells.begin(); cit != cells.end(); ++cit )
2096 {
2097 EntityHandle cell = *cit;
2098 const EntityHandle* connec = NULL;
2099 int num_verts = 0;
2100 rval = mb->get_connectivity( cell, connec, num_verts );MB_CHK_SET_ERR( rval, "Failed to get connectivity" );
2101
2102 std::vector< EntityHandle > newConnec;
2103 newConnec.push_back( connec[0] );
2104 int index = 0;
2105 int new_size = 1;
2106 while( index < num_verts - 2 )
2107 {
2108 int next_index = ( index + 1 );
2109 if( connec[next_index] != newConnec[new_size - 1] )
2110 {
2111 newConnec.push_back( connec[next_index] );
2112 new_size++;
2113 }
2114 index++;
2115 }
2116
2117 if( ( connec[num_verts - 1] != connec[num_verts - 2] ) && ( connec[num_verts - 1] != connec[0] ) )
2118 {
2119 newConnec.push_back( connec[num_verts - 1] );
2120 new_size++;
2121 }
2122 if( new_size < num_verts )
2123 {
2124
2125 modifiedCells.insert( cell );
2126
2127 EntityType type = MBTRI;
2128 if( new_size == 3 )
2129 type = MBTRI;
2130 else if( new_size == 4 )
2131 type = MBQUAD;
2132 else if( new_size > 4 )
2133 type = MBPOLYGON;
2134
2135
2136 EntityHandle newCell;
2137 rval = mb->create_element( type, &newConnec[0], new_size, newCell );MB_CHK_SET_ERR( rval, "Failed to create new cell" );
2138
2139 newCells.insert( newCell );
2140 double value;
2141 for( size_t i = 0; i < tagList.size(); i++ )
2142 {
2143 rval = mb->tag_get_data( tagList[i], &cell, 1, (void*)( &value ) );MB_CHK_SET_ERR( rval, "Failed to get tag value" );
2144 rval = mb->tag_set_data( tagList[i], &newCell, 1, (void*)( &value ) );MB_CHK_SET_ERR( rval, "Failed to set tag value on new cell" );
2145 }
2146 }
2147 }
2148
2149 rval = mb->remove_entities( file_set, modifiedCells );MB_CHK_SET_ERR( rval, "Failed to remove old cells from file set" );
2150 rval = mb->delete_entities( modifiedCells );MB_CHK_SET_ERR( rval, "Failed to delete old cells" );
2151 rval = mb->add_entities( file_set, newCells );MB_CHK_SET_ERR( rval, "Failed to add new cells to file set" );
2152 rval = mb->add_entities( file_set, verts );MB_CHK_SET_ERR( rval, "Failed to add verts to the file set" );
2153
2154 return MB_SUCCESS;
2155 }
2156
2157 ErrorCode IntxUtils::max_diagonal( Interface* mb, Range cells, int max_edges, double& diagonal )
2158 {
2159 diagonal = 0.0;
2160 std::vector< CartVect > coords( max_edges );
2161 for( auto it = cells.begin(); it != cells.end(); ++it )
2162 {
2163
2164 EntityHandle cell = *it;
2165 const EntityHandle* connec = NULL;
2166 int num_verts = 0;
2167 MB_CHK_SET_ERR( mb->get_connectivity( cell, connec, num_verts ), "Failed to get connectivity" );
2168 MB_CHK_SET_ERR( mb->get_coords( connec, num_verts, &( coords[0][0] ) ), "Failed to get coordinates" );
2169
2170 for( int i = 0; i < num_verts - 1; i++ )
2171 {
2172 for( int j = i + 1; j < num_verts; j++ )
2173 {
2174 double len_sq = ( coords[i] - coords[j] ).length_squared();
2175 if( len_sq > diagonal ) diagonal = len_sq;
2176 }
2177 }
2178 }
2179
2180
2181 diagonal = std::sqrt( diagonal );
2182 return MB_SUCCESS;
2183 }
2184
2185 }