MayaFlux 0.2.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches

◆ compute_convex_hull_2d()

std::vector< glm::vec3 > MayaFlux::Kinesis::compute_convex_hull_2d ( const std::vector< glm::vec3 > &  vertices,
const glm::vec3 &  projection_normal = glm::vec3(0, 0, 1) 
)

Compute convex hull of vertex set (2D projection)

Parameters
verticesInput vertex set
projection_normalNormal of projection plane (default: Z-axis)
Returns
Vertices forming convex hull boundary (closed path)

Uses Graham scan on projected coordinates.

Definition at line 459 of file GeometryPrimitives.cpp.

462{
463 if (vertices.size() < 3) {
464 return vertices;
465 }
466
467 glm::vec3 n = glm::normalize(projection_normal);
468 glm::vec3 u;
469
470 if (std::abs(n.z) < 0.9F) {
471 u = glm::normalize(glm::cross(n, glm::vec3(0, 0, 1)));
472 } else {
473 u = glm::normalize(glm::cross(n, glm::vec3(1, 0, 0)));
474 }
475
476 glm::vec3 v = glm::cross(n, u);
477
478 struct Point2D {
479 glm::vec2 pos;
480 size_t index;
481 };
482
483 std::vector<Point2D> points;
484 points.reserve(vertices.size());
485
486 for (size_t i = 0; i < vertices.size(); ++i) {
487 glm::vec3 offset = vertices[i];
488 float x = glm::dot(offset, u);
489 float y = glm::dot(offset, v);
490 points.push_back({ glm::vec2(x, y), i });
491 }
492
493 auto pivot_it = std::ranges::min_element(points,
494 [](const Point2D& a, const Point2D& b) {
495 if (std::abs(a.pos.y - b.pos.y) < 1e-6F) {
496 return a.pos.x < b.pos.x;
497 }
498 return a.pos.y < b.pos.y;
499 });
500
501 std::swap(points[0], *pivot_it);
502 Point2D pivot = points[0];
503
504 std::sort(points.begin() + 1, points.end(),
505 [&pivot](const Point2D& a, const Point2D& b) {
506 glm::vec2 va = a.pos - pivot.pos;
507 glm::vec2 vb = b.pos - pivot.pos;
508
509 float cross = va.x * vb.y - va.y * vb.x;
510 if (std::abs(cross) < 1e-6F) {
511 return glm::length(va) < glm::length(vb);
512 }
513 return cross > 0.0F;
514 });
515
516 // Graham scan
517 std::vector<size_t> hull;
518 hull.push_back(points[0].index);
519 hull.push_back(points[1].index);
520
521 auto ccw = [](const glm::vec2& a, const glm::vec2& b, const glm::vec2& c) {
522 return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x) > 0.0F;
523 };
524
525 for (size_t i = 2; i < points.size(); ++i) {
526 while (hull.size() >= 2) {
527 size_t top = hull.back();
528 size_t second = hull[hull.size() - 2];
529
530 glm::vec2 p1 = points[second].pos;
531 glm::vec2 p2 = points[top].pos;
532 glm::vec2 p3 = points[i].pos;
533
534 if (ccw(p1, p2, p3)) {
535 break;
536 }
537 hull.pop_back();
538 }
539 hull.push_back(points[i].index);
540 }
541
542 std::vector<glm::vec3> result;
543 result.reserve(hull.size() + 1);
544
545 for (size_t idx : hull) {
546 result.push_back(vertices[idx]);
547 }
548
549 result.push_back(vertices[hull[0]]);
550
551 return result;
552}
size_t a
size_t b

References a, and b.