mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-13 00:39:02 +08:00
Refactor seams - due to new rear implementation shells are now only required for aligned seams.
This commit is contained in:
parent
7d6563641c
commit
f6396f59e9
@ -261,6 +261,29 @@ struct SeamCandidate {
|
||||
std::vector<double> visibilities;
|
||||
};
|
||||
|
||||
std::vector<SeamChoice> get_shell_seam(
|
||||
const Shells::Shell<> &shell,
|
||||
const std::function<SeamChoice(const Perimeters::Perimeter &, std::size_t)> &chooser
|
||||
) {
|
||||
std::vector<SeamChoice> result;
|
||||
result.reserve(shell.size());
|
||||
for (std::size_t i{0}; i < shell.size(); ++i) {
|
||||
const Shells::Slice<> &slice{shell[i]};
|
||||
if (slice.boundary.is_degenerate) {
|
||||
if (std::optional<SeamChoice> seam_choice{
|
||||
choose_degenerate_seam_point(slice.boundary)}) {
|
||||
result.push_back(*seam_choice);
|
||||
} else {
|
||||
result.emplace_back();
|
||||
}
|
||||
} else {
|
||||
const SeamChoice choice{chooser(slice.boundary, i)};
|
||||
result.push_back(choice);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
SeamCandidate get_seam_candidate(
|
||||
const Shells::Shell<> &shell,
|
||||
const Vec2d &starting_position,
|
||||
@ -273,7 +296,7 @@ SeamCandidate get_seam_candidate(
|
||||
|
||||
std::vector<double> choice_visibilities(shell.size(), 1.0);
|
||||
std::vector<SeamChoice> choices{
|
||||
Seams::get_shell_seam(shell, [&, previous_position{starting_position}](const Perimeter &perimeter, std::size_t slice_index) mutable {
|
||||
get_shell_seam(shell, [&, previous_position{starting_position}](const Perimeter &perimeter, std::size_t slice_index) mutable {
|
||||
SeamChoice candidate{Seams::choose_seam_point(
|
||||
perimeter, Impl::Nearest{previous_position, params.max_detour}
|
||||
)};
|
||||
|
@ -47,65 +47,4 @@ std::optional<SeamChoice> choose_degenerate_seam_point(const Perimeters::Perimet
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::vector<SeamChoice>> maybe_get_shell_seam(
|
||||
const Shells::Shell<> &shell,
|
||||
const std::function<std::optional<SeamChoice>(const Perimeters::Perimeter &, std::size_t)> &chooser
|
||||
) {
|
||||
std::vector<SeamChoice> result;
|
||||
result.reserve(shell.size());
|
||||
for (std::size_t i{0}; i < shell.size(); ++i) {
|
||||
const Shells::Slice<> &slice{shell[i]};
|
||||
if (slice.boundary.is_degenerate) {
|
||||
if (std::optional<SeamChoice> seam_choice{
|
||||
choose_degenerate_seam_point(slice.boundary)}) {
|
||||
result.push_back(*seam_choice);
|
||||
} else {
|
||||
result.emplace_back();
|
||||
}
|
||||
} else {
|
||||
const std::optional<SeamChoice> choice{chooser(slice.boundary, i)};
|
||||
if (!choice) {
|
||||
return std::nullopt;
|
||||
}
|
||||
result.push_back(*choice);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<SeamChoice> get_shell_seam(
|
||||
const Shells::Shell<> &shell,
|
||||
const std::function<SeamChoice(const Perimeters::Perimeter &, std::size_t)> &chooser
|
||||
) {
|
||||
std::optional<std::vector<SeamChoice>> seam{maybe_get_shell_seam(
|
||||
shell,
|
||||
[&](const Perimeters::Perimeter &perimeter, std::size_t slice_index) {
|
||||
return chooser(perimeter, slice_index);
|
||||
}
|
||||
)};
|
||||
if (!seam) {
|
||||
// Should be unreachable as chooser always returns a SeamChoice!
|
||||
return std::vector<SeamChoice>(shell.size());
|
||||
}
|
||||
return *seam;
|
||||
}
|
||||
|
||||
std::vector<std::vector<SeamPerimeterChoice>> get_object_seams(
|
||||
Shells::Shells<> &&shells,
|
||||
const std::function<std::vector<SeamChoice>(const Shells::Shell<>&)> &get_shell_seam
|
||||
) {
|
||||
std::vector<std::vector<SeamPerimeterChoice>> layer_seams(get_layer_count(shells));
|
||||
|
||||
for (Shells::Shell<> &shell : shells) {
|
||||
std::vector<SeamChoice> seam{get_shell_seam(shell)};
|
||||
|
||||
for (std::size_t perimeter_id{}; perimeter_id < shell.size(); ++perimeter_id) {
|
||||
const SeamChoice &choice{seam[perimeter_id]};
|
||||
Perimeters::Perimeter &perimeter{shell[perimeter_id].boundary};
|
||||
layer_seams[shell[perimeter_id].layer_index].emplace_back(choice, std::move(perimeter));
|
||||
}
|
||||
}
|
||||
|
||||
return layer_seams;
|
||||
}
|
||||
} // namespace Slic3r::Seams
|
||||
|
@ -2,7 +2,7 @@
|
||||
#define libslic3r_SeamChoice_hpp_
|
||||
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/GCode/SeamPerimeters.hpp"
|
||||
#include "libslic3r/GCode/SeamShells.hpp"
|
||||
|
||||
namespace Slic3r::Seams {
|
||||
|
||||
@ -52,21 +52,6 @@ SeamChoice choose_seam_point(
|
||||
|
||||
std::optional<SeamChoice> choose_degenerate_seam_point(const Perimeters::Perimeter &perimeter);
|
||||
|
||||
std::optional<std::vector<SeamChoice>> maybe_get_shell_seam(
|
||||
const Shells::Shell<> &shell,
|
||||
const std::function<std::optional<SeamChoice>(const Perimeters::Perimeter &, std::size_t)> &chooser
|
||||
);
|
||||
|
||||
std::vector<SeamChoice> get_shell_seam(
|
||||
const Shells::Shell<> &shell,
|
||||
const std::function<SeamChoice(const Perimeters::Perimeter &, std::size_t)> &chooser
|
||||
);
|
||||
|
||||
std::vector<std::vector<SeamPerimeterChoice>> get_object_seams(
|
||||
Shells::Shells<> &&shells,
|
||||
const std::function<std::vector<SeamChoice>(const Shells::Shell<> &)> &get_shell_seam
|
||||
);
|
||||
|
||||
} // namespace Slic3r::Seams
|
||||
|
||||
#endif // libslic3r_SeamChoice_hpp_
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "libslic3r/GCode/SeamGeometry.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "KDTreeIndirect.hpp"
|
||||
#include "Layer.hpp"
|
||||
#include <fstream>
|
||||
@ -188,6 +189,54 @@ std::vector<Extrusions> get_extrusions(tcb::span<const Slic3r::Layer *const> obj
|
||||
return result;
|
||||
}
|
||||
|
||||
BoundedPolygons project_to_geometry(const Geometry::Extrusions &external_perimeters, const double max_bb_distance) {
|
||||
BoundedPolygons result;
|
||||
result.reserve(external_perimeters.size());
|
||||
|
||||
using std::transform, std::back_inserter;
|
||||
|
||||
transform(
|
||||
external_perimeters.begin(), external_perimeters.end(), back_inserter(result),
|
||||
[&](const Geometry::Extrusion &external_perimeter) {
|
||||
const auto [choosen_index, _]{Geometry::pick_closest_bounding_box(
|
||||
external_perimeter.bounding_box,
|
||||
external_perimeter.island_boundary_bounding_boxes
|
||||
)};
|
||||
|
||||
const double distance{Geometry::bounding_box_distance(
|
||||
external_perimeter.island_boundary_bounding_boxes[choosen_index],
|
||||
external_perimeter.bounding_box
|
||||
)};
|
||||
|
||||
if (distance > max_bb_distance) {
|
||||
Polygons expanded_extrusion{expand(external_perimeter.polygon, external_perimeter.width / 2.0)};
|
||||
if (!expanded_extrusion.empty()) {
|
||||
return BoundedPolygon{
|
||||
expanded_extrusion.front(), expanded_extrusion.front().bounding_box(), external_perimeter.polygon.is_clockwise()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const bool is_hole{choosen_index != 0};
|
||||
const Polygon &adjacent_boundary{
|
||||
!is_hole ? external_perimeter.island_boundary.contour :
|
||||
external_perimeter.island_boundary.holes[choosen_index - 1]};
|
||||
return BoundedPolygon{adjacent_boundary, external_perimeter.island_boundary_bounding_boxes[choosen_index], is_hole};
|
||||
}
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<BoundedPolygons> project_to_geometry(const std::vector<Geometry::Extrusions> &extrusions, const double max_bb_distance) {
|
||||
std::vector<BoundedPolygons> result(extrusions.size());
|
||||
|
||||
for (std::size_t layer_index{0}; layer_index < extrusions.size(); ++layer_index) {
|
||||
result[layer_index] = project_to_geometry(extrusions[layer_index], max_bb_distance);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<Vec2d> oversample_edge(const Vec2d &from, const Vec2d &to, const double max_distance) {
|
||||
const double total_distance{(from - to).norm()};
|
||||
const auto points_count{static_cast<std::size_t>(std::ceil(total_distance / max_distance)) + 1};
|
||||
|
@ -43,6 +43,17 @@ using Extrusions = std::vector<Extrusion>;
|
||||
|
||||
std::vector<Extrusions> get_extrusions(tcb::span<const Slic3r::Layer *const> object_layers);
|
||||
|
||||
struct BoundedPolygon {
|
||||
Polygon polygon;
|
||||
BoundingBox bounding_box;
|
||||
bool is_hole{false};
|
||||
};
|
||||
|
||||
using BoundedPolygons = std::vector<BoundedPolygon>;
|
||||
|
||||
BoundedPolygons project_to_geometry(const Geometry::Extrusions &external_perimeters, const double max_bb_distance);
|
||||
std::vector<BoundedPolygons> project_to_geometry(const std::vector<Geometry::Extrusions> &extrusions, const double max_bb_distance);
|
||||
|
||||
Vec2d get_polygon_normal(
|
||||
const std::vector<Vec2d> &points, const std::size_t index, const double min_arm_length
|
||||
);
|
||||
|
@ -384,26 +384,32 @@ Perimeter Perimeter::create(
|
||||
std::move(angle_types)};
|
||||
}
|
||||
|
||||
Shells::Shells<> create_perimeters(
|
||||
const std::vector<Shells::Shell<Polygon>> &shells,
|
||||
LayerPerimeters create_perimeters(
|
||||
const std::vector<Geometry::BoundedPolygons> &polygons,
|
||||
const std::vector<LayerInfo> &layer_infos,
|
||||
const ModelInfo::Painting &painting,
|
||||
const PerimeterParams ¶ms
|
||||
) {
|
||||
std::vector<Shells::Shell<>> result;
|
||||
result.reserve(shells.size());
|
||||
LayerPerimeters result;
|
||||
result.reserve(polygons.size());
|
||||
|
||||
std::transform(
|
||||
shells.begin(), shells.end(), std::back_inserter(result),
|
||||
[](const Shells::Shell<Polygon> &shell) { return Shells::Shell<>(shell.size()); }
|
||||
polygons.begin(), polygons.end(), std::back_inserter(result),
|
||||
[](const Geometry::BoundedPolygons &layer) { return BoundedPerimeters(layer.size()); }
|
||||
);
|
||||
|
||||
Geometry::iterate_nested(shells, [&](const std::size_t shell_index, const std::size_t polygon_index){
|
||||
const Shells::Shell<Polygon> &shell{shells[shell_index]};
|
||||
const Shells::Slice<Polygon>& slice{shell[polygon_index]};
|
||||
const Polygon &polygon{slice.boundary};
|
||||
const LayerInfo &layer_info{layer_infos[slice.layer_index]};
|
||||
result[shell_index][polygon_index] = {Perimeter::create(polygon, painting, layer_info, params), slice.layer_index};
|
||||
});
|
||||
Geometry::iterate_nested(
|
||||
polygons,
|
||||
[&](const std::size_t layer_index, const std::size_t polygon_index) {
|
||||
const Geometry::BoundedPolygons &layer{polygons[layer_index]};
|
||||
const Geometry::BoundedPolygon &bounded_polygon{layer[polygon_index]};
|
||||
const LayerInfo &layer_info{layer_infos[layer_index]};
|
||||
result[layer_index][polygon_index] = BoundedPerimeter{
|
||||
Perimeter::create(bounded_polygon.polygon, painting, layer_info, params),
|
||||
bounded_polygon.bounding_box};
|
||||
}
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Slic3r::Seams::Perimeter
|
||||
|
@ -5,8 +5,8 @@
|
||||
|
||||
#include "libslic3r/GCode/SeamPainting.hpp"
|
||||
#include "libslic3r/KDTreeIndirect.hpp"
|
||||
|
||||
#include "libslic3r/GCode/SeamShells.hpp"
|
||||
#include "libslic3r/AABBTreeLines.hpp"
|
||||
#include "libslic3r/GCode/SeamGeometry.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
class Layer;
|
||||
@ -164,37 +164,25 @@ struct Perimeter
|
||||
PointTrees blocked_points{};
|
||||
};
|
||||
|
||||
using Perimeters = std::vector<Perimeter>;
|
||||
|
||||
struct BoundedPerimeter {
|
||||
Perimeters::Perimeter perimeter;
|
||||
Perimeter perimeter;
|
||||
BoundingBox bounding_box;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a Perimeter for each polygon in each of the shells.
|
||||
*/
|
||||
Shells::Shells<Perimeter> create_perimeters(
|
||||
const std::vector<Shells::Shell<Polygon>> &shells,
|
||||
using BoundedPerimeters = std::vector<BoundedPerimeter>;
|
||||
using LayerPerimeters = std::vector<BoundedPerimeters>;
|
||||
|
||||
LayerPerimeters create_perimeters(
|
||||
const std::vector<Geometry::BoundedPolygons> &polygons,
|
||||
const std::vector<LayerInfo> &layer_infos,
|
||||
const ModelInfo::Painting &painting,
|
||||
const PerimeterParams ¶ms
|
||||
);
|
||||
|
||||
inline std::size_t get_layer_count(
|
||||
const Shells::Shells<> &shells
|
||||
) {
|
||||
std::size_t layer_count{0};
|
||||
for (const Shells::Shell<> &shell : shells) {
|
||||
for (const Shells::Slice<>& slice : shell) {
|
||||
if (slice.layer_index >= layer_count) {
|
||||
layer_count = slice.layer_index + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return layer_count;
|
||||
}
|
||||
|
||||
inline std::vector<Vec2d> extract_points(
|
||||
const Perimeters::Perimeter &perimeter, const Perimeters::PointType point_type
|
||||
const Perimeter &perimeter, const PointType point_type
|
||||
) {
|
||||
std::vector<Vec2d> result;
|
||||
for (std::size_t i{0}; i < perimeter.positions.size(); ++i) {
|
||||
|
@ -7,8 +7,10 @@
|
||||
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
|
||||
#include "SeamPlacer.hpp"
|
||||
|
||||
#include "libslic3r/GCode/SeamShells.hpp"
|
||||
#include "libslic3r/GCode/SeamAligned.hpp"
|
||||
#include "libslic3r/GCode/SeamRear.hpp"
|
||||
#include "libslic3r/GCode/SeamRandom.hpp"
|
||||
@ -17,16 +19,15 @@
|
||||
|
||||
namespace Slic3r::Seams {
|
||||
|
||||
using ObjectShells = std::vector<std::pair<const PrintObject *, Shells::Shells<>>>;
|
||||
using ObjectPainting = std::map<const PrintObject*, ModelInfo::Painting>;
|
||||
|
||||
ObjectShells partition_to_shells(
|
||||
ObjectLayerPerimeters get_perimeters(
|
||||
SpanOfConstPtrs<PrintObject> objects,
|
||||
const Params ¶ms,
|
||||
const ObjectPainting& object_painting,
|
||||
const std::function<void(void)> &throw_if_canceled
|
||||
) {
|
||||
ObjectShells result;
|
||||
ObjectLayerPerimeters result;
|
||||
|
||||
for (const PrintObject *print_object : objects) {
|
||||
const ModelInfo::Painting &painting{object_painting.at(print_object)};
|
||||
@ -37,20 +38,18 @@ ObjectShells partition_to_shells(
|
||||
const Perimeters::LayerInfos layer_infos{Perimeters::get_layer_infos(
|
||||
print_object->layers(), params.perimeter.elephant_foot_compensation
|
||||
)};
|
||||
Shells::Shells<Polygon> shell_polygons{
|
||||
Shells::create_shells(extrusions, params.max_distance)};
|
||||
const std::vector<Geometry::BoundedPolygons> projected{Geometry::project_to_geometry(extrusions, params.max_distance)};
|
||||
Perimeters::LayerPerimeters perimeters{Perimeters::create_perimeters(projected, layer_infos, painting, params.perimeter)};
|
||||
|
||||
Shells::Shells<> perimeters{
|
||||
Perimeters::create_perimeters(shell_polygons, layer_infos, painting, params.perimeter)};
|
||||
throw_if_canceled();
|
||||
result.emplace_back(print_object, std::move(perimeters));
|
||||
result.emplace(print_object, std::move(perimeters));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
LayerPerimeters sort_to_layers(Shells::Shells<> &&shells) {
|
||||
const std::size_t layer_count{Perimeters::get_layer_count(shells)};
|
||||
LayerPerimeters result(layer_count);
|
||||
Perimeters::LayerPerimeters sort_to_layers(Shells::Shells<> &&shells) {
|
||||
const std::size_t layer_count{Shells::get_layer_count(shells)};
|
||||
Perimeters::LayerPerimeters result(layer_count);
|
||||
|
||||
for (Shells::Shell<> &shell : shells) {
|
||||
for (Shells::Slice<> &slice : shell) {
|
||||
@ -63,22 +62,14 @@ LayerPerimeters sort_to_layers(Shells::Shells<> &&shells) {
|
||||
return result;
|
||||
}
|
||||
|
||||
ObjectLayerPerimeters sort_to_layers(ObjectShells &&object_shells) {
|
||||
ObjectLayerPerimeters result;
|
||||
for (auto &[print_object, shells] : object_shells) {
|
||||
result[print_object] = sort_to_layers(std::move(shells));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ObjectSeams precalculate_seams(
|
||||
const Params ¶ms,
|
||||
ObjectShells &&seam_data,
|
||||
ObjectLayerPerimeters &&seam_data,
|
||||
const std::function<void(void)> &throw_if_canceled
|
||||
) {
|
||||
ObjectSeams result;
|
||||
|
||||
for (auto &[print_object, shells] : seam_data) {
|
||||
for (auto &[print_object, layer_perimeters] : seam_data) {
|
||||
switch (params.seam_preference) {
|
||||
case spAligned: {
|
||||
const Transform3d transformation{print_object->trafo_centered()};
|
||||
@ -91,17 +82,18 @@ ObjectSeams precalculate_seams(
|
||||
points_visibility, params.convex_visibility_modifier,
|
||||
params.concave_visibility_modifier};
|
||||
|
||||
Shells::Shells<> shells{Shells::create_shells(std::move(layer_perimeters), params.max_distance)};
|
||||
result[print_object] = Aligned::get_object_seams(
|
||||
std::move(shells), visibility_calculator, params.aligned
|
||||
);
|
||||
break;
|
||||
}
|
||||
case spRear: {
|
||||
result[print_object] = Rear::get_object_seams(sort_to_layers(std::move(shells)), params.rear_tolerance, params.rear_y_offset);
|
||||
result[print_object] = Rear::get_object_seams(std::move(layer_perimeters), params.rear_tolerance, params.rear_y_offset);
|
||||
break;
|
||||
}
|
||||
case spRandom: {
|
||||
result[print_object] = Random::get_object_seams(std::move(shells), params.random_seed);
|
||||
result[print_object] = Random::get_object_seams(std::move(layer_perimeters), params.random_seed);
|
||||
break;
|
||||
}
|
||||
case spNearest: {
|
||||
@ -166,14 +158,14 @@ void Placer::init(
|
||||
object_painting.emplace(print_object, ModelInfo::Painting{transformation, volumes});
|
||||
}
|
||||
|
||||
ObjectShells seam_data{partition_to_shells(objects, params, object_painting, throw_if_canceled)};
|
||||
ObjectLayerPerimeters perimeters{get_perimeters(objects, params, object_painting, throw_if_canceled)};
|
||||
this->params = params;
|
||||
|
||||
if (this->params.seam_preference != spNearest) {
|
||||
this->seams_per_object =
|
||||
precalculate_seams(params, std::move(seam_data), throw_if_canceled);
|
||||
precalculate_seams(params, std::move(perimeters), throw_if_canceled);
|
||||
} else {
|
||||
this->perimeters_per_layer = sort_to_layers(std::move(seam_data));
|
||||
this->perimeters_per_layer = std::move(perimeters);
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: init: end";
|
||||
|
@ -23,8 +23,7 @@ namespace Slic3r::Seams {
|
||||
|
||||
using ObjectSeams =
|
||||
std::unordered_map<const PrintObject *, std::vector<std::vector<SeamPerimeterChoice>>>;
|
||||
using LayerPerimeters = std::vector<std::vector<Perimeters::BoundedPerimeter>>;
|
||||
using ObjectLayerPerimeters = std::unordered_map<const PrintObject *, LayerPerimeters>;
|
||||
using ObjectLayerPerimeters = std::unordered_map<const PrintObject *, Perimeters::LayerPerimeters>;
|
||||
|
||||
struct Params
|
||||
{
|
||||
|
@ -122,15 +122,33 @@ std::optional<SeamChoice> Random::operator()(
|
||||
} // namespace Impl
|
||||
|
||||
std::vector<std::vector<SeamPerimeterChoice>> get_object_seams(
|
||||
Shells::Shells<> &&shells, const unsigned fixed_seed
|
||||
Perimeters::LayerPerimeters &&perimeters, const unsigned fixed_seed
|
||||
) {
|
||||
std::mt19937 random_engine{fixed_seed};
|
||||
const Impl::Random random{random_engine};
|
||||
|
||||
return Seams::get_object_seams(std::move(shells), [&](const Shells::Shell<> &shell) {
|
||||
return Seams::get_shell_seam(shell, [&](const Perimeters::Perimeter &perimeter, std::size_t) {
|
||||
return Seams::choose_seam_point(perimeter, random);
|
||||
});
|
||||
});
|
||||
std::vector<std::vector<SeamPerimeterChoice>> result;
|
||||
|
||||
for (std::vector<Perimeters::BoundedPerimeter> &layer : perimeters) {
|
||||
result.emplace_back();
|
||||
for (Perimeters::BoundedPerimeter &perimeter : layer) {
|
||||
if (perimeter.perimeter.is_degenerate) {
|
||||
std::optional<Seams::SeamChoice> seam_choice{
|
||||
Seams::choose_degenerate_seam_point(perimeter.perimeter)};
|
||||
if (seam_choice) {
|
||||
result.back().push_back(
|
||||
SeamPerimeterChoice{*seam_choice, std::move(perimeter.perimeter)}
|
||||
);
|
||||
} else {
|
||||
result.back().push_back(SeamPerimeterChoice{SeamChoice{}, std::move(perimeter.perimeter)});
|
||||
}
|
||||
} else {
|
||||
result.back().push_back(SeamPerimeterChoice{
|
||||
Seams::choose_seam_point(perimeter.perimeter, random),
|
||||
std::move(perimeter.perimeter)});
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace Slic3r::Seams::Random
|
||||
|
@ -24,6 +24,6 @@ struct Random
|
||||
};
|
||||
}
|
||||
std::vector<std::vector<SeamPerimeterChoice>> get_object_seams(
|
||||
Shells::Shells<> &&shells, const unsigned fixed_seed
|
||||
Perimeters::LayerPerimeters &&perimeters, const unsigned fixed_seed
|
||||
);
|
||||
}
|
||||
|
@ -75,9 +75,26 @@ std::vector<std::vector<SeamPerimeterChoice>> get_object_seams(
|
||||
for (std::vector<Perimeters::BoundedPerimeter> &layer : perimeters) {
|
||||
result.emplace_back();
|
||||
for (Perimeters::BoundedPerimeter &perimeter : layer) {
|
||||
BoundingBoxf bounding_box{unscaled(perimeter.bounding_box)};
|
||||
const SeamChoice seam_choice{Seams::choose_seam_point(perimeter.perimeter, Impl::RearestPointCalculator{rear_tolerance, rear_y_offset, bounding_box})};
|
||||
result.back().push_back(SeamPerimeterChoice{seam_choice, std::move(perimeter.perimeter)});
|
||||
if (perimeter.perimeter.is_degenerate) {
|
||||
std::optional<Seams::SeamChoice> seam_choice{
|
||||
Seams::choose_degenerate_seam_point(perimeter.perimeter)};
|
||||
if (seam_choice) {
|
||||
result.back().push_back(
|
||||
SeamPerimeterChoice{*seam_choice, std::move(perimeter.perimeter)}
|
||||
);
|
||||
} else {
|
||||
result.back().push_back(SeamPerimeterChoice{SeamChoice{}, std::move(perimeter.perimeter)});
|
||||
}
|
||||
} else {
|
||||
BoundingBoxf bounding_box{unscaled(perimeter.bounding_box)};
|
||||
const SeamChoice seam_choice{Seams::choose_seam_point(
|
||||
perimeter.perimeter,
|
||||
Impl::RearestPointCalculator{rear_tolerance, rear_y_offset, bounding_box}
|
||||
)};
|
||||
result.back().push_back(
|
||||
SeamPerimeterChoice{seam_choice, std::move(perimeter.perimeter)}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,65 +5,17 @@
|
||||
|
||||
namespace Slic3r::Seams::Shells::Impl {
|
||||
|
||||
BoundedPolygons project_to_geometry(const Geometry::Extrusions &external_perimeters, const double max_bb_distance) {
|
||||
BoundedPolygons result;
|
||||
result.reserve(external_perimeters.size());
|
||||
|
||||
using std::transform, std::back_inserter;
|
||||
|
||||
transform(
|
||||
external_perimeters.begin(), external_perimeters.end(), back_inserter(result),
|
||||
[&](const Geometry::Extrusion &external_perimeter) {
|
||||
const auto [choosen_index, _]{Geometry::pick_closest_bounding_box(
|
||||
external_perimeter.bounding_box,
|
||||
external_perimeter.island_boundary_bounding_boxes
|
||||
)};
|
||||
|
||||
const double distance{Geometry::bounding_box_distance(
|
||||
external_perimeter.island_boundary_bounding_boxes[choosen_index],
|
||||
external_perimeter.bounding_box
|
||||
)};
|
||||
|
||||
if (distance > max_bb_distance) {
|
||||
Polygons expanded_extrusion{expand(external_perimeter.polygon, external_perimeter.width / 2.0)};
|
||||
if (!expanded_extrusion.empty()) {
|
||||
return BoundedPolygon{
|
||||
expanded_extrusion.front(), expanded_extrusion.front().bounding_box(), external_perimeter.polygon.is_clockwise()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const bool is_hole{choosen_index != 0};
|
||||
const Polygon &adjacent_boundary{
|
||||
!is_hole ? external_perimeter.island_boundary.contour :
|
||||
external_perimeter.island_boundary.holes[choosen_index - 1]};
|
||||
return BoundedPolygon{adjacent_boundary, external_perimeter.island_boundary_bounding_boxes[choosen_index], is_hole};
|
||||
}
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<BoundedPolygons> project_to_geometry(const std::vector<Geometry::Extrusions> &extrusions, const double max_bb_distance) {
|
||||
std::vector<BoundedPolygons> result(extrusions.size());
|
||||
|
||||
for (std::size_t layer_index{0}; layer_index < extrusions.size(); ++layer_index) {
|
||||
result[layer_index] = project_to_geometry(extrusions[layer_index], max_bb_distance);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Shells<Polygon> map_to_shells(
|
||||
std::vector<BoundedPolygons> &&layers, const Geometry::Mapping &mapping, const std::size_t shell_count
|
||||
Shells<> map_to_shells(
|
||||
Perimeters::LayerPerimeters &&layers, const Geometry::Mapping &mapping, const std::size_t shell_count
|
||||
) {
|
||||
Shells<Polygon> result(shell_count);
|
||||
Shells<> result(shell_count);
|
||||
for (std::size_t layer_index{0}; layer_index < layers.size(); ++layer_index) {
|
||||
BoundedPolygons &perimeters{layers[layer_index]};
|
||||
Perimeters::BoundedPerimeters &perimeters{layers[layer_index]};
|
||||
for (std::size_t perimeter_index{0}; perimeter_index < perimeters.size();
|
||||
perimeter_index++) {
|
||||
Polygon &perimeter{perimeters[perimeter_index].polygon};
|
||||
Perimeters::Perimeter &perimeter{perimeters[perimeter_index].perimeter};
|
||||
result[mapping[layer_index][perimeter_index]].push_back(
|
||||
Slice<Polygon>{std::move(perimeter), layer_index}
|
||||
Slice<>{std::move(perimeter), layer_index}
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -72,30 +24,31 @@ Shells<Polygon> map_to_shells(
|
||||
} // namespace Slic3r::Seams::Shells::Impl
|
||||
|
||||
namespace Slic3r::Seams::Shells {
|
||||
Shells<Polygon> create_shells(
|
||||
const std::vector<Geometry::Extrusions> &extrusions, const double max_distance
|
||||
Shells<> create_shells(
|
||||
Perimeters::LayerPerimeters &&perimeters, const double max_distance
|
||||
) {
|
||||
std::vector<Impl::BoundedPolygons> projected{Impl::project_to_geometry(extrusions, max_distance)};
|
||||
using Perimeters::BoundedPerimeters;
|
||||
using Perimeters::BoundedPerimeter;
|
||||
|
||||
std::vector<std::size_t> layer_sizes;
|
||||
layer_sizes.reserve(projected.size());
|
||||
for (const Impl::BoundedPolygons &perimeters : projected) {
|
||||
layer_sizes.push_back(perimeters.size());
|
||||
layer_sizes.reserve(perimeters.size());
|
||||
for (const BoundedPerimeters &layer : perimeters) {
|
||||
layer_sizes.push_back(layer.size());
|
||||
}
|
||||
|
||||
const auto &[shell_mapping, shell_count]{Geometry::get_mapping(
|
||||
layer_sizes,
|
||||
[&](const std::size_t layer_index,
|
||||
const std::size_t item_index) -> Geometry::MappingOperatorResult {
|
||||
const Impl::BoundedPolygons &layer{projected[layer_index]};
|
||||
const Impl::BoundedPolygons &next_layer{projected[layer_index + 1]};
|
||||
const BoundedPerimeters &layer{perimeters[layer_index]};
|
||||
const BoundedPerimeters &next_layer{perimeters[layer_index + 1]};
|
||||
if (next_layer.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
BoundingBoxes next_layer_bounding_boxes;
|
||||
for (const Impl::BoundedPolygon &bounded_polygon : next_layer) {
|
||||
next_layer_bounding_boxes.emplace_back(bounded_polygon.bounding_box);
|
||||
for (const BoundedPerimeter &bounded_perimeter : next_layer) {
|
||||
next_layer_bounding_boxes.emplace_back(bounded_perimeter.bounding_box);
|
||||
}
|
||||
|
||||
const auto [perimeter_index, distance] = Geometry::pick_closest_bounding_box(
|
||||
@ -109,6 +62,6 @@ Shells<Polygon> create_shells(
|
||||
}
|
||||
)};
|
||||
|
||||
return Impl::map_to_shells(std::move(projected), shell_mapping, shell_count);
|
||||
return Impl::map_to_shells(std::move(perimeters), shell_mapping, shell_count);
|
||||
}
|
||||
} // namespace Slic3r::Seams::Shells
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <vector>
|
||||
#include <tcbspan/span.hpp>
|
||||
|
||||
#include "libslic3r/GCode/SeamPerimeters.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/GCode/SeamGeometry.hpp"
|
||||
|
||||
@ -11,23 +12,6 @@ namespace Slic3r {
|
||||
class Layer;
|
||||
}
|
||||
|
||||
namespace Slic3r::Seams::Perimeters {
|
||||
struct Perimeter;
|
||||
}
|
||||
|
||||
namespace Slic3r::Seams::Shells::Impl {
|
||||
|
||||
struct BoundedPolygon {
|
||||
Polygon polygon;
|
||||
BoundingBox bounding_box;
|
||||
bool is_hole{false};
|
||||
};
|
||||
|
||||
using BoundedPolygons = std::vector<BoundedPolygon>;
|
||||
|
||||
BoundedPolygons project_to_geometry(const Geometry::Extrusions &extrusions, const double max_bb_distance);
|
||||
}
|
||||
|
||||
namespace Slic3r::Seams::Shells {
|
||||
template<typename T = Perimeters::Perimeter> struct Slice
|
||||
{
|
||||
@ -39,8 +23,22 @@ template<typename T = Perimeters::Perimeter> using Shell = std::vector<Slice<T>>
|
||||
|
||||
template<typename T = Perimeters::Perimeter> using Shells = std::vector<Shell<T>>;
|
||||
|
||||
Shells<Polygon> create_shells(
|
||||
const std::vector<Geometry::Extrusions> &extrusions, const double max_distance
|
||||
inline std::size_t get_layer_count(
|
||||
const Shells<> &shells
|
||||
) {
|
||||
std::size_t layer_count{0};
|
||||
for (const Shell<> &shell : shells) {
|
||||
for (const Slice<>& slice : shell) {
|
||||
if (slice.layer_index >= layer_count) {
|
||||
layer_count = slice.layer_index + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return layer_count;
|
||||
}
|
||||
|
||||
Shells<> create_shells(
|
||||
Perimeters::LayerPerimeters &&perimeters, const double max_distance
|
||||
);
|
||||
} // namespace Slic3r::Seams::Shells
|
||||
|
||||
|
@ -12,8 +12,18 @@ TEST_CASE_METHOD(Slic3r::Test::SeamsFixture, "Seam benchmarks", "[Seams][.Benchm
|
||||
};
|
||||
|
||||
using namespace Slic3r::Seams;
|
||||
|
||||
BENCHMARK_ADVANCED("Create shells benchy")(Catch::Benchmark::Chronometer meter) {
|
||||
meter.measure([&] { return Shells::create_shells(extrusions, params.max_distance); });
|
||||
std::vector<Perimeters::LayerPerimeters> inputs;
|
||||
inputs.reserve(meter.runs());
|
||||
std::generate_n(std::back_inserter(inputs), meter.runs(), [&]() {
|
||||
return Slic3r::Seams::Perimeters::create_perimeters(
|
||||
projected, layer_infos, painting, params.perimeter
|
||||
);
|
||||
});
|
||||
meter.measure([&](const int i) {
|
||||
return Shells::create_shells(std::move(inputs[i]), params.max_distance);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -27,7 +37,7 @@ TEST_CASE_METHOD(Slic3r::Test::SeamsFixture, "Seam benchmarks", "[Seams][.Benchm
|
||||
|
||||
BENCHMARK_ADVANCED("Create perimeters benchy")(Catch::Benchmark::Chronometer meter) {
|
||||
meter.measure([&] {
|
||||
return Perimeters::create_perimeters(shell_polygons, layer_infos, painting, params.perimeter);
|
||||
return Perimeters::create_perimeters(projected, layer_infos, painting, params.perimeter);
|
||||
});
|
||||
};
|
||||
|
||||
@ -35,8 +45,12 @@ TEST_CASE_METHOD(Slic3r::Test::SeamsFixture, "Seam benchmarks", "[Seams][.Benchm
|
||||
std::vector<Shells::Shells<>> inputs;
|
||||
inputs.reserve(meter.runs());
|
||||
std::generate_n(std::back_inserter(inputs), meter.runs(), [&]() {
|
||||
return Perimeters::create_perimeters(
|
||||
shell_polygons, layer_infos, painting, params.perimeter
|
||||
Slic3r::Seams::Perimeters::LayerPerimeters perimeters{
|
||||
Slic3r::Seams::Perimeters::create_perimeters(
|
||||
projected, layer_infos, painting, params.perimeter
|
||||
)};
|
||||
return Shells::create_shells(
|
||||
std::move(perimeters), params.max_distance
|
||||
);
|
||||
});
|
||||
meter.measure([&](const int i) {
|
||||
@ -54,27 +68,25 @@ TEST_CASE_METHOD(Slic3r::Test::SeamsFixture, "Seam benchmarks", "[Seams][.Benchm
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
BENCHMARK_ADVANCED("Generate rear seam benchy")(Catch::Benchmark::Chronometer meter) {
|
||||
std::vector<Shells::Shells<>> inputs;
|
||||
std::vector<Perimeters::LayerPerimeters> inputs;
|
||||
inputs.reserve(meter.runs());
|
||||
std::generate_n(std::back_inserter(inputs), meter.runs(), [&]() {
|
||||
return create_perimeters(
|
||||
shell_polygons, layer_infos, painting, params.perimeter
|
||||
return Slic3r::Seams::Perimeters::create_perimeters(
|
||||
projected, layer_infos, painting, params.perimeter
|
||||
);
|
||||
});
|
||||
meter.measure([&](const int i) {
|
||||
return Rear::get_object_seams(std::move(inputs[i]), params.rear_project_threshold);
|
||||
return Rear::get_object_seams(std::move(inputs[i]), params.rear_tolerance, params.rear_y_offset);
|
||||
});
|
||||
};
|
||||
*/
|
||||
|
||||
BENCHMARK_ADVANCED("Generate random seam benchy")(Catch::Benchmark::Chronometer meter) {
|
||||
std::vector<Shells::Shells<>> inputs;
|
||||
std::vector<Perimeters::LayerPerimeters> inputs;
|
||||
inputs.reserve(meter.runs());
|
||||
std::generate_n(std::back_inserter(inputs), meter.runs(), [&]() {
|
||||
return Perimeters::create_perimeters(
|
||||
shell_polygons, layer_infos, painting, params.perimeter
|
||||
return Slic3r::Seams::Perimeters::create_perimeters(
|
||||
projected, layer_infos, painting, params.perimeter
|
||||
);
|
||||
});
|
||||
meter.measure([&](const int i) {
|
||||
|
@ -219,10 +219,8 @@ struct SeamsFixture
|
||||
const Seams::Perimeters::LayerInfos layer_infos{Seams::Perimeters::get_layer_infos(
|
||||
print_object->layers(), params.perimeter.elephant_foot_compensation
|
||||
)};
|
||||
Seams::Shells::Shells<Polygon> shell_polygons{
|
||||
Seams::Shells::create_shells(extrusions, params.max_distance)};
|
||||
|
||||
const std::size_t shell_index{15};
|
||||
const std::vector<Seams::Geometry::BoundedPolygons> projected{
|
||||
Seams::Geometry::project_to_geometry(extrusions, params.max_distance)};
|
||||
|
||||
const ModelInfo::Visibility visibility{transformation, volumes, params.visibility, [](){}};
|
||||
Seams::Aligned::VisibilityCalculator
|
||||
|
@ -115,13 +115,13 @@ TEST_CASE_METHOD(PickSeamOptionFixture, "Least visible point", "[Seams][SeamAlig
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(Test::SeamsFixture, "Generate aligned seam", "[Seams][SeamAligned][Integration]") {
|
||||
Shells::Shells<> perimeters{
|
||||
Perimeters::create_perimeters(shell_polygons, layer_infos, painting, params.perimeter)};
|
||||
Shells::Shells<> shell_perimeters;
|
||||
shell_perimeters.push_back(std::move(perimeters[shell_index]));
|
||||
Seams::Perimeters::LayerPerimeters perimeters{
|
||||
Seams::Perimeters::create_perimeters(projected, layer_infos, painting, params.perimeter)};
|
||||
Seams::Shells::Shells<> shells{
|
||||
Seams::Shells::create_shells(std::move(perimeters), params.max_distance)};
|
||||
|
||||
const std::vector<std::vector<SeamPerimeterChoice>> seam{
|
||||
Aligned::get_object_seams(std::move(shell_perimeters), visibility_calculator, params.aligned)};
|
||||
REQUIRE(seam.size() == 125);
|
||||
Aligned::get_object_seams(std::move(shells), visibility_calculator, params.aligned)};
|
||||
|
||||
if constexpr (debug_files) {
|
||||
std::ofstream csv{"aligned_seam.csv"};
|
||||
@ -133,9 +133,13 @@ TEST_CASE_METHOD(Test::SeamsFixture, "Calculate visibility", "[Seams][SeamAligne
|
||||
if constexpr (debug_files) {
|
||||
std::ofstream csv{"visibility.csv"};
|
||||
csv << "x,y,z,visibility,total_visibility" << std::endl;
|
||||
Shells::Shells<> perimeters{
|
||||
Perimeters::create_perimeters(shell_polygons, layer_infos, painting, params.perimeter)};
|
||||
for (const Shells::Shell<> &shell : perimeters) {
|
||||
|
||||
Seams::Perimeters::LayerPerimeters perimeters{
|
||||
Seams::Perimeters::create_perimeters(projected, layer_infos, painting, params.perimeter)};
|
||||
|
||||
Seams::Shells::Shells<> shells{
|
||||
Seams::Shells::create_shells(std::move(perimeters), params.max_distance)};
|
||||
for (const Shells::Shell<> &shell : shells) {
|
||||
for (const Shells::Slice<> &slice : shell) {
|
||||
for (std::size_t index{0}; index < slice.boundary.positions.size(); ++index) {
|
||||
const Vec2d &position{slice.boundary.positions[index]};
|
||||
|
@ -167,15 +167,14 @@ void serialize_shell(std::ostream &output, const Shells::Shell<Perimeters::Perim
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(Test::SeamsFixture, "Create perimeters", "[Seams][SeamPerimeters][Integration]") {
|
||||
const Shells::Shells<> perimeters{
|
||||
create_perimeters(shell_polygons, layer_infos, painting, params.perimeter)};
|
||||
Seams::Perimeters::LayerPerimeters perimeters{
|
||||
Seams::Perimeters::create_perimeters(projected, layer_infos, painting, params.perimeter)};
|
||||
|
||||
const Shells::Shell<> &shell{perimeters[shell_index]};
|
||||
Seams::Shells::Shells<> shells{
|
||||
Seams::Shells::create_shells(std::move(perimeters), params.max_distance)};
|
||||
|
||||
if constexpr (debug_files) {
|
||||
std::ofstream csv{"perimeters.csv"};
|
||||
serialize_shell(csv, shell);
|
||||
serialize_shell(csv, shells[0]);
|
||||
}
|
||||
|
||||
REQUIRE(shell.size() == 54);
|
||||
}
|
||||
|
@ -84,16 +84,13 @@ TEST_CASE("Random respects point type", "[Seams][SeamRandom]") {
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(Test::SeamsFixture, "Generate random seam", "[Seams][SeamRandom][Integration]") {
|
||||
Shells::Shells<> perimeters{
|
||||
Seams::Perimeters::create_perimeters(shell_polygons, layer_infos, painting, params.perimeter)};
|
||||
Shells::Shells<> shell_perimeters;
|
||||
shell_perimeters.push_back(std::move(perimeters[shell_index]));
|
||||
const std::vector<std::vector<SeamPerimeterChoice>> seam{
|
||||
Random::get_object_seams(std::move(shell_perimeters), params.random_seed)};
|
||||
REQUIRE(seam.size() == 125);
|
||||
Seams::Perimeters::LayerPerimeters perimeters{
|
||||
Seams::Perimeters::create_perimeters(projected, layer_infos, painting, params.perimeter)};
|
||||
const std::vector<std::vector<SeamPerimeterChoice>> seams{
|
||||
Random::get_object_seams(std::move(perimeters), params.random_seed)};
|
||||
|
||||
if constexpr (debug_files) {
|
||||
std::ofstream csv{"random_seam.csv"};
|
||||
Test::serialize_seam(csv, seam);
|
||||
Test::serialize_seam(csv, seams);
|
||||
}
|
||||
}
|
||||
|
@ -34,19 +34,14 @@ Perimeters::Perimeter get_perimeter() {
|
||||
}
|
||||
} // namespace RearTest
|
||||
|
||||
/**
|
||||
TEST_CASE_METHOD(Test::SeamsFixture, "Generate rear seam", "[Seams][SeamRear][Integration]") {
|
||||
Shells::Shells<> perimeters{
|
||||
Perimeters::create_perimeters(shell_polygons, layer_infos, painting, params.perimeter)};
|
||||
Shells::Shells<> shell_perimeters;
|
||||
shell_perimeters.push_back(std::move(perimeters[shell_index]));
|
||||
const std::vector<std::vector<SeamPerimeterChoice>> seam{
|
||||
Rear::get_object_seams(std::move(shell_perimeters), params.rear_project_threshold)};
|
||||
REQUIRE(seam.size() == 125);
|
||||
Seams::Perimeters::LayerPerimeters perimeters{
|
||||
Seams::Perimeters::create_perimeters(projected, layer_infos, painting, params.perimeter)};
|
||||
const std::vector<std::vector<SeamPerimeterChoice>> seams{
|
||||
Rear::get_object_seams(std::move(perimeters), params.rear_tolerance, params.rear_y_offset)};
|
||||
|
||||
if constexpr (debug_files) {
|
||||
std::ofstream csv{"rear_seam.csv"};
|
||||
Test::serialize_seam(csv, seam);
|
||||
Test::serialize_seam(csv, seams);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -33,7 +33,7 @@ TEST_CASE_METHOD(ProjectionFixture, "Project to geometry matches", "[Seams][Seam
|
||||
boundary_polygon.scale(1.0 + extrusion_width / 2.0 + 0.1);
|
||||
island_boundary.contour = boundary_polygon;
|
||||
|
||||
Shells::Impl::BoundedPolygons result{Shells::Impl::project_to_geometry(extrusions, 5.0)};
|
||||
Seams::Geometry::BoundedPolygons result{Seams::Geometry::project_to_geometry(extrusions, 5.0)};
|
||||
REQUIRE(result.size() == 1);
|
||||
REQUIRE(result[0].polygon.size() == 4);
|
||||
// Boundary polygon is picked.
|
||||
@ -48,7 +48,7 @@ TEST_CASE_METHOD(ProjectionFixture, "Project to geometry does not match", "[Seam
|
||||
|
||||
island_boundary.contour = boundary_polygon;
|
||||
|
||||
Shells::Impl::BoundedPolygons result{Shells::Impl::project_to_geometry(extrusions, 1.0)};
|
||||
Seams::Geometry::BoundedPolygons result{Seams::Geometry::project_to_geometry(extrusions, 1.0)};
|
||||
REQUIRE(result.size() == 1);
|
||||
REQUIRE(result[0].polygon.size() == 4);
|
||||
|
||||
@ -57,35 +57,3 @@ TEST_CASE_METHOD(ProjectionFixture, "Project to geometry does not match", "[Seam
|
||||
// The extrusion is expanded and returned.
|
||||
CHECK(result[0].polygon == expanded);
|
||||
}
|
||||
|
||||
void serialize_shells(
|
||||
std::ostream &out, const Shells::Shells<Polygon> &shells, const double layer_height
|
||||
) {
|
||||
out << "x,y,z,layer_index,slice_id,shell_id" << std::endl;
|
||||
for (std::size_t shell_id{}; shell_id < shells.size(); ++shell_id) {
|
||||
const Shells::Shell<Polygon> &shell{shells[shell_id]};
|
||||
for (std::size_t slice_id{}; slice_id < shell.size(); ++slice_id) {
|
||||
const Shells::Slice<Polygon> &slice{shell[slice_id]};
|
||||
for (const Point &point : slice.boundary) {
|
||||
// clang-format off
|
||||
out
|
||||
<< point.x() << ","
|
||||
<< point.y() << ","
|
||||
<< slice.layer_index * 1e6 * layer_height << ","
|
||||
<< slice.layer_index << ","
|
||||
<< slice_id << ","
|
||||
<< shell_id << std::endl;
|
||||
// clang-format on
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(Test::SeamsFixture, "Create shells", "[Seams][SeamShells][Integration]") {
|
||||
if constexpr (debug_files) {
|
||||
std::ofstream csv{"shells.csv"};
|
||||
serialize_shells(csv, shell_polygons, print->full_print_config().opt_float("layer_height"));
|
||||
}
|
||||
|
||||
CHECK(shell_polygons.size() == 36);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user