Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
ContinentsOnGlobe.cpp
Go to the documentation of this file.
1 /**
2  * @file ContinentsOnGlobe.cpp
3  * @brief Example demonstrating continent boundary detection on spherical meshes
4  *
5  * This example shows how to:
6  * - Load spherical mesh files and continent boundary data
7  * - Convert 3D spherical coordinates to 2D lat-lon coordinates
8  * - Perform point-in-polygon tests for continent detection
9  * - Create mesh sets for different continents and islands
10  * - Tag mesh elements with continent information
11  * - Handle complex boundary loops for major landmasses
12  * - Write continent-mapped mesh files
13  *
14  * This tool is useful for climate and geophysical applications
15  * where continent boundaries need to be identified on spherical meshes.
16  *
17  * @author MOAB Development Team
18  * @date 2024
19  *
20  * @example ContinentsOnGlobe.cpp
21  * Description: read a mesh on a sphere and boundaries of continents and major islands,
22  * and write a boundaries mesh file (bound.vtk) and a file with sets for major continents
23  * (map.h5m). Boundaries exist as 2 files, a list of boundary points and a list of loops,
24  * representing each continent and major islands; there are 796 loops (islands). The first one has
25  * 1239 edges/segments (Asia+Europe), while the last one has only 3. It must be a small island :)
26  * ContinentsOnGlobe <input.h5m>
27  * default values: poly2000.h5m : a mesh with 2000 polygons on a sphere of radius 1
28  *
29  * @param argc Number of command line arguments
30  * @param argv Command line arguments array
31  * @return 0 on success, 1 on failure
32  */
33 
34 #include "moab/Core.hpp"
35 #include "moab/ReadUtilIface.hpp"
36 #include <cmath>
37 #include "moab/CartVect.hpp"
38 
39 #include <iostream>
40 #include <fstream>
41 
42 using namespace moab;
43 using namespace std;
44 
45 string bd_name = string( MESH_DIR ) + string( "/../examples/earth/boundary_points.dat" );
46 string loops = string( MESH_DIR ) + string( "/../examples/earth/SaveLoopCounts" );
47 string input_file = string( MESH_DIR ) + string( "/../examples/earth/poly2000.h5m" );
48 
49 double getLat( CartVect p )
50 {
51  p.normalize();
52  return asin( p[2] );
53 }
54 double getLon( CartVect p )
55 {
56  p.normalize();
57  double lon;
58 
59  lon = atan2( p[1], p[0] );
60 
61  if( lon < -2.95 )
62  { // separate Asia/Europe from Americas
63  return 2.0 * M_PI + lon;
64  }
65  else
66  {
67  return lon;
68  }
69 }
70 
71 // we project sphere points on a 2d map. We decide if a point is in interior of a loop
72 // with the span angle test; it will work for any island except Antarctica
73 
74 bool interior_point( vector< double >& coords, int& startLoop, int& endLoop, double lat, double lon )
75 {
76  // compute oriented angle between point and edges in the loop
77  // if angle ~ +/-2Pi, it is in the interior
78  double totalAngle = 0;
79  for( int i = startLoop; i <= endLoop; i++ )
80  {
81  double x1 = coords[2 * i], y1 = coords[2 * i + 1];
82  int i2 = i + 1;
83  if( i == endLoop ) i2 = startLoop;
84  double x2 = coords[2 * i2], y2 = coords[2 * i2 + 1];
85  CartVect P1( x1 - lat, y1 - lon, 0. );
86  CartVect P2( x2 - lat, y2 - lon, 0. );
87  CartVect cross = P1 * P2;
88  double angle1 = angle( P1, P2 );
89  if( cross[2] < 0 ) angle1 = -angle1;
90  totalAngle += angle1;
91  }
92  if( fabs( totalAngle + 2 * M_PI ) < 0.1 || fabs( totalAngle - 2 * M_PI ) < 0.1 ) return true;
93  return false;
94 }
95 
96 int main( int argc, char** argv )
97 {
98  // Get MOAB instance
99  Interface* mb = new( std::nothrow ) Core;
100  if( NULL == mb ) return 1;
101 
102  if( argc > 1 )
103  {
104  // User has input file for mesh file
105  input_file = argv[1];
106  }
107 
108  cout << "input file : " << input_file << "\n";
109  std::vector< double > coords;
110  ifstream bdFile( bd_name.c_str() );
111  if( !bdFile )
112  {
113  cout << endl << "Failed to open file " << bd_name << endl;
114  ;
115  return 1;
116  }
117  coords.resize( 0 );
118  while( !bdFile.eof() )
119  {
120  double co;
121  bdFile >> co;
122  coords.push_back( co );
123  }
124  cout << " number of boundary points:" << coords.size() / 3 << "\n";
125  /// get loops for boundaries
126  vector< int > loopsindx;
127  ifstream loopFile( loops.c_str() );
128  while( !loopFile.eof() )
129  {
130  int indx;
131  loopFile >> indx;
132  loopsindx.push_back( indx );
133  }
134  cout << "number of loops: " << loopsindx.size() / 2 << "\n";
135  // convert loops to lat-lon loops
136  // it will be easier to determine in-out relations for points in 2d plane
137  // careful with the international time zone; ( + - Pi longitude )
138  vector< double > coords2d;
139  coords2d.resize( coords.size() / 3 * 2 );
140  for( int i = 0; i < (int)coords.size() / 3; i++ )
141  {
142  CartVect p( coords[3 * i], coords[3 * i + 1], coords[3 * i + 2] );
143  coords2d[2 * i] = getLat( p );
144  coords2d[2 * i + 1] = getLon( p );
145  }
146 
147  MB_CHK_SET_ERR( mb->load_file( input_file.c_str() ), "Can't load file" );
148  // look at the center of element, and see if it is inside the loop
149 
150  Range cells;
151  MB_CHK_SET_ERR( mb->get_entities_by_dimension( 0, 2, cells ), "Can't get cells" );
152 
153  cout << "number of cells: " << cells.size() << "\n";
154 
155  // tag for continents
156  Tag tag1;
157  int defa = -1;
158  MB_CHK_SET_ERR( mb->tag_get_handle( "continent", 1, MB_TYPE_INTEGER, tag1, MB_TAG_DENSE | MB_TAG_CREAT, &defa ),
159  "Trouble creating continent tag" );
160  EntityHandle islandSets[6];
161  for( int loop_index = 0; loop_index < 6; loop_index++ )
162  {
163  MB_CHK_SET_ERR( mb->create_meshset( MESHSET_SET, islandSets[loop_index] ), "Can't create island set" );
164  int startLoop = loopsindx[2 * loop_index];
165  int endLoop = loopsindx[2 * loop_index + 1];
166 
167  vector< EntityHandle > interiorCells;
168  for( Range::iterator cit = cells.begin(); cit != cells.end(); cit++ )
169  {
170  EntityHandle cell = *cit;
171  // see if it is in the interior of the loop
173  MB_CHK_SET_ERR( mb->get_coords( &cell, 1, &( center[0] ) ), "Can't get cell center coords" );
174  double lat = getLat( center ), lon = getLon( center );
175  // if NA, use some boxes too, for lat/lon
176  // if (NorthAmerica && (lat < 0.15 || lon < M_PI || lon > 2*M_PI - 0.5) )
177  // continue;
178 
179  if( interior_point( coords2d, startLoop, endLoop, lat, lon ) )
180  {
181  interiorCells.push_back( cell );
182  MB_CHK_SET_ERR( mb->tag_set_data( tag1, &cell, 1, &loop_index ), "Can't get tag on cell" );
183  }
184  }
185 
186  MB_CHK_SET_ERR( mb->add_entities( islandSets[loop_index], &interiorCells[0], interiorCells.size() ),
187  "Can't add entities to set" );
188  }
189 
190  std::stringstream islandFile;
191 
192  islandFile << "map.h5m";
193 
194  MB_CHK_SET_ERR( mb->write_file( islandFile.str().c_str() ), "Can't write island file" );
195  return 0;
196 }