TECA
The Toolkit for Extreme Climate Analysis
teca_shape_file_util.h
Go to the documentation of this file.
1 #ifndef teca_shape_file_util_h
2 #define teca_shape_file_util_h
3 
4 #include "teca_config.h"
5 #include "teca_binary_stream.h"
6 #include "teca_geometry.h"
7 #include "teca_mpi.h"
8 
9 #include <string>
10 #include <vector>
11 #include <ostream>
12 #include <shapefil.h>
13 
14 /// @file
15 
16 namespace teca_shape_file_util
17 {
18 /// Get a string with the name of the shape type
20 const char *shape_type_name(int shpt);
21 
22 /// Send the shape object to the stream in a human readable form
24 std::ostream &operator<<(std::ostream &os, const SHPObject &obj);
25 
26 /// Read polygons from the given file.
27 template<typename coord_t>
29 int load_polygons(const std::string &filename,
30  std::vector<teca_geometry::polygon<coord_t>> &polys,
31  int normalize = 0, int verbose = 0)
32 {
33  if (verbose)
34  TECA_STATUS("Opening shape file \"" << filename << "\"")
35 
36  SHPHandle h = SHPOpen(filename.c_str(), "rb");
37  if (h == nullptr)
38  {
39  TECA_ERROR("Failed to open shape file \"" << filename << "\"")
40  return -1;
41  }
42 
43  int n_shapes = 0;
44  int types = 0;
45  double x0[4] = {0.0};
46  double x1[4] = {0.0};
47 
48  SHPGetInfo(h, &n_shapes, &types, x0, x1);
49 
50  if (verbose)
51  TECA_STATUS("Found " << n_shapes << " shapes of type "
52  << shape_type_name(types))
53 
54  if (types != SHPT_POLYGON)
55  {
56  TECA_ERROR("The shapes contained in \"" << filename
57  << "\" are not polygons.")
58  SHPClose(h);
59  return -1;
60  }
61 
62  polys.reserve(n_shapes);
63 
64  for (int i = 0; i < n_shapes; ++i)
65  {
66  if (verbose > 1)
67  std::cerr << "Reading object " << i << " ... " << std::endl;
68 
69  SHPObject *obj = SHPReadObject(h, i);
70  if (obj == nullptr)
71  {
72  TECA_ERROR("Failed to read the " << i << "th polygon")
73  SHPClose(h);
74  return -1;
75  }
76 
77  if (verbose > 1)
78  std::cerr << "Object" << i << " = " << *obj << std::endl;
79 
80  // process each part
81  std::vector<int> starts(obj->panPartStart, obj->panPartStart + obj->nParts);
82  std::vector<int> ends(obj->panPartStart + 1, obj->panPartStart + obj->nParts);
83  ends.push_back(obj->nVertices);
84  for (int j = 0; j < obj->nParts; ++j)
85  {
86  // only process polygons.
87  if (obj->panPartType[j] != SHPT_POLYGON)
88  {
89  TECA_WARNING("Part " << j << " of object " << i << " is "
90  << shape_type_name(obj->panPartType[j])
91  << " but a SHPT_POLYGON is required")
92  continue;
93  }
94 
95  int start = starts[j];
96  int n_verts = ends[j] - start;
97 
98  // make a polygon
100  poly.copy(obj->padfX + start, obj->padfY + start, n_verts);
101 
102  if (normalize)
103  poly.normalize_coordinates();
104 
105  // add it to the collection
106  polys.push_back(poly);
107  }
108 
109  SHPDestroyObject(obj);
110  }
111 
112  SHPClose(h);
113 
114  return 0;
115 }
116 
117 /** Read polygons from the given file. MPI rank 0 reads and broadcasts to the
118  * other ranks in the job
119  */
120 template<typename coord_t>
122 int load_polygons(MPI_Comm comm, const std::string &filename,
123  std::vector<teca_geometry::polygon<coord_t>> &polys,
124  int normalize = 0, int verbose = 0)
125 {
126  int rank = 0;
127 #if defined(TECA_HAS_MPI)
128  int is_init = 0;
129  MPI_Initialized(&is_init);
130  if (is_init)
131  {
132  MPI_Comm_rank(comm, &rank);
133  }
134 #endif
135 
137 
138  if (rank == 0)
139  {
140  // read the shape file
141  if (teca_shape_file_util::load_polygons(filename, polys, normalize, verbose))
142  {
143  TECA_ERROR("Failed to read polygons from \""
144  << filename << "\"")
145 
146  // returning here would introduce an MPI deadlock
147  }
148 
149  // serialize
150  size_t n_polys = polys.size();
151 
152  bs.pack(n_polys);
153 
154  for (size_t i = 0; i < n_polys; ++i)
155  polys[i].to_stream(bs);
156  }
157 
158  // distribute to all ranks
159  bs.broadcast(comm);
160 
161  if (rank != 0)
162  {
163  // deserialize
164  size_t n_polys = 0;
165  bs.unpack(n_polys);
166 
167  polys.resize(n_polys);
168 
169  for (size_t i = 0; i < n_polys; ++i)
170  polys[i].from_stream(bs);
171  }
172 
173  return 0;
174 }
175 
176 };
177 
178 #endif
Serialize objects into a binary stream.
Definition: teca_binary_stream.h:17
p_teca_error_handler error_handler TECA_EXPORT
The global error handler instance.
TECA_EXPORT std::string filename(const std::string &filename)
Definition: teca_geometry.h:86
void copy(const in_coord_t *in_vx, const in_coord_t *in_vy, unsigned long in_n_verts)
deep copy the vertices of the polygon.
Definition: teca_geometry.h:122
void normalize_coordinates()
transforms coordinates to be in [0 360 -90 90]
Definition: teca_geometry.h:138
TECA_EXPORT std::ostream & operator<<(std::ostream &os, const teca_calendar_util::time_point &tpt)
send the time_point to a stream in humnan readable form
#define TECA_ERROR(_msg)
Constructs an error message and sends it to the stderr stream.
Definition: teca_common.h:161
#define TECA_WARNING(_msg)
Constructs a warning message and sends it to the stderr stream.
Definition: teca_common.h:164
#define TECA_STATUS(_msg)
Constructs a status message and sends it to the stderr stream.
Definition: teca_common.h:167
TECA_EXPORT int load_polygons(const std::string &filename, std::vector< teca_geometry::polygon< coord_t >> &polys, int normalize=0, int verbose=0)
Read polygons from the given file.
Definition: teca_shape_file_util.h:29
TECA_EXPORT const char * shape_type_name(int shpt)
Get a string with the name of the shape type.