mirror of
https://github.com/felt/tippecanoe.git
synced 2026-10-05 18:05:42 +02:00
Upgrade to Wagyu 0.4.3
This commit is contained in:
+288
-118
@@ -5,6 +5,7 @@
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <mapbox/geometry/box.hpp>
|
||||
#include <mapbox/geometry/wagyu/point.hpp>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
@@ -29,35 +30,117 @@ namespace mapbox {
|
||||
namespace geometry {
|
||||
namespace wagyu {
|
||||
|
||||
template <typename T>
|
||||
double area_from_point(point_ptr<T> op, std::size_t& size, mapbox::geometry::box<T>& bbox) {
|
||||
point_ptr<T> startOp = op;
|
||||
size = 0;
|
||||
double a = 0.0;
|
||||
T min_x = op->x;
|
||||
T max_x = op->x;
|
||||
T min_y = op->y;
|
||||
T max_y = op->y;
|
||||
do {
|
||||
++size;
|
||||
if (op->x > max_x) {
|
||||
max_x = op->x;
|
||||
} else if (op->x < min_x) {
|
||||
min_x = op->x;
|
||||
}
|
||||
if (op->y > max_y) {
|
||||
max_y = op->y;
|
||||
} else if (op->y < min_y) {
|
||||
min_y = op->y;
|
||||
}
|
||||
a += static_cast<double>(op->prev->x + op->x) * static_cast<double>(op->prev->y - op->y);
|
||||
op = op->next;
|
||||
} while (op != startOp);
|
||||
bbox.min.x = min_x;
|
||||
bbox.max.x = max_x;
|
||||
bbox.min.y = min_y;
|
||||
bbox.max.y = max_y;
|
||||
return a * 0.5;
|
||||
}
|
||||
|
||||
// NOTE: ring and ring_ptr are forward declared in wagyu/point.hpp
|
||||
|
||||
template <typename T>
|
||||
using ring_vector = std::vector<ring_ptr<T>>;
|
||||
|
||||
template <typename T>
|
||||
using ring_list = std::list<ring_ptr<T>>;
|
||||
|
||||
template <typename T>
|
||||
struct ring {
|
||||
std::size_t ring_index; // To support unset 0 is undefined and indexes offset by 1
|
||||
std::size_t size;
|
||||
double area;
|
||||
|
||||
std::size_t size_; // number of points in the ring
|
||||
double area_; // area of the ring
|
||||
mapbox::geometry::box<T> bbox; // bounding box of the ring
|
||||
|
||||
ring_ptr<T> parent;
|
||||
ring_list<T> children;
|
||||
ring_vector<T> children;
|
||||
|
||||
point_ptr<T> points;
|
||||
point_ptr<T> bottom_point;
|
||||
bool is_hole_;
|
||||
bool corrected;
|
||||
|
||||
ring(ring const&) = delete;
|
||||
ring& operator=(ring const&) = delete;
|
||||
|
||||
ring()
|
||||
: ring_index(0),
|
||||
size(0),
|
||||
area(std::numeric_limits<double>::quiet_NaN()),
|
||||
size_(0),
|
||||
area_(std::numeric_limits<double>::quiet_NaN()),
|
||||
bbox({ 0, 0 }, { 0, 0 }),
|
||||
parent(nullptr),
|
||||
children(),
|
||||
points(nullptr),
|
||||
bottom_point(nullptr) {
|
||||
bottom_point(nullptr),
|
||||
is_hole_(false),
|
||||
corrected(false) {
|
||||
}
|
||||
|
||||
void reset_stats() {
|
||||
area_ = std::numeric_limits<double>::quiet_NaN();
|
||||
is_hole_ = false;
|
||||
bbox.min.x = 0;
|
||||
bbox.min.y = 0;
|
||||
bbox.max.x = 0;
|
||||
bbox.max.y = 0;
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
void recalculate_stats() {
|
||||
if (points != nullptr) {
|
||||
area_ = area_from_point(points, size_, bbox);
|
||||
is_hole_ = !(area_ > 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
void set_stats(double a, std::size_t s, mapbox::geometry::box<T> const& b) {
|
||||
bbox = b;
|
||||
area_ = a;
|
||||
size_ = s;
|
||||
is_hole_ = !(area_ > 0.0);
|
||||
}
|
||||
|
||||
double area() {
|
||||
if (std::isnan(area_)) {
|
||||
recalculate_stats();
|
||||
}
|
||||
return area_;
|
||||
}
|
||||
|
||||
bool is_hole() {
|
||||
if (std::isnan(area_)) {
|
||||
recalculate_stats();
|
||||
}
|
||||
return is_hole_;
|
||||
}
|
||||
|
||||
std::size_t size() {
|
||||
if (std::isnan(area_)) {
|
||||
recalculate_stats();
|
||||
}
|
||||
return size_;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -73,8 +156,8 @@ 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;
|
||||
ring_vector<T> children;
|
||||
point_vector<T> all_points;
|
||||
hot_pixel_vector<T> hot_pixels;
|
||||
hot_pixel_itr<T> current_hp_itr;
|
||||
std::deque<point<T>> points;
|
||||
@@ -104,10 +187,10 @@ void preallocate_point_memory(ring_manager<T>& rings, std::size_t size) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ring_ptr<T> create_new_ring(ring_manager<T>& rings) {
|
||||
rings.rings.emplace_back();
|
||||
ring_ptr<T> result = &rings.rings.back();
|
||||
result->ring_index = rings.index++;
|
||||
ring_ptr<T> create_new_ring(ring_manager<T>& manager) {
|
||||
manager.rings.emplace_back();
|
||||
ring_ptr<T> result = &manager.rings.back();
|
||||
result->ring_index = manager.index++;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -144,81 +227,190 @@ point_ptr<T> create_new_point(ring_ptr<T> r,
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ring1_child_of_ring2(ring_ptr<T> ring1, ring_ptr<T> ring2, ring_manager<T>& manager) {
|
||||
assert(ring1 != ring2);
|
||||
if (ring1->parent == ring2) {
|
||||
return;
|
||||
void set_to_children(ring_ptr<T> r, ring_vector<T>& children) {
|
||||
for (auto& c : children) {
|
||||
if (c == nullptr) {
|
||||
c = r;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ring1->parent == nullptr) {
|
||||
manager.children.remove(ring1);
|
||||
} else {
|
||||
ring1->parent->children.remove(ring1);
|
||||
}
|
||||
if (ring2 == nullptr) {
|
||||
ring1->parent = nullptr;
|
||||
manager.children.push_back(ring1);
|
||||
} else {
|
||||
ring1->parent = ring2;
|
||||
ring2->children.push_back(ring1);
|
||||
children.push_back(r);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void remove_from_children(ring_ptr<T> r, ring_vector<T>& children) {
|
||||
for (auto& c : children) {
|
||||
if (c == r) {
|
||||
c = nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ring1_sibling_of_ring2(ring_ptr<T> ring1, ring_ptr<T> ring2, ring_manager<T>& manager) {
|
||||
assert(ring1 != ring2);
|
||||
if (ring1->parent == ring2->parent) {
|
||||
void assign_as_child(ring_ptr<T> new_ring, ring_ptr<T> parent, ring_manager<T>& manager) {
|
||||
// Assigning as a child assumes that this is
|
||||
// a brand new ring. Therefore it does
|
||||
// not have any existing relationships
|
||||
if ((parent == nullptr && new_ring->is_hole()) ||
|
||||
(parent != nullptr && new_ring->is_hole() == parent->is_hole())) {
|
||||
throw std::runtime_error(
|
||||
"Trying to assign a child that is the same orientation as the parent");
|
||||
}
|
||||
auto& children = parent == nullptr ? manager.children : parent->children;
|
||||
set_to_children(new_ring, children);
|
||||
new_ring->parent = parent;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void reassign_as_child(ring_ptr<T> ring, ring_ptr<T> parent, ring_manager<T>& manager) {
|
||||
// Reassigning a ring assumes it already
|
||||
// has an existing parent
|
||||
if ((parent == nullptr && ring->is_hole()) ||
|
||||
(parent != nullptr && ring->is_hole() == parent->is_hole())) {
|
||||
throw std::runtime_error(
|
||||
"Trying to re-assign a child that is the same orientation as the parent");
|
||||
}
|
||||
|
||||
// Remove the old child relationship
|
||||
auto& old_children = ring->parent == nullptr ? manager.children : ring->parent->children;
|
||||
remove_from_children(ring, old_children);
|
||||
|
||||
// Add new child relationship
|
||||
auto& children = parent == nullptr ? manager.children : parent->children;
|
||||
set_to_children(ring, children);
|
||||
ring->parent = parent;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void assign_as_sibling(ring_ptr<T> new_ring, ring_ptr<T> sibling, ring_manager<T>& manager) {
|
||||
// Assigning as a sibling assumes that this is
|
||||
// a brand new ring. Therefore it does
|
||||
// not have any existing relationships
|
||||
if (new_ring->is_hole() != sibling->is_hole()) {
|
||||
throw std::runtime_error(
|
||||
"Trying to assign to be a sibling that is not the same orientation as the sibling");
|
||||
}
|
||||
auto& children = sibling->parent == nullptr ? manager.children : sibling->parent->children;
|
||||
set_to_children(new_ring, children);
|
||||
new_ring->parent = sibling->parent;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void reassign_as_sibling(ring_ptr<T> ring, ring_ptr<T> sibling, ring_manager<T>& manager) {
|
||||
if (ring->parent == sibling->parent) {
|
||||
return;
|
||||
}
|
||||
if (ring1->parent == nullptr) {
|
||||
manager.children.remove(ring1);
|
||||
} else {
|
||||
ring1->parent->children.remove(ring1);
|
||||
// Assigning as a sibling assumes that this is
|
||||
// a brand new ring. Therefore it does
|
||||
// not have any existing relationships
|
||||
if (ring->is_hole() != sibling->is_hole()) {
|
||||
throw std::runtime_error(
|
||||
"Trying to assign to be a sibling that is not the same orientation as the sibling");
|
||||
}
|
||||
if (ring2->parent == nullptr) {
|
||||
manager.children.push_back(ring1);
|
||||
} else {
|
||||
ring2->parent->children.push_back(ring1);
|
||||
}
|
||||
ring1->parent = ring2->parent;
|
||||
// Remove the old child relationship
|
||||
auto& old_children = ring->parent == nullptr ? manager.children : ring->parent->children;
|
||||
remove_from_children(ring, old_children);
|
||||
// Add new relationship
|
||||
auto& children = sibling->parent == nullptr ? manager.children : sibling->parent->children;
|
||||
set_to_children(ring, children);
|
||||
ring->parent = sibling->parent;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ring1_replaces_ring2(ring_ptr<T> ring1, ring_ptr<T> ring2, ring_manager<T>& manager) {
|
||||
assert(ring1 != ring2);
|
||||
if (ring2->parent == nullptr) {
|
||||
manager.children.remove(ring2);
|
||||
} else {
|
||||
ring2->parent->children.remove(ring2);
|
||||
}
|
||||
auto& ring1_children = ring1 == nullptr ? manager.children : ring1->children;
|
||||
for (auto& c : ring2->children) {
|
||||
if (c == nullptr) {
|
||||
continue;
|
||||
}
|
||||
c->parent = ring1;
|
||||
set_to_children(c, ring1_children);
|
||||
c = nullptr;
|
||||
}
|
||||
if (ring1 == nullptr) {
|
||||
manager.children.splice(manager.children.end(), ring2->children);
|
||||
} else {
|
||||
ring1->children.splice(ring1->children.end(), ring2->children);
|
||||
}
|
||||
ring2->parent = nullptr;
|
||||
// Remove the old child relationship
|
||||
auto& old_children = ring2->parent == nullptr ? manager.children : ring2->parent->children;
|
||||
remove_from_children(ring2, old_children);
|
||||
ring2->points = nullptr;
|
||||
ring2->reset_stats();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void remove_ring(ring_ptr<T> r, ring_manager<T>& manager) {
|
||||
if (r->parent == nullptr) {
|
||||
manager.children.remove(r);
|
||||
for (auto& c : r->children) {
|
||||
c->parent = nullptr;
|
||||
void remove_points(point_ptr<T> pt) {
|
||||
if (pt != nullptr) {
|
||||
pt->prev->next = nullptr;
|
||||
while (pt != nullptr) {
|
||||
point_ptr<T> tmp = pt;
|
||||
pt = pt->next;
|
||||
tmp->next = nullptr;
|
||||
tmp->prev = nullptr;
|
||||
tmp->ring = nullptr;
|
||||
}
|
||||
manager.children.splice(manager.children.end(), r->children);
|
||||
} else {
|
||||
r->parent->children.remove(r);
|
||||
for (auto& c : r->children) {
|
||||
c->parent = r->parent;
|
||||
}
|
||||
r->parent->children.splice(r->parent->children.end(), r->children);
|
||||
r->parent = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void remove_ring_and_points(ring_ptr<T> r,
|
||||
ring_manager<T>& manager,
|
||||
bool remove_children = true,
|
||||
bool remove_from_parent = true) {
|
||||
// Removes a ring and any children that might be
|
||||
// under that ring.
|
||||
for (auto& c : r->children) {
|
||||
if (c == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (remove_children) {
|
||||
remove_ring_and_points(c, manager, true, false);
|
||||
}
|
||||
c = nullptr;
|
||||
}
|
||||
if (remove_from_parent) {
|
||||
// Remove the old child relationship
|
||||
auto& old_children = r->parent == nullptr ? manager.children : r->parent->children;
|
||||
remove_from_children(r, old_children);
|
||||
}
|
||||
point_ptr<T> pt = r->points;
|
||||
if (pt != nullptr) {
|
||||
pt->prev->next = nullptr;
|
||||
while (pt != nullptr) {
|
||||
point_ptr<T> tmp = pt;
|
||||
pt = pt->next;
|
||||
tmp->next = nullptr;
|
||||
tmp->prev = nullptr;
|
||||
tmp->ring = nullptr;
|
||||
}
|
||||
}
|
||||
r->points = nullptr;
|
||||
r->reset_stats();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void remove_ring(ring_ptr<T> r,
|
||||
ring_manager<T>& manager,
|
||||
bool remove_children = true,
|
||||
bool remove_from_parent = true) {
|
||||
// Removes a ring and any children that might be
|
||||
// under that ring.
|
||||
for (auto& c : r->children) {
|
||||
if (c == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (remove_children) {
|
||||
remove_ring(c, manager, true, false);
|
||||
}
|
||||
c = nullptr;
|
||||
}
|
||||
if (remove_from_parent) {
|
||||
// Remove the old child relationship
|
||||
auto& old_children = r->parent == nullptr ? manager.children : r->parent->children;
|
||||
remove_from_children(r, old_children);
|
||||
}
|
||||
r->points = nullptr;
|
||||
r->reset_stats();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::size_t ring_depth(ring_ptr<T> r) {
|
||||
std::size_t depth = 0;
|
||||
@@ -234,6 +426,10 @@ inline std::size_t ring_depth(ring_ptr<T> r) {
|
||||
|
||||
template <typename T>
|
||||
inline bool ring_is_hole(ring_ptr<T> r) {
|
||||
// This is different then the "normal" way of determing if
|
||||
// a ring is a hole or not because it uses the depth of the
|
||||
// the ring to determine if it is a hole or not. This is only done
|
||||
// intially when rings are output from Vatti.
|
||||
return ring_depth(r) & 1;
|
||||
}
|
||||
|
||||
@@ -263,17 +459,6 @@ void init(const_point_ptr<T>& node) {
|
||||
set_prev(node, node);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::size_t point_count(const const_point_ptr<T>& orig_node) {
|
||||
std::size_t size = 0;
|
||||
point_ptr<T> n = orig_node;
|
||||
do {
|
||||
n = get_next(n);
|
||||
++size;
|
||||
} while (n != orig_node);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void link_before(point_ptr<T>& node, point_ptr<T>& new_node) {
|
||||
point_ptr<T> prev_node = get_prev(node);
|
||||
@@ -325,33 +510,11 @@ void reverse_ring(point_ptr<T> pp) {
|
||||
} while (pp1 != pp);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
double area_from_point(point_ptr<T> op, std::size_t& size) {
|
||||
point_ptr<T> startOp = op;
|
||||
size = 1;
|
||||
double a = 0.0;
|
||||
do {
|
||||
++size;
|
||||
a += static_cast<double>(op->prev->x + op->x) * static_cast<double>(op->prev->y - op->y);
|
||||
op = op->next;
|
||||
} while (op != startOp);
|
||||
return a * 0.5;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
double area(ring_ptr<T> r) {
|
||||
assert(r != nullptr);
|
||||
if (std::isnan(r->area)) {
|
||||
r->area = area_from_point(r->points, r->size);
|
||||
}
|
||||
return r->area;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
template <class charT, class traits, typename T>
|
||||
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out,
|
||||
const ring<T>& r) {
|
||||
ring<T>& r) {
|
||||
out << " ring_index: " << r.ring_index << std::endl;
|
||||
if (!r.parent) {
|
||||
// out << " parent_ring ptr: nullptr" << std::endl;
|
||||
@@ -368,7 +531,7 @@ inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, t
|
||||
}
|
||||
auto pt_itr = r.points;
|
||||
if (pt_itr) {
|
||||
out << " area: " << r.area << std::endl;
|
||||
out << " area: " << r.area() << std::endl;
|
||||
out << " points:" << std::endl;
|
||||
out << " [[[" << pt_itr->x << "," << pt_itr->y << "],";
|
||||
pt_itr = pt_itr->next;
|
||||
@@ -384,6 +547,22 @@ inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, t
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string debug_ring_addresses(ring_ptr<T> r) {
|
||||
std::ostringstream out;
|
||||
out << "Ring: " << r->ring_index << std::endl;
|
||||
if (r->points == nullptr) {
|
||||
out << " Ring has no points" << std::endl;
|
||||
return out.str();
|
||||
}
|
||||
auto pt_itr = r->points;
|
||||
do {
|
||||
out << " [" << pt_itr->x << "," << pt_itr->y << "] - " << pt_itr << std::endl;
|
||||
pt_itr = pt_itr->next;
|
||||
} while (pt_itr != r->points);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string output_as_polygon(ring_ptr<T> r) {
|
||||
std::ostringstream out;
|
||||
@@ -399,6 +578,9 @@ std::string output_as_polygon(ring_ptr<T> r) {
|
||||
}
|
||||
out << "[" << pt_itr->x << "," << pt_itr->y << "]]";
|
||||
for (auto const& c : r->children) {
|
||||
if (c == nullptr) {
|
||||
continue;
|
||||
}
|
||||
pt_itr = c->points;
|
||||
if (pt_itr) {
|
||||
out << ",[[" << pt_itr->x << "," << pt_itr->y << "],";
|
||||
@@ -420,22 +602,10 @@ std::string output_as_polygon(ring_ptr<T> r) {
|
||||
|
||||
template <class charT, class traits, typename T>
|
||||
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out,
|
||||
const ring_list<T>& rings) {
|
||||
out << "START RING LIST" << std::endl;
|
||||
for (auto& r : rings) {
|
||||
out << " ring: " << r->ring_index << " - " << r << std::endl;
|
||||
out << *r;
|
||||
}
|
||||
out << "END RING LIST" << std::endl;
|
||||
return out;
|
||||
}
|
||||
|
||||
template <class charT, class traits, typename T>
|
||||
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out,
|
||||
const ring_vector<T>& rings) {
|
||||
ring_vector<T>& rings) {
|
||||
out << "START RING VECTOR" << std::endl;
|
||||
for (auto& r : rings) {
|
||||
if (!r->points) {
|
||||
if (r == nullptr || !r->points) {
|
||||
continue;
|
||||
}
|
||||
out << " ring: " << r->ring_index << " - " << r << std::endl;
|
||||
@@ -447,7 +617,7 @@ inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, t
|
||||
|
||||
template <class charT, class traits, typename T>
|
||||
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out,
|
||||
const std::deque<ring<T>>& rings) {
|
||||
std::deque<ring<T>>& rings) {
|
||||
out << "START RING VECTOR" << std::endl;
|
||||
for (auto& r : rings) {
|
||||
if (!r.points) {
|
||||
@@ -462,7 +632,7 @@ inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, t
|
||||
|
||||
template <class charT, class traits, typename T>
|
||||
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out,
|
||||
const hot_pixel_vector<T>& hp_vec) {
|
||||
hot_pixel_vector<T>& hp_vec) {
|
||||
out << "Hot Pixels: " << std::endl;
|
||||
for (auto& hp : hp_vec) {
|
||||
out << hp << std::endl;
|
||||
|
||||
Reference in New Issue
Block a user