From bfb0104bd1e63ad79b504db90cb7421529b8825f Mon Sep 17 00:00:00 2001 From: Erica Fischer Date: Fri, 22 Dec 2023 12:19:04 -0800 Subject: [PATCH] Sketch of finding intersections by bubbling --- polygon.cpp | 149 ++++++++++++++++++++++++++-------------------------- 1 file changed, 74 insertions(+), 75 deletions(-) diff --git a/polygon.cpp b/polygon.cpp index e714ee40..310a6c1f 100644 --- a/polygon.cpp +++ b/polygon.cpp @@ -58,7 +58,7 @@ bool spindle_visible(segment const &seg, long long extent) { } } -bool fix_opposites(std::vector &segs, std::set &affected, long long extent) { +bool fix_opposites(std::vector &segs, long long extent) { bool changed = false; std::multimap opposites; segment erased = std::make_pair(point(INT_MAX, INT_MAX), point(INT_MAX, INT_MAX)); @@ -92,8 +92,6 @@ bool fix_opposites(std::vector &segs, std::set &affected, long segs.emplace_back(point(cx, cy), segs[i].second); segs[i] = std::make_pair(segs[i].first, point(cx, cy)); - affected.insert(segs[i]); - affected.insert(segs.back()); changed = true; // segs[i] is not erased, so segs[f.first->second] @@ -165,21 +163,19 @@ std::pair get_line_intersection(long long p0_x, long long p0_y, return SAME_SLOPE; } -bool vertical(std::vector &segs, size_t s, long long y, std::set &affected) { +bool vertical(std::vector &segs, size_t s, long long y) { if ((y > segs[s].first.y && y < segs[s].second.y) || (y > segs[s].second.y && y < segs[s].first.y)) { segs.push_back(std::make_pair(point(segs[s].first.x, y), segs[s].second)); segs[s] = std::make_pair(segs[s].first, point(segs[s].first.x, y)); - affected.insert(segs[s]); - affected.insert(segs.back()); return true; } return false; } -bool horizontal(std::vector &segs, size_t s, long long x, std::set &affected) { +bool horizontal(std::vector &segs, size_t s, long long x) { if ((x > segs[s].first.x && x < segs[s].second.x) || (x > segs[s].second.x && x < segs[s].first.x)) { double slope = (segs[s].second.y - segs[s].first.y) / @@ -188,15 +184,13 @@ bool horizontal(std::vector &segs, size_t s, long long x, std::set &segs, size_t s1, size_t s2, std::set &affected) { +bool intersect_collinear(std::vector &segs, size_t s1, size_t s2) { bool changed = false; if (segs[s1].first.x == segs[s1].second.x) { @@ -208,16 +202,16 @@ bool intersect_collinear(std::vector &segs, size_t s1, size_t s2, std:: if (segs[s1].first.x == segs[s2].first.x) { // collinear, not parallel - if (vertical(segs, s1, segs[s2].first.y, affected)) { + if (vertical(segs, s1, segs[s2].first.y)) { changed = true; } - if (vertical(segs, s1, segs[s2].second.y, affected)) { + if (vertical(segs, s1, segs[s2].second.y)) { changed = true; } - if (vertical(segs, s2, segs[s1].first.y, affected)) { + if (vertical(segs, s2, segs[s1].first.y)) { changed = true; } - if (vertical(segs, s2, segs[s1].second.y, affected)) { + if (vertical(segs, s2, segs[s1].second.y)) { changed = true; } } @@ -244,16 +238,16 @@ bool intersect_collinear(std::vector &segs, size_t s1, size_t s2, std:: if (y1 == y2) { // collinear, not parallel - if (horizontal(segs, s1, segs[s2].first.x, affected)) { + if (horizontal(segs, s1, segs[s2].first.x)) { changed = true; } - if (horizontal(segs, s1, segs[s2].second.x, affected)) { + if (horizontal(segs, s1, segs[s2].second.x)) { changed = true; } - if (horizontal(segs, s2, segs[s1].first.x, affected)) { + if (horizontal(segs, s2, segs[s1].first.x)) { changed = true; } - if (horizontal(segs, s2, segs[s1].second.x, affected)) { + if (horizontal(segs, s2, segs[s1].second.x)) { changed = true; } } @@ -269,7 +263,7 @@ bool intersect_collinear(std::vector &segs, size_t s1, size_t s2, std:: return changed; } -bool intersect(std::vector &segs, size_t s1, size_t s2, std::set &affected) { +bool intersect(std::vector &segs, size_t s1, size_t s2) { auto intersections = get_line_intersection(segs[s1].first.x, segs[s1].first.y, segs[s1].second.x, segs[s1].second.y, segs[s2].first.x, segs[s2].first.y, @@ -289,8 +283,6 @@ bool intersect(std::vector &segs, size_t s1, size_t s2, std::set &segs, size_t s1, size_t s2, std::set &segs, size_t s1, size_t s2, std::set const &segs, size_t seg, long long y) { + return 0; +} + void snap_round(std::vector &segs, long long extent) { bool again = true; - // affected is indexed by segment instead of just segment index - // because fix_opposites() causes renumbering - std::set affected; - while (again) { again = false; - std::set previously_affected = affected; - affected.clear(); // find identical opposite-winding segments and adjust for them // @@ -356,75 +349,81 @@ void snap_round(std::vector &segs, long long extent) { // in the course of trying to keep spindles alive, and will then need to // resolve those. - if (fix_opposites(segs, affected, extent)) { + if (fix_opposites(segs, extent)) { again = true; } // set up for a scanline traversal of the segments // to find the pairs that intersect // while not looking at pairs that can't possibly intersect + // index by y coordinates - // index by rounded y coordinates, since we will be - // intersecting with rounded coordinates - - std::vector tops; - std::vector bottoms; + std::vector transitions; for (size_t i = 0; i < segs.size(); i++) { if (segs[i].first.y < segs[i].second.y) { - tops.emplace_back(segs[i].first.y, i); - bottoms.emplace_back(segs[i].second.y, i); + transitions.emplace_back(segs[i].first.y, -1, i); // top + transitions.emplace_back(segs[i].second.y, 1, i); // bottom + } else if (segs[i].first.y > segs[i].second.y) { + transitions.emplace_back(segs[i].second.y, -1, i); // top + transitions.emplace_back(segs[i].first.y, 1, i); // bottom } else { - tops.emplace_back(segs[i].second.y, i); - bottoms.emplace_back(segs[i].first.y, i); + transitions.emplace_back(segs[i].first.y, 0, i); // horizontal } } - std::sort(tops.begin(), tops.end()); - std::sort(bottoms.begin(), bottoms.end()); + std::sort(transitions.begin(), transitions.end()); // do the scan - std::set active; - size_t bottom = 0; + std::vector> active; - for (size_t i = 0; i < tops.size(); i++) { - // activate anything that is coming into view. + size_t i = 0; + while (i < transitions.size()) { + long long y = transitions[i].y; - active.insert(tops[i].segment); - // fprintf(stderr, "into scope: %zu at %lld\n", tops[i].segment, tops[i].y); + // update the active positions to correspond to the new Y coordinate - // compare anything coming into view with the other - // currently-active segments + for (size_t j = 0; j < active.size(); j++) { + active[j].first = xcoord(segs, active[j].second, y); + } - for (size_t s2 : active) { - size_t s1 = tops[i].segment; + // are they still in order? - if (s1 != s2) { - if (previously_affected.size() == 0 || // first time - previously_affected.count(segs[s1]) > 0 || - previously_affected.count(segs[s2]) > 0) { - // fprintf(stderr, "check %zu vs %zu\n", s1, s2); - if (intersect(segs, s1, s2, affected)) { - // if the segments intersected, - // we need to do another scan, - // because introducing a new node - // may have caused new intersections - again = true; - } + for (size_t j = 0; j < active.size(); j++) { + for (size_t k = j; k + 1 < active.size() && active[k].first > active[k + 1].first; k++) { + // no, they are out of order. bubble them into order, + // and check where the intersection was at each step + + std::swap(active[k], active[k + 1]); + if (intersect(segs, active[k].second, active[k + 1].second)) { + again = true; + } else { + fprintf(stderr, "can't happen: they don't actually intersect?\n"); + exit(EXIT_IMPOSSIBLE); } } } - // deactivate anything that is going out of view + // activate any new tops at this y coordinate - if (i + 1 < tops.size()) { - while (bottom < bottoms.size() && bottoms[bottom].y < tops[i + 1].y) { - auto found = active.find(bottoms[bottom].segment); - active.erase(found); - // fprintf(stderr, "out of scope: %zu at %lld\n", bottoms[bottom].segment, bottoms[bottom].y); - bottom++; - } + for (; i < transitions.size() && transitions[i].kind < 0 && transitions[i].y == y; i++) { + std::pair top(xcoord(segs, transitions[i].segment, y), transitions[i].segment); + auto where = std::upper_bound(active.begin(), active.end(), top); + active.insert(where, top); + } + + // check any horizontals at this y coordinate against the active set + + for (; i < transitions.size() && transitions[i].kind == 0 && transitions[i].y == y; i++) { + } + + // deactivate any bottoms at this y coordinate + + for (; i < transitions.size() && transitions[i].kind > 0 && transitions[i].y == y; i++) { + std::pair bottom(xcoord(segs, transitions[i].segment, y), transitions[i].segment); + auto where = std::lower_bound(active.begin(), active.end(), bottom); + active.erase(where); } } }