NDEVR
API Documentation
SelectionArea.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: SelectionArea
29Included in API: True
30Author(s): Tyler Parke
31 *-----------------------------------------------------------------------------------------**/
32#pragma once
33#include <NDEVR/LineSegment.h>
34#include <NDEVR/Polygon.h>
35#include <NDEVR/RadialObject.h>
36#include <NDEVR/Bounds.h>
37#include <NDEVR/Matrix.h>
38#include <NDEVR/Intersection.h>
39#include <NDEVR/Plane.h>
40namespace NDEVR
41{
46 {
47 e_selection_point_2D
48 , e_selection_point
49 , e_selection_line
50 , e_selection_polygon
51 , e_selection_bounds
52 , e_selection_plane
53 };
54
58 template<uint01 t_dims, class t_type>
59 class SelectionArea
60 {
61 public:
62 SelectionArea()
63 : m_point(Constant<Vertex<t_dims, t_type>>::Invalid)
64 , m_mode(SelectionMode::e_selection_line)
65 , m_is_pre_transformed(true)
66 , m_is_inverse(false)
67 , m_is_enabled(true)
68 {}
69
70 SelectionArea(const SelectionArea& area)
71 : m_matrix(area.m_matrix)
72 , m_inverse_matrix(area.m_inverse_matrix)
73 , m_mode(area.m_mode)
74 , m_is_pre_transformed(area.m_is_pre_transformed)
75 , m_is_inverse(area.m_is_inverse)
76 , m_is_enabled(area.m_is_enabled)
77 {
78 switch(m_mode)
79 {
80 case e_selection_point_2D:
81 case e_selection_point: m_point = area.m_point; break;
82 case e_selection_line: m_line = area.m_line; break;
83 case e_selection_bounds: m_bounds = area.m_bounds; break;
84 case e_selection_polygon: new (&m_polygon) Polygon<t_type>(area.m_polygon); break;
85 case e_selection_plane: m_plane = area.m_plane; break;
86 default: lib_assert(false, "unknown selection copy");
87 }
88 }
89 SelectionArea(const Vertex<t_dims, t_type>& point)
90 : m_point(point)
91 , m_mode(e_selection_point)
92 , m_is_pre_transformed(true)
93 , m_is_inverse(false)
94 , m_is_enabled(true)
95 {}
96 SelectionArea(const LineSegment<t_dims, t_type>& segment)
97 : m_line(segment)
98 , m_mode(e_selection_line)
99 , m_is_pre_transformed(true)
100 , m_is_inverse(false)
101 , m_is_enabled(true)
102 {}
103
104 SelectionArea(const Polygon<t_type>& poly)
105 : m_polygon(poly)
106 , m_mode(e_selection_polygon)
107 , m_is_pre_transformed(true)
108 , m_is_inverse(false)
109 , m_is_enabled(true)
110 {}
111
112 SelectionArea(Polygon<t_type>&& poly)
113 : m_polygon(std::move(poly))
114 , m_mode(e_selection_polygon)
115 , m_is_pre_transformed(true)
116 , m_is_inverse(false)
117 , m_is_enabled(true)
118 {}
119
120 SelectionArea(const Bounds<t_dims, t_type>& bounds)
121 : m_bounds(bounds)
122 , m_mode(e_selection_bounds)
123 , m_is_pre_transformed(true)
124 , m_is_inverse(false)
125 , m_is_enabled(true)
126 {}
127
128 SelectionArea(const Plane<t_dims, t_type>& plane)
129 : m_plane(plane)
130 , m_mode(e_selection_plane)
131 , m_is_pre_transformed(true)
132 , m_is_inverse(false)
133 , m_is_enabled(true)
134 {}
135
136 SelectionArea& operator=(const SelectionArea& area)
137 {
138 cleanup();
139 m_mode = area.m_mode;
140 switch(m_mode)
141 {
142 case e_selection_point_2D:
143 case e_selection_point: m_point = area.m_point; break;
144 case e_selection_line: m_line = area.m_line; break;
145 case e_selection_bounds: m_bounds = area.m_bounds; break;
146 case e_selection_polygon: new (&m_polygon) Polygon<t_type>(area.m_polygon); break;
147 case e_selection_plane: m_plane = area.m_plane; break;
148 default: lib_assert(false, "unknown selection copy");
149 }
150 m_is_inverse = area.m_is_inverse;
151 m_is_pre_transformed = area.m_is_pre_transformed;
152 m_matrix = area.m_matrix;
153 m_inverse_matrix = area.m_inverse_matrix;
154 m_is_enabled = area.m_is_enabled;
155 return *this;
156 }
157 ~SelectionArea()
158 {
159 cleanup();
160 }
161 void setSelection(const Vertex<2, t_type>& point)
162 {
163 cleanup();
164 m_mode = e_selection_point_2D;
165 m_point = point.template as<t_dims, t_type>(cast<t_type>(1));
166 }
167 void setSelection(const Vertex<t_dims, t_type>& point)
168 {
169 cleanup();
170 m_mode = e_selection_point;
171 m_point = point;
172 }
173
174 void setSelection(const LineSegment<t_dims, t_type>& segment)
175 {
176 cleanup();
177 m_mode = e_selection_line;
178 m_line = segment;
179 }
180
181 void setSelection(const Polygon<t_type>& poly)
182 {
183 cleanup();
184 m_mode = e_selection_polygon;
185 new (&m_polygon) Polygon<t_type>(poly);
186 }
187
188 void setSelection(Polygon<t_type>&& poly)
189 {
190 cleanup();
191 m_mode = e_selection_polygon;
192 new (&m_polygon) Polygon<t_type>();
193 std::swap(poly, m_polygon);
194 }
195
196 void setSelection(const Bounds<t_dims, t_type>& bounds)
197 {
198 cleanup();
199 m_mode = e_selection_bounds;
200 m_bounds = bounds;
201 }
202
203 void setSelection(const Plane<t_dims, t_type>& plane)
204 {
205 cleanup();
206 m_mode = e_selection_plane;
207 m_plane = plane;
208 }
209 SelectionMode mode() const { return m_mode; }
210
211 const Vertex<t_dims, t_type>& point() const { return m_point; }
212 Vertex<t_dims, t_type>& point() { return m_point; }
213
214 Vertex<2, t_type> point2D() const { return m_point.template as<2, t_type>(); }
215
216 const LineSegment<t_dims, t_type>& line() const { return m_line; }
217 LineSegment<t_dims, t_type>& line() { return m_line; }
218
219 const Bounds<t_dims, t_type>& bounds() const { return m_bounds; }
220 Bounds<t_dims, t_type>& bounds() { return m_bounds; }
221
222 const Polygon<t_type>& polygon() const { return m_polygon; }
223 Polygon<t_type>& polygon() { return m_polygon; }
224
225 const Plane<t_dims, t_type>& plane() const { return m_plane; }
226 Plane<t_dims, t_type>& plane() { return m_plane; }
227
228
229
230 void setTransform(const Matrix<t_type>& matrix)
231 {
232 m_matrix = matrix;
233 m_inverse_matrix = matrix.invert();
234 m_is_pre_transformed = (matrix == Matrix<t_type>(1.0));
235 }
236 const Matrix<t_type>& transform() const
237 {
238 return m_matrix;
239 }
240 const Matrix<t_type>& inverseTransform() const
241 {
242 return m_inverse_matrix;
243 }
244 Bounds<t_dims, t_type> selectionBounds() const
245 {
246 switch (m_mode)
247 {
248 case e_selection_point_2D:
249 case e_selection_point: return Bounds<t_dims, t_type>(m_point);
250 case e_selection_line: return Bounds<t_dims, t_type>(m_line);
251 case e_selection_bounds: return m_bounds;
252 case e_selection_polygon: return m_polygon.bounds().template as<t_dims, t_type>();
253 case e_selection_plane:
254 {
256 for (uint01 dim = 0; dim < t_dims; dim++)
257 {
258 if (m_plane.normal[dim] == 1)
259 bounds[dim][MAX] = bounds[dim][MIN] = m_plane.d;
260 else if (m_plane.normal[dim] == -1)
261 bounds[dim][MAX] = bounds[dim][MIN] = -m_plane.d;
262 }
263 return bounds;
264 }
265 default: lib_assert(false, "Unknown selection area mode in as()"); break;
266 }
267 return Constant<Bounds<t_dims, t_type>>::Invalid;
268 }
269
270 template<uint01 t_new_dims, class t_new_type>
271 SelectionArea<t_new_dims, t_new_type> as() const
272 {
273 SelectionArea<t_new_dims, t_new_type> new_selection;
274 switch (m_mode)
275 {
276 case e_selection_point_2D:
277 new_selection.setSelection(m_point.template as<2, t_new_type>());
278 new_selection.set2DDistanceCutoff(cast<t_new_type>(m_point[Z]));
279 break;
280 case e_selection_point: new_selection.setSelection(m_point.template as<t_new_dims, t_new_type>()); break;
281 case e_selection_line: new_selection.setSelection(m_line.template as<t_new_dims, t_new_type>()); break;
282 case e_selection_bounds: new_selection.setSelection(m_bounds.template as<t_new_dims, t_new_type>()); break;
283 case e_selection_polygon: new_selection.setSelection(m_polygon.template as<t_new_type>()); break;
284 case e_selection_plane: new_selection.setSelection(m_plane.template as<t_new_dims, t_new_type>()); break;
285 default: lib_assert(false, "Unknown selection area mode in as()"); break;
286 }
287 new_selection.setTransform(m_matrix.template as<t_new_type>());
288 new_selection.setIsInverse(m_is_inverse);
289 new_selection.setIsEnabled(m_is_enabled);
290 return new_selection;
291 }
292 bool isPreTransformed() const
293 {
294 return m_is_pre_transformed;
295 }
296 template<uint01 t_new_dims, class t_new_type>
297 SelectionArea<t_new_dims, t_new_type> preTransformed() const
298 {
299 SelectionArea<t_new_dims, t_new_type> area;
300 if (sizeof(t_new_type) > sizeof(t_type))
301 {
302 Matrix<t_new_type> matrix = m_matrix.template as<t_new_type>().invert();
303
304 switch (m_mode)
305 {
306 case e_selection_point_2D:
307 {
308 Vertex<3, t_new_type> p(matrix * m_point.template as<t_new_dims, t_new_type>());
309 setSelection(p.template as<2, t_new_type>());
310 set2DDistanceCutoff(p[Z]);
311 } break;
312 area.setSelection((matrix * m_point.template as<t_new_dims, t_new_type>()).template as<2, t_new_type>()); break;
313 case e_selection_point: area.setSelection(matrix * m_point.template as<t_new_dims, t_new_type>()); break;
314 case e_selection_line: area.setSelection(matrix * m_line.template as<t_new_dims, t_new_type>()); break;
315 case e_selection_bounds: area.setSelection(matrix * m_bounds.template as<t_new_dims, t_new_type>()); break;
316 case e_selection_polygon: area.setSelection(matrix * m_polygon.template as<t_new_type>()); break;
317 default: lib_assert(false, "Unknown object to pre-transform");
318 }
319 }
320 else//we want higher precision so multiply first
321 {
322 Matrix<t_type> matrix = m_matrix.invert();
323 switch (m_mode)
324 {
325 case e_selection_point_2D:
326 {
327 Vertex<3, t_new_type> p = (matrix * m_point).template as<t_new_dims, t_new_type>();
328 setSelection(p.template as<2, t_new_type>());
329 set2DDistanceCutoff(p[Z]);
330 } break;
331 case e_selection_point: area.setSelection((matrix * m_point).template as<t_new_dims, t_new_type>()); break;
332 case e_selection_line: area.setSelection((matrix * m_line).template as<t_new_dims, t_new_type>()); break;
333 case e_selection_bounds: area.setSelection((matrix * m_bounds).template as<t_new_dims, t_new_type>()); break;
334 case e_selection_polygon: area.setSelection((matrix * m_polygon).template as<t_new_type>()); break;
335 default: lib_assert(false, "Unknown object to pre-transform");
336 }
337 }
338 area.setIsEnabled(m_is_enabled);
339 area.setIsInverse(m_is_inverse);
340 return area;
341 }
342
343 void preTransform(const Matrix<t_type>& mat)
344 {
345 switch (m_mode)
346 {
347 case e_selection_point_2D:
348 {
349 Vertex<3, t_type> p = (mat * m_point);
350 setSelection(p.template as<2, t_type>());
351 set2DDistanceCutoff(p[Z]);
352 } break;
353 case e_selection_point: setSelection(mat * m_point); break;
354 case e_selection_line: setSelection(mat * m_line); break;
355 case e_selection_bounds: setSelection(mat * m_bounds); break;
356 case e_selection_polygon: setSelection(mat * m_polygon); break;
357 default: lib_assert(false, "Unknown object to pre-transform");
358 }
359 }
360 bool isInverse() const
361 {
362 return m_is_inverse;
363 }
364 void setIsInverse(bool is_inverse)
365 {
366 m_is_inverse = is_inverse;
367 }
368 bool isEnabled() const
369 {
370 return m_is_enabled;
371 }
372 void setIsEnabled(bool is_enabled)
373 {
374 m_is_enabled = is_enabled;
375 }
376 void set2DDistanceCutoff(t_type distance)
377 {
378 m_point[Z] = distance;
379 }
380 bool check2DBounds(const Bounds<3, t_type>& point) const
381 {
382 if (point[MIN][Z] > m_point[Z])
383 return false;
384 if (point[MAX][Z] < cast<t_type>(0))
385 return false;
386 for (uint01 i = 0; i < 2; i++)
387 {
388 if (point[MAX][i] < cast<t_type>(-1))
389 return false;
390 if (point[MIN][i] > cast<t_type>(1))
391 return false;
392 }
393 return true;
394 }
395 bool check2DBounds(const Vector<3, t_type>& point) const
396 {
397 if (point[Z] > m_point[Z])
398 return false;
399 if (point[Z] < cast<t_type>(0))
400 return false;
401 for (uint01 i = 0; i < 2; i++)
402 {
403 if (point[i] < cast<t_type>(-1))
404 return false;
405 if (point[i] > cast<t_type>(1))
406 return false;
407 }
408 return true;
409 }
410 bool check2DBounds(const LineSegment<3, t_type>& seg) const
411 {
412 if (seg[A][Z] > m_point[Z] && seg[B][Z] > m_point[Z])
413 return false;
414 if (seg[A][Z] < cast<t_type>(0) && seg[B][Z] < cast<t_type>(0))
415 return false;
416 return true;
417 }
418 bool check2DBounds(const Triangle<3, t_type>& seg) const
419 {
420 if (seg[A][Z] > m_point[Z] && seg[B][Z] > m_point[Z] && seg[C][Z] > m_point[Z])
421 return false;
422 if (seg[A][Z] < cast<t_type>(0) && seg[B][Z] < cast<t_type>(0) && seg[C][Z] < cast<t_type>(0))
423 return false;
424 return true;
425 }
426 template<class t_other_type>
427 bool check2DContains(const t_other_type&) const
428 {
429 return false;
430 }
431 bool check2DContains(const Triangle<2, t_type>& seg) const
432 {
433 return seg.contains(m_point.template as<2, t_type>());
434 }
435 bool operator==(const SelectionArea& area) const
436 {
437 if(m_mode != area.m_mode)
438 return false;
439 switch(m_mode)
440 {
441
442 case SelectionMode::e_selection_bounds:
443 if(m_bounds != area.m_bounds)
444 return false;
445 break;
446 case SelectionMode::e_selection_line:
447 if(m_line != area.m_line)
448 return false;
449 break;
450 case SelectionMode::e_selection_polygon:
451 if(m_polygon != area.m_polygon)
452 return false;
453 break;
454 case SelectionMode::e_selection_point_2D:
455 case SelectionMode::e_selection_point:
456 if(m_point != area.m_point)
457 return false;
458 break;
459 case SelectionMode::e_selection_plane:
460 if (m_plane != area.m_plane)
461 return false;
462 break;
463 default:
464 lib_assert(false, "unknown selection mode");
465 }
466 return m_matrix == area.m_matrix;
467 }
468 bool operator!=(const SelectionArea& area) const
469 {
470 if(m_mode != area.m_mode)
471 return true;
472 switch(m_mode)
473 {
474 case SelectionMode::e_selection_bounds:
475 if(m_bounds != area.m_bounds)
476 return true;
477 break;
478 case SelectionMode::e_selection_line:
479 if(m_line != area.m_line)
480 return true;
481 break;
482 case SelectionMode::e_selection_polygon:
483 if(m_polygon != area.m_polygon)
484 return false;
485 break;
486 case SelectionMode::e_selection_point_2D:
487 case SelectionMode::e_selection_point:
488 if(AreSame(m_point, area.m_point))
489 return true;
490 break;
491 case SelectionMode::e_selection_plane:
492 if (m_plane != area.m_plane)
493 return true;
494 break;
495 default:
496 lib_assert(false, "unknown selection mode");
497 }
498 return m_matrix != area.m_matrix;
499 }
500 protected:
501 void cleanup()
502 {
503 if(m_mode == e_selection_polygon)
504 {
505 m_polygon.~Polygon<t_type>();
506 m_mode = e_selection_point;
507 }
508 }
509 protected:
510 Matrix<t_type> m_matrix = Matrix<t_type>(1);
511 Matrix<t_type> m_inverse_matrix = Matrix<t_type>(1);
512 union
513 {
516 Bounds<t_dims, t_type> m_bounds;
517 Polygon<t_type> m_polygon;
518 Plane<t_dims, t_type> m_plane;
519 };
520 SelectionMode m_mode;
521 bool m_is_pre_transformed;
522 bool m_is_inverse;
523 bool m_is_enabled;
524 };
525
539 template<class t_other_type, uint01 t_dims, class t_type>
540 IntersectionTypes classify(const t_other_type& other, const SelectionArea<t_dims, t_type>& area)
541 {
542 if(!area.isEnabled())
543 {
544 if(area.isInverse())
545 return IntersectionTypes::e_inside;
546 else
547 return IntersectionTypes::e_outside;
548 }
549 //t_other_type trans_other = area.isPreTransformed() ? other : area.transform() * other;
551 if (area.isPreTransformed())
552 {
553 switch (area.mode())
554 {
555 case e_selection_line:
556 intersection = classify(other, area.line());
557 break;
558 case e_selection_bounds:
559 intersection = classify(other, area.bounds());
560 break;
561 case e_selection_polygon:
562 intersection = classify(other, area.polygon());
563 break;
564 case e_selection_plane:
565 intersection = classify(other, area.plane());
566 break;
567 default:
568 lib_assert(false, "unknown intersection");
569 intersection = IntersectionTypes::e_outside;
570 break;
571 }
572 }
573 else
574 {
575 switch (area.mode())
576 {
577 case e_selection_line:
578 intersection = classify(other, area.inverseTransform() * area.line());
579 break;
580 case e_selection_bounds:
581 intersection = classify(other, area.inverseTransform() * area.bounds());
582 break;
583 case e_selection_polygon:
584 intersection = classify(area.transform() * other, area.polygon());
585 break;
586 case e_selection_plane:
587 intersection = classify(other, area.inverseTransform() * area.plane());
588 break;
589 default:
590 lib_assert(false, "unknown intersection");
591 intersection = IntersectionTypes::e_outside;
592 break;
593 }
594 }
595 if(area.isInverse())
596 {
597 switch(intersection)
598 {
599 case IntersectionTypes::e_outside: intersection = IntersectionTypes::e_inside; break;
600 case IntersectionTypes::e_inside: intersection = IntersectionTypes::e_outside; break;
601 default: break;
602 }
603 }
604 return intersection;
605 }
606 template<uint01 t_dims, class t_type, class t_other_type>
607 IntersectionTypes LineSelectionClassifyOther(const SelectionArea<t_dims, t_type>& area, const t_other_type& other)
608 {
609 return classify(area.line(), area.transform() * other);
610 }
611 template<uint01 t_dims, class t_type>
612 IntersectionTypes LineSelectionClassifyOther(const SelectionArea<t_dims, t_type>& area, const Bounds<t_dims, t_type>& other)
613 {
614 return classify(area.inverseTransform() * area.line(), other);
615 }
616 template<uint01 t_dims, class t_type>
617 IntersectionTypes LineSelectionClassifyOther(const SelectionArea<t_dims, t_type>& area, const Triangle<t_dims, t_type>& other)
618 {
619 return classify(area.inverseTransform() * area.line(), other);
620 }
621 template<class t_other_type, uint01 t_dims, class t_type>
622 IntersectionTypes classify(const SelectionArea<t_dims, t_type>& area, const t_other_type& other)
623 {
624 if(!area.isEnabled())
625 {
626 if(area.isInverse())
627 return IntersectionTypes::e_inside;
628 else
629 return IntersectionTypes::e_outside;
630 }
631 IntersectionTypes intersection = IntersectionTypes::e_outside;
632 if (area.isPreTransformed())
633 {
634 switch (area.mode())
635 {
636 case e_selection_point_2D:
637 intersection = classify(area.point2D(), other.template as<2, t_type>());
638 break;
639 case e_selection_point:
640 intersection = classify(area.point(), other);
641 break;
642 case e_selection_line:
643 intersection = classify(area.line(), other);
644 break;
645 case e_selection_bounds:
646 intersection = classify(area.bounds(), other);
647 break;
648 case e_selection_polygon:
649 intersection = classify(area.polygon(), other.template as<2, t_type>());
650 break;
651 case e_selection_plane:
652 intersection = classify(area.plane(), other);
653 break;
654 default:
655 lib_assert(false, "unknown selection");
656 break;
657 }
658 }
659 else
660 {
661 switch (area.mode())
662 {
663 case e_selection_point_2D:
664 intersection = classify(area.point2D(), (area.transform() * other).template as<2, t_type>());
665 break;
666 case e_selection_point:
667 intersection = classify(area.inverseTransform() * area.point(), other);
668 break;
669 case e_selection_line:
670 intersection = LineSelectionClassifyOther(area, other);
671 break;
672 case e_selection_bounds:
673 intersection = classify(area.bounds(), area.transform() * other);
674 break;
675 case e_selection_polygon:
676 intersection = classify(area.polygon(), (area.transform() * other).template as<2, t_type>());
677 break;
678 case e_selection_plane:
679 intersection = classify(area.plane(), area.transform() * other);
680 break;
681 default:
682 break;
683 }
684 }
685 if (area.isInverse())
686 {
687 switch (intersection)
688 {
689 case IntersectionTypes::e_outside: intersection = IntersectionTypes::e_inside; break;
690 case IntersectionTypes::e_inside: intersection = IntersectionTypes::e_outside; break;
691 default: break;
692 }
693 }
694 return intersection;
695 }
696
697 template<uint01 t_dims, class t_type>
698 IntersectionTypes classify(const SelectionArea<t_dims, t_type>& area, const Bounds<3, t_type>& other)
699 {
700 if (!area.isEnabled())
701 {
702 if (area.isInverse())
703 return IntersectionTypes::e_inside;
704 else
705 return IntersectionTypes::e_outside;
706 }
707 IntersectionTypes intersection = IntersectionTypes::e_outside;
708 if (area.isPreTransformed())
709 {
710 switch (area.mode())
711 {
712 case e_selection_point_2D:
713 intersection = classify(area.point2D(), other.template as<2, t_type>());
714 break;
715 case e_selection_point:
716 intersection = classify(area.point(), other);
717 break;
718 case e_selection_line:
719 intersection = classify(area.line(), other);
720 break;
721 case e_selection_bounds:
722 intersection = classify(area.bounds(), other);
723 break;
724 case e_selection_polygon:
725 intersection = classify(area.polygon(), other.template as<2, t_type>());
726 break;
727 case e_selection_plane:
728 intersection = classify(area.plane(), other);
729 break;
730 default:
731 lib_assert(false, "unknown selection");
732 break;
733 }
734 }
735 else
736 {
737 Bounds<3, t_type> bounds = TransformBoundsAndClipNearPlane(other, area.transform());
738 switch (area.mode())
739 {
740 case e_selection_point_2D:
741 if (!area.check2DBounds(bounds))
742 intersection = IntersectionTypes::e_outside;
743 else
744 intersection = classify(area.point2D(), bounds.template as<2, t_type>());
745 break;
746 case e_selection_point:
747 intersection = classify(area.point(), bounds);
748 break;
749 case e_selection_line:
750 intersection = classify(area.line(), bounds);
751 break;
752 case e_selection_bounds:
753 intersection = classify(area.bounds(), bounds);
754 break;
755 case e_selection_polygon:
756 intersection = classify(area.polygon(), bounds.template as<2, t_type>());
757 break;
758 case e_selection_plane:
759 intersection = classify(area.plane(), bounds);
760 break;
761 default:
762 break;
763 }
764 }
765 if (area.isInverse())
766 {
767 switch (intersection)
768 {
769 case IntersectionTypes::e_outside: intersection = IntersectionTypes::e_inside; break;
770 case IntersectionTypes::e_inside: intersection = IntersectionTypes::e_outside; break;
771 default: break;
772 }
773 }
774 return intersection;
775 }
776 template<class t_other_type, uint01 t_dims, class t_type>
777 constexpr t_type distanceSquared(const t_other_type& other, const SelectionArea<t_dims, t_type>& area)
778 {
779 return distanceSquared(area, other);
780 }
781 template<uint01 t_dims, class t_type>
782 constexpr t_type distanceSquared(const SelectionArea<t_dims, t_type>& area, const Bounds<3, t_type>& other)
783 {
784 if (area.isPreTransformed())
785 {
786 switch (area.mode())
787 {
788 case e_selection_point_2D:
789 return distanceSquared(area.point2D(), other.template as<2, t_type>());
790 case e_selection_point:
791 return distanceSquared(area.point(), other);
792 case e_selection_line:
793 return distanceSquared(area.line(), other);
794 case e_selection_polygon:
795 return distanceSquared(area.polygon(), other);
796 case e_selection_bounds:
797 return distanceSquared(area.bounds(), other);
798 case e_selection_plane:
799 //distanceSquared(area.radius(), n_vertex);
800 break;
801 }
802 }
803 else
804 {
805 Bounds<3, t_type> bounds = TransformBoundsAndClipNearPlane(other, area.transform());
806 switch (area.mode())
807 {
808 case e_selection_point_2D:
809 if (!area.check2DBounds(bounds))
810 return Constant<t_type>::Max;
811 return distanceSquared(area.point2D(), bounds.template as<2, t_type>());
812 case e_selection_point:
813 return distanceSquared(area.point(), bounds);
814 case e_selection_line:
815 return distanceSquared(area.line(), bounds);
816 case e_selection_polygon:
817 return distanceSquared(area.polygon(), bounds);
818 case e_selection_bounds:
819 return distanceSquared(area.bounds(), bounds);
820 case e_selection_plane:
821 //distanceSquared(area.radius(), n_vertex);
822 break;
823 }
824 }
825 return Constant<t_type>::Max;
826 }
827 template<class t_other_type, uint01 t_dims, class t_type>
828 constexpr t_type distanceSquared(const SelectionArea<t_dims, t_type>& area, const t_other_type& other)
829 {
830 if (area.isPreTransformed())
831 {
832 switch (area.mode())
833 {
834 case e_selection_point_2D:
835 if (!area.check2DBounds(other))
836 return Constant<t_type>::Max;
837 return distanceSquared(area.point2D(), other.template as<2, t_type>());
838 case e_selection_point:
839 return distanceSquared(area.point(), other);
840 case e_selection_line:
841 return distanceSquared(area.line(), other);
842 case e_selection_polygon:
843 return distanceSquared(area.polygon(), other);
844 case e_selection_bounds:
845 return distanceSquared(area.bounds(), other);
846 case e_selection_plane:
847 //distanceSquared(area.radius(), n_vertex);
848 break;
849 }
850 }
851 else
852 {
853 t_other_type t_other(area.transform() * other);
854 switch (area.mode())
855 {
856 case e_selection_point_2D:
857 {
858 if (!area.check2DBounds(t_other))
859 return Constant<t_type>::Max;
860 auto t_flat_other = t_other.template as<2, t_type>();
861 if (area.check2DContains(t_flat_other))
862 return t_type(0);
863 return distanceSquared(area.point2D(), t_flat_other);
864 } break;
865 case e_selection_point:
866 return distanceSquared(area.point(), t_other);
867 case e_selection_line:
868 return distanceSquared(area.line(), t_other);
869 case e_selection_polygon:
870 return distanceSquared(area.polygon(), t_other);
871 case e_selection_bounds:
872 return distanceSquared(area.bounds(), t_other);
873 case e_selection_plane:
874 //distanceSquared(area.radius(), n_vertex);
875 break;
876 }
877 }
878 return Constant<t_type>::Max;
879 }
880
881}
A specification of upper and lower bounds in N-dimensions.
Definition Bounds.hpp:54
Class: LineSegment.
Definition Line.hpp:52
Templated logic for doing matrix multiplication.
Definition Matrix.hpp:182
Logic for a given plane or N-dimensions.
Definition Plane.hpp:53
An N-sided polygon.
Definition Polygon.hpp:55
An area of N-dimensional space that is considered selected.
A three-vertex polygon representing a triangle in N-dimensional space.
Definition Triangle.hpp:142
constexpr bool contains(const Vector< t_dims - 1, t_type > &p) const
Definition Triangle.hpp:447
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.
Bounds< 3, t_type > TransformBoundsAndClipNearPlane(const Bounds< 3, t_type, t_vertex > &bounds, const Matrix< t_type, 4, 4 > &m)
Transforms 3D bounds by a 4x4 matrix and clips edges against the near plane (w=0).
SelectionMode
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.
uint8_t uint01
-Defines an alias representing a 1 byte, unsigned integer -Can represent exact integer values 0 throu...
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...