API Documentation
Loading...
Searching...
No Matches
ConcaveToConvexPolygon.h
Go to the documentation of this file.
1#pragma once
2#include <NDEVR/Polygon.h>
3#include <NDEVR/Dictionary.h>
4#include <NDEVR/OpenMP.h>
5#include <vector>
6#include <cmath>
7#include <map>
8#include <iostream>
9namespace NDEVR
10{
11 template<class t_type, class t_vertex_type>
12 struct SliceVertex : public t_vertex_type
13 {
15 SliceVertex(t_vertex_type const& _position)
16 : t_vertex_type{ _position } {}
17
18 int index;
20 };
21
22 template<class t_type, class t_vertex = Vertex<2, t_type>>
24 {
28 VertexArray vertices;
29 PolygonArray processed_polygons;
30
31
32 static inline fltp08 Det(fltp08 a, fltp08 b, fltp08 c, fltp08 d)
33 {
34 return a * d - b * c;
35 }
36 static inline int orientation(const Vertex<2, t_type>& p, const Vertex<2, t_type>& q, const Vertex<2, t_type>& r)
37 {
38 fltp08 val = (q[Y] - p[Y]) * (r[X] - q[X]) - (q[X] - p[X]) * (r[Y] - q[Y]);
39
40 if (abs(val) < 1E-10)
41 return 0; // collinear
42
43 return (val > 0) ? 1 : 2; // clock or counterclock wise
44 }
45 static inline bool onSegment(const Vertex<2, t_type>& p, const Vertex<2, t_type>& q, const Vertex<2, t_type>& r)
46 {
47 if (q[X] <= getMax(p[X], r[X]) && q[X] >= getMin(p[X], r[X]) &&
48 q[Y] <= getMax(p[Y], r[Y]) && q[Y] >= getMin(p[Y], r[Y]))
49 return true;
50
51 return false;
52 }
53 static inline bool intersects(const Line& s1, const Line& s2)
54 {
55 int o1 = orientation(s1.vertex(A), s1.vertex(B), s2.vertex(A));
56 int o2 = orientation(s1.vertex(A), s1.vertex(B), s2.vertex(B));
57 int o3 = orientation(s2.vertex(A), s2.vertex(B), s1.vertex(A));
58 int o4 = orientation(s2.vertex(A), s2.vertex(B), s1.vertex(B));
59
60 // General case
61 if (o1 != o2 && o3 != o4)
62 return true;
63
64 // Special Cases
65 if (o1 == 0 && onSegment(s1.vertex(A), s2.vertex(A), s1.vertex(B))) return true;
66
67 // p1, q1 and q2 are collinear and q2 lies on segment p1q1
68 if (o2 == 0 && onSegment(s1.vertex(A), s2.vertex(B), s1.vertex(B))) return true;
69
70 // p2, q2 and p1 are collinear and p1 lies on segment p2q2
71 if (o3 == 0 && onSegment(s2.vertex(A), s1.vertex(A), s2.vertex(B))) return true;
72
73 // p2, q2 and q1 are collinear and q1 lies on segment p2q2
74 if (o4 == 0 && onSegment(s2.vertex(A), s1.vertex(B), s2.vertex(B))) return true;
75
76 return false; // Doesn't fall in any of the above cases
77
78 /*const t_type TOLERANCE = 1e-10;
79
80 Vertex<2, t_type> p1 = s1.vertex(A);
81 Vertex<2, t_type> p2 = s2.vertex(A);
82 Vertex<2, t_type> d1 = s1.ray();
83 Vertex<2, t_type> d2 = s2.ray();
84
85 if (abs(cross(d1, d2)) < 1e-30)
86 {
87 return false;
88 }
89 t_type t1 = cross(p2 - p1, d2) / cross(d1, d2);
90
91 if ((t1 < (0.0f - TOLERANCE)) || (t1 > (1.0f + TOLERANCE)))
92 {
93 return false;
94 }
95 Vertex<2, fltp08> intersection_vertex = p1 + d1 * t1;
96
97 t_type t2 = dot(intersection_vertex - p2, s2.vertex(B) - p2);
98
99 if (t2 < (0.0f - TOLERANCE) || t2 / distanceSquared(s2.vertex(B).as<2, fltp08>(), p2) >= 1.0f - TOLERANCE)
100 {
101 return false;
102 }
103 return true;*/
104
105 // Find the four orientations needed for general and
106 }
107 static uint04 mod(int x, int m)
108 {
109 if (x < 0)
110 return m + x;
111 else
112 return x % m;
113 }
114 static t_type CalcHandedness(const t_vertex& v1, const t_vertex& v2, const t_vertex& v3)
115 {
116 t_vertex edge1 = v2 - v1;
117 t_vertex edge2 = v3 - v2;
118
119 return cross(edge1, edge2);
120 }
121 void flipPolygon(VertexArray& _verts)
122 {
123 _verts.flip();
124 }
125
126 static bool checkIfRightHanded(const VertexArray& _verts)
127 {
128 if (_verts.vertexCount() <= 2)
129 return false;
130 return !_verts.hasClockwiseWinding();
131 }
132
133
134
135 static bool isVertexInCone(const Vector<2, t_type>& ls1, const Vector<2, t_type>& ls2, const Vector<2, t_type>& origin, const Vector<2, t_type>& vert)
136 {
137 Vector<2, t_type> relativePos = vert - origin;
138
139 t_type ls1Product = cross(relativePos, ls1);
140 t_type ls2Product = cross(relativePos, ls2);
141
142 if (ls1Product < t_type(0) && ls2Product > t_type(0))
143 return true;
144
145 return false;
146 }
147
148 typedef Buffer<uint04> IntArray;
149
150 static IntArray findVerticesInCone(const Vector<2, t_type>& ls1, const Vector<2, t_type>& ls2, const Vector<2, t_type>& origin, VertexArray const& inputVerts)
151 {
152 IntArray result;
153 for (uint04 i = 0; i < inputVerts.vertexCount(); ++i)
154 {
155 if (isVertexInCone(ls1, ls2, origin, inputVerts.vertex(i).template as<2, t_type>()))
156 result.add(i);
157 }
158 return result;
159 }
160
161 static bool checkVisibility(const VertexArray& vertices, uint04 origin, uint04 vertex_to_check)
162 {
163 lib_assert(origin != vertex_to_check, "Bad visibility check");
164 Line ls(vertices.vertex(vertex_to_check).template as<2, t_type>(), vertices.vertex(origin).template as<2, t_type>());
165
166 const uint04 vertex_count = vertices.vertexCount();
167 for (uint04 i = 0; i < vertex_count; ++i)
168 {
169 if (origin == i || ((i + 1) % vertex_count) == origin)
170 continue;
171 if (vertex_to_check == i || ((i + 1) % vertex_count) == vertex_to_check)
172 continue;
173 Line l = vertices.edge(i).template as<2, t_type>();
174 if (intersects(ls, l))
175 return false;
176 }
177 auto center = ls.center();
178 if (!vertices.contains(center))
179 return false;
180 //lib_assert(result.size() >= 1, "Bad intersection");
181 return true;
182 }
183 static uint04 IsReflexPoint(uint04 index, const VertexArray& vertices)
184 {
185 const t_vertex& prevVert = vertices.vertex(mod(cast<sint04>(index - 1), vertices.vertexCount()));
186 const t_vertex& currVert = vertices.vertex(index);
187 const t_vertex& nextVert = vertices.vertex(mod(index + 1, vertices.vertexCount()));
188 return CalcHandedness(prevVert, currVert, nextVert) < 0.0f;
189
190 }
191
192 static uint04 getBestVertexToConnect(const IntArray& indices, const VertexArray& polygonVertices, const Vector<2, t_type>& origin, uint04 origin_index)
193 {
194 uint04 vert_size = polygonVertices.vertexCount();
195
196 t_type min_distance = Constant<t_type>::Max;
198
199 if (indices.size() == 1)
200 {
201 if (checkVisibility(polygonVertices, origin_index, indices[0]))
202 return indices[0];
203 }
204 else if (indices.size() > 1)
205 {
206 //first try all reflex points to potentially eliminate 2 at once
207 for (uint04 i = 0; i < indices.size(); ++i)
208 {
209 if (indices[i] < origin_index)
210 continue;//can't be reflex point
211 if (!IsReflexPoint(indices[i], polygonVertices))
212 continue;
213 if (checkVisibility(polygonVertices, origin_index, indices[i]))
214 {
215 return indices[i];
216 }
217 else
218 {
219 t_type currDistance = distanceSquared(polygonVertices.vertex(i).template as<2, t_type>(), origin);
220 if (currDistance * 1000 < min_distance)
221 {
222 min_distance = currDistance;
223 min = indices[i];
224 }
225 }
226 }
227 for (uint04 i = 0; i < indices.size(); ++i)
228 {
229 if (indices[i] > origin_index && IsReflexPoint(indices[i], polygonVertices))
230 continue;//we already know these aren't visible
231 if (checkVisibility(polygonVertices, origin_index, indices[i]))
232 {
233 return indices[i];
234 }
235 else
236 {
237 t_type currDistance = distanceSquared(polygonVertices.vertex(i).template as<2, t_type>(), origin);
238 if (currDistance * 1000 < min_distance)
239 {
240 min_distance = currDistance;
241 min = indices[i];
242 }
243 }
244 }
245 }
246 uint04 neighbor_a = mod(cast<sint04>(origin_index) - 1, vert_size);
247 uint04 neighbor_b = mod(cast<sint04>(origin_index) + 1, vert_size);
248
249 for (uint04 i = origin_index + 2; i < polygonVertices.vertexCount(); ++i)
250 {
251 if (i == neighbor_a)
252 continue;
253 if (indices.contains(i))
254 continue;
255 if (IsReflexPoint(i, polygonVertices) && checkVisibility(polygonVertices, origin_index, i))
256 return i;
257 }
258
259 for (uint04 i = 0; i < polygonVertices.vertexCount(); ++i)
260 {
261 if (i == origin_index || i == neighbor_a || i == neighbor_b)
262 continue;
263 if (i > origin_index && IsReflexPoint(i, polygonVertices))
264 continue;
265 t_type currDistance = distanceSquared(polygonVertices.vertex(i).template as<2, t_type>(), origin);
266 if (currDistance < min_distance)
267 {
268 if (indices.contains(i))
269 continue;
270 if (checkVisibility(polygonVertices, origin_index, i))
271 {
272 min_distance = currDistance;
273 min = i;
274 }
275 else if(currDistance * 1000 < min_distance)
276 {
277 min_distance = currDistance;
278 min = i;
279 }
280 }
281
282 }
283 //lib_assert(!isNaN(max), "Bad max");
284 return min;
285 }
286
287
288
289 static uint04 findFirstReflexVertex(const VertexArray& _vertices)
290 {
291 lib_assert(checkIfRightHanded(_vertices), "Should be right handed");
292 for (uint04 i = 0; i < _vertices.vertexCount(); ++i)
293 {
294 if (IsReflexPoint(i, _vertices))
295 return i;
296 }
297
299 }
300
301 void flipPolygon()
302 {
303 flipPolygon(vertices);
304 }
305
307 typedef std::pair<int, Vertex<2, fltp08>> VertexIntPair;
308
309
310 public:
311 ConcavePolygon(const VertexArray& _vertices)
312 : vertices{ _vertices }
313 {
314 if (vertices.vertexCount() >= 3)
315 if (checkIfRightHanded() == false)
316 flipPolygon();
317 }
319
321 {
322 return checkIfRightHanded(vertices);
323 }
325 {
327 for (uint04 i = 0; i < vertices.vertexCount(); i++)
328 {
329 bounds.addToBounds(vertices.vertex(i).template as<2, t_type>());
330 }
331 Buffer<VertexArray> sub_polygons_to_process;
332 Buffer<VertexArray> next_sub_polygons_to_process = { vertices };
333 std::mutex mtx;
334 while (next_sub_polygons_to_process.size() > 0)
335 {
336 sub_polygons_to_process.clear();
337 for (uint04 i = 0; i < next_sub_polygons_to_process.size(); i++)
338 {
339 if (next_sub_polygons_to_process[i].vertexCount() > 3)
340 sub_polygons_to_process.add(next_sub_polygons_to_process[i]);
341 else if(next_sub_polygons_to_process[i].vertexCount() == 3)
342 processed_polygons.add(next_sub_polygons_to_process[i]);
343 }
344 next_sub_polygons_to_process.clear();
345 next_sub_polygons_to_process.setSize(2 * sub_polygons_to_process.size());
346 int size = sub_polygons_to_process.size();
347 _parallel_for(int i = 0; i < size; i++)
348 {
349 std::unique_lock<std::mutex> lck(mtx, std::defer_lock);
350 const VertexArray& _vertices = sub_polygons_to_process[cast<uint04>(i)];
351 lib_assert(checkIfRightHanded(_vertices), "undexpected handiness");
352 uint04 reflexIndex = findFirstReflexVertex(_vertices);
353 if (isNaN(reflexIndex))
354 {
355 lib_assert(_vertices.isConvex(), "Should be convex");
356 continue;
357 }
358 Vertex<2, t_type> prevVertPos = _vertices.vertex(mod(cast<sint04>(reflexIndex) - 1, _vertices.vertexCount())).template as<2, t_type>();
359 Vertex<2, t_type> currVertPos = _vertices.vertex(reflexIndex).template as<2, t_type>();
360 Vertex<2, t_type> nextVertPos = _vertices.vertex(mod(reflexIndex + 1, _vertices.vertexCount())).template as<2, t_type>();
361
362 Vector<2, t_type> prev_ray = (currVertPos - prevVertPos);
363 Vector<2, t_type> next_ray = (currVertPos - nextVertPos);
364
365 IntArray vertsInCone = findVerticesInCone(prev_ray, next_ray, currVertPos, _vertices);
366
367 uint04 bestVert = getBestVertexToConnect(vertsInCone, _vertices, currVertPos, reflexIndex);
368 if (isNaN(bestVert))
369 continue;
370 lib_assert(!isNaN(bestVert), "Not sure why this is true");
371 uint04 start = getMin(bestVert, reflexIndex);
372 uint04 end = getMax(bestVert, reflexIndex);
373 next_sub_polygons_to_process[2 * i + 0].addVertices(_vertices.begin(), start + 1);
374 next_sub_polygons_to_process[2 * i + 1].addVertices(_vertices.begin() + start, (end + 1) - start);
375 next_sub_polygons_to_process[2 * i + 0].addVertices(_vertices.begin() + end, _vertices.vertexCount() - end);
376 sub_polygons_to_process[cast<uint04>(i)].clear();//indicate we are finished processing
377
378 //add to polygons
379 lib_assert(next_sub_polygons_to_process[2 * i + 0].vertexCount() > 2, "Bad a size");
380 lib_assert(next_sub_polygons_to_process[2 * i + 1].vertexCount() > 2, "Bad b size");
381 lib_assert(checkIfRightHanded(next_sub_polygons_to_process[2 * i + 0]), "Vertex A not right");
382 lib_assert(checkIfRightHanded(next_sub_polygons_to_process[2 * i + 1]), "Vertex B not right");
383 }
384 //gather all polygons that are convex
385 for (uint04 i = 0; i < sub_polygons_to_process.size(); i++)
386 {
387 if (sub_polygons_to_process[i].vertexCount() > 3)
388 {
389 lib_assert(sub_polygons_to_process[i].isConvex(), "Should be convex");
390 processed_polygons.add(sub_polygons_to_process[i]);
391 }
392 }
393 }
394 }
395
397 {
398 return vertices;
399 }
400
401
403 {
404 returnArr.addAll(processed_polygons);
405 }
406
407 t_vertex getPoint(uint04 index) const
408 {
409 if (index >= 0 && index < vertices.size())
410 return vertices[index];
411 lib_assert(false, "Bad vertex get");
412 return t_vertex(0.0f);
413 }
414
415 int getPointCount() const
416 {
417 return vertices.vertexCount();
418 }
419 };
420
421}
#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
#define _parallel_for
Definition OpenMP.hpp:18
A specification of upper and lower bounds in N-dimensions.
Definition Bounds.hpp:57
constexpr void addToBounds(const t_vertex &vector)
Adds to the bounds such that the new bounds fully encompasses the argument.
Definition Bounds.hpp:498
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
bool contains(const t_type &element) const
Definition Buffer.hpp:674
constexpr t_index_type size() const
Definition Buffer.hpp:1461
void setSize(t_index_type new_size)
Definition Buffer.hpp:1413
void clear()
Definition Buffer.hpp:572
Definition ConcaveToConvexPolygon.h:24
void returnLowestLevelPolys(Buffer< Polygon< t_type, t_vertex >, uint04, ObjectAllocator< false > > &returnArr)
Definition ConcaveToConvexPolygon.h:402
t_vertex getPoint(uint04 index) const
Definition ConcaveToConvexPolygon.h:407
bool checkIfRightHanded()
Definition ConcaveToConvexPolygon.h:320
void convexDecomp()
Definition ConcaveToConvexPolygon.h:324
int getPointCount() const
Definition ConcaveToConvexPolygon.h:415
ConcavePolygon()
Definition ConcaveToConvexPolygon.h:318
const VertexArray & getVertices() const
Definition ConcaveToConvexPolygon.h:396
ConcavePolygon(const VertexArray &_vertices)
Definition ConcaveToConvexPolygon.h:311
Definition Dictionary.h:48
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
constexpr t_vertex center() const
Definition Line.hpp:151
Definition MemoryManager.h:283
An N-sided polygon.
Definition Polygon.hpp:58
LineSegment< 2, t_type, t_vertex > edge(uint04 index) const
Definition Polygon.hpp:185
void flip()
Definition Polygon.hpp:401
bool contains(const Vertex< 2, t_type > &vector) const
Definition Polygon.hpp:515
uint04 vertexCount() const
Definition Polygon.hpp:219
bool hasClockwiseWinding() const
Definition Polygon.hpp:735
decltype(auto) begin()
Definition Polygon.hpp:602
bool isConvex() const
Definition Polygon.hpp:240
const t_vertex & vertex(uint04 index) const
Definition Polygon.hpp:165
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 t_type getMax(const t_type &left, const t_type &right)
Finds the max of the given arguments using the > operator.
Definition BaseFunctions.hpp:116
t_type distanceSquared(const Bounds< t_dims, t_type, t_vertex > &bounds, const Vector< t_dims, t_type > &vertex)
Definition Distance.hpp:42
constexpr Vector< 1, t_type > cross(const Vector< 1, t_type > &, const Vector< 1, t_type > &)
Definition VectorFunctions.hpp:954
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
double fltp08
Defines an alias representing an 8 byte floating-point number.
Definition BaseValues.hpp:181
constexpr t_type getMin(const t_type &left, const t_type &right)
Finds the minimum of the given arguments based on the < operator.
Definition BaseFunctions.hpp:67
Definition BaseValues.hpp:272
Definition ConcaveToConvexPolygon.h:13
SliceVertex()
Definition ConcaveToConvexPolygon.h:14
int index
Definition ConcaveToConvexPolygon.h:18
t_type distanceToSlice
Definition ConcaveToConvexPolygon.h:19
SliceVertex(t_vertex_type const &_position)
Definition ConcaveToConvexPolygon.h:15