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