acme
Foundational cross-platform layer of the ca2 framework
Loading...
Searching...
No Matches
point_array.h
1#pragma once
2
3
4#include "_function.h"
5//#include "bounding_box.h"
6
7
8//#include "_concept.h"
9
10
11//#include "acme/prototype/collection/array.h"
14
15
16inline bool tolerance_is_equal(::f64 tolerance, ::f64 d1, ::f64 d2)
17{
18 return ::abs(d1 - d2) <= tolerance;
19}
20
21
22template < prototype_number NUMBER >
24 public ::array_base < ::point_type < NUMBER > >
25{
26public:
27
28
29 using BASE_ARRAY = ::array_base < ::point_type < NUMBER > >;
30 //using POINT_BASE_TYPE = POINT_TYPE;
31 using UNIT_TYPE = NUMBER;
32 //using SIZE_TYPE = typename POINT_TYPE::SIZE_TYPE;
33 //using RECTANGLE_TYPE = typename POINT_TYPE::RECTANGLE_TYPE;
34 //using RECTANGLE_BASE_TYPE = typename RECTANGLE_TYPE::RECTANGLE_BASE_TYPE;
35
36 using BASE_ARRAY::BASE_ARRAY;
37 using BASE_ARRAY::operator =;
38
39 //inline point_array_base() : ::array < ::point_type < NUMBER > >() {}
40 //template < std::size_t n >
41 //inline point_array_base(const ::point_type < NUMBER > p[n]) : ::array < ::point_type < NUMBER > >(p, n){ }
42 //inline point_array_base(point_array_base && pointset) : ::array < ::point_type < NUMBER > >(::transfer(pointset)) { }
43 //inline point_array_base(const point_array_base & pointset) { operator=(pointset); }
44 //~point_array_base() { }
45
46
47 //operator ::point_type < UNIT_TYPE > * () { return this->get_data(); }
48
49 void offset(UNIT_TYPE x, UNIT_TYPE y);
50 void offset(::point_type < UNIT_TYPE > point) { offset(point.x, point.y); }
51
52 void rotate(::f64 dAngle);
53
54 void rotate(::f64 dAngle, ::point_type < UNIT_TYPE > pointCenter);
55
56 void expand_bounding_box(::point_type < UNIT_TYPE > & top_left, ::point_type < UNIT_TYPE > & bottom_right) const;
57
58 bool get_bounding_box(::point_type < UNIT_TYPE > & top_left, ::point_type < UNIT_TYPE > & bottom_right) const;
59
60 bool polygon_contains_winding(const ::point_type < UNIT_TYPE > & point) const;
61 bool polygon_contains_alternate(const ::point_type < UNIT_TYPE > & point) const;
62
63 inline ::collection::index add(UNIT_TYPE x, UNIT_TYPE y) { return ::array_base < ::point_type < NUMBER > >::add({x, y}); }
64 inline ::collection::index add(const ::point_type < NUMBER > & point) { return ::array_base < ::point_type < NUMBER > >::add(point); }
65 inline point_array_base & operator =(const point_array_base & pointset) { this->copy(pointset); return *this; }
66
67 inline ::collection::index tolerance_add_unique(UNIT_TYPE tolerance, const ::point_type < NUMBER > & pointAdd)
68 {
69
70 for (auto & point : *this)
71 {
72
73 if (tolerance_is_equal(tolerance, point.x, pointAdd.x) && tolerance_is_equal(tolerance, point.y, pointAdd.y))
74 {
75
78
79 return -1;
80
81 }
82
83 }
84
85 return ::array_base < ::point_type < NUMBER > >::add(pointAdd);
86
87 }
88
89 //virtual void xml_import(::xml::input_tree & xmlif);
90 //virtual void xml_export(::xml::output_tree & xmlof);
91
92
93 ::collection::count add_unique_range(const ::point_type < NUMBER > & pBeg, const ::point_type < NUMBER > & pointEnd, const ::size_type < NUMBER > & s = e_unit_size);
94 //https://www.geeksforgeeks.org/area-of-a-i32_polygon-with-given-n-ordered-vertexes/
95 // (X[i], Y[i]) are coordinates of i'th point.
96
97 UNIT_TYPE polygon_area()
98 {
99
100 UNIT_TYPE area = (UNIT_TYPE) 0;
101
102 ::i32 n = (::i32) this->get_count();
103
104 // Calculate value of shoelace formula
105 ::i32 j = n - 1;
106
107 for (::i32 i = 0; i < n; i++)
108 {
109
110 area += (this->element_at(j).x + this->element_at(i).x)
111 * (this->element_at(j).y - this->element_at(i).y);
112
113 j = i; // j is previous vertex to i
114
115 }
116
117 return area / 2;
118
119 }
120
121
122 auto points_beyond_right(UNIT_TYPE x) const
123 {
124
125 return ::transfer(container_predicate_get(*this, [x](const ::point_type < NUMBER > & p) {return p.x > x; }));
126
127 }
128
129
130 auto points_beyond_left(UNIT_TYPE x) const
131 {
132
133 return ::transfer(container_predicate_get(*this, [x](const ::point_type < NUMBER > & p) {return p.x < x; }));
134
135 }
136
137
138 auto points_beyond_top(UNIT_TYPE y) const
139 {
140
141 return ::transfer(container_predicate_get(*this, [y](const ::point_type < NUMBER > & p) {return p.y < y; }));
142
143 }
144
145
146 auto points_beyond_bottom(UNIT_TYPE y) const
147 {
148
149 return ::transfer(container_predicate_get(*this, [y](const ::point_type < NUMBER > & p) {return p.y > y; }));
150
151 }
152
153
154 auto points_beyond_right() const
155 {
156
157 return this->points_beyond_right(this->first().x);
158
159 }
160
161
162 auto points_beyond_left() const
163 {
164
165 return this->points_beyond_left(this->first().x);
166
167 }
168
169
170 auto points_beyond_top() const
171 {
172
173 return this->points_beyond_top(this->first().y);
174
175 }
176
177
178 auto points_beyond_bottom() const
179 {
180
181 return this->points_beyond_bottom(this->first().y);
182
183 }
184
185
186};
187
188
189
190
191
192template < prototype_number NUMBER >
193void point_array_base < NUMBER >::offset(UNIT_TYPE x, UNIT_TYPE y)
194{
195 for (::i32 i = 0; i < this->get_size(); i++)
196 {
197 this->element_at(i).x += x;
198 this->element_at(i).y += y;
199 }
200}
201
202
203template < prototype_number NUMBER >
204void point_array_base < NUMBER >::rotate(::f64 dAngle)
205{
206
207 UNIT_TYPE x;
208 UNIT_TYPE y;
209 ::f64 dCos = ::cos(dAngle);
210 ::f64 dSin = ::sin(dAngle);
211
212 for (::i32 i = 0; i < this->get_count(); i++)
213 {
214 x = this->element_at(i).x;
215 y = this->element_at(i).y;
216 this->element_at(i).x = (::i32)(x * dCos - y * dSin);
217 this->element_at(i).y = (::i32)(x * dSin + y * dCos);
218 }
219
220}
221
222
223
224
225//
226//template < typename POINT_TYPE >
227//void point_array_base < POINT_TYPE >::get_bounding_box(RECTANGLE_BASE_TYPE & rectangle) const
228//{
229//
230// ::get_bounding_box(rectangle, this->get_data(), this->get_count());
231//
232//}
233
234
235
236template < prototype_number NUMBER >
237void point_array_base < NUMBER >::rotate(::f64 dAngle, ::point_type < NUMBER > pointCenter)
238{
239
240 UNIT_TYPE x;
241 UNIT_TYPE y;
242 ::f64 dCos = cos(dAngle);
243 ::f64 dSin = sin(dAngle);
244
245 for (::i32 i = 0; i < this->get_count(); i++)
246 {
247 this->element_at(i) -= pointCenter;
248 x = this->element_at(i).x;
249 y = this->element_at(i).y;
250 this->element_at(i).x = (::i32)(x * dCos - y * dSin);
251 this->element_at(i).y = (::i32)(x * dSin + y * dCos);
252 this->element_at(i) += pointCenter;
253 }
254
255}
256
257
258//template < typename POINT_TYPE >
259//::xml::input_tree & operator >> (::xml::input_tree & xmlif, point_array_base < POINT_TYPE > & pointa);
260//
261//template < typename POINT_TYPE >
262//::xml::output_tree & operator << (::xml::output_tree & xmlof, point_array_base < POINT_TYPE > & pointa);
263
264/*
265http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
266https://stackoverflow.com/questions/217578/how-can-i-determine-whether-a-2d-i32_point-is-within-a-i32_polygon
267::i32 pnpoly(::i32 nvert, ::f32 * vertx, ::f32 * verty, ::f32 testx, ::f32 testy)
268{
269 ::i32 i, j, c = 0;
270 for (i = 0, j = nvert - 1; i < nvert; j = i++) {
271 if (((verty[i] > testy) != (verty[j] > testy)) &&
272 (testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i]))
273 c = !c;
274 }
275 return c;
276}
277*/
278//template < typename POINT_TYPE >
279//bool polygon_contains_point(const POINT_TYPE * ppointa, ::collection::count c, const POINT_TYPE & point)
280//{
281// ::i32 i, j, c = 0;
282// for (i = 0, j = nvert - 1; i < nvert; j = i++)
283// {
284// if (((ppointa[i].y > point.y) != (ppointa[j].y > point.y)) &&
285// (point.x < (ppointa[j].x - ppointa[i].x) * (point.y - ppointa[i].y) / (ppointa[j].y - ppointa[i].y) + ppointa[i].x))
286// c = !c;
287// }
288// return c;
289//}
290
291template < prototype_number NUMBER >
292bool point_array_base < NUMBER >::polygon_contains_winding(const ::point_type < NUMBER > & point) const
293{
294
295 return ::polygon_contains_winding( this->data(), (::i32)this->size(), point);
296
297}
298
299
300template < prototype_number NUMBER >
301bool point_array_base < NUMBER >::polygon_contains_alternate(const ::point_type < NUMBER > & point) const
302{
303
304 return ::polygon_contains_alternate(this->data(), (::i32)this->size(), point, true);
305
306}
307
308
309template < prototype_number NUMBER >
310::collection::count point_array_base < NUMBER >::add_unique_range(const ::point_type < NUMBER > & pointBeg, const ::point_type < NUMBER > & pointEnd, const ::size_type < NUMBER > & size)
311{
312
313 auto x1 = pointBeg.x;
314
315 auto x2 = pointEnd.x;
316
317 auto y1 = pointBeg.y;
318
319 auto y2 = pointEnd.y;
320
321 __sort(x1, x2);
322
323 __sort(y1, y2);
324
325 ::collection::count c = 0;
326
327 for (auto x = x1; x <= x2; x += size.cx)
328 {
329
330 for (auto y = y1; y <= y2; y += size.cy)
331 {
332
333 if (this->add_unique(POINT_TYPE(x, y)))
334 {
335
336 c++;
337
338 }
339
340 }
341
342 }
343
344 return c;
345
346}
347
348
349template < prototype_number NUMBER >
350void point_array_base < NUMBER >::expand_bounding_box(::point_type < UNIT_TYPE > & top_left, ::point_type < UNIT_TYPE > & bottom_right) const
351{
352
353 ::point_type < NUMBER > ::expand_bounding_box(top_left, bottom_right, this->data(), this->size());
354
355}
356
357
358template < prototype_number NUMBER >
359bool point_array_base < NUMBER >::get_bounding_box(::point_type < UNIT_TYPE > & top_left, ::point_type < UNIT_TYPE > & bottom_right) const
360{
361
362 if(this->is_empty())
363 {
364
365 return false;
366
367 }
368
369 top_left = this->first();
370
371 bottom_right = this->first();
372
373 this->expand_bounding_box(top_left, bottom_right, this->element_at[1], this->count() - 1);
374
375 return true;
376
377}
378
379
380
381
382
383
384
385
386
387
388
389
390
Definition point_array.h:25
inline ::collection::index tolerance_add_unique(UNIT_TYPE tolerance, const ::point_type< NUMBER > &pointAdd)
Definition point_array.h:67