NDEVR
API Documentation
Polygon.hpp
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>
40namespace NDEVR
41{
53 template<class t_type, class t_vertex = Vertex<2, t_type>>
54 class Polygon
55 {
56 public:
57 Polygon()
58 : m_vertices()
59 , m_cache_bounds(Constant<Bounds<2, t_type, t_vertex>>::Invalid)
60 , m_cache_length(Constant<t_type>::Invalid)
61 , m_is_inside_cached(false)
62 , m_is_convex_cached(false)
63 , m_is_convex(false)
64 , m_polygon_plane(Vector<3, t_type>(0, 0, 1), 0)
65 {}
66 Polygon(const Polygon& polygon)
67 : m_vertices(polygon.m_vertices)
68 , m_cache_bounds(polygon.m_cache_bounds)
69 , m_cache_length(polygon.m_cache_length)
70 , m_cache_constant(polygon.m_cache_constant)
71 , m_cache_multiple(polygon.m_cache_multiple)
72 , m_is_inside_cached(polygon.m_is_inside_cached)
73 , m_is_convex_cached(polygon.m_is_convex_cached)
74 , m_is_convex(polygon.m_is_convex)
75 , m_polygon_plane(polygon.m_polygon_plane)
76 {}
77 Polygon(Polygon&& polygon) noexcept
78 : m_cache_bounds(polygon.m_cache_bounds)
79 , m_cache_length(polygon.m_cache_length)
80 , m_is_inside_cached(polygon.m_is_inside_cached)
81 , m_is_convex_cached(polygon.m_is_convex_cached)
82 , m_is_convex(polygon.m_is_convex)
83 , m_polygon_plane(polygon.m_polygon_plane)
84 {
85 std::swap(m_vertices, polygon.m_vertices);
86 std::swap(m_cache_multiple, polygon.m_cache_multiple);
87 std::swap(m_cache_constant, polygon.m_cache_constant);
88 }
89 explicit Polygon(Buffer<t_vertex>& vertices)
90 : m_vertices(vertices)
91 , m_cache_bounds(Constant<Bounds<2, t_type, t_vertex>>::Invalid)
92 , m_cache_length(Constant<t_type>::Invalid)
93 , m_is_inside_cached(false)
94 , m_is_convex_cached(false)
95 , m_is_convex(false)
96 , m_polygon_plane(Vector<3, t_type>(0, 0, 1), 0)
97 {}
98 explicit Polygon(const Buffer<Vertex<3, fltp08>>& points)
99 : m_cache_bounds(Constant<Bounds<2, t_type, t_vertex>>::Invalid)
100 , m_cache_length(Constant<t_type>::Invalid)
101 , m_is_inside_cached(false)
102 , m_is_convex_cached(false)
103 , m_is_convex(false)
104 , m_polygon_plane(Plane<3, fltp08>::CreateBestFitPlane(points))
105 {
106 Matrix<fltp08> plane_transform = m_polygon_plane.projectionMatrix();
107 for (uint04 n = 0; n < points.size(); n++)
108 {
109 add(t_vertex(plane_transform * points[n]).template as<2, t_type>());
110 }
111 }
112 explicit Polygon(uint04 allocated_size)
113 : m_vertices(allocated_size)
114 , m_cache_bounds(Constant<Bounds<2, t_type, t_vertex>>::Invalid)
115 , m_cache_length(Constant<t_type>::Invalid)
116 , m_is_inside_cached(false)
117 , m_is_convex_cached(false)
118 , m_is_convex(false)
119 , m_polygon_plane(Vector<3, t_type>(0, 0, 1), 0)
120 {}
121
132 {
133 if (IsInvalid(m_cache_bounds))
134 {
135 m_cache_bounds = Constant<Bounds<2, t_type, t_vertex>>::Min;
136 for (uint04 i = 0; i < m_vertices.size(); i++)
137 {
138 m_cache_bounds.addToBounds(m_vertices[i]);
139 }
140 }
141 return m_cache_bounds;
142 }
143
144
157
158 const t_vertex& vertex(uint04 index) const
159 {
160 return m_vertices[index];
161 }
162
175
177 {
178 return LineSegment<2, t_type, t_vertex>(vertex(index), vertex((index + 1) % m_vertices.size()));
179 }
180
190
191 inline const Buffer<t_vertex>& vertices() const
192 {
193 return m_vertices;
194 }
195
205
206 inline uint04 vertexCount() const
207 {
208 return m_vertices.size();
209 }
210
220
221 inline uint04 edgeCount() const
222 {
223 return m_vertices.size();
224 }
225 bool isConvex() const
226 {
227 if (!m_is_convex_cached)
228 {
229 if (edgeCount() < 3)
230 {
231 m_is_convex = false;
232 }
233 else if (edgeCount() == 3)
234 {
235 m_is_convex = true;
236 }
237 else
238 {
239 m_is_convex = true;
240 t_type last_cross_prod = 0;
241 const uint04 vert_count = vertexCount();
242 for (uint04 i = 0; i < vert_count; i++)
243 {
244 const Vector<2, t_type> d1 = vertex((i + 1) % vert_count) - vertex((i + 0) % vert_count);
245 const Vector<2, t_type> d2 = vertex((i + 2) % vert_count) - vertex((i + 1) % vert_count);
246 const t_type cross_prod = d1[X] * d2[Y] - d1[Y] * d2[X];
247 if (cross_prod != cast<t_type>(0))
248 {
249 if ((last_cross_prod > cast<t_type>(0) && cross_prod < cast<t_type>(0))
250 || (last_cross_prod < cast<t_type>(0) && cross_prod > cast<t_type>(0)))
251 {
252 m_is_convex = false;
253 break;
254 }
255 last_cross_prod = cross_prod;
256 }
257 }
258 }
259 m_is_convex_cached = true;
260 }
261 return m_is_convex;
262 }
273
275 {
276 updateVertices(vertices);
277 }
278 inline void addVertices(const t_vertex* vertices, uint04 size)
279 {
280 m_vertices.addAll(vertices, size);
281 invalidateCache();
282 }
283
294
295 void add(const t_vertex& vertex)
296 {
297 m_vertices.add(vertex);
298 invalidateCache();
299 }
300 void insert(uint04 index, const t_vertex& vertex)
301 {
302 m_vertices.insert(index, vertex);
303 invalidateCache();
304 }
305
306 void replace(uint04 index, const t_vertex& vector)
307 {
308 if (m_vertices[index] != vector)
309 {
310 m_vertices[index] = vector;
311 invalidateCache();
312 }
313 }
314 void simplify()
315 {
316 if (vertexCount() <= 1)
317 return;
318 for (uint04 i = 0; i < vertexCount() - 1; i++)
319 {
320 if (vertex(i).template as<2, t_type>() == vertex(i + 1).template as<2, t_type>())
321 {
322 remove(i + 1);
323 i--;
324 }
325 else if (i > 0 && edge(i).template isParallel<t_type>(edge(i - 1), cast<t_type>(0.00001)))
326 {
327 remove(i);
328 i--;
329 }
330 }
331 while (vertexCount() > 0 && vertex(vertexCount() - 1).template as<2, t_type>() == vertex(0).template as<2, t_type>())
332 {
333 remove(vertexCount() - 1);
334 }
335 while (vertexCount() > 2 && edge(edgeCount() - 1).template isParallel<t_type>(edge(0), cast<t_type>(0.00001)))
336 {
337 remove(0);
338 }
339 }
340 void flip()
341 {
342 uint04 iMax = vertexCount() / 2;
343
344 if (vertexCount() % 2 != 0)
345 iMax += 1;
346
347 for (uint04 i = 1; i < iMax; ++i)
348 std::swap(m_vertices[i], m_vertices[vertexCount() - i]);
349 invalidateCache();
350 }
351 void remove(uint04 index)
352 {
353 m_vertices.removeIndex(index);
354 invalidateCache();
355 }
356 void clear()
357 {
358 m_vertices.clear();
359 invalidateCache();
360 }
361 template<class t_new_type, class t_new_vertex_type = Vertex<2, t_new_type>>
362 Polygon<t_new_type, t_new_vertex_type> as() const
363 {
364 Polygon<t_new_type, t_new_vertex_type> poly;
365 for(uint04 i = 0; i < vertexCount(); i++)
366 {
367 poly.add(t_new_vertex_type(vertex(i).template as<2, t_new_type>()));
368 }
369 return poly;
370 }
371 t_type perimeter() const
372 {
373 if(IsInvalid(m_cache_length))
374 {
375 if(vertexCount() > 0)
376 {
377 m_cache_length = cast<t_type>(0);
378 }
379 if (vertexCount() > 1)
380 {
381 for (uint04 i = 0; i < edgeCount(); i++)
382 {
383 m_cache_length += edge(i).template length<t_type>();
384 }
385 }
386 }
387 return m_cache_length;
388 }
389 bool contains(const Vertex<2, t_type>& vector) const
390 {
391 if (!bounds().template as<2, t_type>().contains(vector))
392 return false;
393 cacheBoundaryCheck();
394 uint04 last = vertexCount() - 1;
395 bool odd_vertices = false;
396 for (uint04 current = 0; current < vertexCount(); ++current)
397 {
398 if ((m_vertices[current][Y] < vector[Y] && m_vertices[last][Y] >= vector[Y])
399 || (m_vertices[last][Y] < vector[Y] && m_vertices[current][Y] >= vector[Y]))
400 {
401 odd_vertices ^= ((vector[Y] * m_cache_multiple[current] + m_cache_constant[current]) < vector[X]);
402 }
403 last = current;
404 }
405 return odd_vertices;
406 }
407
408 template<class t_precision>
409 IntersectionTypes contains(const LineSegment<2, t_type, t_vertex>& line) const
410 {
411 if (m_vertices.size() <= 2)
412 return IntersectionTypes::e_outside;
413 if (!bounds().intersects(line))
414 return IntersectionTypes::e_outside;
415 bool is_inside = contains(line.vertex(A));
416 if (contains(line.vertex(B)) != is_inside)
417 return IntersectionTypes::e_mixed;
418
419 for (uint04 i = 0; i < edgeCount(); i++)
420 {
421 LineSegment<2, t_type, t_vertex> current_edge = edge(i);
422 if (current_edge.template intersects<t_precision>(line))
423 return IntersectionTypes::e_mixed;
424 }
425 return is_inside ? IntersectionTypes::e_inside : IntersectionTypes::e_outside;
426 }
427 template<class t_precision>
428 IntersectionTypes contains(const Bounds<2, t_type, t_vertex>& o_bounds) const
429 {
430 if(vertexCount() <= 2)
431 return IntersectionTypes::e_outside;
432 if (!bounds().intersects(o_bounds))
433 return IntersectionTypes::e_outside;
434 const t_vertex v1(o_bounds[MIN][X], o_bounds[MIN][Y]);
435 const t_vertex v2(o_bounds[MAX][X], o_bounds[MIN][Y]);
436 const t_vertex v3(o_bounds[MAX][X], o_bounds[MAX][Y]);
437 const t_vertex v4(o_bounds[MIN][X], o_bounds[MAX][Y]);
438
439 const bool is_inside = contains(v1);
440 if(contains(v2) != is_inside) return IntersectionTypes::e_mixed;
441 if(contains(v3) != is_inside) return IntersectionTypes::e_mixed;
442 if(contains(v4) != is_inside) return IntersectionTypes::e_mixed;
443 // If all of the bounding points are outside, we need only prove that a single polygon vertex is
444 // inside (Which is cheap)
445 if(!is_inside) for (uint04 i = 0; i < edgeCount(); i++)
446 {
447 if (o_bounds.contains(vertex(i)))
448 return IntersectionTypes::e_mixed;
449 }
450 for(uint04 i = 0; i < edgeCount(); i++)
451 {
452 const LineSegment<2, t_type, t_vertex> current_edge = edge(i);
453 if(current_edge.template intersects<t_precision>(LineSegment<2, t_type>(v1, v2))) return IntersectionTypes::e_mixed;
454 if(current_edge.template intersects<t_precision>(LineSegment<2, t_type>(v2, v3))) return IntersectionTypes::e_mixed;
455 if(current_edge.template intersects<t_precision>(LineSegment<2, t_type>(v3, v4))) return IntersectionTypes::e_mixed;
456 if(current_edge.template intersects<t_precision>(LineSegment<2, t_type>(v4, v1))) return IntersectionTypes::e_mixed;
457 }
458 return is_inside ? IntersectionTypes::e_inside : IntersectionTypes::e_outside;
459 }
460
461 decltype(auto) begin()
462 {
463 return m_vertices.begin();
464 }
465 decltype(auto) begin() const
466 {
467 return m_vertices.begin();
468 }
469
470 decltype(auto) begin(uint04 index) const
471 {
472 return m_vertices.begin(index);
473 }
474 decltype(auto) begin(uint04 index)
475 {
476 return m_vertices.begin(index);
477 }
478
479 decltype(auto) end()
480 {
481 return m_vertices.end();
482 }
483 decltype(auto) end() const
484 {
485 return m_vertices.end();
486 }
487 template<class t_precision>
488 IntersectionTypes contains(const Triangle<2, t_type, t_vertex>& tri) const
489 {
490 //Check each vertex, if some are inside, or some are outside, we know we are mixed
491 if(m_vertices.size() <= 2)
492 return IntersectionTypes::e_outside;
493 //if (!bounds().intersects(tri))
494 //return outside;
495 bool is_inside = contains(tri.vertex(A));
496 if(contains(tri.vertex(B)) != is_inside) return IntersectionTypes::e_mixed;
497 if(contains(tri.vertex(C)) != is_inside) return IntersectionTypes::e_mixed;
498
499 // If all of the triangles points are outside, we need only prove that a single polygon vertex is
500 // inside (Which is cheap)
501 if (!is_inside) for (uint04 i = 0; i < edgeCount(); i++)
502 {
503 if (tri.contains(vertex(i)))
504 return IntersectionTypes::e_mixed;
505 }
506 for (uint04 i = 0; i < edgeCount(); i++)
507 {
508 const LineSegment<2, t_type, t_vertex> current_edge = edge(i);
509 if(current_edge.template intersects<t_precision>(tri.edge(A, B))) return IntersectionTypes::e_mixed;
510 if(current_edge.template intersects<t_precision>(tri.edge(B, C))) return IntersectionTypes::e_mixed;
511 if(current_edge.template intersects<t_precision>(tri.edge(C, A))) return IntersectionTypes::e_mixed;
512 }
513 return is_inside ? IntersectionTypes::e_inside : IntersectionTypes::e_outside;
514 }
515
516 template<class t_precision, class t_other_vertex>
517 IntersectionTypes contains(const Polygon<t_type, t_other_vertex>& poly) const
518 {
519 if (m_vertices.size() <= 2 || poly.edgeCount() == 0)
520 return IntersectionTypes::e_outside;
521 if (!bounds().intersects(poly.bounds()))
522 return IntersectionTypes::e_outside;
523
524 IntersectionTypes type = contains<t_precision>(poly.edge(0));
525 if (type == IntersectionTypes::e_mixed || (type == IntersectionTypes::e_outside && poly.contains(vertex(0))))
526 return IntersectionTypes::e_mixed;
527 for (uint04 i = 1; i < poly.edgeCount(); i++)
528 {
529 if (type != contains<t_precision>(poly.edge(i)))
530 return IntersectionTypes::e_mixed;
531 }
532
533 return type;
534 }
535
536 Polygon clip(const Bounds<t_vertex::NumberOfDimensions(), t_type>& bounds) const
537 {
538 if (bounds.template as<2, t_type>().template contains<true>(this->bounds().template as<2, t_type>()))
539 return *this;
540 if (!bounds.template as<2, t_type>().intersects(this->bounds()))
541 return Polygon();
542 Polygon polygon(vertexCount());
543 for (uint04 ii = 0; ii < vertexCount() - 1; ++ii)
544 {
545 LineSegment<t_vertex::NumberOfDimensions(), t_type> line(vertex(ii), vertex(ii + 1));
546 line = intersection(bounds, line);
547 if (IsValid(line))
548 {
549 if (polygon.vertexCount() == 0 || polygon.vertex(polygon.vertexCount() - 1) != polygon.vertex(A))
550 polygon.add(line.vertex(A));
551 polygon.add(line.vertex(B));
552 }
553 }
554 LineSegment<t_vertex::NumberOfDimensions(), t_type> line(vertex(vertexCount() - 1), vertex(0));
555 if (IsValid(line))
556 {
557 line = intersection(bounds, line);
558 if (IsValid(line))
559 {
560 if (polygon.vertexCount() == 0 || polygon.vertex(polygon.vertexCount() - 1) != polygon.vertex(A))
561 polygon.add(line.vertex(A));
562 polygon.add(line.vertex(B));
563 }
564 }
565
566 polygon.simplify();
567 return polygon;
568 }
569
570 Plane<3, t_type> plane() const
571 {
572 return m_polygon_plane;
573 }
574 void setPlane(const Plane<3, t_type>& plane)
575 {
576 m_polygon_plane = plane;
577 }
578 bool hasClockwiseWinding() const
579 {
580 t_type sum = 0;
581 for (uint04 i = 0; i < edgeCount(); i++)
582 {
583 auto side = edge(i);
584 sum += (side[B][X] - side[A][X]) * (side[B][Y] + side[A][Y]);
585 }
586 return sum > 0.0;//this is also half surface area
587 }
588 bool operator==(const Polygon& polygon) const
589 {
590 return m_vertices == polygon.m_vertices && m_polygon_plane == polygon.m_polygon_plane;
591 }
592 bool operator!=(const Polygon& polygon) const
593 {
594 return m_vertices != polygon.m_vertices || m_polygon_plane != polygon.m_polygon_plane;
595 }
596 bool isEquivalent(const Polygon& polygon, fltp08 epsilon)
597 {
598 if (bounds().template as<2, fltp08>() != polygon.bounds().template as<2, fltp08>())
599 return false;
600 if (abs(perimeter() - polygon.perimeter()) > epsilon)
601 return false;
602 for (uint04 i = 0; i < polygon.edgeCount(); i++)
603 {
604 bool found = false;
605 for (uint04 n = 0; n < edgeCount(); n++)
606 {
607 if (edge(n).template as<2, fltp08>().template isCollinear<fltp08>(polygon.edge(i).template as<2, fltp08>(), epsilon))
608 {
609 found = true;
610 break;
611 }
612 }
613 if (!found)
614 return false;
615 }
616 return true;
617 }
618 Polygon opheimSimplification(t_type min_tol, t_type max_tol) const
619 {
620
621 uint04 count = vertexCount();
622 t_type min_tol2 = min_tol * min_tol; // squared minimum distance tolerance
623 t_type max_tol2 = max_tol * max_tol; // squared maximum distance tolerance
624
625 // validate input and check if simplification required
626 if (count < 3 || min_tol2 == 0 || max_tol2 == 0)
627 return *this;
628 // define the ray R(r0, r1)
629 uint04 r0 = 0; // indicates the current key and start of the ray
630 uint04 r1 = 0; // indicates a point on the ray
631 bool rayDefined = false;
632
633 // keep track of two test points
634 uint04 pi = r0; // the previous test point
635 uint04 pj = pi;
636
637 Polygon poly;
638 poly.add(vertex(r0));
639 for (uint04 j = 1; j < count; ++j)
640 {
641 pi = pj++;
642
643 t_type dist_squared = distanceSquared(vertex(r0), vertex(pj));
644 if (!rayDefined) {
645 // discard each point within minimum tolerance
646 if (dist_squared < min_tol2)
647 continue;
648 // the last point within minimum tolerance pi defines the ray R(r0, r1)
649 r1 = pi;
650 rayDefined = true;
651 }
652
653 // check each point pj against R(r0, r1)
654 if (dist_squared < max_tol2)
655 {
656 t_vertex v = vertex(r1) - vertex(r0); // vector r1 --> r2
657 t_vertex w = vertex(pj) - vertex(r0); // vector r1 --> p
658
659 t_type cv = dot(v, v); // squared length of v
660 t_type cw = dot(w, v); // project w onto v
661
662 if (cw <= 0)
663 {
664 // projection of w lies to the left of r1 (not on the ray)
665 if (distanceSquared(vertex(pj), vertex(r0)) < min_tol2)
666 continue;
667 }
668 else
669 {
670 // avoid problems with divisions when value_type is an integer type
671 t_type fraction = cv == 0 ? 0 : cw /cv;
672
673
674 t_vertex proj = vertex(r0) + (fraction * (vertex(r1) - vertex(r0)));
675
676 if (distanceSquared(vertex(pj), proj) < min_tol2)
677 continue;
678 }
679 }
680 poly.add(vertex(pi));
681 r0 = pi;
682 rayDefined = false;
683 }
684 return poly;
685 }
686 Polygon& operator=(const Polygon& poly)
687 {
688 m_vertices = poly.m_vertices;
689 m_cache_bounds = poly.m_cache_bounds;
690 m_cache_length = poly.m_cache_length;
691 m_cache_constant = poly.m_cache_constant;
692 m_cache_multiple = poly.m_cache_multiple;
693 m_is_inside_cached = poly.m_is_inside_cached;
694 return *this;
695 }
696 Polygon& operator=(Polygon&& poly)
697 {
698 std::swap(m_vertices, poly.m_vertices);
699 m_cache_bounds = poly.m_cache_bounds;
700 m_cache_length = poly.m_cache_length;
701 m_cache_constant = poly.m_cache_constant;
702 m_cache_multiple = poly.m_cache_multiple;
703 m_is_inside_cached = poly.m_is_inside_cached;
704 return *this;
705 }
706 bool validate() const
707 {
708 for (uint04 i = 0; i < edgeCount(); i++)
709 {
710 auto seg_to_check = edge(i);
711 for (uint04 n = i + 2; n < edgeCount(); n++)
712 {
713 if (n == i || (n == edgeCount() - 1 && i == 0))
714 continue;
715 auto seg = edge(n);
716 if (IsValid(seg_to_check.template intersection<fltp08>(seg, 0.000000001)))
717 {
718 lib_assert(false, "Bad polygon");
719 return false;
720 }
721 }
722 }
723 return true;
724 }
725 private:
726
734
735 inline void invalidateCache() const
736 {
737 m_cache_length = Constant<t_type>::Invalid;
738 m_is_inside_cached = false;
739 m_is_convex_cached = false;
740 m_cache_constant.clear();
741 m_cache_multiple.clear();
742 m_cache_bounds = Constant<Bounds<2, t_type, t_vertex>>::Invalid;
743 }
744
755
756 void updateVertices(const Buffer<t_vertex>& vertices)
757 {
758 m_vertices = vertices;
759 invalidateCache();
760 }
761
769
770 void cacheBoundaryCheck() const
771 {
772 if(m_is_inside_cached)
773 return;
774 m_cache_constant.setSize(m_vertices.size());
775 m_cache_multiple.setSize(m_vertices.size());
776 uint04 jj = m_vertices.size() - 1;
777 for(uint04 ii = 0; ii < m_vertices.size(); ++ii)
778 {
779 if(m_vertices[jj][Y] == m_vertices[ii][Y])
780 {
781 m_cache_constant[ii] = cast<fltp08>(m_vertices[ii][X]);
782 m_cache_multiple[ii] = 0;
783 }
784 else
785 {
786 m_cache_constant[ii] = m_vertices[ii][X]
787 - cast<fltp08>(m_vertices[ii][Y] * m_vertices[jj][X])
788 / cast<fltp08>(m_vertices[jj][Y] - m_vertices[ii][Y])
789 + cast<fltp08>(m_vertices[ii][Y] * m_vertices[ii][X])
790 / cast<fltp08>(m_vertices[jj][Y] - m_vertices[ii][Y]);
791 m_cache_multiple[ii] = cast<fltp08>(m_vertices[jj][X] - m_vertices[ii][X])
792 / cast<fltp08>(m_vertices[jj][Y] - m_vertices[ii][Y]);
793 }
794 jj = ii;
795 }
796 m_is_inside_cached = true;
797 }
798
799 private:
801 Buffer<t_vertex> m_vertices;
802
810
811 mutable Bounds<2, t_type, t_vertex> m_cache_bounds;
812
820
821 mutable t_type m_cache_length;
822
830
831 mutable Buffer<fltp08> m_cache_constant;
832
840
841 mutable Buffer<fltp08> m_cache_multiple;
842
850
851 mutable bool m_is_inside_cached;
852 mutable bool m_is_convex_cached;
853 mutable bool m_is_convex;
854 Plane<3, t_type> m_polygon_plane;
855 };
856
857 template<class t_type, class t_vertex, uint01 t_row_dims, uint01 t_col_dims>
859 {
860 Polygon<t_type, t_vertex> polygon(poly.vertexCount());
861 for (uint04 i = 0; i < poly.vertexCount(); i++)
862 {
863 polygon.add(matrix * poly.vertex(i));
864 }
865 return polygon;
866 }
867
868 template<class t_type, class t_vertex>
869 static bool IsInvalid(const Polygon<t_type, t_vertex>& poly)
870 {
871 Polygon<t_type, t_vertex> polygon(poly.vertexCount());
872 for (uint04 i = 0; i < poly.vertexCount(); i++)
873 {
874 if(IsInvalid(poly.vertex(i)))
875 return true;
876 }
877 return false;
878 }
879 template<class t_type, class t_vertex>
880 static bool IsValid(const Polygon<t_type, t_vertex>& poly)
881 {
882 Polygon<t_type, t_vertex> polygon(poly.vertexCount());
883 for (uint04 i = 0; i < poly.vertexCount(); i++)
884 {
885 if (IsInvalid(poly.vertex(i)))
886 return false;
887 }
888 return true;
889 }
890
891}
A specification of upper and lower bounds in N-dimensions.
Definition Bounds.hpp:54
The equivelent of std::vector but with a bit more control.
Definition Buffer.hpp:58
Class: LineSegment.
Definition Line.hpp:52
Templated logic for doing matrix multiplication.
Definition Matrix.hpp:182
An N-sided polygon.
Definition Polygon.hpp:55
Bounds< 2, t_type, t_vertex > bounds() const
Definition Polygon.hpp:131
const t_vertex & vertex(uint04 index) const
Definition Polygon.hpp:158
void setVertices(const Buffer< t_vertex > &vertices)
Definition Polygon.hpp:274
uint04 vertexCount() const
Definition Polygon.hpp:206
uint04 edgeCount() const
Definition Polygon.hpp:221
const Buffer< t_vertex > & vertices() const
Definition Polygon.hpp:191
LineSegment< 2, t_type, t_vertex > edge(uint04 index) const
Definition Polygon.hpp:176
void add(const t_vertex &vertex)
Definition Polygon.hpp:295
A fixed-size array with N dimensions used as the basis for geometric and mathematical types.
Definition Vector.hpp:62
A point in N-dimensional space, used primarily for spatial location information.
Definition Vertex.hpp:44
The primary namespace for the NDEVR SDK.
@ type
The type identifier string for this model node.
Definition Model.h:58
static constexpr bool IsValid(const Angle< t_type > &value)
Checks whether the given Angle holds a valid value.
Definition Angle.h:398
t_type dot(const Vector< t_dims, t_type > &v1, const Vector< t_dims, t_type > &v2)
constexpr Angle< t_angle_type > abs(const Angle< t_angle_type > &value)
Changes an input with a negative sign, to a positive sign.
constexpr HSLColor Constant< HSLColor >::Invalid
The invalid HSLColor constant with all components set to invalid.
Definition HSLColor.h:264
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
static Bounds< t_dims, t_type, t_vertex > intersection(const Bounds< t_dims, t_type, t_vertex > &bounds_1, const Bounds< t_dims, t_type, t_vertex > &bounds_2)
Given two bounds, returns the intersection between the two of them.
double fltp08
Defines an alias representing an 8 byte floating-point number.
static constexpr Angle< t_type > operator*(const Angle< t_type > &angle_a, const Angle< t_type > &angle_b)
Multiplication operator.
static constexpr bool IsInvalid(const Angle< t_type > &value)
Checks whether the given Angle holds an invalid value.
Definition Angle.h:388
IntersectionTypes
Used for classifying shape intersections.
constexpr t_to cast(const Angle< t_from > &value)
Casts an Angle from one backing type to another.
Definition Angle.h:408
Defines for a given type (such as sint04, fltp08, UUID, etc) a maximum, minimum, and reserved 'invali...