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