Upgrade Wagyu to cfc895 and use its Sutherland-Hodgman implementation

This commit is contained in:
Eric Fischer 2017-01-11 15:43:07 -08:00
parent 2fdec7d2e4
commit 72086b7e92
6 changed files with 146 additions and 99 deletions

View File

@ -1,3 +1,7 @@
## 1.16.4
* Use Wagyu's quick_lr_clip() instead of a separate implementation
## 1.16.3
* Upgrade Wagyu to bfbf2893

View File

@ -43,7 +43,7 @@ PG=
H = $(wildcard *.h) $(wildcard *.hpp)
C = $(wildcard *.c) $(wildcard *.cpp)
INCLUDES = -I../wagyu/include -I/usr/local/include -I.
INCLUDES = -I/usr/local/include -I.
LIBS = -L/usr/local/lib
tippecanoe: geojson.o jsonpull/jsonpull.o tile.o pool.o mbtiles.o geometry.o projection.o memfile.o mvt.o serial.o main.o text.o

View File

@ -424,100 +424,6 @@ drawvec close_poly(drawvec &geom) {
return out;
}
static bool inside(draw d, int edge, long long minx, long long miny, long long maxx, long long maxy) {
switch (edge) {
case 0: // top
return d.y > miny;
case 1: // right
return d.x < maxx;
case 2: // bottom
return d.y < maxy;
case 3: // left
return d.x > minx;
}
fprintf(stderr, "internal error inside\n");
exit(EXIT_FAILURE);
}
static draw intersect(draw a, draw b, int edge, long long minx, long long miny, long long maxx, long long maxy) {
// The casts to double are because the product of coordinates
// can overflow a long long if the tile buffer is large.
switch (edge) {
case 0: // top
return draw(VT_LINETO, a.x + (double) (b.x - a.x) * (miny - a.y) / (b.y - a.y), miny);
case 1: // right
return draw(VT_LINETO, maxx, a.y + (double) (b.y - a.y) * (maxx - a.x) / (b.x - a.x));
case 2: // bottom
return draw(VT_LINETO, a.x + (double) (b.x - a.x) * (maxy - a.y) / (b.y - a.y), maxy);
case 3: // left
return draw(VT_LINETO, minx, a.y + (double) (b.y - a.y) * (minx - a.x) / (b.x - a.x));
}
fprintf(stderr, "internal error intersecting\n");
exit(EXIT_FAILURE);
}
// http://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm
static drawvec clip_poly1(drawvec &geom, long long minx, long long miny, long long maxx, long long maxy) {
drawvec out = geom;
for (int edge = 0; edge < 4; edge++) {
if (out.size() > 0) {
drawvec in = out;
out.resize(0);
draw S = in[in.size() - 1];
for (size_t e = 0; e < in.size(); e++) {
draw E = in[e];
if (inside(E, edge, minx, miny, maxx, maxy)) {
if (!inside(S, edge, minx, miny, maxx, maxy)) {
out.push_back(intersect(S, E, edge, minx, miny, maxx, maxy));
}
out.push_back(E);
} else if (inside(S, edge, minx, miny, maxx, maxy)) {
out.push_back(intersect(S, E, edge, minx, miny, maxx, maxy));
}
S = E;
}
}
}
if (out.size() > 0) {
// If the polygon begins and ends outside the edge,
// the starting and ending points will be left as the
// places where it intersects the edge. Need to add
// another point to close the loop.
if (out[0].x != out[out.size() - 1].x || out[0].y != out[out.size() - 1].y) {
out.push_back(out[0]);
}
if (out.size() < 3) {
// fprintf(stderr, "Polygon degenerated to a line segment\n");
out.clear();
return out;
}
out[0].op = VT_MOVETO;
for (size_t i = 1; i < out.size(); i++) {
out[i].op = VT_LINETO;
}
}
return out;
}
drawvec simple_clip_poly(drawvec &geom, long long minx, long long miny, long long maxx, long long maxy) {
drawvec out;

View File

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

View File

@ -485,15 +485,15 @@ bool first_is_bottom_point(const_point_ptr<T> btmPt1, const_point_ptr<T> btmPt2)
template <typename T>
point_ptr<T> get_bottom_point(point_ptr<T> pp) {
point_ptr<T> dups = 0;
point_ptr<T> dups = nullptr;
point_ptr<T> p = pp->next;
while (p != pp) {
if (p->y > pp->y) {
pp = p;
dups = 0;
dups = nullptr;
} else if (p->y == pp->y && p->x <= pp->x) {
if (p->x < pp->x) {
dups = 0;
dups = nullptr;
pp = p;
} else {
if (p->next != pp && p->prev != pp) {

View File

@ -1 +1 @@
#define VERSION "tippecanoe v1.16.3\n"
#define VERSION "tippecanoe v1.16.4\n"