60 , m_cache_length(Constant<t_type>::Invalid)
61 , m_is_inside_cached(
false)
62 , m_is_convex_cached(
false)
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)
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)
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);
92 , m_cache_length(Constant<t_type>::Invalid)
93 , m_is_inside_cached(
false)
94 , m_is_convex_cached(
false)
100 , m_cache_length(Constant<t_type>::Invalid)
101 , m_is_inside_cached(
false)
102 , m_is_convex_cached(
false)
104 , m_polygon_plane(Plane<3, fltp08>::CreateBestFitPlane(points))
106 Matrix<fltp08> plane_transform = m_polygon_plane.projectionMatrix();
107 for (
uint04 n = 0; n < points.size(); n++)
109 add(t_vertex(plane_transform * points[n]).
template as<2, t_type>());
112 explicit Polygon(
uint04 allocated_size)
113 : m_vertices(allocated_size)
115 , m_cache_length(Constant<t_type>::Invalid)
116 , m_is_inside_cached(
false)
117 , m_is_convex_cached(
false)
136 for (
uint04 i = 0; i < m_vertices.size(); i++)
138 m_cache_bounds.addToBounds(m_vertices[i]);
141 return m_cache_bounds;
160 return m_vertices[index];
208 return m_vertices.size();
223 return m_vertices.size();
225 bool isConvex()
const
227 if (!m_is_convex_cached)
240 t_type last_cross_prod = 0;
242 for (
uint04 i = 0; i < vert_count; i++)
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];
255 last_cross_prod = cross_prod;
259 m_is_convex_cached =
true;
302 m_vertices.insert(index,
vertex);
306 void replace(
uint04 index,
const t_vertex& vector)
308 if (m_vertices[index] != vector)
310 m_vertices[index] = vector;
320 if (
vertex(i).
template as<2, t_type>() ==
vertex(i + 1).
template as<2, t_type>())
347 for (
uint04 i = 1; i < iMax; ++i)
348 std::swap(m_vertices[i], m_vertices[
vertexCount() - i]);
353 m_vertices.removeIndex(index);
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
364 Polygon<t_new_type, t_new_vertex_type> poly;
367 poly.add(t_new_vertex_type(
vertex(i).
template as<2, t_new_type>()));
371 t_type perimeter()
const
383 m_cache_length +=
edge(i).template length<t_type>();
387 return m_cache_length;
389 bool contains(
const Vertex<2, t_type>& vector)
const
391 if (!
bounds().
template as<2, t_type>().contains(vector))
393 cacheBoundaryCheck();
395 bool odd_vertices =
false;
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]))
401 odd_vertices ^= ((vector[Y] * m_cache_multiple[current] + m_cache_constant[current]) < vector[X]);
408 template<
class t_precision>
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;
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;
425 return is_inside ? IntersectionTypes::e_inside : IntersectionTypes::e_outside;
427 template<
class t_precision>
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]);
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;
447 if (o_bounds.contains(
vertex(i)))
448 return IntersectionTypes::e_mixed;
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;
458 return is_inside ? IntersectionTypes::e_inside : IntersectionTypes::e_outside;
461 decltype(
auto) begin()
463 return m_vertices.begin();
465 decltype(
auto) begin()
const
467 return m_vertices.begin();
470 decltype(
auto) begin(
uint04 index)
const
472 return m_vertices.begin(index);
474 decltype(
auto) begin(
uint04 index)
476 return m_vertices.begin(index);
481 return m_vertices.end();
483 decltype(
auto) end()
const
485 return m_vertices.end();
487 template<
class t_precision>
491 if(m_vertices.size() <= 2)
492 return IntersectionTypes::e_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;
503 if (tri.contains(
vertex(i)))
504 return IntersectionTypes::e_mixed;
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;
513 return is_inside ? IntersectionTypes::e_inside : IntersectionTypes::e_outside;
516 template<
class t_precision,
class t_other_vertex>
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;
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++)
529 if (
type != contains<t_precision>(poly.edge(i)))
530 return IntersectionTypes::e_mixed;
536 Polygon clip(
const Bounds<t_vertex::NumberOfDimensions(), t_type>&
bounds)
const
538 if (
bounds.template as<2, t_type>().template contains<true>(this->bounds().template as<2, t_type>()))
540 if (!
bounds.template as<2, t_type>().intersects(this->bounds()))
545 LineSegment<t_vertex::NumberOfDimensions(), t_type> line(
vertex(ii),
vertex(ii + 1));
550 polygon.
add(line.vertex(A));
551 polygon.
add(line.vertex(B));
561 polygon.
add(line.vertex(A));
562 polygon.
add(line.vertex(B));
570 Plane<3, t_type> plane()
const
572 return m_polygon_plane;
574 void setPlane(
const Plane<3, t_type>& plane)
576 m_polygon_plane = plane;
578 bool hasClockwiseWinding()
const
584 sum += (side[B][X] - side[A][X]) * (side[B][Y] + side[A][Y]);
588 bool operator==(
const Polygon& polygon)
const
590 return m_vertices == polygon.m_vertices && m_polygon_plane == polygon.m_polygon_plane;
592 bool operator!=(
const Polygon& polygon)
const
594 return m_vertices != polygon.m_vertices || m_polygon_plane != polygon.m_polygon_plane;
596 bool isEquivalent(
const Polygon& polygon,
fltp08 epsilon)
598 if (
bounds().
template as<2, fltp08>() != polygon.bounds().template as<2, fltp08>())
600 if (
abs(perimeter() - polygon.perimeter()) > epsilon)
602 for (
uint04 i = 0; i < polygon.edgeCount(); i++)
607 if (
edge(n).
template as<2, fltp08>().
template isCollinear<fltp08>(polygon.edge(i).template as<2, fltp08>(), epsilon))
618 Polygon opheimSimplification(t_type min_tol, t_type max_tol)
const
622 t_type min_tol2 = min_tol * min_tol;
623 t_type max_tol2 = max_tol * max_tol;
626 if (count < 3 || min_tol2 == 0 || max_tol2 == 0)
631 bool rayDefined =
false;
639 for (
uint04 j = 1; j < count; ++j)
643 t_type dist_squared = distanceSquared(
vertex(r0),
vertex(pj));
646 if (dist_squared < min_tol2)
654 if (dist_squared < max_tol2)
659 t_type cv =
dot(v, v);
660 t_type cw =
dot(w, v);
671 t_type fraction = cv == 0 ? 0 : cw /cv;
676 if (distanceSquared(
vertex(pj), proj) < min_tol2)
686 Polygon& operator=(
const Polygon& poly)
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;
696 Polygon& operator=(Polygon&& poly)
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;
706 bool validate()
const
710 auto seg_to_check =
edge(i);
713 if (n == i || (n ==
edgeCount() - 1 && i == 0))
718 lib_assert(
false,
"Bad polygon");
735 inline void invalidateCache()
const
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;
756 void updateVertices(
const Buffer<t_vertex>&
vertices)
770 void cacheBoundaryCheck()
const
772 if(m_is_inside_cached)
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)
779 if(m_vertices[jj][Y] == m_vertices[ii][Y])
782 m_cache_multiple[ii] = 0;
786 m_cache_constant[ii] = m_vertices[ii][X]
791 m_cache_multiple[ii] =
cast<fltp08>(m_vertices[jj][X] - m_vertices[ii][X])
796 m_is_inside_cached =
true;
801 Buffer<t_vertex> m_vertices;
811 mutable Bounds<2, t_type, t_vertex> m_cache_bounds;
821 mutable t_type m_cache_length;
831 mutable Buffer<fltp08> m_cache_constant;
841 mutable Buffer<fltp08> m_cache_multiple;
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;