mirror of
https://github.com/felt/tippecanoe.git
synced 2026-10-02 08:25:40 +02:00
Upgrade Wagyu to bfbf2893
This commit is contained in:
@@ -8,7 +8,6 @@
|
||||
#include <mapbox/geometry/wagyu/bound.hpp>
|
||||
#include <mapbox/geometry/wagyu/config.hpp>
|
||||
#include <mapbox/geometry/wagyu/edge.hpp>
|
||||
#include <mapbox/geometry/wagyu/exceptions.hpp>
|
||||
#include <mapbox/geometry/wagyu/local_minimum.hpp>
|
||||
#include <mapbox/geometry/wagyu/local_minimum_util.hpp>
|
||||
#include <mapbox/geometry/wagyu/ring.hpp>
|
||||
@@ -119,8 +118,7 @@ active_bound_list_itr<T> insert_bound_into_ABL(bound<T>& bnd,
|
||||
|
||||
template <typename T>
|
||||
inline bool is_maxima(bound<T>& bnd, T y) {
|
||||
return bnd.next_edge == bnd.edges.end() &&
|
||||
bnd.current_edge->top.y == y;
|
||||
return bnd.next_edge == bnd.edges.end() && bnd.current_edge->top.y == y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -130,8 +128,7 @@ inline bool is_maxima(active_bound_list_itr<T>& bnd, T y) {
|
||||
|
||||
template <typename T>
|
||||
inline bool is_intermediate(bound<T>& bnd, T y) {
|
||||
return bnd.next_edge != bnd.edges.end() &&
|
||||
bnd.current_edge->top.y == y;
|
||||
return bnd.next_edge != bnd.edges.end() && bnd.current_edge->top.y == y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -155,9 +152,9 @@ inline void swap_positions_in_ABL(active_bound_list_itr<T>& bnd1,
|
||||
active_bound_list<T>& active_bounds) {
|
||||
if (std::next(bnd2) == bnd1) {
|
||||
active_bounds.splice(bnd2, active_bounds, bnd1);
|
||||
} else {
|
||||
} else {
|
||||
active_bounds.splice(bnd1, active_bounds, bnd2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -188,19 +185,12 @@ active_bound_list_itr<T> get_maxima_pair(active_bound_list_itr<T> bnd,
|
||||
template <typename T>
|
||||
void set_winding_count(active_bound_list_itr<T>& bnd_itr,
|
||||
active_bound_list<T>& active_bounds,
|
||||
clip_type cliptype,
|
||||
fill_type subject_fill_type,
|
||||
fill_type clip_fill_type) {
|
||||
|
||||
auto rev_bnd_itr = active_bound_list_rev_itr<T>(bnd_itr);
|
||||
if (rev_bnd_itr == active_bounds.rend()) {
|
||||
if ((*bnd_itr)->winding_delta == 0) {
|
||||
fill_type pft = ((*bnd_itr)->poly_type == polygon_type_subject) ? subject_fill_type
|
||||
: clip_fill_type;
|
||||
(*bnd_itr)->winding_count = (pft == fill_type_negative ? -1 : 1);
|
||||
} else {
|
||||
(*bnd_itr)->winding_count = (*bnd_itr)->winding_delta;
|
||||
}
|
||||
(*bnd_itr)->winding_count = (*bnd_itr)->winding_delta;
|
||||
(*bnd_itr)->winding_count2 = 0;
|
||||
return;
|
||||
}
|
||||
@@ -208,39 +198,15 @@ void set_winding_count(active_bound_list_itr<T>& bnd_itr,
|
||||
// find the edge of the same polytype that immediately preceeds 'edge' in
|
||||
// AEL
|
||||
while (rev_bnd_itr != active_bounds.rend() &&
|
||||
((*rev_bnd_itr)->poly_type != (*bnd_itr)->poly_type ||
|
||||
(*rev_bnd_itr)->winding_delta == 0)) {
|
||||
(*rev_bnd_itr)->poly_type != (*bnd_itr)->poly_type) {
|
||||
++rev_bnd_itr;
|
||||
}
|
||||
if (rev_bnd_itr == active_bounds.rend()) {
|
||||
if ((*bnd_itr)->winding_delta == 0) {
|
||||
fill_type pft = ((*bnd_itr)->poly_type == polygon_type_subject) ? subject_fill_type
|
||||
: clip_fill_type;
|
||||
(*bnd_itr)->winding_count = (pft == fill_type_negative ? -1 : 1);
|
||||
} else {
|
||||
(*bnd_itr)->winding_count = (*bnd_itr)->winding_delta;
|
||||
}
|
||||
(*bnd_itr)->winding_count = (*bnd_itr)->winding_delta;
|
||||
(*bnd_itr)->winding_count2 = 0;
|
||||
} else if ((*bnd_itr)->winding_delta == 0 && cliptype != clip_type_union) {
|
||||
(*bnd_itr)->winding_count = 1;
|
||||
(*bnd_itr)->winding_count2 = (*rev_bnd_itr)->winding_count2;
|
||||
} else if (is_even_odd_fill_type(*(*bnd_itr), subject_fill_type, clip_fill_type)) {
|
||||
// EvenOdd filling ...
|
||||
if ((*bnd_itr)->winding_delta == 0) {
|
||||
// are we inside a subj polygon ...
|
||||
bool inside = true;
|
||||
auto rev2 = std::next(rev_bnd_itr);
|
||||
while (rev2 != active_bounds.rend()) {
|
||||
if ((*rev2)->poly_type == (*rev_bnd_itr)->poly_type &&
|
||||
(*rev2)->winding_delta != 0) {
|
||||
inside = !inside;
|
||||
}
|
||||
++rev2;
|
||||
}
|
||||
(*bnd_itr)->winding_count = (inside ? 0 : 1);
|
||||
} else {
|
||||
(*bnd_itr)->winding_count = (*bnd_itr)->winding_delta;
|
||||
}
|
||||
(*bnd_itr)->winding_count = (*bnd_itr)->winding_delta;
|
||||
(*bnd_itr)->winding_count2 = (*rev_bnd_itr)->winding_count2;
|
||||
} else {
|
||||
// nonZero, Positive or Negative filling ...
|
||||
@@ -259,17 +225,12 @@ void set_winding_count(active_bound_list_itr<T>& bnd_itr,
|
||||
}
|
||||
} else {
|
||||
// now outside all polys of same polytype so set own WC ...
|
||||
(*bnd_itr)->winding_count =
|
||||
((*bnd_itr)->winding_delta == 0 ? 1 : (*bnd_itr)->winding_delta);
|
||||
(*bnd_itr)->winding_count = (*bnd_itr)->winding_delta;
|
||||
}
|
||||
} else {
|
||||
// prev edge is 'increasing' WindCount (WC) away from zero
|
||||
// so we're inside the previous polygon ...
|
||||
if ((*bnd_itr)->winding_delta == 0) {
|
||||
(*bnd_itr)->winding_count =
|
||||
((*rev_bnd_itr)->winding_count < 0 ? (*rev_bnd_itr)->winding_count - 1
|
||||
: (*rev_bnd_itr)->winding_count + 1);
|
||||
} else if ((*rev_bnd_itr)->winding_delta * (*bnd_itr)->winding_delta < 0) {
|
||||
if ((*rev_bnd_itr)->winding_delta * (*bnd_itr)->winding_delta < 0) {
|
||||
// if wind direction is reversing prev then use same WC
|
||||
(*bnd_itr)->winding_count = (*rev_bnd_itr)->winding_count;
|
||||
} else {
|
||||
@@ -314,11 +275,6 @@ bool is_contributing(bound<T> const& bnd,
|
||||
|
||||
switch (pft) {
|
||||
case fill_type_even_odd:
|
||||
// return false if a subj line has been flagged as inside a subj
|
||||
// polygon
|
||||
if (bnd.winding_delta == 0 && bnd.winding_count != 1) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case fill_type_non_zero:
|
||||
if (std::abs(static_cast<int>(bnd.winding_count)) != 1) {
|
||||
@@ -388,45 +344,13 @@ bool is_contributing(bound<T> const& bnd,
|
||||
}
|
||||
break;
|
||||
case clip_type_x_or:
|
||||
if (bnd.winding_delta == 0) {
|
||||
// XOr always contributing unless open
|
||||
switch (pft2) {
|
||||
case fill_type_even_odd:
|
||||
case fill_type_non_zero:
|
||||
return (bnd.winding_count2 == 0);
|
||||
case fill_type_positive:
|
||||
return (bnd.winding_count2 <= 0);
|
||||
case fill_type_negative:
|
||||
default:
|
||||
return (bnd.winding_count2 >= 0);
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void insert_lm_only_one_bound(bound<T>& bnd,
|
||||
active_bound_list<T>& active_bounds,
|
||||
ring_manager<T>& rings,
|
||||
scanbeam_list<T>& scanbeam,
|
||||
clip_type cliptype,
|
||||
fill_type subject_fill_type,
|
||||
fill_type clip_fill_type) {
|
||||
auto abl_itr = insert_bound_into_ABL(bnd, active_bounds);
|
||||
set_winding_count(abl_itr, active_bounds, cliptype, subject_fill_type, clip_fill_type);
|
||||
if (is_contributing(bnd, cliptype, subject_fill_type, clip_fill_type)) {
|
||||
add_first_point(abl_itr, active_bounds, (*abl_itr)->current_edge->bot, rings);
|
||||
}
|
||||
if (!current_edge_is_horizontal<T>(abl_itr)) {
|
||||
scanbeam.push((*abl_itr)->current_edge->top.y);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void insert_lm_left_and_right_bound(bound<T>& left_bound,
|
||||
bound<T>& right_bound,
|
||||
@@ -439,8 +363,8 @@ void insert_lm_left_and_right_bound(bound<T>& left_bound,
|
||||
|
||||
// Both left and right bound
|
||||
auto lb_abl_itr = insert_bound_into_ABL(left_bound, active_bounds);
|
||||
auto rb_abl_itr = insert_bound_into_ABL(right_bound, lb_abl_itr, active_bounds);
|
||||
set_winding_count(lb_abl_itr, active_bounds, cliptype, subject_fill_type, clip_fill_type);
|
||||
auto rb_abl_itr = active_bounds.insert(std::next(lb_abl_itr), &right_bound);
|
||||
set_winding_count(lb_abl_itr, active_bounds, subject_fill_type, clip_fill_type);
|
||||
(*rb_abl_itr)->winding_count = (*lb_abl_itr)->winding_count;
|
||||
(*rb_abl_itr)->winding_count2 = (*lb_abl_itr)->winding_count2;
|
||||
if (is_contributing(left_bound, cliptype, subject_fill_type, clip_fill_type)) {
|
||||
@@ -454,16 +378,6 @@ void insert_lm_left_and_right_bound(bound<T>& left_bound,
|
||||
if (!current_edge_is_horizontal<T>(rb_abl_itr)) {
|
||||
scanbeam.push((*rb_abl_itr)->current_edge->top.y);
|
||||
}
|
||||
auto abl_itr = std::next(lb_abl_itr);
|
||||
while (abl_itr != rb_abl_itr && abl_itr != active_bounds.end()) {
|
||||
// We call intersect_bounds here, but we do not swap positions in the ABL
|
||||
// this is the logic that was copied from angus, but it might be correct
|
||||
// to swap the positions in the ABL following this or at least move
|
||||
// lb and rb to be next to each other in the ABL.
|
||||
intersect_bounds(rb_abl_itr, abl_itr, (*lb_abl_itr)->current_edge->bot, cliptype,
|
||||
subject_fill_type, clip_fill_type, rings, active_bounds);
|
||||
++abl_itr;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -480,16 +394,8 @@ void insert_local_minima_into_ABL(T const bot_y,
|
||||
initialize_lm<T>(current_lm);
|
||||
auto& left_bound = (*current_lm)->left_bound;
|
||||
auto& right_bound = (*current_lm)->right_bound;
|
||||
if (left_bound.edges.empty() && !right_bound.edges.empty()) {
|
||||
insert_lm_only_one_bound(right_bound, active_bounds, rings, scanbeam, cliptype,
|
||||
subject_fill_type, clip_fill_type);
|
||||
} else if (right_bound.edges.empty() && !left_bound.edges.empty()) {
|
||||
insert_lm_only_one_bound(left_bound, active_bounds, rings, scanbeam, cliptype,
|
||||
subject_fill_type, clip_fill_type);
|
||||
} else {
|
||||
insert_lm_left_and_right_bound(left_bound, right_bound, active_bounds, rings, scanbeam,
|
||||
cliptype, subject_fill_type, clip_fill_type);
|
||||
}
|
||||
insert_lm_left_and_right_bound(left_bound, right_bound, active_bounds, rings, scanbeam,
|
||||
cliptype, subject_fill_type, clip_fill_type);
|
||||
++current_lm;
|
||||
}
|
||||
}
|
||||
@@ -509,16 +415,8 @@ void insert_horizontal_local_minima_into_ABL(T const top_y,
|
||||
initialize_lm<T>(current_lm);
|
||||
auto& left_bound = (*current_lm)->left_bound;
|
||||
auto& right_bound = (*current_lm)->right_bound;
|
||||
if (left_bound.edges.empty() && !right_bound.edges.empty()) {
|
||||
insert_lm_only_one_bound(right_bound, active_bounds, rings, scanbeam, cliptype,
|
||||
subject_fill_type, clip_fill_type);
|
||||
} else if (right_bound.edges.empty() && !left_bound.edges.empty()) {
|
||||
throw clipper_exception(
|
||||
"There should only be horizontal local minimum on right bounds!");
|
||||
} else {
|
||||
insert_lm_left_and_right_bound(left_bound, right_bound, active_bounds, rings, scanbeam,
|
||||
cliptype, subject_fill_type, clip_fill_type);
|
||||
}
|
||||
insert_lm_left_and_right_bound(left_bound, right_bound, active_bounds, rings, scanbeam,
|
||||
cliptype, subject_fill_type, clip_fill_type);
|
||||
++current_lm;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@ struct bound {
|
||||
poly_type(polygon_type_subject),
|
||||
side(edge_left) {
|
||||
}
|
||||
|
||||
bound(bound<T> && b) noexcept
|
||||
|
||||
bound(bound<T>&& b) noexcept
|
||||
: edges(std::move(b.edges)),
|
||||
current_edge(std::move(b.current_edge)),
|
||||
last_point(std::move(b.last_point)),
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include <mapbox/geometry/wagyu/config.hpp>
|
||||
#include <mapbox/geometry/wagyu/edge.hpp>
|
||||
#include <mapbox/geometry/wagyu/exceptions.hpp>
|
||||
#include <mapbox/geometry/wagyu/util.hpp>
|
||||
|
||||
namespace mapbox {
|
||||
@@ -14,42 +13,8 @@ namespace geometry {
|
||||
namespace wagyu {
|
||||
|
||||
template <typename T>
|
||||
bool build_edge_list(mapbox::geometry::line_string<T> const& path_geometry,
|
||||
edge_list<T>& edges,
|
||||
bool& is_flat) {
|
||||
if (path_geometry.size() < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto itr_next = path_geometry.begin();
|
||||
++itr_next;
|
||||
auto itr = path_geometry.begin();
|
||||
while (itr_next != path_geometry.end()) {
|
||||
if (*itr_next == *itr) {
|
||||
// Duplicate point advance itr_next, but do not
|
||||
// advance itr
|
||||
++itr_next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_flat && itr_next->y != itr->y) {
|
||||
is_flat = false;
|
||||
}
|
||||
edges.emplace_back(*itr, *itr_next);
|
||||
itr = itr_next;
|
||||
++itr_next;
|
||||
}
|
||||
|
||||
if (edges.size() < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool point_2_is_between_point_1_and_point_3(mapbox::geometry::point<T> const& pt1,
|
||||
mapbox::geometry::point<T> const& pt2,
|
||||
bool point_2_is_between_point_1_and_point_3(mapbox::geometry::point<T> const& pt1,
|
||||
mapbox::geometry::point<T> const& pt2,
|
||||
mapbox::geometry::point<T> const& pt3) {
|
||||
if ((pt1 == pt3) || (pt1 == pt2) || (pt3 == pt2)) {
|
||||
return false;
|
||||
@@ -62,7 +27,6 @@ bool point_2_is_between_point_1_and_point_3(mapbox::geometry::point<T> const& pt
|
||||
|
||||
template <typename T>
|
||||
bool build_edge_list(mapbox::geometry::linear_ring<T> const& path_geometry, edge_list<T>& edges) {
|
||||
using value_type = T;
|
||||
|
||||
if (path_geometry.size() < 3) {
|
||||
return false;
|
||||
@@ -73,8 +37,8 @@ bool build_edge_list(mapbox::geometry::linear_ring<T> const& path_geometry, edge
|
||||
|
||||
auto itr_rev = path_geometry.rbegin();
|
||||
auto itr = path_geometry.begin();
|
||||
mapbox::geometry::point<value_type> pt1 = *itr_rev;
|
||||
mapbox::geometry::point<value_type> pt2 = *itr;
|
||||
mapbox::geometry::point<T> pt1 = *itr_rev;
|
||||
mapbox::geometry::point<T> pt2 = *itr;
|
||||
|
||||
// Find next non repeated point going backwards from
|
||||
// end for pt1
|
||||
@@ -86,10 +50,10 @@ bool build_edge_list(mapbox::geometry::linear_ring<T> const& path_geometry, edge
|
||||
pt1 = *itr_rev;
|
||||
}
|
||||
++itr;
|
||||
mapbox::geometry::point<value_type> pt3 = *itr;
|
||||
mapbox::geometry::point<T> pt3 = *itr;
|
||||
auto itr_last = itr_rev.base();
|
||||
mapbox::geometry::point<value_type> front_pt;
|
||||
mapbox::geometry::point<value_type> back_pt;
|
||||
mapbox::geometry::point<T> front_pt;
|
||||
mapbox::geometry::point<T> back_pt;
|
||||
while (true) {
|
||||
if (pt3 == pt2) {
|
||||
// Duplicate point advance itr, but do not
|
||||
@@ -129,13 +93,13 @@ bool build_edge_list(mapbox::geometry::linear_ring<T> const& path_geometry, edge
|
||||
} else {
|
||||
// If this occurs we must look to the back of the
|
||||
// ring for new points.
|
||||
do {
|
||||
while (*itr_rev == pt2) {
|
||||
++itr_rev;
|
||||
if ((itr + 1) == itr_rev.base()) {
|
||||
return false;
|
||||
}
|
||||
pt1 = *itr_rev;
|
||||
} while (pt1 == pt2);
|
||||
}
|
||||
pt1 = *itr_rev;
|
||||
itr_last = itr_rev.base();
|
||||
}
|
||||
continue;
|
||||
|
||||
@@ -34,7 +34,6 @@ bool add_linear_ring(mapbox::geometry::linear_ring<T> const& path_geometry,
|
||||
add_ring_to_local_minima_list(new_edges, minima_list, p_type);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,16 +15,16 @@ void push_ring_to_polygon(mapbox::geometry::polygon<T>& poly, ring_ptr<T>& r, bo
|
||||
auto ptIt = r->points;
|
||||
if (reverse_output) {
|
||||
do {
|
||||
lr.push_back({ ptIt->x, ptIt->y });
|
||||
lr.emplace_back(ptIt->x, ptIt->y);
|
||||
ptIt = ptIt->next;
|
||||
} while (ptIt != firstPt);
|
||||
} else {
|
||||
do {
|
||||
lr.push_back({ ptIt->x, ptIt->y });
|
||||
lr.emplace_back(ptIt->x, ptIt->y);
|
||||
ptIt = ptIt->prev;
|
||||
} while (ptIt != firstPt);
|
||||
}
|
||||
lr.push_back({ firstPt->x, firstPt->y }); // close the ring
|
||||
lr.emplace_back(firstPt->x, firstPt->y); // close the ring
|
||||
poly.push_back(lr);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ void build_result_polygons(std::vector<mapbox::geometry::polygon<T>>& solution,
|
||||
for (auto& r : rings) {
|
||||
assert(r->points);
|
||||
std::size_t cnt = point_count(r->points);
|
||||
if ((r->is_open && cnt < 2) || (!r->is_open && cnt < 3)) {
|
||||
if (cnt < 3) {
|
||||
continue;
|
||||
}
|
||||
solution.emplace_back();
|
||||
@@ -44,7 +44,7 @@ void build_result_polygons(std::vector<mapbox::geometry::polygon<T>>& solution,
|
||||
for (auto& c : r->children) {
|
||||
assert(c->points);
|
||||
cnt = point_count(c->points);
|
||||
if ((c->is_open && cnt < 2) || (!c->is_open && cnt < 3)) {
|
||||
if (cnt < 3) {
|
||||
continue;
|
||||
}
|
||||
push_ring_to_polygon(solution.back(), c, reverse_output);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <list>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace mapbox {
|
||||
namespace geometry {
|
||||
|
||||
@@ -28,19 +28,18 @@ struct edge {
|
||||
mapbox::geometry::point<T> top;
|
||||
double dx;
|
||||
|
||||
edge(edge<T> && e) noexcept
|
||||
: bot(std::move(e.bot)),
|
||||
top(std::move(e.top)),
|
||||
dx(std::move(e.dx)) {}
|
||||
edge(edge<T>&& e) noexcept : bot(std::move(e.bot)), top(std::move(e.top)), dx(std::move(e.dx)) {
|
||||
}
|
||||
|
||||
edge& operator=(edge<T> && e) noexcept {
|
||||
edge& operator=(edge<T>&& e) noexcept {
|
||||
bot = std::move(e.bot);
|
||||
top = std::move(e.top);
|
||||
dx = std::move(e.dx);
|
||||
return *this;
|
||||
}
|
||||
|
||||
edge(mapbox::geometry::point<T> const& current, mapbox::geometry::point<T> const& next_pt) noexcept
|
||||
edge(mapbox::geometry::point<T> const& current,
|
||||
mapbox::geometry::point<T> const& next_pt) noexcept
|
||||
: bot(current), top(current), dx(0.0) {
|
||||
if (current.y >= next_pt.y) {
|
||||
top = next_pt;
|
||||
@@ -54,7 +53,6 @@ struct edge {
|
||||
dx = static_cast<double>(top.x - bot.x) / dy;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -21,12 +21,11 @@ struct intersect_node {
|
||||
active_bound_list_itr<T> bound2;
|
||||
mapbox::geometry::point<double> pt;
|
||||
|
||||
intersect_node(intersect_node<T> && n)
|
||||
: bound1(std::move(n.bound1)),
|
||||
bound2(std::move(n.bound2)),
|
||||
pt(std::move(n.pt)) { }
|
||||
intersect_node(intersect_node<T>&& n)
|
||||
: bound1(std::move(n.bound1)), bound2(std::move(n.bound2)), pt(std::move(n.pt)) {
|
||||
}
|
||||
|
||||
intersect_node& operator=(intersect_node<T> && n) {
|
||||
intersect_node& operator=(intersect_node<T>&& n) {
|
||||
bound1 = std::move(n.bound1);
|
||||
bound2 = std::move(n.bound2);
|
||||
pt = std::move(n.pt);
|
||||
|
||||
@@ -69,12 +69,13 @@ bool get_edge_intersection(edge<T1> const& e1,
|
||||
pt.y = p0_y + (t * s1_y);
|
||||
return true;
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
return false;
|
||||
// LCOV_EXCL_END
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void build_intersect_list(active_bound_list<T>& active_bounds,
|
||||
intersect_list<T>& intersects) {
|
||||
void build_intersect_list(active_bound_list<T>& active_bounds, intersect_list<T>& intersects) {
|
||||
// bubblesort ...
|
||||
bool isModified = false;
|
||||
do {
|
||||
@@ -87,8 +88,10 @@ void build_intersect_list(active_bound_list<T>& active_bounds,
|
||||
mapbox::geometry::point<double> pt;
|
||||
if (!get_edge_intersection<T, double>(*((*bnd)->current_edge),
|
||||
*((*bnd_next)->current_edge), pt)) {
|
||||
// LCOV_EXCL_START
|
||||
throw std::runtime_error(
|
||||
"Trying to find intersection of lines that do not intersect");
|
||||
// LCOV_EXCL_END
|
||||
}
|
||||
intersects.emplace_back(bnd, bnd_next, pt);
|
||||
swap_positions_in_ABL(bnd, bnd_next, active_bounds);
|
||||
@@ -113,50 +116,6 @@ void intersect_bounds(active_bound_list_itr<T>& b1,
|
||||
active_bound_list<T>& active_bounds) {
|
||||
bool b1Contributing = ((*b1)->ring != nullptr);
|
||||
bool b2Contributing = ((*b2)->ring != nullptr);
|
||||
// if either bound is on an OPEN path ...
|
||||
if ((*b1)->winding_delta == 0 || (*b2)->winding_delta == 0) {
|
||||
// ignore subject-subject open path intersections UNLESS they
|
||||
// are both open paths, AND they are both 'contributing maximas' ...
|
||||
if ((*b1)->winding_delta == 0 && (*b2)->winding_delta == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if intersecting a subj line with a subj poly ...
|
||||
else if ((*b1)->poly_type == (*b2)->poly_type &&
|
||||
(*b1)->winding_delta != (*b2)->winding_delta && cliptype == clip_type_union) {
|
||||
if ((*b1)->winding_delta == 0) {
|
||||
if (b2Contributing) {
|
||||
add_point(b1, active_bounds, pt, rings);
|
||||
if (b1Contributing) {
|
||||
(*b1)->ring = nullptr;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (b1Contributing) {
|
||||
add_point(b2, active_bounds, pt, rings);
|
||||
if (b2Contributing) {
|
||||
(*b2)->ring = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ((*b1)->poly_type != (*b2)->poly_type) {
|
||||
// toggle subj open path index on/off when std::abs(clip.WndCnt) == 1
|
||||
if (((*b1)->winding_delta == 0) && std::abs(static_cast<int>((*b2)->winding_count)) == 1 &&
|
||||
(cliptype != clip_type_union || (*b2)->winding_count2 == 0)) {
|
||||
add_point(b1, active_bounds, pt, rings);
|
||||
if (b1Contributing) {
|
||||
(*b1)->ring = nullptr;
|
||||
}
|
||||
} else if (((*b2)->winding_delta == 0) && (std::abs(static_cast<int>((*b1)->winding_count)) == 1) &&
|
||||
(cliptype != clip_type_union || (*b1)->winding_count2 == 0)) {
|
||||
add_point(b2, active_bounds, pt, rings);
|
||||
if (b2Contributing) {
|
||||
(*b2)->ring = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// update winding counts...
|
||||
// assumes that b1 will be to the Right of b2 ABOVE the intersection
|
||||
@@ -347,7 +306,7 @@ void process_intersect_list(intersect_list<T>& intersects,
|
||||
template <typename T>
|
||||
void update_current_x(active_bound_list<T>& active_bounds, T top_y) {
|
||||
std::size_t pos = 0;
|
||||
for (auto & bnd : active_bounds) {
|
||||
for (auto& bnd : active_bounds) {
|
||||
bnd->pos = pos++;
|
||||
bnd->current_x = get_current_x(*bnd->current_edge, top_y);
|
||||
}
|
||||
@@ -372,9 +331,8 @@ void process_intersections(T top_y,
|
||||
}
|
||||
|
||||
// Restore order of active bounds list
|
||||
active_bounds.sort([] (bound_ptr<T> const& b1, bound_ptr<T> const& b2) {
|
||||
return b1->pos < b2->pos;
|
||||
});
|
||||
active_bounds.sort(
|
||||
[](bound_ptr<T> const& b1, bound_ptr<T> const& b2) { return b1->pos < b2->pos; });
|
||||
|
||||
// Sort the intersection list
|
||||
std::stable_sort(intersects.begin(), intersects.end(), intersect_list_sorter<T>());
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <mapbox/geometry/wagyu/local_minimum.hpp>
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <mapbox/geometry/wagyu/exceptions.hpp>
|
||||
#include <stdexcept>
|
||||
#endif
|
||||
|
||||
namespace mapbox {
|
||||
@@ -194,106 +194,8 @@ void move_horizontals_on_left_to_right(bound<T>& left_bound, bound<T>& right_bou
|
||||
auto dist = std::distance(left_bound.edges.begin(), edge_itr);
|
||||
std::move(left_bound.edges.begin(), edge_itr, std::back_inserter(right_bound.edges));
|
||||
left_bound.edges.erase(left_bound.edges.begin(), edge_itr);
|
||||
std::rotate(right_bound.edges.begin(), std::prev(right_bound.edges.end(), dist), right_bound.edges.end());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void add_line_to_local_minima_list(edge_list<T>& edges, local_minimum_list<T>& minima_list) {
|
||||
|
||||
if (edges.empty()) {
|
||||
return;
|
||||
}
|
||||
// Adjust the order of the ring so we start on a local maximum
|
||||
// therefore we start right away on a bound.
|
||||
start_list_on_local_maximum(edges);
|
||||
bound_ptr<T> last_maximum = nullptr;
|
||||
while (!edges.empty()) {
|
||||
bool lm_minimum_has_horizontal = false;
|
||||
auto to_minimum = create_bound_towards_minimum(edges);
|
||||
assert(!to_minimum.edges.empty());
|
||||
fix_horizontals(to_minimum);
|
||||
to_minimum.poly_type = polygon_type_subject;
|
||||
to_minimum.maximum_bound = last_maximum;
|
||||
to_minimum.winding_delta = 0;
|
||||
auto to_min_first_non_horizontal = to_minimum.edges.begin();
|
||||
while (to_min_first_non_horizontal != to_minimum.edges.end() &&
|
||||
is_horizontal(*to_min_first_non_horizontal)) {
|
||||
lm_minimum_has_horizontal = true;
|
||||
++to_min_first_non_horizontal;
|
||||
}
|
||||
if (edges.empty()) {
|
||||
if (to_min_first_non_horizontal != to_minimum.edges.end() &&
|
||||
to_min_first_non_horizontal->dx > 0.0) {
|
||||
to_minimum.side = edge_left;
|
||||
bound<T> right_bound;
|
||||
right_bound.winding_delta = 0;
|
||||
right_bound.side = edge_right;
|
||||
right_bound.poly_type = polygon_type_subject;
|
||||
move_horizontals_on_left_to_right(to_minimum, right_bound);
|
||||
auto const& min_front = to_minimum.edges.front();
|
||||
minima_list.emplace_back(std::move(to_minimum), std::move(right_bound), min_front.y,
|
||||
lm_minimum_has_horizontal);
|
||||
if (last_maximum) {
|
||||
last_maximum->maximum_bound = &(minima_list.back().left_bound);
|
||||
last_maximum = nullptr;
|
||||
}
|
||||
} else {
|
||||
to_minimum.side = edge_right;
|
||||
bound<T> left_bound;
|
||||
left_bound.winding_delta = 0;
|
||||
left_bound.side = edge_left;
|
||||
left_bound.poly_type = polygon_type_subject;
|
||||
auto const& min_front = to_minimum.edges.front();
|
||||
minima_list.emplace_back(std::move(left_bound), std::move(to_minimum), min_front.y);
|
||||
if (last_maximum) {
|
||||
last_maximum->maximum_bound = &(minima_list.back().right_bound);
|
||||
last_maximum = nullptr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
bool minimum_is_left = true;
|
||||
auto to_maximum = create_bound_towards_maximum(edges);
|
||||
assert(!to_maximum.edges.empty());
|
||||
fix_horizontals(to_maximum);
|
||||
auto to_max_first_non_horizontal = to_minimum.edges.begin();
|
||||
while (to_max_first_non_horizontal != to_maximum.edges.end() &&
|
||||
is_horizontal(*to_max_first_non_horizontal)) {
|
||||
lm_minimum_has_horizontal = true;
|
||||
++to_max_first_non_horizontal;
|
||||
}
|
||||
if (to_max_first_non_horizontal != to_maximum.edges.end() &&
|
||||
(to_min_first_non_horizontal == to_minimum.edges.end() ||
|
||||
to_max_first_non_horizontal->dx > to_min_first_non_horizontal->dx)) {
|
||||
minimum_is_left = false;
|
||||
move_horizontals_on_left_to_right(to_maximum, to_minimum);
|
||||
} else {
|
||||
minimum_is_left = true;
|
||||
move_horizontals_on_left_to_right(to_minimum, to_maximum);
|
||||
}
|
||||
auto const& min_front = to_minimum.edges.front();
|
||||
to_maximum.poly_type = polygon_type_subject;
|
||||
to_maximum.winding_delta = 0;
|
||||
if (!minimum_is_left) {
|
||||
to_minimum.side = edge_right;
|
||||
to_maximum.side = edge_left;
|
||||
minima_list.emplace_back(std::move(to_maximum), std::move(to_minimum), min_front.bot.y,
|
||||
lm_minimum_has_horizontal);
|
||||
if (last_maximum) {
|
||||
last_maximum->maximum_bound = &(minima_list.back().right_bound);
|
||||
}
|
||||
last_maximum = &(minima_list.back().left_bound);
|
||||
} else {
|
||||
to_minimum.side = edge_left;
|
||||
to_maximum.side = edge_right;
|
||||
minima_list.emplace_back(std::move(to_minimum), std::move(to_maximum), min_front.bot.y,
|
||||
lm_minimum_has_horizontal);
|
||||
if (last_maximum) {
|
||||
last_maximum->maximum_bound = &(minima_list.back().left_bound);
|
||||
}
|
||||
last_maximum = &(minima_list.back().right_bound);
|
||||
}
|
||||
}
|
||||
std::rotate(right_bound.edges.begin(), std::prev(right_bound.edges.end(), dist),
|
||||
right_bound.edges.end());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -335,7 +237,7 @@ void add_ring_to_local_minima_list(edge_list<T>& edges,
|
||||
#ifdef DEBUG
|
||||
if (to_max_first_non_horizontal == to_maximum.edges.end() ||
|
||||
to_min_first_non_horizontal == to_minimum.edges.end()) {
|
||||
throw clipper_exception("should not have a horizontal only bound for a ring");
|
||||
throw std::runtime_error("should not have a horizontal only bound for a ring");
|
||||
}
|
||||
#endif
|
||||
if (lm_minimum_has_horizontal) {
|
||||
|
||||
@@ -37,12 +37,13 @@ struct point {
|
||||
point_ptr<T> next;
|
||||
point_ptr<T> prev;
|
||||
|
||||
point(point<T> && p)
|
||||
point(point<T>&& p)
|
||||
: ring(std::move(p.ring)),
|
||||
x(std::move(p.x)),
|
||||
y(std::move(p.y)),
|
||||
next(std::move(p.next)),
|
||||
prev(std::move(p.prev)) { }
|
||||
prev(std::move(p.prev)) {
|
||||
}
|
||||
|
||||
point() : ring(nullptr), x(0), y(0), prev(this), next(this) {
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include <mapbox/geometry/wagyu/config.hpp>
|
||||
#include <mapbox/geometry/wagyu/edge.hpp>
|
||||
#include <mapbox/geometry/wagyu/exceptions.hpp>
|
||||
#include <mapbox/geometry/wagyu/local_minimum.hpp>
|
||||
#include <mapbox/geometry/wagyu/util.hpp>
|
||||
|
||||
@@ -24,7 +23,6 @@ active_bound_list_itr<T> process_horizontal_left_to_right(T scanline_y,
|
||||
fill_type subject_fill_type,
|
||||
fill_type clip_fill_type) {
|
||||
auto horizontal_itr_behind = horz_bound;
|
||||
bool is_open = (*horz_bound)->winding_delta == 0;
|
||||
bool is_maxima_edge = is_maxima(horz_bound, scanline_y);
|
||||
auto bound_max_pair = active_bounds.end();
|
||||
if (is_maxima_edge) {
|
||||
@@ -32,19 +30,22 @@ active_bound_list_itr<T> process_horizontal_left_to_right(T scanline_y,
|
||||
}
|
||||
|
||||
auto hp_itr = rings.current_hp_itr;
|
||||
while (hp_itr != rings.hot_pixels.end() && (hp_itr->y > scanline_y || (hp_itr->y == scanline_y && hp_itr->x < (*horz_bound)->current_edge->bot.x))) {
|
||||
while (hp_itr != rings.hot_pixels.end() &&
|
||||
(hp_itr->y > scanline_y ||
|
||||
(hp_itr->y == scanline_y && hp_itr->x < (*horz_bound)->current_edge->bot.x))) {
|
||||
++hp_itr;
|
||||
}
|
||||
|
||||
|
||||
auto bnd = std::next(horz_bound);
|
||||
|
||||
while (bnd != active_bounds.end()) {
|
||||
// this code block inserts extra coords into horizontal edges (in output
|
||||
// polygons) wherever hot pixels touch these horizontal edges. This helps
|
||||
//'simplifying' polygons (ie if the Simplify property is set).
|
||||
while (hp_itr != rings.hot_pixels.end() && hp_itr->y == scanline_y && hp_itr->x < std::llround((*bnd)->current_x) &&
|
||||
while (hp_itr != rings.hot_pixels.end() && hp_itr->y == scanline_y &&
|
||||
hp_itr->x < std::llround((*bnd)->current_x) &&
|
||||
hp_itr->x < (*horz_bound)->current_edge->top.x) {
|
||||
if ((*horz_bound)->ring && !is_open) {
|
||||
if ((*horz_bound)->ring) {
|
||||
add_point_to_ring(*(*horz_bound), *hp_itr, rings);
|
||||
}
|
||||
++hp_itr;
|
||||
@@ -63,11 +64,10 @@ active_bound_list_itr<T> process_horizontal_left_to_right(T scanline_y,
|
||||
}
|
||||
|
||||
// note: may be done multiple times
|
||||
if ((*horz_bound)->ring && !is_open) {
|
||||
add_point_to_ring(*(*horz_bound),
|
||||
mapbox::geometry::point<T>(std::llround((*bnd)->current_x),
|
||||
scanline_y),
|
||||
rings);
|
||||
if ((*horz_bound)->ring) {
|
||||
add_point_to_ring(
|
||||
*(*horz_bound),
|
||||
mapbox::geometry::point<T>(std::llround((*bnd)->current_x), scanline_y), rings);
|
||||
}
|
||||
|
||||
// OK, so far we're still in range of the horizontal Edge but make sure
|
||||
@@ -87,8 +87,7 @@ active_bound_list_itr<T> process_horizontal_left_to_right(T scanline_y,
|
||||
}
|
||||
|
||||
intersect_bounds(horz_bound, bnd,
|
||||
mapbox::geometry::point<T>(std::llround((*bnd)->current_x),
|
||||
scanline_y),
|
||||
mapbox::geometry::point<T>(std::llround((*bnd)->current_x), scanline_y),
|
||||
cliptype, subject_fill_type, clip_fill_type, rings, active_bounds);
|
||||
auto next_bnd = std::next(bnd);
|
||||
swap_positions_in_ABL(horz_bound, bnd, active_bounds);
|
||||
@@ -98,7 +97,7 @@ active_bound_list_itr<T> process_horizontal_left_to_right(T scanline_y,
|
||||
bnd = next_bnd;
|
||||
} // end while (bnd != active_bounds.end())
|
||||
|
||||
if ((*horz_bound)->ring && !is_open) {
|
||||
if ((*horz_bound)->ring) {
|
||||
while (hp_itr != rings.hot_pixels.end() && hp_itr->y == scanline_y &&
|
||||
hp_itr->x < std::llround((*horz_bound)->current_edge->top.x)) {
|
||||
add_point_to_ring(*(*horz_bound), *hp_itr, rings);
|
||||
@@ -110,14 +109,6 @@ active_bound_list_itr<T> process_horizontal_left_to_right(T scanline_y,
|
||||
if ((*horz_bound)->ring) {
|
||||
add_point_to_ring(*(*horz_bound), (*horz_bound)->current_edge->top, rings);
|
||||
next_edge_in_bound(horz_bound, scanbeam);
|
||||
|
||||
if ((*horz_bound)->winding_delta == 0) {
|
||||
if (horizontal_itr_behind != horz_bound) {
|
||||
return horizontal_itr_behind;
|
||||
} else {
|
||||
return std::next(horz_bound);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
next_edge_in_bound(horz_bound, scanbeam);
|
||||
}
|
||||
@@ -148,14 +139,15 @@ active_bound_list_itr<T> process_horizontal_right_to_left(T scanline_y,
|
||||
clip_type cliptype,
|
||||
fill_type subject_fill_type,
|
||||
fill_type clip_fill_type) {
|
||||
bool is_open = (*horz_bound)->winding_delta == 0;
|
||||
bool is_maxima_edge = is_maxima(horz_bound, scanline_y);
|
||||
auto bound_max_pair = active_bounds.end();
|
||||
if (is_maxima_edge) {
|
||||
bound_max_pair = get_maxima_pair<T>(horz_bound, active_bounds);
|
||||
}
|
||||
auto hp_itr_fwd = rings.current_hp_itr;
|
||||
while (hp_itr_fwd != rings.hot_pixels.end() && (hp_itr_fwd->y < scanline_y || (hp_itr_fwd->y == scanline_y && hp_itr_fwd->x < (*horz_bound)->current_edge->top.x))) {
|
||||
while (hp_itr_fwd != rings.hot_pixels.end() &&
|
||||
(hp_itr_fwd->y < scanline_y ||
|
||||
(hp_itr_fwd->y == scanline_y && hp_itr_fwd->x < (*horz_bound)->current_edge->top.x))) {
|
||||
++hp_itr_fwd;
|
||||
}
|
||||
auto hp_itr = hot_pixel_rev_itr<T>(hp_itr_fwd);
|
||||
@@ -164,9 +156,10 @@ active_bound_list_itr<T> process_horizontal_right_to_left(T scanline_y,
|
||||
while (bnd != active_bounds.rend()) {
|
||||
// this code block inserts extra coords into horizontal edges (in output
|
||||
// polygons) wherever hot pixels touch these horizontal edges.
|
||||
while (hp_itr != rings.hot_pixels.rend() && hp_itr->y == scanline_y && hp_itr->x > std::llround((*bnd)->current_x) &&
|
||||
while (hp_itr != rings.hot_pixels.rend() && hp_itr->y == scanline_y &&
|
||||
hp_itr->x > std::llround((*bnd)->current_x) &&
|
||||
hp_itr->x > (*horz_bound)->current_edge->top.x) {
|
||||
if ((*horz_bound)->ring && !is_open) {
|
||||
if ((*horz_bound)->ring) {
|
||||
add_point_to_ring(*(*horz_bound), *hp_itr, rings);
|
||||
}
|
||||
++hp_itr;
|
||||
@@ -185,11 +178,10 @@ active_bound_list_itr<T> process_horizontal_right_to_left(T scanline_y,
|
||||
}
|
||||
|
||||
// note: may be done multiple times
|
||||
if ((*horz_bound)->ring && !is_open) {
|
||||
add_point_to_ring(*(*horz_bound),
|
||||
mapbox::geometry::point<T>(std::llround((*bnd)->current_x),
|
||||
scanline_y),
|
||||
rings);
|
||||
if ((*horz_bound)->ring) {
|
||||
add_point_to_ring(
|
||||
*(*horz_bound),
|
||||
mapbox::geometry::point<T>(std::llround((*bnd)->current_x), scanline_y), rings);
|
||||
}
|
||||
auto bnd_forward = --(bnd.base());
|
||||
|
||||
@@ -205,8 +197,7 @@ active_bound_list_itr<T> process_horizontal_right_to_left(T scanline_y,
|
||||
}
|
||||
|
||||
intersect_bounds(bnd_forward, horz_bound,
|
||||
mapbox::geometry::point<T>(std::llround((*bnd)->current_x),
|
||||
scanline_y),
|
||||
mapbox::geometry::point<T>(std::llround((*bnd)->current_x), scanline_y),
|
||||
cliptype, subject_fill_type, clip_fill_type, rings, active_bounds);
|
||||
swap_positions_in_ABL(horz_bound, bnd_forward, active_bounds);
|
||||
// Why are we not incrementing the bnd iterator here:
|
||||
@@ -216,8 +207,9 @@ active_bound_list_itr<T> process_horizontal_right_to_left(T scanline_y,
|
||||
// so what the reverse bound points to will have changed.
|
||||
} // end while (bnd != active_bounds.rend())
|
||||
|
||||
if ((*horz_bound)->ring && !is_open) {
|
||||
while (hp_itr != rings.hot_pixels.rend() && hp_itr->y == scanline_y && hp_itr->x > (*horz_bound)->current_edge->top.x) {
|
||||
if ((*horz_bound)->ring) {
|
||||
while (hp_itr != rings.hot_pixels.rend() && hp_itr->y == scanline_y &&
|
||||
hp_itr->x > (*horz_bound)->current_edge->top.x) {
|
||||
add_point_to_ring(*(*horz_bound), *hp_itr, rings);
|
||||
++hp_itr;
|
||||
}
|
||||
@@ -227,10 +219,6 @@ active_bound_list_itr<T> process_horizontal_right_to_left(T scanline_y,
|
||||
if ((*horz_bound)->ring) {
|
||||
add_point_to_ring(*(*horz_bound), (*horz_bound)->current_edge->top, rings);
|
||||
next_edge_in_bound(horz_bound, scanbeam);
|
||||
|
||||
if ((*horz_bound)->winding_delta == 0) {
|
||||
return std::next(horz_bound);
|
||||
}
|
||||
} else {
|
||||
next_edge_in_bound(horz_bound, scanbeam);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <mapbox/geometry/wagyu/active_bound_list.hpp>
|
||||
#include <mapbox/geometry/wagyu/config.hpp>
|
||||
#include <mapbox/geometry/wagyu/edge.hpp>
|
||||
#include <mapbox/geometry/wagyu/exceptions.hpp>
|
||||
#include <mapbox/geometry/wagyu/intersect_util.hpp>
|
||||
#include <mapbox/geometry/wagyu/local_minimum.hpp>
|
||||
#include <mapbox/geometry/wagyu/local_minimum_util.hpp>
|
||||
@@ -47,14 +46,8 @@ active_bound_list_itr<T> do_maxima(active_bound_list_itr<T>& bnd,
|
||||
} else if ((*bnd)->ring && (*bndMaxPair)->ring) {
|
||||
add_local_maximum_point(bnd, bndMaxPair, (*bnd)->current_edge->top, rings, active_bounds);
|
||||
active_bounds.erase(bndMaxPair);
|
||||
} else if ((*bnd)->winding_delta == 0 && (*bnd)->ring) {
|
||||
add_point_to_ring(*(*bnd), (*bnd)->current_edge->top, rings);
|
||||
active_bounds.erase(bndMaxPair);
|
||||
} else if ((*bnd)->winding_delta == 0 && (*bndMaxPair)->ring) {
|
||||
add_point_to_ring(*(*bndMaxPair), (*bnd)->current_edge->top, rings);
|
||||
active_bounds.erase(bndMaxPair);
|
||||
} else {
|
||||
throw clipper_exception("DoMaxima error");
|
||||
throw std::runtime_error("DoMaxima error");
|
||||
}
|
||||
auto prev_itr = active_bounds.erase(bnd);
|
||||
if (skipped) {
|
||||
@@ -78,7 +71,7 @@ void process_edges_at_top_of_scanbeam(T top_y,
|
||||
for (auto bnd = active_bounds.begin(); bnd != active_bounds.end();) {
|
||||
// 1. Process maxima, treating them as if they are "bent" horizontal edges,
|
||||
// but exclude maxima with horizontal edges.
|
||||
|
||||
|
||||
bool is_maxima_edge = is_maxima(bnd, top_y);
|
||||
|
||||
if (is_maxima_edge) {
|
||||
@@ -87,8 +80,8 @@ void process_edges_at_top_of_scanbeam(T top_y,
|
||||
!current_edge_is_horizontal<T>(bnd_max_pair)) &&
|
||||
is_maxima(bnd_max_pair, top_y));
|
||||
if (is_maxima_edge) {
|
||||
bnd = do_maxima(bnd, bnd_max_pair, cliptype, subject_fill_type, clip_fill_type, rings,
|
||||
active_bounds);
|
||||
bnd = do_maxima(bnd, bnd_max_pair, cliptype, subject_fill_type, clip_fill_type,
|
||||
rings, active_bounds);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -127,7 +120,6 @@ void process_edges_at_top_of_scanbeam(T top_y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <mapbox/geometry/wagyu/point.hpp>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <mapbox/geometry/wagyu/point.hpp>
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <execinfo.h>
|
||||
@@ -46,10 +46,9 @@ struct ring {
|
||||
ring_list<T> children;
|
||||
point_ptr<T> points;
|
||||
point_ptr<T> bottom_point;
|
||||
bool is_open;
|
||||
|
||||
ring( ring const& ) = delete;
|
||||
ring& operator=(ring const& ) = delete;
|
||||
ring(ring const&) = delete;
|
||||
ring& operator=(ring const&) = delete;
|
||||
|
||||
ring()
|
||||
: ring_index(0),
|
||||
@@ -58,8 +57,7 @@ struct ring {
|
||||
parent(nullptr),
|
||||
children(),
|
||||
points(nullptr),
|
||||
bottom_point(nullptr),
|
||||
is_open(false) {
|
||||
bottom_point(nullptr) {
|
||||
}
|
||||
};
|
||||
|
||||
@@ -74,7 +72,7 @@ using hot_pixel_rev_itr = typename hot_pixel_vector<T>::reverse_iterator;
|
||||
|
||||
template <typename T>
|
||||
struct ring_manager {
|
||||
|
||||
|
||||
ring_list<T> children;
|
||||
std::vector<point_ptr<T>> all_points;
|
||||
hot_pixel_vector<T> hot_pixels;
|
||||
@@ -84,8 +82,8 @@ struct ring_manager {
|
||||
std::vector<point<T>> storage;
|
||||
std::size_t index;
|
||||
|
||||
ring_manager( ring_manager const& ) = delete;
|
||||
ring_manager& operator=(ring_manager const& ) = delete;
|
||||
ring_manager(ring_manager const&) = delete;
|
||||
ring_manager& operator=(ring_manager const&) = delete;
|
||||
|
||||
ring_manager()
|
||||
: children(),
|
||||
@@ -328,12 +326,9 @@ void reverse_ring(point_ptr<T> pp) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
double area_from_point(point_ptr<T> op, std::size_t & size) {
|
||||
double area_from_point(point_ptr<T> op, std::size_t& size) {
|
||||
point_ptr<T> startOp = op;
|
||||
size = 1;
|
||||
if (!op) {
|
||||
return 0.0;
|
||||
}
|
||||
double a = 0.0;
|
||||
do {
|
||||
++size;
|
||||
|
||||
@@ -83,13 +83,14 @@ void set_hole_state(active_bound_list_rev_itr<T>& bnd,
|
||||
template <typename T>
|
||||
void update_current_hp_itr(T scanline_y, ring_manager<T>& rings) {
|
||||
while (rings.current_hp_itr->y > scanline_y) {
|
||||
++rings.current_hp_itr;
|
||||
++rings.current_hp_itr;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct hot_pixel_sorter {
|
||||
inline bool operator()(mapbox::geometry::point<T> const& pt1, mapbox::geometry::point<T> const& pt2) {
|
||||
inline bool operator()(mapbox::geometry::point<T> const& pt1,
|
||||
mapbox::geometry::point<T> const& pt2) {
|
||||
if (pt1.y == pt2.y) {
|
||||
return pt1.x < pt2.x;
|
||||
} else {
|
||||
@@ -100,7 +101,7 @@ struct hot_pixel_sorter {
|
||||
|
||||
// Due to the nature of floating point calculations
|
||||
// and the high likely hood of values around X.5, we
|
||||
// need to fudge what is X.5 some for our rounding.
|
||||
// need to fudge what is X.5 some for our rounding.
|
||||
const double rounding_offset = 1e-12;
|
||||
const double rounding_offset_y = 5e-13;
|
||||
|
||||
@@ -141,8 +142,9 @@ inline T get_edge_min_x(edge<T> const& edge, const T current_y) {
|
||||
if (current_y == edge.bot.y) {
|
||||
return edge.bot.x;
|
||||
} else {
|
||||
double return_val = static_cast<double>(edge.bot.x) +
|
||||
edge.dx * (static_cast<double>(current_y - edge.bot.y) + 0.5 - rounding_offset_y);
|
||||
double return_val =
|
||||
static_cast<double>(edge.bot.x) +
|
||||
edge.dx * (static_cast<double>(current_y - edge.bot.y) + 0.5 - rounding_offset_y);
|
||||
T value = round_towards_min<T>(return_val);
|
||||
return value;
|
||||
}
|
||||
@@ -170,8 +172,9 @@ inline T get_edge_max_x(edge<T> const& edge, const T current_y) {
|
||||
if (current_y == edge.bot.y) {
|
||||
return edge.bot.x;
|
||||
} else {
|
||||
double return_val = static_cast<double>(edge.bot.x) +
|
||||
edge.dx * (static_cast<double>(current_y - edge.bot.y) + 0.5 - rounding_offset_y);
|
||||
double return_val =
|
||||
static_cast<double>(edge.bot.x) +
|
||||
edge.dx * (static_cast<double>(current_y - edge.bot.y) + 0.5 - rounding_offset_y);
|
||||
T value = round_towards_max<T>(return_val);
|
||||
return value;
|
||||
}
|
||||
@@ -184,14 +187,14 @@ void hot_pixel_set_left_to_right(T y,
|
||||
T end_x,
|
||||
bound<T>& bnd,
|
||||
ring_manager<T>& rings,
|
||||
hot_pixel_itr<T> & itr,
|
||||
hot_pixel_itr<T> & end,
|
||||
hot_pixel_itr<T>& itr,
|
||||
hot_pixel_itr<T>& end,
|
||||
bool add_end_point) {
|
||||
T x_min = get_edge_min_x(*(bnd.current_edge), y);
|
||||
x_min = std::max(x_min, start_x);
|
||||
T x_max = get_edge_max_x(*(bnd.current_edge), y);
|
||||
x_max = std::min(x_max, end_x);
|
||||
for (;itr != end; ++itr) {
|
||||
for (; itr != end; ++itr) {
|
||||
if (itr->x < x_min) {
|
||||
continue;
|
||||
}
|
||||
@@ -221,16 +224,16 @@ void hot_pixel_set_right_to_left(T y,
|
||||
T end_x,
|
||||
bound<T>& bnd,
|
||||
ring_manager<T>& rings,
|
||||
hot_pixel_rev_itr<T> & itr,
|
||||
hot_pixel_rev_itr<T> & end,
|
||||
hot_pixel_rev_itr<T>& itr,
|
||||
hot_pixel_rev_itr<T>& end,
|
||||
bool add_end_point) {
|
||||
T x_min = get_edge_min_x(*(bnd.current_edge), y);
|
||||
x_min = std::max(x_min, end_x);
|
||||
T x_max = get_edge_max_x(*(bnd.current_edge), y);
|
||||
x_max = std::min(x_max, start_x);
|
||||
for (;itr != end; ++itr) {
|
||||
for (; itr != end; ++itr) {
|
||||
if (itr->x > x_max) {
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
if (itr->x < x_min) {
|
||||
break;
|
||||
@@ -267,10 +270,6 @@ void insert_hot_pixels_in_path(bound<T>& bnd,
|
||||
if (end_pt == bnd.last_point) {
|
||||
return;
|
||||
}
|
||||
if (!bnd.ring) {
|
||||
bnd.last_point = end_pt;
|
||||
return;
|
||||
}
|
||||
|
||||
T start_y = bnd.last_point.y;
|
||||
T start_x = bnd.last_point.x;
|
||||
@@ -336,11 +335,8 @@ void add_first_point(active_bound_list_itr<T>& bnd,
|
||||
|
||||
ring_ptr<T> r = create_new_ring(rings);
|
||||
(*bnd)->ring = r;
|
||||
r->is_open = ((*bnd)->winding_delta == 0);
|
||||
r->points = create_new_point(r, pt, rings);
|
||||
if (!r->is_open) {
|
||||
set_hole_state(bnd, active_bounds, rings);
|
||||
}
|
||||
set_hole_state(bnd, active_bounds, rings);
|
||||
(*bnd)->last_point = pt;
|
||||
}
|
||||
|
||||
@@ -352,11 +348,8 @@ void add_first_point(active_bound_list_rev_itr<T>& bnd,
|
||||
ring_ptr<T> r = create_new_ring(rings);
|
||||
// no ring currently set!
|
||||
(*bnd)->ring = r;
|
||||
r->is_open = ((*bnd)->winding_delta == 0);
|
||||
r->points = create_new_point(r, pt, rings);
|
||||
if (!r->is_open) {
|
||||
set_hole_state(bnd, active_bounds, rings);
|
||||
}
|
||||
set_hole_state(bnd, active_bounds, rings);
|
||||
(*bnd)->last_point = pt;
|
||||
}
|
||||
|
||||
@@ -556,7 +549,7 @@ ring_ptr<T> get_lower_most_ring(ring_ptr<T> outRec1, ring_ptr<T> outRec2) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool ring1_right_of_ring2(ring_ptr<T> ring1, ring_ptr<T> ring2) {
|
||||
bool ring1_child_below_ring2(ring_ptr<T> ring1, ring_ptr<T> ring2) {
|
||||
do {
|
||||
ring1 = ring1->parent;
|
||||
if (ring1 == ring2) {
|
||||
@@ -588,12 +581,12 @@ void append_ring(active_bound_list_itr<T>& b1,
|
||||
bound_ptr<T> keep_bound;
|
||||
ring_ptr<T> remove_ring;
|
||||
bound_ptr<T> remove_bound;
|
||||
if (ring1_right_of_ring2(outRec1, outRec2)) {
|
||||
if (ring1_child_below_ring2(outRec1, outRec2)) {
|
||||
keep_ring = outRec2;
|
||||
keep_bound = *b2;
|
||||
remove_ring = outRec1;
|
||||
remove_bound = *b1;
|
||||
} else if (ring1_right_of_ring2(outRec2, outRec1)) {
|
||||
} else if (ring1_child_below_ring2(outRec2, outRec1)) {
|
||||
keep_ring = outRec1;
|
||||
keep_bound = *b1;
|
||||
remove_ring = outRec2;
|
||||
@@ -688,9 +681,6 @@ void add_local_maximum_point(active_bound_list_itr<T>& b1,
|
||||
active_bound_list<T>& active_bounds) {
|
||||
insert_hot_pixels_in_path(*(*b2), pt, rings, false);
|
||||
add_point(b1, active_bounds, pt, rings);
|
||||
if ((*b2)->winding_delta == 0) {
|
||||
add_point(b2, active_bounds, pt, rings);
|
||||
}
|
||||
if ((*b1)->ring == (*b2)->ring) {
|
||||
(*b1)->ring = nullptr;
|
||||
(*b2)->ring = nullptr;
|
||||
@@ -881,7 +871,9 @@ point_in_polygon_result inside_or_outside_special(point_ptr<T> first_pt, point_p
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool poly2_contains_poly1(point_ptr<T> outpt1, point_ptr<T> outpt2) {
|
||||
bool poly2_contains_poly1(ring_ptr<T> ring1, ring_ptr<T> ring2) {
|
||||
point_ptr<T> outpt1 = ring1->points->next;
|
||||
point_ptr<T> outpt2 = ring2->points->next;
|
||||
point_ptr<T> op = outpt1;
|
||||
do {
|
||||
// nb: PointInPolygon returns 0 if false, +1 if true, -1 if pt on polygon
|
||||
@@ -907,7 +899,6 @@ void dispose_out_points(point_ptr<T>& pp) {
|
||||
tmpPp->next = tmpPp;
|
||||
tmpPp->prev = tmpPp;
|
||||
tmpPp->ring = nullptr;
|
||||
// delete tmpPp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <mapbox/geometry/wagyu/active_bound_list.hpp>
|
||||
#include <mapbox/geometry/wagyu/edge.hpp>
|
||||
#include <mapbox/geometry/wagyu/bound.hpp>
|
||||
#include <mapbox/geometry/wagyu/config.hpp>
|
||||
#include <mapbox/geometry/wagyu/edge.hpp>
|
||||
#include <mapbox/geometry/wagyu/intersect.hpp>
|
||||
#include <mapbox/geometry/wagyu/intersect_util.hpp>
|
||||
#include <mapbox/geometry/wagyu/ring.hpp>
|
||||
@@ -30,11 +30,14 @@ void process_hot_pixel_intersections(T top_y,
|
||||
auto bnd = active_bounds.begin();
|
||||
auto bnd_next = std::next(bnd);
|
||||
while (bnd_next != active_bounds.end()) {
|
||||
if ((*bnd)->current_x > (*bnd_next)->current_x && !slopes_equal(*(*bnd)->current_edge, *(*bnd_next)->current_edge)) {
|
||||
if ((*bnd)->current_x > (*bnd_next)->current_x &&
|
||||
!slopes_equal(*(*bnd)->current_edge, *(*bnd_next)->current_edge)) {
|
||||
mapbox::geometry::point<double> pt;
|
||||
if (!get_edge_intersection<T, double>(*((*bnd)->current_edge),
|
||||
*((*bnd_next)->current_edge), pt)) {
|
||||
*((*bnd_next)->current_edge), pt)) {
|
||||
// LCOV_EXCL_START
|
||||
throw std::runtime_error("Edges do not intersect!");
|
||||
// LCOV_EXCL_END
|
||||
}
|
||||
add_to_hot_pixels(round_point<T>(pt), rings);
|
||||
swap_positions_in_ABL(bnd, bnd_next, active_bounds);
|
||||
@@ -55,16 +58,20 @@ void process_hot_pixel_edges_at_top_of_scanbeam(T top_y,
|
||||
ring_manager<T>& rings) {
|
||||
for (auto bnd = active_bounds.begin(); bnd != active_bounds.end();) {
|
||||
auto bnd_2 = std::next(bnd);
|
||||
while ((*bnd)->current_edge != (*bnd)->edges.end() && (*bnd)->current_edge->top.y == top_y) {
|
||||
while ((*bnd)->current_edge != (*bnd)->edges.end() &&
|
||||
(*bnd)->current_edge->top.y == top_y) {
|
||||
add_to_hot_pixels((*bnd)->current_edge->top, rings);
|
||||
if (current_edge_is_horizontal<T>(bnd)) {
|
||||
(*bnd)->current_x = static_cast<double>((*bnd)->current_edge->top.x);
|
||||
if ((*bnd)->current_edge->bot.x < (*bnd)->current_edge->top.x) {
|
||||
// left to right
|
||||
auto bnd_next = std::next(bnd);
|
||||
while (bnd_next != active_bounds.end() && (*bnd_next)->current_x < (*bnd)->current_x) {
|
||||
if (std::llround((*bnd_next)->current_edge->top.y) != top_y && std::llround((*bnd_next)->current_edge->bot.y) != top_y) {
|
||||
mapbox::geometry::point<T> pt(std::llround((*bnd_next)->current_x), top_y);
|
||||
while (bnd_next != active_bounds.end() &&
|
||||
(*bnd_next)->current_x < (*bnd)->current_x) {
|
||||
if (std::llround((*bnd_next)->current_edge->top.y) != top_y &&
|
||||
std::llround((*bnd_next)->current_edge->bot.y) != top_y) {
|
||||
mapbox::geometry::point<T> pt(std::llround((*bnd_next)->current_x),
|
||||
top_y);
|
||||
add_to_hot_pixels(pt, rings);
|
||||
}
|
||||
swap_positions_in_ABL(bnd, bnd_next, active_bounds);
|
||||
@@ -74,9 +81,12 @@ void process_hot_pixel_edges_at_top_of_scanbeam(T top_y,
|
||||
// right to left
|
||||
if (bnd != active_bounds.begin()) {
|
||||
auto bnd_prev = std::prev(bnd);
|
||||
while (bnd != active_bounds.begin() && (*bnd_prev)->current_x > (*bnd)->current_x) {
|
||||
if (std::llround((*bnd_prev)->current_edge->top.y) != top_y && std::llround((*bnd_prev)->current_edge->bot.y) != top_y) {
|
||||
mapbox::geometry::point<T> pt(std::llround((*bnd_prev)->current_x), top_y);
|
||||
while (bnd != active_bounds.begin() &&
|
||||
(*bnd_prev)->current_x > (*bnd)->current_x) {
|
||||
if (std::llround((*bnd_prev)->current_edge->top.y) != top_y &&
|
||||
std::llround((*bnd_prev)->current_edge->bot.y) != top_y) {
|
||||
mapbox::geometry::point<T> pt(std::llround((*bnd_prev)->current_x),
|
||||
top_y);
|
||||
add_to_hot_pixels(pt, rings);
|
||||
}
|
||||
swap_positions_in_ABL(bnd, bnd_prev, active_bounds);
|
||||
@@ -96,18 +106,13 @@ void process_hot_pixel_edges_at_top_of_scanbeam(T top_y,
|
||||
|
||||
template <typename T>
|
||||
void insert_local_minima_into_ABL_hot_pixel(T top_y,
|
||||
local_minimum_ptr_list<T> & minima_sorted,
|
||||
local_minimum_ptr_list_itr<T> & lm,
|
||||
local_minimum_ptr_list<T>& minima_sorted,
|
||||
local_minimum_ptr_list_itr<T>& lm,
|
||||
active_bound_list<T>& active_bounds,
|
||||
ring_manager<T>& rings,
|
||||
scanbeam_list<T>& scanbeam) {
|
||||
while (lm != minima_sorted.end() && (*lm)->y == top_y) {
|
||||
if ((*lm)->left_bound.edges.empty() || (*lm)->right_bound.edges.empty()) {
|
||||
++lm;
|
||||
continue;
|
||||
}
|
||||
|
||||
add_to_hot_pixels((*lm)->left_bound.edges.front().bot, rings);
|
||||
add_to_hot_pixels((*lm)->left_bound.edges.front().bot, rings);
|
||||
auto& left_bound = (*lm)->left_bound;
|
||||
left_bound.current_edge = left_bound.edges.begin();
|
||||
left_bound.current_x = static_cast<double>(left_bound.current_edge->bot.x);
|
||||
@@ -127,12 +132,7 @@ void insert_local_minima_into_ABL_hot_pixel(T top_y,
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void build_hot_pixels(local_minimum_list<T>& minima_list,
|
||||
ring_manager<T>& rings) {
|
||||
if (minima_list.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
void build_hot_pixels(local_minimum_list<T>& minima_list, ring_manager<T>& rings) {
|
||||
active_bound_list<T> active_bounds;
|
||||
scanbeam_list<T> scanbeam;
|
||||
T scanline_y = std::numeric_limits<T>::max();
|
||||
@@ -149,7 +149,7 @@ void build_hot_pixels(local_minimum_list<T>& minima_list,
|
||||
|
||||
// Estimate size for reserving hot pixels
|
||||
std::size_t reserve = 0;
|
||||
for (auto & lm : minima_list) {
|
||||
for (auto& lm : minima_list) {
|
||||
reserve += lm.left_bound.edges.size() + 2;
|
||||
reserve += lm.right_bound.edges.size() + 2;
|
||||
}
|
||||
@@ -160,15 +160,13 @@ void build_hot_pixels(local_minimum_list<T>& minima_list,
|
||||
process_hot_pixel_intersections(scanline_y, active_bounds, rings);
|
||||
|
||||
insert_local_minima_into_ABL_hot_pixel(scanline_y, minima_sorted, current_lm, active_bounds,
|
||||
rings, scanbeam);
|
||||
|
||||
rings, scanbeam);
|
||||
|
||||
process_hot_pixel_edges_at_top_of_scanbeam(scanline_y, scanbeam, active_bounds, rings);
|
||||
|
||||
}
|
||||
preallocate_point_memory(rings, rings.hot_pixels.size());
|
||||
sort_hot_pixels(rings);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,22 +28,19 @@ struct point_ptr_pair {
|
||||
point_ptr<T> op1;
|
||||
point_ptr<T> op2;
|
||||
|
||||
constexpr point_ptr_pair(point_ptr<T> o1, point_ptr<T> o2)
|
||||
: op1(o1),
|
||||
op2(o2) {}
|
||||
constexpr point_ptr_pair(point_ptr<T> o1, point_ptr<T> o2) : op1(o1), op2(o2) {
|
||||
}
|
||||
|
||||
point_ptr_pair(point_ptr_pair<T> const& p) = default;
|
||||
|
||||
point_ptr_pair(point_ptr_pair<T> && p)
|
||||
: op1(std::move(p.op1)),
|
||||
op2(std::move(p.op2)) {}
|
||||
point_ptr_pair(point_ptr_pair<T>&& p) : op1(std::move(p.op1)), op2(std::move(p.op2)) {
|
||||
}
|
||||
|
||||
point_ptr_pair& operator=(point_ptr_pair<T> && p) {
|
||||
point_ptr_pair& operator=(point_ptr_pair<T>&& p) {
|
||||
op1 = std::move(p.op1);
|
||||
op2 = std::move(p.op2);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -202,19 +199,65 @@ void remove_spikes(point_ptr<T>& pt) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void fixup_children(ring_ptr<T> old_ring, ring_ptr<T> new_ring) {
|
||||
void fixup_children_complex(ring_ptr<T> old_ring,
|
||||
ring_ptr<T> new_ring,
|
||||
ring_vector<T> const& grand_children,
|
||||
ring_manager<T> const& rings) {
|
||||
// Tests if any of the children from the old ring are now children of the new ring
|
||||
assert(old_ring != new_ring);
|
||||
for (auto r = old_ring->children.begin(); r != old_ring->children.end();) {
|
||||
assert((*r)->points);
|
||||
assert((*r) != old_ring);
|
||||
if ((*r) != new_ring && !ring1_right_of_ring2(new_ring, (*r)) &&
|
||||
poly2_contains_poly1((*r)->points, new_ring->points)) {
|
||||
if ((*r) == new_ring) {
|
||||
++r;
|
||||
continue;
|
||||
}
|
||||
if (poly2_contains_poly1(*r, new_ring)) {
|
||||
(*r)->parent = new_ring;
|
||||
new_ring->children.push_back((*r));
|
||||
r = old_ring->children.erase(r);
|
||||
} else {
|
||||
} else if (poly2_contains_poly1(*r, old_ring)) {
|
||||
++r;
|
||||
} else {
|
||||
// Rare situation where one of old_rings's previous grand children
|
||||
// should actually contain this ring.
|
||||
bool found = false;
|
||||
for (auto const& gc : grand_children) {
|
||||
if (poly2_contains_poly1(*r, gc)) {
|
||||
(*r)->parent = gc;
|
||||
gc->children.push_back((*r));
|
||||
r = old_ring->children.erase(r);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (old_ring->parent == nullptr) {
|
||||
for (auto const& r2 : rings.children) {
|
||||
if (r2 != new_ring && r2 != old_ring && r2->points && r2 != (*r) &&
|
||||
poly2_contains_poly1(*r, r2)) {
|
||||
(*r)->parent = r2;
|
||||
r2->children.push_back((*r));
|
||||
r = old_ring->children.erase(r);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto const& r2 : old_ring->parent->children) {
|
||||
if (r2 != new_ring && r2 != old_ring && r2->points && r2 != (*r) &&
|
||||
poly2_contains_poly1((*r), r2)) {
|
||||
(*r)->parent = r2;
|
||||
r2->children.push_back((*r));
|
||||
r = old_ring->children.erase(r);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
throw std::runtime_error("No proper parent for child ring found");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -266,16 +309,7 @@ bool fix_intersects(std::unordered_multimap<ring_ptr<T>, point_ptr_pair<T>>& dup
|
||||
if (ring_parent != ring_search->parent) {
|
||||
// The two holes do not have the same parent, do not add them
|
||||
// simply return!
|
||||
if (ring_parent->parent != ring_search &&
|
||||
poly2_contains_poly1(ring_search->points, ring_parent->points) &&
|
||||
!ring1_right_of_ring2(ring_search, ring_parent)) {
|
||||
ring_ptr<T> old_parent = ring_search->parent;
|
||||
ring_search->parent = ring_parent;
|
||||
old_parent->children.remove(ring_search);
|
||||
ring_parent->children.push_back(ring_search);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool found = false;
|
||||
std::list<std::pair<ring_ptr<T>, point_ptr_pair<T>>> iList;
|
||||
@@ -459,11 +493,15 @@ bool fix_intersects(std::unordered_multimap<ring_ptr<T>, point_ptr_pair<T>>& dup
|
||||
|
||||
ring_origin->bottom_point = nullptr;
|
||||
|
||||
ring_vector<T> grand_children;
|
||||
for (auto& iRing : iList) {
|
||||
ring_ptr<T> ring_itr = iRing.first;
|
||||
ring_itr->points = nullptr;
|
||||
ring_itr->area = std::numeric_limits<double>::quiet_NaN();
|
||||
ring_itr->bottom_point = nullptr;
|
||||
for (auto& c : ring_itr->children) {
|
||||
grand_children.push_back(c);
|
||||
}
|
||||
if (ring_is_hole(ring_origin)) {
|
||||
ring1_replaces_ring2(ring_origin, ring_itr, rings);
|
||||
} else {
|
||||
@@ -473,8 +511,8 @@ bool fix_intersects(std::unordered_multimap<ring_ptr<T>, point_ptr_pair<T>>& dup
|
||||
if (ring_is_hole(ring_origin)) {
|
||||
ring_new->parent = ring_origin;
|
||||
ring_new->parent->children.push_back(ring_new);
|
||||
fixup_children(ring_origin, ring_new);
|
||||
fixup_children(ring_parent, ring_new);
|
||||
fixup_children_complex(ring_origin, ring_new, grand_children, rings);
|
||||
fixup_children_complex(ring_parent, ring_new, grand_children, rings);
|
||||
} else {
|
||||
ring_new->parent = ring_origin->parent;
|
||||
if (ring_new->parent == nullptr) {
|
||||
@@ -482,7 +520,7 @@ bool fix_intersects(std::unordered_multimap<ring_ptr<T>, point_ptr_pair<T>>& dup
|
||||
} else {
|
||||
ring_new->parent->children.push_back(ring_new);
|
||||
}
|
||||
fixup_children(ring_origin, ring_new);
|
||||
fixup_children_complex(ring_origin, ring_new, grand_children, rings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,6 +639,58 @@ bool parent_in_tree(ring_ptr<T> r, ring_ptr<T> possible_parent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void fixup_children_sibling(ring_ptr<T> old_ring, ring_ptr<T> new_ring) {
|
||||
for (auto r = old_ring->children.begin(); r != old_ring->children.end();) {
|
||||
if ((*r) == new_ring) {
|
||||
++r;
|
||||
continue;
|
||||
}
|
||||
if (poly2_contains_poly1(*r, new_ring)) {
|
||||
(*r)->parent = new_ring;
|
||||
new_ring->children.push_back((*r));
|
||||
r = old_ring->children.erase(r);
|
||||
} else {
|
||||
++r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void fixup_parents_siblings(ring_ptr<T> parent, ring_ptr<T> ring, ring_manager<T>& rings) {
|
||||
bool parent_ring_area_is_positive = area(parent) > 0.0;
|
||||
if (parent->parent == nullptr) {
|
||||
for (auto r = rings.children.begin(); r != rings.children.end();) {
|
||||
assert((*r)->points);
|
||||
bool ring_area_is_positive = area((*r)) > 0.0;
|
||||
if ((*r) != parent && ring_area_is_positive == parent_ring_area_is_positive &&
|
||||
poly2_contains_poly1(ring, (*r))) {
|
||||
ring->parent = (*r);
|
||||
(*r)->children.push_back(ring);
|
||||
parent->children.remove(ring);
|
||||
break;
|
||||
} else {
|
||||
++r;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ring_ptr<T> grand_parent = parent->parent;
|
||||
for (auto r = grand_parent->children.begin(); r != grand_parent->children.end();) {
|
||||
assert((*r)->points);
|
||||
bool ring_area_is_positive = area((*r)) > 0.0;
|
||||
if ((*r) != parent && ring_area_is_positive == parent_ring_area_is_positive &&
|
||||
poly2_contains_poly1(ring, (*r))) {
|
||||
ring->parent = (*r);
|
||||
(*r)->children.push_back(ring);
|
||||
parent->children.remove(ring);
|
||||
break;
|
||||
} else {
|
||||
++r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void fixup_children_new_interior_ring(ring_ptr<T> old_ring,
|
||||
ring_ptr<T> new_ring,
|
||||
@@ -614,7 +704,7 @@ void fixup_children_new_interior_ring(ring_ptr<T> old_ring,
|
||||
assert((*r)->points);
|
||||
bool ring_area_is_positive = area((*r)) > 0.0;
|
||||
if ((*r) != new_ring && ring_area_is_positive == old_ring_area_is_positive &&
|
||||
poly2_contains_poly1((*r)->points, new_ring->points)) {
|
||||
poly2_contains_poly1((*r), new_ring)) {
|
||||
(*r)->parent = new_ring;
|
||||
new_ring->children.push_back((*r));
|
||||
r = rings.children.erase(r);
|
||||
@@ -629,7 +719,7 @@ void fixup_children_new_interior_ring(ring_ptr<T> old_ring,
|
||||
assert((*r) != parent);
|
||||
bool ring_area_is_positive = area((*r)) > 0.0;
|
||||
if ((*r) != new_ring && ring_area_is_positive == old_ring_area_is_positive &&
|
||||
poly2_contains_poly1((*r)->points, new_ring->points)) {
|
||||
poly2_contains_poly1((*r), new_ring)) {
|
||||
(*r)->parent = new_ring;
|
||||
new_ring->children.push_back((*r));
|
||||
r = parent->children.erase(r);
|
||||
@@ -804,23 +894,23 @@ void handle_self_intersections(point_ptr<T> op,
|
||||
}
|
||||
update_points_ring(ring);
|
||||
update_points_ring(new_ring);
|
||||
if (poly2_contains_poly1(new_ring->points, ring->points)) {
|
||||
// This is the situation where there is the new ring is
|
||||
// created inside the ring. Later on this should be inherited
|
||||
// as child of a newly created hole. However, we should check existing
|
||||
// holes of this polygon to see if they might belong inside this polygon.
|
||||
new_ring->parent = ring;
|
||||
new_ring->parent->children.push_back(new_ring);
|
||||
fixup_children(ring, new_ring);
|
||||
// Polygons are completely seperate
|
||||
new_ring->parent = ring->parent;
|
||||
if (new_ring->parent == nullptr) {
|
||||
rings.children.push_back(new_ring);
|
||||
} else {
|
||||
// Polygons are completely seperate
|
||||
new_ring->parent = ring->parent;
|
||||
if (new_ring->parent == nullptr) {
|
||||
rings.children.push_back(new_ring);
|
||||
} else {
|
||||
new_ring->parent->children.push_back(new_ring);
|
||||
new_ring->parent->children.push_back(new_ring);
|
||||
}
|
||||
fixup_children_sibling(ring, new_ring);
|
||||
// The parent might need to be reassigned in rare situations
|
||||
if (ring->parent) {
|
||||
if (!poly2_contains_poly1(ring, ring->parent)) {
|
||||
// Parent ring split on outside - search parent's siblings
|
||||
fixup_parents_siblings(ring->parent, ring, rings);
|
||||
} else if (!poly2_contains_poly1(new_ring, ring->parent)) {
|
||||
// child ring split on the outside
|
||||
fixup_parents_siblings(ring->parent, new_ring, rings);
|
||||
}
|
||||
fixup_children(ring, new_ring);
|
||||
}
|
||||
}
|
||||
update_duplicate_point_entries(ring, dupe_ring);
|
||||
@@ -1190,7 +1280,8 @@ bool clockwise_of_next(point_ptr<T> const& origin, point_ptr<T> pt) {
|
||||
} else if (ot_next_prev == orientation_collinear_line) {
|
||||
// This shouldn't happen?
|
||||
// LCOV_EXCL_START
|
||||
throw std::runtime_error("Impossible situation reached in clockwise_of_next - 2");
|
||||
throw std::runtime_error(
|
||||
"Impossible situation reached in clockwise_of_next - 2");
|
||||
// LCOV_EXCL_END
|
||||
} else {
|
||||
// Pt next is counter clockwise of origin prev
|
||||
@@ -1548,7 +1639,6 @@ bool process_repeated_point_set(std::size_t first_index,
|
||||
std::unordered_multimap<ring_ptr<T>, point_ptr_pair<T>>& dupe_ring,
|
||||
ring_manager<T>& rings) {
|
||||
point_ptr<T> point_1 = rings.all_points[current_index];
|
||||
|
||||
if (point_1->ring == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@@ -1576,8 +1666,10 @@ bool process_repeated_point_set(std::size_t first_index,
|
||||
if (ot_next == orientation_collinear_spike) {
|
||||
orientation_type ot_prev = orientation_of_points(point_2, point_2->prev, point_3->prev);
|
||||
if (ot_prev == orientation_collinear_spike) {
|
||||
// Start at point_1 and we will travel around the circle until we find another point at
|
||||
// the same location. We will measure its area, and then continue till the next point at
|
||||
// Start at point_1 and we will travel around the circle until we find another point
|
||||
// at
|
||||
// the same location. We will measure its area, and then continue till the next
|
||||
// point at
|
||||
// the same location. The smallest absolute value of area is the one we will use.
|
||||
point_ptr<T> point_a = point_1;
|
||||
point_ptr<T> min_a = nullptr;
|
||||
@@ -1586,7 +1678,8 @@ bool process_repeated_point_set(std::size_t first_index,
|
||||
double area = 0.0;
|
||||
double min_area = std::numeric_limits<double>::max();
|
||||
while (pt != point_1) {
|
||||
area += static_cast<double>(pt->prev->x + pt->x) * static_cast<double>(pt->prev->y - pt->y);
|
||||
area += static_cast<double>(pt->prev->x + pt->x) *
|
||||
static_cast<double>(pt->prev->y - pt->y);
|
||||
if (*pt == *point_1) {
|
||||
if (std::fabs(area) < min_area) {
|
||||
min_area = std::fabs(area);
|
||||
@@ -1603,7 +1696,8 @@ bool process_repeated_point_set(std::size_t first_index,
|
||||
throw std::runtime_error("No other point was between point_1 on the path");
|
||||
// LCOV_EXCL_END
|
||||
}
|
||||
area += static_cast<double>(pt->prev->x + pt->x) * static_cast<double>(pt->prev->y - pt->y);
|
||||
area += static_cast<double>(pt->prev->x + pt->x) *
|
||||
static_cast<double>(pt->prev->y - pt->y);
|
||||
if (std::fabs(area) < min_area) {
|
||||
min_area = std::fabs(area);
|
||||
min_a = point_a;
|
||||
@@ -1659,7 +1753,7 @@ void process_repeated_points(std::size_t first_index,
|
||||
}
|
||||
}
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
// LCOV_EXCL_END
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1721,14 +1815,10 @@ bool index_is_after_point(std::size_t const& i,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rings.all_points[i]->y < pt.y) {
|
||||
return true;
|
||||
} else if (rings.all_points[i]->y > pt.y) {
|
||||
return false;
|
||||
} else if (rings.all_points[i]->x >= pt.x) {
|
||||
return true;
|
||||
if (rings.all_points[i]->y == pt.y) {
|
||||
return rings.all_points[i]->x >= pt.x;
|
||||
} else {
|
||||
return false;
|
||||
return rings.all_points[i]->y < pt.y;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1771,35 +1861,6 @@ void remove_spikes_in_polygons(ring_ptr<T> r, ring_manager<T>& rings) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void fixup_out_polyline(ring<T>& ring, ring_manager<T>& rings) {
|
||||
point_ptr<T> pp = ring.points;
|
||||
point_ptr<T> lastPP = pp->prev;
|
||||
while (pp != lastPP) {
|
||||
pp = pp->next;
|
||||
if (*pp == *pp->prev) {
|
||||
if (pp == lastPP)
|
||||
lastPP = pp->prev;
|
||||
point_ptr<T> tmpPP = pp->prev;
|
||||
tmpPP->next = pp->next;
|
||||
pp->next->prev = tmpPP;
|
||||
// delete pp;
|
||||
pp->next = pp;
|
||||
pp->prev = pp;
|
||||
pp->ring = nullptr;
|
||||
pp = tmpPP;
|
||||
}
|
||||
}
|
||||
|
||||
if (pp == pp->prev) {
|
||||
remove_ring(&ring, rings);
|
||||
dispose_out_points(pp);
|
||||
ring.points = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void fixup_out_polygon(ring<T>& ring, ring_manager<T>& rings) {
|
||||
// FixupOutPolygon() - removes duplicate points and simplifies consecutive
|
||||
@@ -1820,8 +1881,7 @@ void fixup_out_polygon(ring<T>& ring, ring_manager<T>& rings) {
|
||||
}
|
||||
|
||||
// test for duplicate points and collinear edges ...
|
||||
if ((*pp == *pp->next) || (*pp == *pp->prev) ||
|
||||
(slopes_equal(*pp->prev, *pp, *pp->next))) {
|
||||
if ((*pp == *pp->next) || (*pp == *pp->prev) || (slopes_equal(*pp->prev, *pp, *pp->next))) {
|
||||
lastOK = nullptr;
|
||||
point_ptr<T> tmp = pp;
|
||||
pp->prev->next = pp->next;
|
||||
@@ -1842,13 +1902,11 @@ void fixup_out_polygon(ring<T>& ring, ring_manager<T>& rings) {
|
||||
ring.points = pp;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void do_simple_polygons(ring_manager<T>& rings) {
|
||||
|
||||
// fix orientations ...
|
||||
for (auto& r : rings.rings) {
|
||||
if (!r.points || r.is_open) {
|
||||
if (!r.points) {
|
||||
continue;
|
||||
}
|
||||
std::size_t s = 0;
|
||||
@@ -1904,7 +1962,7 @@ void do_simple_polygons(ring_manager<T>& rings) {
|
||||
#if DEBUG
|
||||
// LCOV_EXCL_START
|
||||
for (auto& r : rings.rings) {
|
||||
if (!r.points || r.is_open) {
|
||||
if (!r.points) {
|
||||
continue;
|
||||
}
|
||||
double stored_area = area(&r);
|
||||
@@ -1914,18 +1972,14 @@ void do_simple_polygons(ring_manager<T>& rings) {
|
||||
throw std::runtime_error("Difference in stored area vs calculated area!");
|
||||
}
|
||||
}
|
||||
// LCOV_EXCL_END
|
||||
// LCOV_EXCL_END
|
||||
#endif
|
||||
|
||||
for (auto& r : rings.rings) {
|
||||
if (!r.points || r.is_open) {
|
||||
if (!r.points) {
|
||||
continue;
|
||||
}
|
||||
fixup_out_polygon(r, rings);
|
||||
if (ring_is_hole(&r) == (area(&r) > 0.0)) {
|
||||
reverse_ring(r.points);
|
||||
r.area = std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,10 +46,6 @@ inline bool greater_than_or_equal(double x, double y) {
|
||||
return x > y || values_are_equal(x, y);
|
||||
}
|
||||
|
||||
inline bool less_than_or_equal(double x, double y) {
|
||||
return x < y || values_are_equal(x, y);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool slopes_equal(mapbox::geometry::point<T> const& pt1,
|
||||
mapbox::geometry::point<T> const& pt2,
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include <mapbox/geometry/wagyu/active_bound_list.hpp>
|
||||
#include <mapbox/geometry/wagyu/config.hpp>
|
||||
#include <mapbox/geometry/wagyu/exceptions.hpp>
|
||||
#include <mapbox/geometry/wagyu/intersect_util.hpp>
|
||||
#include <mapbox/geometry/wagyu/local_minimum.hpp>
|
||||
#include <mapbox/geometry/wagyu/local_minimum_util.hpp>
|
||||
@@ -29,7 +28,7 @@ bool execute_vatti(local_minimum_list<T>& minima_list,
|
||||
if (minima_list.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
active_bound_list<T> active_bounds;
|
||||
scanbeam_list<T> scanbeam;
|
||||
T scanline_y = std::numeric_limits<T>::max();
|
||||
@@ -48,8 +47,8 @@ bool execute_vatti(local_minimum_list<T>& minima_list,
|
||||
|
||||
while (pop_from_scanbeam(scanline_y, scanbeam) || current_lm != minima_sorted.end()) {
|
||||
|
||||
process_intersections(scanline_y, active_bounds, cliptype,
|
||||
subject_fill_type, clip_fill_type, rings);
|
||||
process_intersections(scanline_y, active_bounds, cliptype, subject_fill_type,
|
||||
clip_fill_type, rings);
|
||||
|
||||
update_current_hp_itr(scanline_y, rings);
|
||||
|
||||
@@ -63,10 +62,8 @@ bool execute_vatti(local_minimum_list<T>& minima_list,
|
||||
// Next we will add local minima bounds to the active bounds list that are on the local
|
||||
// minima queue at
|
||||
// this current scanline_y
|
||||
insert_local_minima_into_ABL(scanline_y, minima_sorted, current_lm, active_bounds,
|
||||
rings, scanbeam, cliptype, subject_fill_type,
|
||||
clip_fill_type);
|
||||
|
||||
insert_local_minima_into_ABL(scanline_y, minima_sorted, current_lm, active_bounds, rings,
|
||||
scanbeam, cliptype, subject_fill_type, clip_fill_type);
|
||||
}
|
||||
// std::clog << rings.rings << std::endl;
|
||||
// std::clog << output_as_polygon(rings.all_rings[0]);
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
#include <mapbox/geometry/multi_polygon.hpp>
|
||||
#include <mapbox/geometry/polygon.hpp>
|
||||
|
||||
#include <mapbox/geometry/wagyu/build_result.hpp>
|
||||
#include <mapbox/geometry/wagyu/build_local_minima_list.hpp>
|
||||
#include <mapbox/geometry/wagyu/build_result.hpp>
|
||||
#include <mapbox/geometry/wagyu/config.hpp>
|
||||
#include <mapbox/geometry/wagyu/local_minimum.hpp>
|
||||
#include <mapbox/geometry/wagyu/snap_rounding.hpp>
|
||||
@@ -25,28 +25,19 @@ private:
|
||||
using value_type = T;
|
||||
|
||||
local_minimum_list<value_type> minima_list;
|
||||
bool has_open_paths;
|
||||
bool reverse_output;
|
||||
|
||||
wagyu( wagyu const& ) = delete;
|
||||
wagyu& operator=(wagyu const& ) = delete;
|
||||
wagyu(wagyu const&) = delete;
|
||||
wagyu& operator=(wagyu const&) = delete;
|
||||
|
||||
public:
|
||||
wagyu() : minima_list(), has_open_paths(false), reverse_output(false) {
|
||||
wagyu() : minima_list(), reverse_output(false) {
|
||||
}
|
||||
|
||||
~wagyu() {
|
||||
clear();
|
||||
}
|
||||
|
||||
bool add_line(mapbox::geometry::line_string<value_type> const& pg) {
|
||||
bool success = add_line_string(pg, minima_list);
|
||||
if (success) {
|
||||
has_open_paths = true;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool add_ring(mapbox::geometry::linear_ring<value_type> const& pg,
|
||||
polygon_type p_type = polygon_type_subject) {
|
||||
return add_linear_ring(pg, minima_list, p_type);
|
||||
@@ -69,7 +60,6 @@ public:
|
||||
|
||||
void clear() {
|
||||
minima_list.clear();
|
||||
has_open_paths = false;
|
||||
}
|
||||
|
||||
mapbox::geometry::box<value_type> get_bounds() {
|
||||
@@ -122,13 +112,13 @@ public:
|
||||
fill_type clip_fill_type) {
|
||||
|
||||
ring_manager<T> rings;
|
||||
|
||||
|
||||
build_hot_pixels(minima_list, rings);
|
||||
|
||||
if (!execute_vatti(minima_list, rings, cliptype, subject_fill_type, clip_fill_type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
do_simple_polygons(rings);
|
||||
|
||||
build_result(solution, rings, reverse_output);
|
||||
|
||||
Reference in New Issue
Block a user