mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-11 17:59:10 +08:00
SPE-2495: Do not put scarft seam start on overhangs and blockers
Update the function offset_along_lines to offset along perimeters and add a stop condition.
This commit is contained in:
parent
b037828aef
commit
61291d9219
@ -95,6 +95,7 @@ PenaltyBreakString: 600
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 50
|
||||
PenaltyReturnTypeOnItsOwnLine: 300
|
||||
PenaltyIndentedWhitespace: 10
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
|
@ -41,42 +41,17 @@ const Perimeters::Perimeter::OptionalPointTree &pick_tree(
|
||||
throw std::runtime_error("Point tree for classification does not exist.");
|
||||
}
|
||||
|
||||
unsigned point_value(PointType point_type, PointClassification point_classification) {
|
||||
// Better be explicit than smart.
|
||||
switch (point_type) {
|
||||
case PointType::enforcer:
|
||||
switch (point_classification) {
|
||||
case PointClassification::embedded: return 9;
|
||||
case PointClassification::common: return 8;
|
||||
case PointClassification::overhang: return 7;
|
||||
}
|
||||
case PointType::common:
|
||||
switch (point_classification) {
|
||||
case PointClassification::embedded: return 6;
|
||||
case PointClassification::common: return 5;
|
||||
case PointClassification::overhang: return 4;
|
||||
}
|
||||
case PointType::blocker:
|
||||
switch (point_classification) {
|
||||
case PointClassification::embedded: return 3;
|
||||
case PointClassification::common: return 2;
|
||||
case PointClassification::overhang: return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
SeamChoice pick_seam_option(const Perimeters::Perimeter &perimeter, const SeamOptions &options) {
|
||||
const std::vector<PointType> &types{perimeter.point_types};
|
||||
const std::vector<PointClassification> &classifications{perimeter.point_classifications};
|
||||
const std::vector<Vec2d> &positions{perimeter.positions};
|
||||
|
||||
unsigned closeset_point_value =
|
||||
point_value(types.at(options.closest), classifications[options.closest]);
|
||||
get_point_value(types.at(options.closest), classifications[options.closest]);
|
||||
|
||||
if (options.snapped) {
|
||||
unsigned snapped_point_value =
|
||||
point_value(types.at(*options.snapped), classifications[*options.snapped]);
|
||||
get_point_value(types.at(*options.snapped), classifications[*options.snapped]);
|
||||
if (snapped_point_value >= closeset_point_value) {
|
||||
const Vec2d position{positions.at(*options.snapped)};
|
||||
return {*options.snapped, *options.snapped, position};
|
||||
@ -84,7 +59,7 @@ SeamChoice pick_seam_option(const Perimeters::Perimeter &perimeter, const SeamOp
|
||||
}
|
||||
|
||||
unsigned adjacent_point_value =
|
||||
point_value(types.at(options.adjacent), classifications[options.adjacent]);
|
||||
get_point_value(types.at(options.adjacent), classifications[options.adjacent]);
|
||||
if (adjacent_point_value < closeset_point_value) {
|
||||
const Vec2d position = positions[options.closest];
|
||||
return {options.closest, options.closest, position};
|
||||
|
@ -14,17 +14,7 @@
|
||||
#include "libslic3r/Point.hpp"
|
||||
|
||||
namespace Slic3r::Seams {
|
||||
|
||||
/**
|
||||
* When previous_index == next_index, the point is at the point.
|
||||
* Otherwise the point is at the edge.
|
||||
*/
|
||||
struct SeamChoice
|
||||
{
|
||||
std::size_t previous_index{};
|
||||
std::size_t next_index{};
|
||||
Vec2d position{Vec2d::Zero()};
|
||||
};
|
||||
using SeamChoice = Perimeters::PointOnPerimeter;
|
||||
|
||||
struct SeamPerimeterChoice
|
||||
{
|
||||
|
@ -469,56 +469,4 @@ Polygon to_polygon(const ExtrusionLoop &loop) {
|
||||
return Polygon{loop_points};
|
||||
}
|
||||
|
||||
std::optional<PointOnLine> offset_along_lines(
|
||||
const Vec2d &point,
|
||||
const std::size_t loop_line_index,
|
||||
const Linesf &loop_lines,
|
||||
const double offset,
|
||||
const Direction1D direction
|
||||
) {
|
||||
const Linef initial_line{loop_lines[loop_line_index]};
|
||||
double distance{
|
||||
direction == Direction1D::forward ? (initial_line.b - point).norm() :
|
||||
(point - initial_line.a).norm()};
|
||||
if (distance >= offset) {
|
||||
const Vec2d edge_direction{(initial_line.b - initial_line.a).normalized()};
|
||||
const Vec2d offset_point{direction == Direction1D::forward ? Vec2d{point + offset * edge_direction} : Vec2d{point - offset * edge_direction}};
|
||||
return {{offset_point, loop_line_index}};
|
||||
}
|
||||
|
||||
std::optional<PointOnLine> offset_point;
|
||||
|
||||
bool skip_first{direction == Direction1D::forward};
|
||||
const auto visitor{[&](std::size_t index) {
|
||||
if (skip_first) {
|
||||
skip_first = false;
|
||||
return false;
|
||||
}
|
||||
const Vec2d previous_point{
|
||||
direction == Direction1D::forward ? loop_lines[index].a : loop_lines[index].b};
|
||||
const Vec2d next_point{
|
||||
direction == Direction1D::forward ? loop_lines[index].b : loop_lines[index].a};
|
||||
const Vec2d edge{next_point - previous_point};
|
||||
|
||||
if (distance + edge.norm() > offset) {
|
||||
const double remaining_distance{offset - distance};
|
||||
offset_point =
|
||||
PointOnLine{previous_point + remaining_distance * edge.normalized(), index};
|
||||
return true;
|
||||
}
|
||||
|
||||
distance += edge.norm();
|
||||
|
||||
return false;
|
||||
}};
|
||||
|
||||
if (direction == Direction1D::forward) {
|
||||
Geometry::visit_forward(loop_line_index, loop_lines.size(), visitor);
|
||||
} else {
|
||||
Geometry::visit_backward(loop_line_index, loop_lines.size(), visitor);
|
||||
}
|
||||
|
||||
return offset_point;
|
||||
}
|
||||
|
||||
} // namespace Slic3r::Seams::Geometry
|
||||
|
@ -210,14 +210,6 @@ struct PointOnLine{
|
||||
std::size_t line_index;
|
||||
};
|
||||
|
||||
std::optional<PointOnLine> offset_along_lines(
|
||||
const Vec2d &point,
|
||||
const std::size_t loop_line_index,
|
||||
const Linesf &loop_lines,
|
||||
const double offset,
|
||||
const Direction1D direction
|
||||
);
|
||||
|
||||
} // namespace Slic3r::Seams::Geometry
|
||||
|
||||
#endif // libslic3r_SeamGeometry_hpp_
|
||||
|
@ -576,4 +576,100 @@ LayerPerimeters create_perimeters(
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<PointOnPerimeter> offset_along_perimeter(
|
||||
const PointOnPerimeter &point,
|
||||
const Perimeter& perimeter,
|
||||
const double offset,
|
||||
const Seams::Geometry::Direction1D direction,
|
||||
const std::function<bool(const Perimeter&, const std::size_t)> &early_stop_condition
|
||||
) {
|
||||
using Dir = Seams::Geometry::Direction1D;
|
||||
|
||||
const Linef initial_line{
|
||||
perimeter.positions[point.previous_index], perimeter.positions[point.next_index]};
|
||||
double distance{
|
||||
direction == Dir::forward ?
|
||||
(initial_line.b - point.position).norm() :
|
||||
(point.position - initial_line.a).norm()};
|
||||
|
||||
if (distance >= offset) {
|
||||
const Vec2d edge_direction{(initial_line.b - initial_line.a).normalized()};
|
||||
const Vec2d offset_point{direction == Dir::forward ? Vec2d{point.position + offset * edge_direction} : Vec2d{point.position - offset * edge_direction}};
|
||||
return {{point.previous_index, point.next_index, offset_point}};
|
||||
}
|
||||
|
||||
std::optional<PointOnPerimeter> offset_point;
|
||||
|
||||
bool skip_first{direction == Dir::forward};
|
||||
const auto visitor{[&](std::size_t index) {
|
||||
if (skip_first) {
|
||||
skip_first = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::size_t previous_index{
|
||||
direction == Dir::forward ?
|
||||
(index == 0 ? perimeter.positions.size() - 1 : index - 1) :
|
||||
(index == perimeter.positions.size() - 1 ? 0 : index + 1)};
|
||||
|
||||
const Vec2d previous_point{perimeter.positions[previous_index]};
|
||||
const Vec2d next_point{perimeter.positions[index]};
|
||||
const Vec2d edge{next_point - previous_point};
|
||||
|
||||
if (early_stop_condition(perimeter, index)) {
|
||||
offset_point = PointOnPerimeter{previous_index, previous_index, perimeter.positions[previous_index]};
|
||||
return true;
|
||||
}
|
||||
|
||||
if (distance + edge.norm() > offset) {
|
||||
const double remaining_distance{offset - distance};
|
||||
const Vec2d result{previous_point + remaining_distance * edge.normalized()};
|
||||
|
||||
if (direction == Dir::forward) {
|
||||
offset_point = PointOnPerimeter{previous_index, index, result};
|
||||
} else {
|
||||
offset_point = PointOnPerimeter{index, previous_index, result};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
distance += edge.norm();
|
||||
|
||||
return false;
|
||||
}};
|
||||
|
||||
if (direction == Dir::forward) {
|
||||
Geometry::visit_forward(point.next_index, perimeter.positions.size(), visitor);
|
||||
} else {
|
||||
Geometry::visit_backward(point.previous_index, perimeter.positions.size(), visitor);
|
||||
}
|
||||
|
||||
return offset_point;
|
||||
}
|
||||
|
||||
unsigned get_point_value(const PointType point_type, const PointClassification point_classification) {
|
||||
// Better be explicit than smart.
|
||||
switch (point_type) {
|
||||
case PointType::enforcer:
|
||||
switch (point_classification) {
|
||||
case PointClassification::embedded: return 9;
|
||||
case PointClassification::common: return 8;
|
||||
case PointClassification::overhang: return 7;
|
||||
}
|
||||
case PointType::common:
|
||||
switch (point_classification) {
|
||||
case PointClassification::embedded: return 6;
|
||||
case PointClassification::common: return 5;
|
||||
case PointClassification::overhang: return 4;
|
||||
}
|
||||
case PointType::blocker:
|
||||
switch (point_classification) {
|
||||
case PointClassification::embedded: return 3;
|
||||
case PointClassification::common: return 2;
|
||||
case PointClassification::overhang: return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Slic3r::Seams::Perimeter
|
||||
|
@ -33,6 +33,17 @@ enum class PointClassification { overhang, embedded, common };
|
||||
struct Perimeter;
|
||||
struct PerimeterParams;
|
||||
|
||||
/**
|
||||
* When previous_index == next_index, the point is at the point.
|
||||
* Otherwise the point is at the edge.
|
||||
*/
|
||||
struct PointOnPerimeter
|
||||
{
|
||||
std::size_t previous_index{};
|
||||
std::size_t next_index{};
|
||||
Vec2d position{Vec2d::Zero()};
|
||||
};
|
||||
|
||||
struct LayerInfo
|
||||
{
|
||||
static LayerInfo create(
|
||||
@ -209,6 +220,19 @@ inline std::vector<Vec2d> extract_points(
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
using Seams::Geometry::PointOnLine;
|
||||
|
||||
std::optional<PointOnPerimeter> offset_along_perimeter(
|
||||
const PointOnPerimeter &point,
|
||||
const Perimeter& perimeter,
|
||||
const double offset,
|
||||
const Seams::Geometry::Direction1D direction,
|
||||
const std::function<bool(const Perimeter&, const std::size_t)> &early_stop_condition
|
||||
);
|
||||
|
||||
unsigned get_point_value(const PointType point_type, const PointClassification point_classification);
|
||||
|
||||
} // namespace Slic3r::Seams::Perimeters
|
||||
|
||||
#endif // libslic3r_SeamPerimeters_hpp_
|
||||
|
@ -251,6 +251,20 @@ Geometry::Direction1D get_direction(
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned get_seam_choice_value(const SeamChoice &seam_choice, const Perimeters::Perimeter& perimeter) {
|
||||
const unsigned previous_value{Perimeters::get_point_value(
|
||||
perimeter.point_types[seam_choice.previous_index],
|
||||
perimeter.point_classifications[seam_choice.previous_index]
|
||||
)};
|
||||
|
||||
const unsigned next_value{Perimeters::get_point_value(
|
||||
perimeter.point_types[seam_choice.next_index],
|
||||
perimeter.point_classifications[seam_choice.next_index]
|
||||
)};
|
||||
|
||||
return std::max(previous_value, next_value);
|
||||
}
|
||||
|
||||
boost::variant<Point, Scarf::Scarf> finalize_seam_position(
|
||||
const ExtrusionLoop &loop,
|
||||
const PrintRegion *region,
|
||||
@ -259,6 +273,9 @@ boost::variant<Point, Scarf::Scarf> finalize_seam_position(
|
||||
const bool staggered_inner_seams,
|
||||
const bool flipped
|
||||
) {
|
||||
using Perimeters::offset_along_perimeter;
|
||||
using Perimeters::PointOnPerimeter;
|
||||
|
||||
const Polygon loop_polygon{Geometry::to_polygon(loop)};
|
||||
const bool do_staggering{staggered_inner_seams && loop.role() == ExtrusionRole::Perimeter};
|
||||
const double loop_width{loop.paths.empty() ? 0.0 : loop.paths.front().width()};
|
||||
@ -273,6 +290,25 @@ boost::variant<Point, Scarf::Scarf> finalize_seam_position(
|
||||
|
||||
const Geometry::Direction1D offset_direction{get_direction(flipped, perimeter_polygon, loop)};
|
||||
|
||||
const auto offset_stop_condition{
|
||||
[choice_value = get_seam_choice_value(seam_choice, perimeter)](
|
||||
const Perimeters::Perimeter &perimeter, const std::size_t index
|
||||
) {
|
||||
const unsigned current_point_value{Perimeters::get_point_value(
|
||||
perimeter.point_types[index], perimeter.point_classifications[index]
|
||||
)};
|
||||
if (
|
||||
current_point_value < choice_value
|
||||
&& (
|
||||
perimeter.point_types[index] == Perimeters::PointType::blocker
|
||||
|| perimeter.point_classifications[index] == Perimeters::PointClassification::overhang
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}};
|
||||
|
||||
// ExtrusionRole::Perimeter is inner perimeter.
|
||||
if (do_staggering) {
|
||||
const double depth = (loop_point - seam_choice.position).norm() -
|
||||
@ -280,13 +316,16 @@ boost::variant<Point, Scarf::Scarf> finalize_seam_position(
|
||||
|
||||
const double staggering_offset{depth};
|
||||
|
||||
std::optional<Geometry::PointOnLine> staggered_point{Geometry::offset_along_lines(
|
||||
loop_point, seam_choice.previous_index, perimeter_lines, staggering_offset,
|
||||
offset_direction
|
||||
std::optional<PointOnPerimeter> staggered_point{offset_along_perimeter(
|
||||
{seam_choice.previous_index, seam_choice.next_index, loop_point},
|
||||
perimeter,
|
||||
staggering_offset,
|
||||
offset_direction,
|
||||
offset_stop_condition
|
||||
)};
|
||||
|
||||
if (staggered_point) {
|
||||
seam_choice = to_seam_choice(*staggered_point, perimeter);
|
||||
seam_choice = *staggered_point;
|
||||
std::tie(loop_line_index, loop_point) = project_to_extrusion_loop(seam_choice, perimeter, distancer);
|
||||
}
|
||||
}
|
||||
@ -315,12 +354,12 @@ boost::variant<Point, Scarf::Scarf> finalize_seam_position(
|
||||
scarf.start_height = std::min(region->config().scarf_seam_start_height.get_abs_value(1.0), 1.0);
|
||||
|
||||
const double offset{scarf.entire_loop ? 0.0 : region->config().scarf_seam_length.value};
|
||||
const std::optional<Geometry::PointOnLine> outter_scarf_start_point{Geometry::offset_along_lines(
|
||||
seam_choice.position,
|
||||
seam_choice.previous_index,
|
||||
perimeter_lines,
|
||||
const std::optional<PointOnPerimeter> outter_scarf_start_point{offset_along_perimeter(
|
||||
seam_choice,
|
||||
perimeter,
|
||||
offset,
|
||||
offset_direction
|
||||
offset_direction,
|
||||
offset_stop_condition
|
||||
)};
|
||||
if (!outter_scarf_start_point) {
|
||||
return scaled(loop_point);
|
||||
@ -328,11 +367,11 @@ boost::variant<Point, Scarf::Scarf> finalize_seam_position(
|
||||
|
||||
if (loop.role() != ExtrusionRole::Perimeter) { // Outter perimeter
|
||||
const Vec2d start_point_candidate{project_to_extrusion_loop(
|
||||
to_seam_choice(*outter_scarf_start_point, perimeter),
|
||||
*outter_scarf_start_point,
|
||||
perimeter,
|
||||
distancer
|
||||
).second};
|
||||
if ((start_point_candidate - outter_scarf_start_point->point).norm() > 5.0) {
|
||||
if ((start_point_candidate - outter_scarf_start_point->position).norm() > 5.0) {
|
||||
return scaled(loop_point);
|
||||
}
|
||||
scarf.start_point = scaled(start_point_candidate);
|
||||
@ -340,7 +379,7 @@ boost::variant<Point, Scarf::Scarf> finalize_seam_position(
|
||||
scarf.end_point_previous_index = loop_line_index;
|
||||
return scarf;
|
||||
} else {
|
||||
Geometry::PointOnLine inner_scarf_end_point{
|
||||
PointOnPerimeter inner_scarf_end_point{
|
||||
*outter_scarf_start_point
|
||||
};
|
||||
|
||||
@ -350,12 +389,12 @@ boost::variant<Point, Scarf::Scarf> finalize_seam_position(
|
||||
Geometry::Direction1D::backward :
|
||||
Geometry::Direction1D::forward
|
||||
};
|
||||
if (auto result{Geometry::offset_along_lines(
|
||||
seam_choice.position,
|
||||
seam_choice.previous_index,
|
||||
perimeter_lines,
|
||||
if (auto result{offset_along_perimeter(
|
||||
seam_choice,
|
||||
perimeter,
|
||||
offset,
|
||||
external_first_offset_direction
|
||||
external_first_offset_direction,
|
||||
offset_stop_condition
|
||||
)}) {
|
||||
inner_scarf_end_point = *result;
|
||||
} else {
|
||||
@ -364,36 +403,36 @@ boost::variant<Point, Scarf::Scarf> finalize_seam_position(
|
||||
}
|
||||
|
||||
if (!region->config().scarf_seam_on_inner_perimeters) {
|
||||
return scaled(inner_scarf_end_point.point);
|
||||
return scaled(inner_scarf_end_point.position);
|
||||
}
|
||||
|
||||
const std::optional<Geometry::PointOnLine> inner_scarf_start_point{Geometry::offset_along_lines(
|
||||
inner_scarf_end_point.point,
|
||||
inner_scarf_end_point.line_index,
|
||||
perimeter_lines,
|
||||
const std::optional<PointOnPerimeter> inner_scarf_start_point{offset_along_perimeter(
|
||||
inner_scarf_end_point,
|
||||
perimeter,
|
||||
offset,
|
||||
offset_direction
|
||||
offset_direction,
|
||||
offset_stop_condition
|
||||
)};
|
||||
|
||||
if (!inner_scarf_start_point) {
|
||||
return scaled(inner_scarf_end_point.point);
|
||||
return scaled(inner_scarf_end_point.position);
|
||||
}
|
||||
const Vec2d start_point_candidate{project_to_extrusion_loop(
|
||||
to_seam_choice(*inner_scarf_start_point, perimeter),
|
||||
*inner_scarf_start_point,
|
||||
perimeter,
|
||||
distancer
|
||||
).second};
|
||||
if ((start_point_candidate - inner_scarf_start_point->point).norm() > 5.0) {
|
||||
if ((start_point_candidate - inner_scarf_start_point->position).norm() > 5.0) {
|
||||
return scaled(loop_point);
|
||||
}
|
||||
scarf.start_point = scaled(start_point_candidate);
|
||||
|
||||
const auto [end_point_previous_index, end_point]{project_to_extrusion_loop(
|
||||
to_seam_choice(inner_scarf_end_point, perimeter),
|
||||
inner_scarf_end_point,
|
||||
perimeter,
|
||||
distancer
|
||||
)};
|
||||
if ((end_point - inner_scarf_end_point.point).norm() > 5.0) {
|
||||
if ((end_point - inner_scarf_end_point.position).norm() > 5.0) {
|
||||
return scaled(loop_point);
|
||||
}
|
||||
|
||||
|
@ -3,12 +3,12 @@
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "libslic3r/GCode/SeamGeometry.hpp"
|
||||
#include "libslic3r/GCode/SeamChoice.hpp"
|
||||
#include "libslic3r/GCode/SeamPerimeters.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace Seams {
|
||||
struct SeamChoice;
|
||||
struct SeamPerimeterChoice;
|
||||
} // namespace Seams
|
||||
} // namespace Slic3r
|
||||
|
@ -126,30 +126,3 @@ TEST_CASE("Vertex angle is rotation agnostic", "[Seams][SeamGeometry]") {
|
||||
std::vector<double> rotated_angles = Seams::Geometry::get_vertex_angles(points, 0.1);
|
||||
CHECK(rotated_angles[1] == Approx(angles[1]));
|
||||
}
|
||||
|
||||
const Linesf lines{to_unscaled_linesf({ExPolygon{
|
||||
scaled(Vec2d{0.0, 0.0}),
|
||||
scaled(Vec2d{1.0, 0.0}),
|
||||
scaled(Vec2d{1.0, 1.0}),
|
||||
scaled(Vec2d{0.0, 1.0})
|
||||
}})};
|
||||
|
||||
TEST_CASE("Offset along loop lines forward", "[Seams][SeamGeometry]") {
|
||||
const std::optional<Seams::Geometry::PointOnLine> result{Seams::Geometry::offset_along_lines(
|
||||
{0.5, 0.0}, 0, lines, 3.9, Seams::Geometry::Direction1D::forward
|
||||
)};
|
||||
REQUIRE(result);
|
||||
const auto &[point, line_index] = *result;
|
||||
CHECK((scaled(point) - Point::new_scale(0.4, 0.0)).norm() < scaled(EPSILON));
|
||||
CHECK(line_index == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Offset along loop lines backward", "[Seams][SeamGeometry]") {
|
||||
const std::optional<Seams::Geometry::PointOnLine> result{Seams::Geometry::offset_along_lines(
|
||||
{1.0, 0.5}, 1, lines, 1.8, Seams::Geometry::Direction1D::backward
|
||||
)};
|
||||
REQUIRE(result);
|
||||
const auto &[point, line_index] = *result;
|
||||
CHECK((scaled(point) - Point::new_scale(0.0, 0.3)).norm() < scaled(EPSILON));
|
||||
CHECK(line_index == 3);
|
||||
}
|
||||
|
@ -196,3 +196,57 @@ TEST_CASE_METHOD(Test::SeamsFixture, "Create perimeters", "[Seams][SeamPerimeter
|
||||
serialize_shells(csv, shells);
|
||||
}
|
||||
}
|
||||
|
||||
using Dir = Seams::Geometry::Direction1D;
|
||||
|
||||
Perimeters::Perimeter get_perimeter(){
|
||||
Perimeters::Perimeter perimeter;
|
||||
perimeter.positions = {
|
||||
Vec2d{0.0, 0.0},
|
||||
Vec2d{1.0, 0.0},
|
||||
Vec2d{1.0, 1.0},
|
||||
Vec2d{0.0, 1.0}
|
||||
};
|
||||
return perimeter;
|
||||
}
|
||||
|
||||
TEST_CASE("Offset along perimeter forward", "[Seams][SeamPerimeters]") {
|
||||
const std::optional<Perimeters::PointOnPerimeter> result{Perimeters::offset_along_perimeter(
|
||||
{0, 1, {0.5, 0.0}}, get_perimeter(), 3.9, Dir::forward,
|
||||
[](const Perimeters::Perimeter &, const std::size_t) { return false; }
|
||||
)};
|
||||
REQUIRE(result);
|
||||
const auto &[previous_index, next_index, point] = *result;
|
||||
CHECK((scaled(point) - Point::new_scale(0.4, 0.0)).norm() < scaled(EPSILON));
|
||||
CHECK(previous_index == 0);
|
||||
CHECK(next_index == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("Offset along perimeter backward", "[Seams][SeamPerimeters]") {
|
||||
const std::optional<Perimeters::PointOnPerimeter> result{Perimeters::offset_along_perimeter(
|
||||
{1, 2, {1.0, 0.5}}, get_perimeter(), 1.8, Dir::backward,
|
||||
[](const Perimeters::Perimeter &, const std::size_t) { return false; }
|
||||
)};
|
||||
REQUIRE(result);
|
||||
const auto &[previous_index, next_index, point] = *result;
|
||||
CHECK((scaled(point) - Point::new_scale(0.0, 0.3)).norm() < scaled(EPSILON));
|
||||
CHECK(previous_index == 3);
|
||||
CHECK(next_index == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Offset along perimeter forward respects stop condition", "[Seams][SeamPerimeters]") {
|
||||
Perimeters::Perimeter perimeter{get_perimeter()};
|
||||
perimeter.point_types = std::vector<Perimeters::PointType>(perimeter.positions.size(), Perimeters::PointType::common);
|
||||
perimeter.point_types[2] = Perimeters::PointType::blocker;
|
||||
const std::optional<Perimeters::PointOnPerimeter> result{Perimeters::offset_along_perimeter(
|
||||
{0, 1, {0.5, 0.0}}, perimeter, 3.9, Dir::forward,
|
||||
[](const Perimeters::Perimeter &perimeter, const std::size_t index) {
|
||||
return perimeter.point_types[index] == Perimeters::PointType::blocker;
|
||||
}
|
||||
)};
|
||||
REQUIRE(result);
|
||||
const auto &[previous_index, next_index, point] = *result;
|
||||
CHECK((scaled(point) - Point::new_scale(1.0, 0.0)).norm() < scaled(EPSILON));
|
||||
CHECK(previous_index == 1);
|
||||
CHECK(next_index == 1);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user