TECA
The Toolkit for Extreme Climate Analysis
teca_geometry.h
Go to the documentation of this file.
1 #ifndef teca_geometry_h
2 #define teca_geometry_h
3 
4 #include "teca_config.h"
5 #include "teca_binary_stream.h"
6 
7 #include <memory>
8 #include <limits>
9 
10 /// @file
11 
12 /// Codes dealing with computational geometry
13 namespace teca_geometry
14 {
15 
16 /// tests if a point is Left|On|Right of an infinite line.
17 template<typename n_t>
19 bool left(n_t e0x, n_t e0y, n_t e1x, n_t e1y, n_t px, n_t py)
20 {
21  // >0 for p left of the line through e0 and e1
22  // =0 for p on the line
23  // <0 for p right of the line
24  return
25  ((e1x - e0x)*(py - e0y) - (px - e0x)*(e1y - e0y)) >= n_t();
26 }
27 
28 /** Winding number test for a point in a polygon. The winding number is 0 when
29  * the point is outside. The polygon is defined a series of x, y points in
30  * counter clockwise order. Defining in clock wise order changes the sign of
31  * the winding number. the first and last point of the polygon are required to
32  * be the same.
33  *
34  * @param [in] px the x coordinate of the point.
35  * @param [in] py the y coordinate of the point.
36  * @param [in] vx the x coordinates of the polygon.
37  * @param [in] vy the y coordinates of the polygon.
38  * @param [in] nppts the number of points in the polygon.
39  *
40  */
41 template<typename n_t>
43 bool point_in_poly(n_t px, n_t py,
44  n_t *vx, n_t *vy, unsigned long nppts)
45 {
46  int wn = 0;
47  // loop through all edges of the polygon
48  unsigned long npptsm1 = nppts - 1;
49  for (unsigned long i = 0; i < npptsm1; ++i)
50  {
51  // edge from vx[i], vy[i] to vx[i+1], vy[i+1]
52  if (vy[i] <= py)
53  {
54  // if upward crossing and px, py left of edge then
55  // have a valid up intersect
56  if ((vy[i+1] > py) &&
57  (left(vx[i], vy[i], vx[i+1], vy[i+1], px, py))) ++wn;
58  }
59  else
60  {
61  // if downward crossing and px, py right of edge then
62  // have a valid down intersect
63  if ((vy[i+1] <= py) &&
64  (!left(vx[i], vy[i], vx[i+1], vy[i+1], px, py))) --wn;
65  }
66  }
67  return wn;
68 }
69 
70 /** @breif The vertices of a 2D polygon in clockwise order. The first
71  * and last point are required to be the same.
72  */
73 template <typename coord_t>
75 {
76  polygon() : vx(nullptr), vy(nullptr), n_verts(0) {}
77 
78  /// deep copy the vertices of the polygon.
79  template <typename in_coord_t>
80  void copy(const in_coord_t *in_vx,
81  const in_coord_t *in_vy, unsigned long in_n_verts);
82 
83  /// transforms coordinates to be in [0 360 -90 90]
84  void normalize_coordinates();
85 
86  /// returns true if a point is inside the polygon
87  bool inside(coord_t px, coord_t py);
88 
89  /** compute an axis aligned bounding box around the polygon
90  * with the layout [x0 x1 y0 y1].
91  */
92  void get_bounds(coord_t *bounds);
93 
94  /// serialize to the given stream
95  void to_stream(teca_binary_stream &bs);
96 
97  /// deseriealize from the given stream
98  int from_stream(teca_binary_stream &bs);
99 
100  std::shared_ptr<coord_t> vx;
101  std::shared_ptr<coord_t> vy;
102  unsigned long n_verts;
103 };
104 
105 
106 // --------------------------------------------------------------------------
107 template <typename coord_t>
108 template <typename in_coord_t>
109 void polygon<coord_t>::copy(const in_coord_t *in_vx,
110  const in_coord_t *in_vy, unsigned long in_n_verts)
111 {
112  unsigned long nbytes = in_n_verts*sizeof(coord_t);
113 
114  vx = std::shared_ptr<coord_t>((coord_t*)malloc(nbytes), free);
115  memcpy(vx.get(), in_vx, nbytes);
116 
117  vy = std::shared_ptr<coord_t>((coord_t*)malloc(nbytes), free);
118  memcpy(vy.get(), in_vy, nbytes);
119 
120  n_verts = in_n_verts;
121 }
122 
123 // --------------------------------------------------------------------------
124 template <typename coord_t>
126 {
127  coord_t *pvx = vx.get();
128  for (unsigned long i = 0; i < n_verts; ++i)
129  pvx[i] = pvx[i] < coord_t(0) ? pvx[i] + coord_t(360) : pvx[i];
130 }
131 
132 // --------------------------------------------------------------------------
133 template <typename coord_t>
134 bool polygon<coord_t>::inside(coord_t px, coord_t py)
135 {
136  return teca_geometry::point_in_poly(px, py, vx.get(), vy.get(), n_verts);
137 }
138 
139 // --------------------------------------------------------------------------
140 template <typename coord_t>
141 void polygon<coord_t>::get_bounds(coord_t *bounds)
142 {
143  const coord_t *pvx = vx.get();
144  const coord_t *pvy = vy.get();
145 
146  bounds[0] = std::numeric_limits<coord_t>::max();
147  for (unsigned long i = 0; i < n_verts; ++i)
148  bounds[0] = pvx[i] < bounds[0] ? pvx[i] : bounds[0];
149 
150  bounds[1] = std::numeric_limits<coord_t>::lowest();
151  for (unsigned long i = 0; i < n_verts; ++i)
152  bounds[1] = pvx[i] > bounds[1] ? pvx[i] : bounds[1];
153 
154  bounds[2] = std::numeric_limits<coord_t>::max();
155  for (unsigned long i = 0; i < n_verts; ++i)
156  bounds[2] = pvy[i] < bounds[2] ? pvy[i] : bounds[2];
157 
158  bounds[3] = std::numeric_limits<coord_t>::lowest();
159  for (unsigned long i = 0; i < n_verts; ++i)
160  bounds[3] = pvy[i] > bounds[3] ? pvy[i] : bounds[3];
161 }
162 
163 // --------------------------------------------------------------------------
164 template <typename coord_t>
166 {
167  bs.pack(n_verts);
168  bs.pack(vx.get(), n_verts);
169  bs.pack(vy.get(), n_verts);
170 }
171 
172 // --------------------------------------------------------------------------
173 template <typename coord_t>
175 {
176  bs.unpack(n_verts);
177 
178  unsigned long nbytes = n_verts*sizeof(coord_t);
179  vx = std::shared_ptr<coord_t>((coord_t*)malloc(nbytes), free);
180  vy = std::shared_ptr<coord_t>((coord_t*)malloc(nbytes), free);
181 
182  bs.unpack(vx.get(), n_verts);
183  bs.unpack(vy.get(), n_verts);
184 
185  return 0;
186 }
187 
188 };
189 
190 #endif
teca_binary_stream
Serialize objects into a binary stream.
Definition: teca_binary_stream.h:16
teca_geometry::polygon::copy
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:109
teca_geometry::polygon::from_stream
int from_stream(teca_binary_stream &bs)
deseriealize from the given stream
Definition: teca_geometry.h:174
teca_geometry::polygon::normalize_coordinates
void normalize_coordinates()
transforms coordinates to be in [0 360 -90 90]
Definition: teca_geometry.h:125
teca_geometry::polygon::inside
bool inside(coord_t px, coord_t py)
returns true if a point is inside the polygon
Definition: teca_geometry.h:134
teca_geometry::polygon::get_bounds
void get_bounds(coord_t *bounds)
Definition: teca_geometry.h:141
teca_geometry::polygon::to_stream
void to_stream(teca_binary_stream &bs)
serialize to the given stream
Definition: teca_geometry.h:165
teca_geometry
Codes dealing with computational geometry.
Definition: teca_geometry.h:13
teca_py_array::copy
TECA_EXPORT bool copy(teca_variant_array *varr, PyObject *obj)
Copy values from the object into variant array.
Definition: teca_py_array.h:290
teca_geometry::left
TECA_EXPORT bool left(n_t e0x, n_t e0y, n_t e1x, n_t e1y, n_t px, n_t py)
tests if a point is Left|On|Right of an infinite line.
Definition: teca_geometry.h:19
teca_geometry::point_in_poly
TECA_EXPORT bool point_in_poly(n_t px, n_t py, n_t *vx, n_t *vy, unsigned long nppts)
Definition: teca_geometry.h:43
teca_error::TECA_EXPORT
p_teca_error_handler error_handler TECA_EXPORT
The global error handler instance.
teca_geometry::polygon
Definition: teca_geometry.h:74