mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-12 06:09:01 +08:00
Generalize the implementation of the Douglas Peucker algorithm to allow using a custom predicate to decide if points between the anchor and the floater should be removed.
This commit is contained in:
parent
b6fd7f7758
commit
225d52b084
@ -58,10 +58,7 @@ std::pair<std::vector<Vec2d>, std::vector<PointType>> remove_redundant_points(
|
|||||||
const std::int64_t index{std::distance(points.begin(), iterator)};
|
const std::int64_t index{std::distance(points.begin(), iterator)};
|
||||||
if (next(iterator) == points.end() || point_types[index] != point_types[index + 1]) {
|
if (next(iterator) == points.end() || point_types[index] != point_types[index + 1]) {
|
||||||
std::vector<Vec2d> simplification_result;
|
std::vector<Vec2d> simplification_result;
|
||||||
douglas_peucker<double>(
|
douglas_peucker(range_start, next(iterator), std::back_inserter(simplification_result), tolerance);
|
||||||
range_start, next(iterator), std::back_inserter(simplification_result), tolerance,
|
|
||||||
[](const Vec2d &point) { return point; }
|
|
||||||
);
|
|
||||||
|
|
||||||
points_result.insert(
|
points_result.insert(
|
||||||
points_result.end(), simplification_result.begin(), simplification_result.end()
|
points_result.end(), simplification_result.begin(), simplification_result.end()
|
||||||
|
@ -33,8 +33,8 @@ class BoundingBox3;
|
|||||||
|
|
||||||
// Reduces polyline in the <begin, end) range, outputs into the output iterator.
|
// Reduces polyline in the <begin, end) range, outputs into the output iterator.
|
||||||
// Output iterator may be equal to input iterator as long as the iterator value type move operator supports move at the same input / output address.
|
// Output iterator may be equal to input iterator as long as the iterator value type move operator supports move at the same input / output address.
|
||||||
template<typename SquareLengthType, typename InputIterator, typename OutputIterator, typename PointGetter>
|
template<typename SquareLengthType, typename InputIterator, typename OutputIterator, typename TakeFloaterPredicate, typename PointGetter>
|
||||||
inline OutputIterator douglas_peucker(InputIterator begin, InputIterator end, OutputIterator out, const double tolerance, PointGetter point_getter)
|
inline OutputIterator douglas_peucker(InputIterator begin, InputIterator end, OutputIterator out, TakeFloaterPredicate take_floater_predicate, PointGetter point_getter)
|
||||||
{
|
{
|
||||||
using InputIteratorCategory = typename std::iterator_traits<InputIterator>::iterator_category;
|
using InputIteratorCategory = typename std::iterator_traits<InputIterator>::iterator_category;
|
||||||
static_assert(std::is_base_of_v<std::input_iterator_tag, InputIteratorCategory>);
|
static_assert(std::is_base_of_v<std::input_iterator_tag, InputIteratorCategory>);
|
||||||
@ -50,7 +50,6 @@ inline OutputIterator douglas_peucker(InputIterator begin, InputIterator end, Ou
|
|||||||
// Two points input.
|
// Two points input.
|
||||||
*out ++ = std::move(*next);
|
*out ++ = std::move(*next);
|
||||||
} else {
|
} else {
|
||||||
const auto tolerance_sq = SquareLengthType(sqr(tolerance));
|
|
||||||
InputIterator anchor = begin;
|
InputIterator anchor = begin;
|
||||||
InputIterator floater = std::prev(end);
|
InputIterator floater = std::prev(end);
|
||||||
std::vector<InputIterator> dpStack;
|
std::vector<InputIterator> dpStack;
|
||||||
@ -108,8 +107,8 @@ inline OutputIterator douglas_peucker(InputIterator begin, InputIterator end, Ou
|
|||||||
|
|
||||||
assert(max_dist_sq.has_value());
|
assert(max_dist_sq.has_value());
|
||||||
|
|
||||||
// remove point if less than tolerance
|
// Remove points between the anchor and the floater when the predicate is satisfied.
|
||||||
take_floater = max_dist_sq <= tolerance_sq;
|
take_floater = take_floater_predicate(anchor, floater, *max_dist_sq);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (take_floater) {
|
if (take_floater) {
|
||||||
@ -138,14 +137,29 @@ inline OutputIterator douglas_peucker(InputIterator begin, InputIterator end, Ou
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduces polyline in the <begin, end) range, outputs into the output iterator.
|
template<typename SquareLengthType, typename InputIterator, typename OutputIterator, typename PointGetter>
|
||||||
// Output iterator may be equal to input iterator as long as the iterator value type move operator supports move at the same input / output address.
|
inline OutputIterator douglas_peucker(InputIterator begin, InputIterator end, OutputIterator out, const double tolerance, PointGetter point_getter) {
|
||||||
|
const auto tolerance_sq = static_cast<SquareLengthType>(sqr(tolerance));
|
||||||
|
|
||||||
|
const auto take_floater_predicate = [&tolerance_sq](InputIterator, InputIterator, const SquareLengthType max_dist_sq) -> bool {
|
||||||
|
return max_dist_sq <= tolerance_sq;
|
||||||
|
};
|
||||||
|
|
||||||
|
return douglas_peucker<SquareLengthType>(begin, end, out, take_floater_predicate, point_getter);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename OutputIterator>
|
template<typename OutputIterator>
|
||||||
inline OutputIterator douglas_peucker(Points::const_iterator begin, Points::const_iterator end, OutputIterator out, const double tolerance)
|
inline OutputIterator douglas_peucker(Points::const_iterator begin, Points::const_iterator end, OutputIterator out, const double tolerance)
|
||||||
{
|
{
|
||||||
return douglas_peucker<int64_t>(begin, end, out, tolerance, [](const Point &p) { return p; });
|
return douglas_peucker<int64_t>(begin, end, out, tolerance, [](const Point &p) { return p; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename OutputIterator>
|
||||||
|
inline OutputIterator douglas_peucker(Pointfs::const_iterator begin, Pointfs::const_iterator end, OutputIterator out, const double tolerance)
|
||||||
|
{
|
||||||
|
return douglas_peucker<double>(begin, end, out, tolerance, [](const Vec2d &p) { return p; });
|
||||||
|
}
|
||||||
|
|
||||||
inline Points douglas_peucker(const Points &src, const double tolerance)
|
inline Points douglas_peucker(const Points &src, const double tolerance)
|
||||||
{
|
{
|
||||||
Points out;
|
Points out;
|
||||||
|
@ -81,14 +81,14 @@ SCENARIO("Simplify polyne, template", "[Polyline]")
|
|||||||
Points polyline{ {0,0}, {1000,0}, {2000,0}, {2000,1000}, {2000,2000}, {1000,2000}, {0,2000}, {0,1000}, {0,0} };
|
Points polyline{ {0,0}, {1000,0}, {2000,0}, {2000,1000}, {2000,2000}, {1000,2000}, {0,2000}, {0,1000}, {0,0} };
|
||||||
WHEN("simplified with Douglas-Peucker with back inserter") {
|
WHEN("simplified with Douglas-Peucker with back inserter") {
|
||||||
Points out;
|
Points out;
|
||||||
douglas_peucker<int64_t>(polyline.begin(), polyline.end(), std::back_inserter(out), 10, [](const Point &p) { return p; });
|
douglas_peucker<int64_t>(polyline.begin(), polyline.end(), std::back_inserter(out), 10., [](const Point &p) { return p; });
|
||||||
THEN("simplified correctly") {
|
THEN("simplified correctly") {
|
||||||
REQUIRE(out == Points{ {0,0}, {2000,0}, {2000,2000}, {0,2000}, {0,0} });
|
REQUIRE(out == Points{ {0,0}, {2000,0}, {2000,2000}, {0,2000}, {0,0} });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WHEN("simplified with Douglas-Peucker in place") {
|
WHEN("simplified with Douglas-Peucker in place") {
|
||||||
Points out{ polyline };
|
Points out{ polyline };
|
||||||
out.erase(douglas_peucker<int64_t>(out.begin(), out.end(), out.begin(), 10, [](const Point &p) { return p; }), out.end());
|
out.erase(douglas_peucker<int64_t>(out.begin(), out.end(), out.begin(), 10., [](const Point &p) { return p; }), out.end());
|
||||||
THEN("simplified correctly") {
|
THEN("simplified correctly") {
|
||||||
REQUIRE(out == Points{ {0,0}, {2000,0}, {2000,2000}, {0,2000}, {0,0} });
|
REQUIRE(out == Points{ {0,0}, {2000,0}, {2000,2000}, {0,2000}, {0,0} });
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user