#pragma once #include #include #include #include namespace mapbox { namespace geometry { namespace wagyu { namespace quick_clip { template mapbox::geometry::point intersect(mapbox::geometry::point a, mapbox::geometry::point b, size_t edge, mapbox::geometry::box const& box) { switch (edge) { case 0: return mapbox::geometry::point( static_cast(a.x + static_cast(b.x - a.x) * (box.min.y - a.y) / (b.y - a.y)), box.min.y); case 1: return mapbox::geometry::point( box.max.x, static_cast(a.y + static_cast(b.y - a.y) * (box.max.x - a.x) / (b.x - a.x))); case 2: return mapbox::geometry::point( static_cast(a.x + static_cast(b.x - a.x) * (box.max.y - a.y) / (b.y - a.y)), box.max.y); default: // case 3 return mapbox::geometry::point( box.min.x, static_cast(a.y + static_cast(b.y - a.y) * (box.min.x - a.x) / (b.x - a.x))); } } template bool inside(mapbox::geometry::point p, size_t edge, mapbox::geometry::box const& b) { switch (edge) { case 0: return p.y > b.min.y; case 1: return p.x < b.max.x; case 2: return p.y < b.max.y; default: // case 3 return p.x > b.min.x; } } template mapbox::geometry::linear_ring quick_lr_clip(mapbox::geometry::linear_ring const& ring, mapbox::geometry::box const& b) { mapbox::geometry::linear_ring out = ring; for (size_t edge = 0; edge < 4; edge++) { if (out.size() > 0) { mapbox::geometry::linear_ring in = out; mapbox::geometry::point S = in[in.size() - 1]; out.resize(0); for (size_t e = 0; e < in.size(); e++) { mapbox::geometry::point E = in[e]; if (inside(E, edge, b)) { if (!inside(S, edge, b)) { out.push_back(intersect(S, E, edge, b)); } out.push_back(E); } else if (inside(S, edge, b)) { out.push_back(intersect(S, E, edge, b)); } S = E; } } } if (out.size() < 3) { out.clear(); return out; } // Close the ring if the first/last point was outside if (out[0] != out[out.size() - 1]) { out.push_back(out[0]); } return out; } } template mapbox::geometry::multi_polygon clip(mapbox::geometry::polygon const& poly, mapbox::geometry::box const& b, fill_type subject_fill_type) { mapbox::geometry::multi_polygon result; wagyu clipper; for (auto const& lr : poly) { auto new_lr = quick_clip::quick_lr_clip(lr, b); if (!new_lr.empty()) { clipper.add_ring(new_lr, polygon_type_subject); } } clipper.execute(clip_type_union, result, subject_fill_type, fill_type_even_odd); return result; } template mapbox::geometry::multi_polygon clip(mapbox::geometry::multi_polygon const& mp, mapbox::geometry::box const& b, fill_type subject_fill_type) { mapbox::geometry::multi_polygon result; wagyu clipper; for (auto const& poly : mp) { for (auto const& lr : poly) { auto new_lr = quick_clip::quick_lr_clip(lr, b); if (!new_lr.empty()) { clipper.add_ring(new_lr, polygon_type_subject); } } } clipper.execute(clip_type_union, result, subject_fill_type, fill_type_even_odd); return result; } } } }