API Documentation
Loading...
Searching...
No Matches
Polygon.hpp
Go to the documentation of this file.
1/**--------------------------------------------------------------------------------------------
2Copyright (c) 2019, NDEVR LLC
3tyler.parke@ndevr.org
4 __ __ ____ _____ __ __ _______
5 | \ | | | __ \ | ___|\ \ / / | __ \
6 | \ | | | | \ \ | |___ \ \ / / | |__) |
7 | . \| | | |__/ / | |___ \ V / | _ /
8 | |\ |_|_____/__|_____|___\_/____| | \ \
9 |__| \__________________________________| \__\
10
11Subject to the terms of the Enterprise+ Agreement, NDEVR hereby grants
12Licensee a limited, non-exclusive, non-transferable, royalty-free license
13(without the right to sublicense) to use the API solely for the purpose of
14Licensee's internal development efforts to develop applications for which
15the API was provided.
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
21INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
22PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
23FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25DEALINGS IN THE SOFTWARE.
26
27Library: Base
28File: Polygon
29Included in API: True
30Author(s): Tyler Parke
31 *-----------------------------------------------------------------------------------------**/
32#pragma once
33#include <NDEVR/BaseValues.h>
34#include <NDEVR/MatrixFunctions.h>
35#include <NDEVR/Buffer.h>
36#include <NDEVR/Vertex.h>
37#include <NDEVR/Bounds.h>
38#include <NDEVR/LineSegment.h>
39#include <NDEVR/Plane.h>
40/**--------------------------------------------------------------------------------------------------
41Namespace: Parke
42Namespace that wraps all Logic created by Tyler Parke
43 *-----------------------------------------------------------------------------------------------**/
44
45namespace NDEVR
46{
47 /**--------------------------------------------------------------------------------------------------
48 Class: Polygon
49
50 \brief An N-sided polygon.
51
52 Author: Tyler Parke
53
54 Date: 2017-11-19
55 *-----------------------------------------------------------------------------------------------**/
56 template<class t_type, class t_vertex = Vertex<2, t_type>>
57 class Polygon
58 {
59 public:
61 : m_vertices()
62 , m_cache_bounds(Constant<Bounds<2, t_type, t_vertex>>::NaN)
63 , m_cache_length(Constant<t_type>::NaN)
64 , m_is_inside_cached(false)
65 , m_is_convex_cached(false)
66 , m_is_convex(false)
67 , m_polygon_plane(Vector<3, t_type>(0, 0, 1), 0)
68 {}
69 Polygon(const Polygon& polygon)
70 : m_vertices(polygon.m_vertices)
71 , m_cache_bounds(polygon.m_cache_bounds)
72 , m_cache_length(polygon.m_cache_length)
73 , m_cache_constant(polygon.m_cache_constant)
74 , m_cache_multiple(polygon.m_cache_multiple)
75 , m_is_inside_cached(polygon.m_is_inside_cached)
76 , m_is_convex_cached(polygon.m_is_convex_cached)
77 , m_is_convex(polygon.m_is_convex)
78 , m_polygon_plane(polygon.m_polygon_plane)
79 {}
80 Polygon(Polygon&& polygon) noexcept
81 : m_cache_bounds(polygon.m_cache_bounds)
82 , m_cache_length(polygon.m_cache_length)
83 , m_is_inside_cached(polygon.m_is_inside_cached)
84 , m_is_convex_cached(polygon.m_is_convex_cached)
85 , m_is_convex(polygon.m_is_convex)
86 , m_polygon_plane(polygon.m_polygon_plane)
87 {
88 std::swap(m_vertices, polygon.m_vertices);
89 std::swap(m_cache_multiple, polygon.m_cache_multiple);
90 std::swap(m_cache_constant, polygon.m_cache_constant);
91 }
93 : m_vertices(vertices)
94 , m_cache_bounds(Constant<Bounds<2, t_type, t_vertex>>::NaN)
95 , m_cache_length(Constant<t_type>::NaN)
96 , m_is_inside_cached(false)
97 , m_is_convex_cached(false)
98 , m_is_convex(false)
99 , m_polygon_plane(Vector<3, t_type>(0, 0, 1), 0)
100 {}
101 explicit Polygon(const Buffer<Vertex<3, fltp08>>& points)
102 : m_cache_bounds(Constant<Bounds<2, t_type, t_vertex>>::NaN)
103 , m_cache_length(Constant<t_type>::NaN)
104 , m_is_inside_cached(false)
105 , m_is_convex_cached(false)
106 , m_is_convex(false)
107 , m_polygon_plane(Plane<3, fltp08>::CreateBestFitPlane(points))
108 {
109 Matrix<fltp08> plane_transform = m_polygon_plane.projectionMatrix();
110 for (uint04 n = 0; n < points.size(); n++)
111 {
112 add(t_vertex(plane_transform * points[n]).template as<2, t_type>());
113 }
114 }
115 explicit Polygon(uint04 allocated_size)
116 : m_vertices(allocated_size)
117 , m_cache_bounds(Constant<Bounds<2, t_type, t_vertex>>::NaN)
118 , m_cache_length(Constant<t_type>::NaN)
119 , m_is_inside_cached(false)
120 , m_is_convex_cached(false)
121 , m_is_convex(false)
122 , m_polygon_plane(Vector<3, t_type>(0, 0, 1), 0)
123 {}
124
125 /**--------------------------------------------------------------------------------------------------
126 Fn: Bounds<2, t_type> Polygon::bounds() const
127
128 Gets the bounds.
129
130 Author: Tyler Parke
131
132 Date: 2017-11-19
133
134 Returns: A Bounds&lt;2,t_type&gt;
135 *-----------------------------------------------------------------------------------------------**/
137 {
138 if (isNaN(m_cache_bounds))
139 {
140 m_cache_bounds = Constant<Bounds<2, t_type, t_vertex>>::Min;
141 for (uint04 i = 0; i < m_vertices.size(); i++)
142 {
143 m_cache_bounds.addToBounds(m_vertices[i]);
144 }
145 }
146 return m_cache_bounds;
147 }
148
149
150 /**--------------------------------------------------------------------------------------------------
151 Fn: const t_vertex& Polygon::vertex(uint04 index) const
152
153 Vertices the given index.
154
155 Author: Tyler Parke
156
157 Date: 2017-11-19
158
159 Parameters:
160 index - Zero-based index of the.
161
162 Returns: A reference to a const t_vertex.
163 *-----------------------------------------------------------------------------------------------**/
164
165 const t_vertex& vertex(uint04 index) const
166 {
167 return m_vertices[index];
168 }
169
170 /**--------------------------------------------------------------------------------------------------
171 Fn: LineSegment<2, t_type, t_vertex> Polygon::edge(uint04 index) const
172
173 Edges the given index.
174
175 Author: Tyler Parke
176
177 Date: 2017-11-19
178
179 Parameters:
180 index - Zero-based index of the.
181
182 Returns: A LineSegment&lt;2,t_type,t_vertex&gt;
183 *-----------------------------------------------------------------------------------------------**/
184
186 {
187 return LineSegment<2, t_type, t_vertex>(vertex(index), vertex((index + 1) % m_vertices.size()));
188 }
189
190 /**--------------------------------------------------------------------------------------------------
191 Fn: inline const Buffer<t_vertex>& Polygon::vertices() const
192
193 Gets the vertices.
194
195 Author: Tyler Parke
196
197 Date: 2017-11-19
198
199 Returns: A reference to a const Buffer&lt;t_vertex&gt;
200 *-----------------------------------------------------------------------------------------------**/
201
202 inline const Buffer<t_vertex>& vertices() const
203 {
204 return m_vertices;
205 }
206
207 /**--------------------------------------------------------------------------------------------------
208 Fn: inline uint04 Polygon::visibleVertexCount() const
209
210 Vertex count.
211
212 Author: Tyler Parke
213
214 Date: 2017-11-19
215
216 Returns: An uint04.
217 *-----------------------------------------------------------------------------------------------**/
218
219 inline uint04 vertexCount() const
220 {
221 return m_vertices.size();
222 }
223
224 /**--------------------------------------------------------------------------------------------------
225 Fn: inline uint04 Polygon::edgeCount() const
226
227 Edge count.
228
229 Author: Tyler Parke
230
231 Date: 2017-11-19
232
233 Returns: An uint04.
234 *-----------------------------------------------------------------------------------------------**/
235
236 inline uint04 edgeCount() const
237 {
238 return m_vertices.size();
239 }
240 bool isConvex() const
241 {
242 if (!m_is_convex_cached)
243 {
244 if (edgeCount() < 3)
245 {
246 m_is_convex = false;
247 }
248 else if (edgeCount() == 3)
249 {
250 m_is_convex = true;
251 }
252 else
253 {
254 m_is_convex = true;
255 t_type last_cross_prod = 0;
256 const uint04 vert_count = vertexCount();
257 for (uint04 i = 0; i < vert_count; i++)
258 {
259 const Vector<2, t_type> d1 = vertex((i + 1) % vert_count) - vertex((i + 0) % vert_count);
260 const Vector<2, t_type> d2 = vertex((i + 2) % vert_count) - vertex((i + 1) % vert_count);
261 const t_type cross_prod = d1[X] * d2[Y] - d1[Y] * d2[X];
262 if (cross_prod != cast<t_type>(0))
263 {
264 if ((last_cross_prod > cast<t_type>(0) && cross_prod < cast<t_type>(0))
265 || (last_cross_prod < cast<t_type>(0) && cross_prod > cast<t_type>(0)))
266 {
267 m_is_convex = false;
268 break;
269 }
270 last_cross_prod = cross_prod;
271 }
272 }
273 }
274 m_is_convex_cached = true;
275 }
276 return m_is_convex;
277 }
278 /**--------------------------------------------------------------------------------------------------
279 Fn: inline void Polygon::setVertices(const Buffer<t_vertex>& vertices)
280
281 Sets the vertices.
282
283 Author: Tyler Parke
284
285 Date: 2017-11-19
286
287 Parameters:
288 vertices - The vertices.
289 *-----------------------------------------------------------------------------------------------**/
290
292 {
293 updateVertices(vertices);
294 }
295 inline void addVertices(const t_vertex* vertices, uint04 size)
296 {
297 m_vertices.addAll(vertices, size);
298 invalidateCache();
299 }
300
301 /**--------------------------------------------------------------------------------------------------
302 Fn: void Polygon::add(const t_vertex& vertex)
303
304 Adds vertex.
305
306 Author: Tyler Parke
307
308 Date: 2017-11-19
309
310 Parameters:
311 vertex - The vertex to add.
312 *-----------------------------------------------------------------------------------------------**/
313
314 void add(const t_vertex& vertex)
315 {
316 m_vertices.add(vertex);
317 invalidateCache();
318 }
319
320 /**--------------------------------------------------------------------------------------------------
321 Fn: void Polygon::insert(uint04 index, const t_vertex& vertex)
322
323 Inserts.
324
325 Author: Tyler Parke
326
327 Date: 2017-11-19
328
329 Parameters:
330 index - Zero-based index of the.
331 vertex - The vertex.
332 *-----------------------------------------------------------------------------------------------**/
333
334 void insert(uint04 index, const t_vertex& vertex)
335 {
336 m_vertices.insert(index, vertex);
337 invalidateCache();
338 }
339
340 /**--------------------------------------------------------------------------------------------------
341 Fn: void Polygon::replace(uint04 index, const t_vertex& vector)
342
343 Replaces.
344
345 Author: Tyler Parke
346
347 Date: 2017-11-19
348
349 Parameters:
350 index - Zero-based index of the.
351 vector - The vector.
352 *-----------------------------------------------------------------------------------------------**/
353
354 void replace(uint04 index, const t_vertex& vector)
355 {
356 if (m_vertices[index] != vector)
357 {
358 m_vertices[index] = vector;
359 invalidateCache();
360 }
361 }
362
363 /**--------------------------------------------------------------------------------------------------
364 Fn: void Polygon::simplify()
365
366 Removes all duplicate adjacent vertices.
367
368 Author: Tyler Parke
369
370 Date: 2017-05-16
371
372 Parameters:
373 index - The index to removeRows.
374 *-----------------------------------------------------------------------------------------------**/
375 void simplify()
376 {
377 if (vertexCount() <= 1)
378 return;
379 for (uint04 i = 0; i < vertexCount() - 1; i++)
380 {
381 if (vertex(i).template as<2, t_type>() == vertex(i + 1).template as<2, t_type>())
382 {
383 remove(i + 1);
384 i--;
385 }
386 else if (i > 0 && edge(i).template isParallel<t_type>(edge(i - 1), cast<t_type>(0.00001)))
387 {
388 remove(i);
389 i--;
390 }
391 }
392 while (vertexCount() > 0 && vertex(vertexCount() - 1).template as<2, t_type>() == vertex(0).template as<2, t_type>())
393 {
394 remove(vertexCount() - 1);
395 }
396 while (vertexCount() > 2 && edge(edgeCount() - 1).template isParallel<t_type>(edge(0), cast<t_type>(0.00001)))
397 {
398 remove(0);
399 }
400 }
401 void flip()
402 {
403 uint04 iMax = vertexCount() / 2;
404
405 if (vertexCount() % 2 != 0)
406 iMax += 1;
407
408 for (uint04 i = 1; i < iMax; ++i)
409 std::swap(m_vertices[i], m_vertices[vertexCount() - i]);
410 invalidateCache();
411 }
412 /**--------------------------------------------------------------------------------------------------
413 Fn: void Polygon::removeRows(uint04 index)
414
415 Removes the given index.
416
417 Author: Tyler Parke
418
419 Date: 2017-11-19
420
421 Parameters:
422 index - The index to removeRows.
423 *-----------------------------------------------------------------------------------------------**/
424
425 void remove(uint04 index)
426 {
427 m_vertices.removeIndex(index);
428 invalidateCache();
429 }
430
431 /**--------------------------------------------------------------------------------------------------
432 Fn: void Polygon::clear()
433
434 Clears this object to its blank/initial state.
435
436 Author: Tyler Parke
437
438 Date: 2017-11-19
439 *-----------------------------------------------------------------------------------------------**/
440
441 void clear()
442 {
443 m_vertices.clear();
444 invalidateCache();
445 }
446
447 /**--------------------------------------------------------------------------------------------------
448 Fn: Polygon<t_new_type, t_new_vertex_type> Polygon::as() const
449
450 Gets as.
451
452 Author: Tyler Parke
453
454 Date: 2017-11-19
455
456 Returns: A Polygon&lt;t_new_type,t_new_vertex_type&gt;
457 *-----------------------------------------------------------------------------------------------**/
458 template<class t_new_type, class t_new_vertex_type = Vertex<2, t_new_type>>
460 {
462 for(uint04 i = 0; i < vertexCount(); i++)
463 {
464 poly.add(t_new_vertex_type(vertex(i).template as<2, t_new_type>()));
465 }
466 return poly;
467 }
468
469 /**--------------------------------------------------------------------------------------------------
470 Fn: t_type Polygon::perimeter() const
471
472 Gets the perimeter.
473
474 Author: Tyler Parke
475
476 Date: 2017-11-19
477
478 Returns: A t_type.
479 *-----------------------------------------------------------------------------------------------**/
480
481 t_type perimeter() const
482 {
483 if(isNaN(m_cache_length))
484 {
485 if(vertexCount() > 0)
486 {
487 m_cache_length = cast<t_type>(0);
488 }
489 if (vertexCount() > 1)
490 {
491 for (uint04 i = 0; i < edgeCount(); i++)
492 {
493 m_cache_length += edge(i).template length<t_type>();
494 }
495 }
496 }
497 return m_cache_length;
498 }
499
500 /**--------------------------------------------------------------------------------------------------
501 Fn: bool Polygon::contains(const t_vertex& vector) const
502
503 Query if this object contains the given vector.
504
505 Author: Tyler Parke
506
507 Date: 2017-11-19
508
509 Parameters:
510 vector - The const t_vertex&amp; to test for containment.
511
512 Returns: True if the object is in this collection, false if not.
513 *-----------------------------------------------------------------------------------------------**/
514
515 bool contains(const Vertex<2, t_type>& vector) const
516 {
517 if (!bounds().template as<2, t_type>().contains(vector))
518 return false;
519 cacheBoundaryCheck();
520 uint04 last = vertexCount() - 1;
521 bool odd_vertices = false;
522 for (uint04 current = 0; current < vertexCount(); ++current)
523 {
524 if ((m_vertices[current][Y] < vector[Y] && m_vertices[last][Y] >= vector[Y])
525 || (m_vertices[last][Y] < vector[Y] && m_vertices[current][Y] >= vector[Y]))
526 {
527 odd_vertices ^= ((vector[Y] * m_cache_multiple[current] + m_cache_constant[current]) < vector[X]);
528 }
529 last = current;
530 }
531 return odd_vertices;
532 }
533
534 template<class t_precision>
536 {
537 if (m_vertices.size() <= 2)
538 return outside;
539 if (!bounds().intersects(line))
540 return outside;
541 bool is_inside = contains(line.vertex(A));
542 if (contains(line.vertex(B)) != is_inside)
543 return mixed;
544
545 for (uint04 i = 0; i < edgeCount(); i++)
546 {
547 LineSegment<2, t_type, t_vertex> current_edge = edge(i);
548 if (current_edge.template intersects<t_precision>(line))
549 return mixed;
550 }
551 return is_inside ? inside : outside;
552 }
553
554 /**--------------------------------------------------------------------------------------------------
555 Fn: IntersectionTypes Polygon::contains(const Bounds<2, t_type, t_vertex>& bounds) const
556
557 Determines if this collection contains a given object.
558
559 Author: Tyler Parke
560
561 Date: 2017-11-19
562
563 Parameters:
564 bounds - The const Bounds&lt;2,t_type,t_vertex&gt;&amp; to test for containment.
565
566 Returns: The IntersectionTypes.
567 *-----------------------------------------------------------------------------------------------**/
568 template<class t_precision>
570 {
571 if(vertexCount() <= 2)
572 return outside;
573 if (!bounds().intersects(o_bounds))
574 return outside;
575 const t_vertex v1(o_bounds[MIN][X], o_bounds[MIN][Y]);
576 const t_vertex v2(o_bounds[MAX][X], o_bounds[MIN][Y]);
577 const t_vertex v3(o_bounds[MAX][X], o_bounds[MAX][Y]);
578 const t_vertex v4(o_bounds[MIN][X], o_bounds[MAX][Y]);
579
580 const bool is_inside = contains(v1);
581 if(contains(v2) != is_inside) return mixed;
582 if(contains(v3) != is_inside) return mixed;
583 if(contains(v4) != is_inside) return mixed;
584 // If all of the bounding points are outside, we need only prove that a single polygon vertex is
585 // inside (Which is cheap)
586 if(!is_inside) for (uint04 i = 0; i < edgeCount(); i++)
587 {
588 if (o_bounds.contains(vertex(i)))
589 return mixed;
590 }
591 for(uint04 i = 0; i < edgeCount(); i++)
592 {
593 const LineSegment<2, t_type, t_vertex> current_edge = edge(i);
594 if(current_edge.template intersects<t_precision>(LineSegment<2, t_type>(v1, v2))) return mixed;
595 if(current_edge.template intersects<t_precision>(LineSegment<2, t_type>(v2, v3))) return mixed;
596 if(current_edge.template intersects<t_precision>(LineSegment<2, t_type>(v3, v4))) return mixed;
597 if(current_edge.template intersects<t_precision>(LineSegment<2, t_type>(v4, v1))) return mixed;
598 }
599 return is_inside ? inside : outside;
600 }
601
602 decltype(auto) begin()
603 {
604 return m_vertices.begin();
605 }
606 decltype(auto) begin() const
607 {
608 return m_vertices.begin();
609 }
610
611 decltype(auto) begin(uint04 index) const
612 {
613 return m_vertices.begin(index);
614 }
615 decltype(auto) begin(uint04 index)
616 {
617 return m_vertices.begin(index);
618 }
619
620 decltype(auto) end()
621 {
622 return m_vertices.end();
623 }
624 decltype(auto) end() const
625 {
626 return m_vertices.end();
627 }
628
629
630 /**--------------------------------------------------------------------------------------------------
631 Fn: IntersectionTypes Polygon::contains(const Triangle<2, t_type, t_vertex>& tri) const
632
633 Determines if this collection contains a given object.
634
635 Author: Tyler Parke
636
637 Date: 2017-11-19
638
639 Parameters:
640 tri - The const Triangle&lt;2,t_type,t_vertex&gt;&amp; to test for containment.
641
642 Returns: The IntersectionTypes.
643 *-----------------------------------------------------------------------------------------------**/
644 template<class t_precision>
646 {
647 //Check each vertex, if some are inside, or some are outside, we know we are mixed
648 if(m_vertices.size() <= 2)
649 return outside;
650 //if (!bounds().intersects(tri))
651 //return outside;
652 bool is_inside = contains(tri.vertex(A));
653 if(contains(tri.vertex(B)) != is_inside) return mixed;
654 if(contains(tri.vertex(C)) != is_inside) return mixed;
655
656 // If all of the triangles points are outside, we need only prove that a single polygon vertex is
657 // inside (Which is cheap)
658 if (!is_inside) for (uint04 i = 0; i < edgeCount(); i++)
659 {
660 if (tri.contains(vertex(i)))
661 return mixed;
662 }
663 for (uint04 i = 0; i < edgeCount(); i++)
664 {
665 const LineSegment<2, t_type, t_vertex> current_edge = edge(i);
666 if(current_edge.template intersects<t_precision>(tri.edge(A, B))) return mixed;
667 if(current_edge.template intersects<t_precision>(tri.edge(B, C))) return mixed;
668 if(current_edge.template intersects<t_precision>(tri.edge(C, A))) return mixed;
669 }
670 return is_inside ? inside : outside;
671 }
672
673 template<class t_precision, class t_other_vertex>
675 {
676 if (m_vertices.size() <= 2 || poly.edgeCount() == 0)
677 return outside;
678 if (!bounds().intersects(poly.bounds()))
679 return outside;
680
682 if (type == mixed || (type == outside && poly.contains(vertex(0))))
683 return mixed;
684 for (uint04 i = 1; i < poly.edgeCount(); i++)
685 {
686 if (type != contains<t_precision>(poly.edge(i)))
687 return mixed;
688 }
689
690 return type;
691 }
692
693 Polygon clip(const Bounds<t_vertex::NumberOfDimensions(), t_type>& bounds) const
694 {
695 if (bounds.template as<2, t_type>().template contains<true>(this->bounds().template as<2, t_type>()))
696 return *this;
697 if (!bounds.template as<2, t_type>().intersects(this->bounds()))
698 return Polygon();
699 Polygon polygon(vertexCount());
700 for (uint04 ii = 0; ii < vertexCount() - 1; ++ii)
701 {
702 LineSegment<t_vertex::NumberOfDimensions(), t_type> line(vertex(ii), vertex(ii + 1));
703 line = intersection(bounds, line);
704 if (!isNaN(line))
705 {
706 if (polygon.vertexCount() == 0 || polygon.vertex(polygon.vertexCount() - 1) != polygon.vertex(A))
707 polygon.add(line.vertex(A));
708 polygon.add(line.vertex(B));
709 }
710 }
711 LineSegment<t_vertex::NumberOfDimensions(), t_type> line(vertex(vertexCount() - 1), vertex(0));
712 if (!isNaN(line))
713 {
714 line = intersection(bounds, line);
715 if (!isNaN(line))
716 {
717 if (polygon.vertexCount() == 0 || polygon.vertex(polygon.vertexCount() - 1) != polygon.vertex(A))
718 polygon.add(line.vertex(A));
719 polygon.add(line.vertex(B));
720 }
721 }
722
723 polygon.simplify();
724 return polygon;
725 }
726
728 {
729 return m_polygon_plane;
730 }
732 {
733 m_polygon_plane = plane;
734 }
736 {
737 t_type sum = 0;
738 for (uint04 i = 0; i < edgeCount(); i++)
739 {
740 auto side = edge(i);
741 sum += (side[B][X] - side[A][X]) * (side[B][Y] + side[A][Y]);
742 }
743 return sum > 0.0;//this is also half surface area
744 }
745 /**--------------------------------------------------------------------------------------------------
746 Fn: bool Polygon::operator==(const Polygon& polygon) const
747
748 Equality operator.
749
750 Author: Tyler Parke
751
752 Date: 2017-11-19
753
754 Parameters:
755 polygon - The polygon.
756
757 Returns: True if the parameters are considered equivalent.
758 *-----------------------------------------------------------------------------------------------**/
759
760 bool operator==(const Polygon& polygon) const
761 {
762 return m_vertices == polygon.m_vertices && m_polygon_plane == polygon.m_polygon_plane;
763 }
764 bool operator!=(const Polygon& polygon) const
765 {
766 return m_vertices != polygon.m_vertices || m_polygon_plane != polygon.m_polygon_plane;
767 }
768 bool isEquivalent(const Polygon& polygon, fltp08 epsilon)
769 {
770 if (bounds().template as<2, fltp08>() != polygon.bounds().template as<2, fltp08>())
771 return false;
772 if (abs(perimeter() - polygon.perimeter()) > epsilon)
773 return false;
774 for (uint04 i = 0; i < polygon.edgeCount(); i++)
775 {
776 bool found = false;
777 for (uint04 n = 0; n < edgeCount(); n++)
778 {
779 if (edge(n).template as<2, fltp08>().template isCollinear<fltp08>(polygon.edge(i).template as<2, fltp08>(), epsilon))
780 {
781 found = true;
782 break;
783 }
784 }
785 if (!found)
786 return false;
787 }
788 return true;
789 }
790 Polygon opheimSimplification(t_type min_tol, t_type max_tol) const
791 {
792
793 uint04 count = vertexCount();
794 t_type min_tol2 = min_tol * min_tol; // squared minimum distance tolerance
795 t_type max_tol2 = max_tol * max_tol; // squared maximum distance tolerance
796
797 // validate input and check if simplification required
798 if (count < 3 || min_tol2 == 0 || max_tol2 == 0)
799 return *this;
800 // define the ray R(r0, r1)
801 uint04 r0 = 0; // indicates the current key and start of the ray
802 uint04 r1 = 0; // indicates a point on the ray
803 bool rayDefined = false;
804
805 // keep track of two test points
806 uint04 pi = r0; // the previous test point
807 uint04 pj = pi;
808
809 Polygon poly;
810 poly.add(vertex(r0));
811 for (uint04 j = 1; j < count; ++j)
812 {
813 pi = pj++;
814
815 t_type dist_squared = distanceSquared(vertex(r0), vertex(pj));
816 if (!rayDefined) {
817 // discard each point within minimum tolerance
818 if (dist_squared < min_tol2)
819 continue;
820 // the last point within minimum tolerance pi defines the ray R(r0, r1)
821 r1 = pi;
822 rayDefined = true;
823 }
824
825 // check each point pj against R(r0, r1)
826 if (dist_squared < max_tol2)
827 {
828 t_vertex v = vertex(r1) - vertex(r0); // vector r1 --> r2
829 t_vertex w = vertex(pj) - vertex(r0); // vector r1 --> p
830
831 t_type cv = dot(v, v); // squared length of v
832 t_type cw = dot(w, v); // project w onto v
833
834 if (cw <= 0)
835 {
836 // projection of w lies to the left of r1 (not on the ray)
837 if (distanceSquared(vertex(pj), vertex(r0)) < min_tol2)
838 continue;
839 }
840 else
841 {
842 // avoid problems with divisions when value_type is an integer type
843 t_type fraction = cv == 0 ? 0 : cw /cv;
844
845
846 t_vertex proj = vertex(r0) + (fraction * (vertex(r1) - vertex(r0)));
847
848 if (distanceSquared(vertex(pj), proj) < min_tol2)
849 continue;
850 }
851 }
852 poly.add(vertex(pi));
853 r0 = pi;
854 rayDefined = false;
855 }
856 return poly;
857 }
859 {
860 m_vertices = poly.m_vertices;
861 m_cache_bounds = poly.m_cache_bounds;
862 m_cache_length = poly.m_cache_length;
863 m_cache_constant = poly.m_cache_constant;
864 m_cache_multiple = poly.m_cache_multiple;
865 m_is_inside_cached = poly.m_is_inside_cached;
866 return *this;
867 }
869 {
870 std::swap(m_vertices, poly.m_vertices);
871 m_cache_bounds = poly.m_cache_bounds;
872 m_cache_length = poly.m_cache_length;
873 m_cache_constant = poly.m_cache_constant;
874 m_cache_multiple = poly.m_cache_multiple;
875 m_is_inside_cached = poly.m_is_inside_cached;
876 return *this;
877 }
878 bool validate() const
879 {
880 for (uint04 i = 0; i < edgeCount(); i++)
881 {
882 auto seg_to_check = edge(i);
883 for (uint04 n = i + 2; n < edgeCount(); n++)
884 {
885 if (n == i || (n == edgeCount() - 1 && i == 0))
886 continue;
887 auto seg = edge(n);
888 if (!isNaN(seg_to_check.template intersection<fltp08>(seg, 0.000000001)))
889 {
890 lib_assert(false, "Bad polygon");
891 return false;
892 }
893 }
894 }
895 return true;
896 }
897 private:
898
899 /**--------------------------------------------------------------------------------------------------
900 Fn: inline void Polygon::invalidateCache() const
901
902 Invalidate cache.
903
904 Author: Tyler Parke
905
906 Date: 2017-11-19
907 *-----------------------------------------------------------------------------------------------**/
908
909 inline void invalidateCache() const
910 {
911 m_cache_length = Constant<t_type>::NaN;
912 m_is_inside_cached = false;
913 m_is_convex_cached = false;
914 m_cache_constant.clear();
915 m_cache_multiple.clear();
916 m_cache_bounds = Constant<Bounds<2, t_type, t_vertex>>::NaN;
917 }
918
919 /**--------------------------------------------------------------------------------------------------
920 Fn: void Polygon::updateVertices(const Buffer<t_vertex>& vertices)
921
922 Updates the vertices described by the given vertices.
923
924 Author: Tyler Parke
925
926 Date: 2017-11-19
927
928 Parameters:
929 vertices - The vertices.
930 *-----------------------------------------------------------------------------------------------**/
931
932 void updateVertices(const Buffer<t_vertex>& vertices)
933 {
934 m_vertices = vertices;
935 invalidateCache();
936 }
937
938 /**--------------------------------------------------------------------------------------------------
939 Fn: void Polygon::cacheBoundaryCheck() const
940
941 Cache boundary check.
942
943 Author: Tyler Parke
944
945 Date: 2017-11-19
946 *-----------------------------------------------------------------------------------------------**/
947
948 void cacheBoundaryCheck() const
949 {
950 if(m_is_inside_cached)
951 return;
952 m_cache_constant.setSize(m_vertices.size());
953 m_cache_multiple.setSize(m_vertices.size());
954 uint04 jj = m_vertices.size() - 1;
955 for(uint04 ii = 0; ii < m_vertices.size(); ++ii)
956 {
957 if(m_vertices[jj][Y] == m_vertices[ii][Y])
958 {
959 m_cache_constant[ii] = cast<fltp08>(m_vertices[ii][X]);
960 m_cache_multiple[ii] = 0;
961 }
962 else
963 {
964 m_cache_constant[ii] = m_vertices[ii][X]
965 - cast<fltp08>(m_vertices[ii][Y] * m_vertices[jj][X])
966 / cast<fltp08>(m_vertices[jj][Y] - m_vertices[ii][Y])
967 + cast<fltp08>(m_vertices[ii][Y] * m_vertices[ii][X])
968 / cast<fltp08>(m_vertices[jj][Y] - m_vertices[ii][Y]);
969 m_cache_multiple[ii] = cast<fltp08>(m_vertices[jj][X] - m_vertices[ii][X])
970 / cast<fltp08>(m_vertices[jj][Y] - m_vertices[ii][Y]);
971 }
972 jj = ii;
973 }
974 m_is_inside_cached = true;
975 }
976
977 private:
978 /** The vertices. */
979 Buffer<t_vertex> m_vertices;
980
981 /**--------------------------------------------------------------------------------------------------
982 Property: mutable Bounds<2, t_type> m_cache_bounds
983
984 Gets the cache bounds.
985
986 Returns: The m cache bounds.
987 *-----------------------------------------------------------------------------------------------**/
988
989 mutable Bounds<2, t_type, t_vertex> m_cache_bounds;
990
991 /**--------------------------------------------------------------------------------------------------
992 Property: mutable t_type m_cache_length
993
994 Gets the length of the cache.
995
996 Returns: The length of the cache.
997 *-----------------------------------------------------------------------------------------------**/
998
999 mutable t_type m_cache_length;
1000
1001 /**--------------------------------------------------------------------------------------------------
1002 Property: mutable Buffer<fltp08> m_cache_constant
1003
1004 Gets the cache constant.
1005
1006 Returns: The m cache constant.
1007 *-----------------------------------------------------------------------------------------------**/
1008
1009 mutable Buffer<fltp08> m_cache_constant;
1010
1011 /**--------------------------------------------------------------------------------------------------
1012 Property: mutable Buffer<fltp08> m_cache_multiple
1013
1014 Gets the cache multiple.
1015
1016 Returns: The m cache multiple.
1017 *-----------------------------------------------------------------------------------------------**/
1018
1019 mutable Buffer<fltp08> m_cache_multiple;
1020
1021 /**--------------------------------------------------------------------------------------------------
1022 Property: mutable bool m_is_inside_cached
1023
1024 Gets a value indicating whether this object is inside cached.
1025
1026 Returns: True if this object m is inside cached, false if not.
1027 *-----------------------------------------------------------------------------------------------**/
1028
1029 mutable bool m_is_inside_cached;
1030 mutable bool m_is_convex_cached;
1031 mutable bool m_is_convex;
1032 Plane<3, t_type> m_polygon_plane;
1033 };
1034
1035 template<class t_type, class t_vertex, uint01 t_row_dims, uint01 t_col_dims>
1037 {
1038 Polygon<t_type, t_vertex> polygon(poly.vertexCount());
1039 for (uint04 i = 0; i < poly.vertexCount(); i++)
1040 {
1041 polygon.add(matrix * poly.vertex(i));
1042 }
1043 return polygon;
1044 }
1045
1046 template<class t_type, class t_vertex>
1047 static bool isNaN(const Polygon<t_type, t_vertex>& poly)
1048 {
1049 Polygon<t_type, t_vertex> polygon(poly.vertexCount());
1050 for (uint04 i = 0; i < poly.vertexCount(); i++)
1051 {
1052 if(isNaN(poly.vertex(i)))
1053 return true;
1054 }
1055 return false;
1056 }
1057
1058}
#define lib_assert(expression, message)
Asserts some logic in the code. Disabled in non debug mode by default. Can be re-enabled in release u...
Definition LibAssert.h:70
A specification of upper and lower bounds in N-dimensions.
Definition Bounds.hpp:57
constexpr bool contains(const t_type &value) const
Query if this object contains the given value.
Definition Bounds.hpp:329
The equivelent of std::vector but with a bit more control. The basic array unit of the library.
Definition Buffer.hpp:64
void add(t_type &&object)
Definition Buffer.hpp:199
void insert(t_index_type offset, const Buffer &buffer)
Definition Buffer.hpp:332
constexpr t_index_type size() const
Definition Buffer.hpp:1461
void addAll(const Buffer< t_type, t_other_index_type, t_other_memory_allocator, t_other_memory_manager > &buffer)
Definition Buffer.hpp:248
decltype(auto) end()
Definition Buffer.hpp:746
void setSize(t_index_type new_size)
Definition Buffer.hpp:1413
void removeIndex(t_index_type location)
Definition Buffer.hpp:1037
decltype(auto) begin()
Definition Buffer.hpp:504
void clear()
Definition Buffer.hpp:572
A line segment represented by two vertices, a start and end.
Definition Line.hpp:55
constexpr const t_vertex & vertex(uint01 index) const
Definition Line.hpp:171
Definition Matrix.hpp:173
Definition Geometry.h:41
Matrix< t_type > projectionMatrix(const Vector< 3, t_type > &up) const
Definition Plane.hpp:134
An N-sided polygon.
Definition Polygon.hpp:58
Polygon & operator=(Polygon &&poly)
Definition Polygon.hpp:868
LineSegment< 2, t_type, t_vertex > edge(uint04 index) const
Definition Polygon.hpp:185
IntersectionTypes contains(const Triangle< 2, t_type, t_vertex > &tri) const
Definition Polygon.hpp:645
void simplify()
Definition Polygon.hpp:375
Polygon< t_new_type, t_new_vertex_type > as() const
Definition Polygon.hpp:459
void flip()
Definition Polygon.hpp:401
Polygon opheimSimplification(t_type min_tol, t_type max_tol) const
Definition Polygon.hpp:790
Plane< 3, t_type > plane() const
Definition Polygon.hpp:727
Polygon clip(const Bounds< t_vertex::NumberOfDimensions(), t_type > &bounds) const
Definition Polygon.hpp:693
void replace(uint04 index, const t_vertex &vector)
Definition Polygon.hpp:354
bool validate() const
Definition Polygon.hpp:878
void addVertices(const t_vertex *vertices, uint04 size)
Definition Polygon.hpp:295
bool contains(const Vertex< 2, t_type > &vector) const
Definition Polygon.hpp:515
decltype(auto) begin(uint04 index)
Definition Polygon.hpp:615
uint04 vertexCount() const
Definition Polygon.hpp:219
Polygon(const Buffer< Vertex< 3, fltp08 > > &points)
Definition Polygon.hpp:101
void insert(uint04 index, const t_vertex &vertex)
Definition Polygon.hpp:334
t_type perimeter() const
Definition Polygon.hpp:481
Polygon(const Polygon &polygon)
Definition Polygon.hpp:69
IntersectionTypes contains(const Bounds< 2, t_type, t_vertex > &o_bounds) const
Definition Polygon.hpp:569
bool hasClockwiseWinding() const
Definition Polygon.hpp:735
bool isEquivalent(const Polygon &polygon, fltp08 epsilon)
Definition Polygon.hpp:768
void setVertices(const Buffer< t_vertex > &vertices)
Definition Polygon.hpp:291
void remove(uint04 index)
Definition Polygon.hpp:425
decltype(auto) end()
Definition Polygon.hpp:620
Polygon & operator=(const Polygon &poly)
Definition Polygon.hpp:858
bool operator==(const Polygon &polygon) const
Definition Polygon.hpp:760
IntersectionTypes contains(const LineSegment< 2, t_type, t_vertex > &line) const
Definition Polygon.hpp:535
Bounds< 2, t_type, t_vertex > bounds() const
Definition Polygon.hpp:136
decltype(auto) begin()
Definition Polygon.hpp:602
void setPlane(const Plane< 3, t_type > &plane)
Definition Polygon.hpp:731
decltype(auto) begin(uint04 index) const
Definition Polygon.hpp:611
void add(const t_vertex &vertex)
Definition Polygon.hpp:314
bool isConvex() const
Definition Polygon.hpp:240
Polygon(uint04 allocated_size)
Definition Polygon.hpp:115
void clear()
Definition Polygon.hpp:441
decltype(auto) begin() const
Definition Polygon.hpp:606
const t_vertex & vertex(uint04 index) const
Definition Polygon.hpp:165
Polygon(Polygon &&polygon) noexcept
Definition Polygon.hpp:80
Polygon()
Definition Polygon.hpp:60
const Buffer< t_vertex > & vertices() const
Definition Polygon.hpp:202
Polygon(Buffer< t_vertex > &vertices)
Definition Polygon.hpp:92
uint04 edgeCount() const
Definition Polygon.hpp:236
decltype(auto) end() const
Definition Polygon.hpp:624
IntersectionTypes contains(const Polygon< t_type, t_other_vertex > &poly) const
Definition Polygon.hpp:674
bool operator!=(const Polygon &polygon) const
Definition Polygon.hpp:764
Definition Triangle.hpp:143
constexpr bool contains(const Vector< t_dims - 1, t_type > &p) const
Definition Triangle.hpp:481
constexpr t_vertex & vertex(TriangleLocation triangle_node)
Vertices the given triangle node.
Definition Triangle.hpp:180
constexpr LineSegment< t_dims, t_type, t_vertex > edge(uint01 triangle_node_a, uint01 triangle_node_b) const
Definition Triangle.hpp:276
An element of a vector space. An element of the real coordinate space Rn Basis vector,...
Definition Vector.hpp:62
A vertex.
Definition Vertex.hpp:54
Definition ACIColor.h:37
constexpr std::enable_if< IsVecType< t_vector_type, Angle< fltp08 > >::value, t_vector_type >::type operator*(const t_vector_type &angle, const t_type &mult)
Definition AngleFunctions.h:403
t_type dot(const Vector< t_dims, t_type > &v1, const Vector< t_dims, t_type > &v2)
Definition VectorFunctions.hpp:1096
@ MIN
Definition BaseValues.hpp:226
@ MAX
Definition BaseValues.hpp:227
t_type distanceSquared(const Bounds< t_dims, t_type, t_vertex > &bounds, const Vector< t_dims, t_type > &vertex)
Definition Distance.hpp:42
IntersectionTypes
Used for classifying shape intersections.
Definition BaseValues.hpp:241
@ inside
Definition BaseValues.hpp:243
@ mixed
Definition BaseValues.hpp:244
@ outside
Definition BaseValues.hpp:242
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
Definition BaseValues.hpp:120
constexpr t_to cast(const Angle< t_from > &value)
Definition Angle.h:514
constexpr Angle< t_angle_type > abs(const Angle< t_angle_type > &value)
Definition AngleFunctions.h:750
constexpr bool isNaN(const t_type &value)
Query if 'value' is valid or invalid.
Definition BaseFunctions.hpp:200
@ B
Definition BaseValues.hpp:203
@ A
Definition BaseValues.hpp:201
@ Y
Definition BaseValues.hpp:202
@ X
Definition BaseValues.hpp:200
@ C
Definition BaseValues.hpp:205
double fltp08
Defines an alias representing an 8 byte floating-point number.
Definition BaseValues.hpp:181
Definition BaseValues.hpp:272