mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-02 06:20:36 +08:00
Refactor: Separate gcode generator layer changes utilities to a file.
This commit is contained in:
parent
1ec4cbe2d6
commit
e298593a2e
@ -194,6 +194,8 @@ set(SLIC3R_SOURCES
|
|||||||
GCode/AvoidCrossingPerimeters.hpp
|
GCode/AvoidCrossingPerimeters.hpp
|
||||||
GCode/Travels.cpp
|
GCode/Travels.cpp
|
||||||
GCode/Travels.hpp
|
GCode/Travels.hpp
|
||||||
|
GCode/LayerChanges.cpp
|
||||||
|
GCode/LayerChanges.hpp
|
||||||
GCode.cpp
|
GCode.cpp
|
||||||
GCode.hpp
|
GCode.hpp
|
||||||
GCodeReader.cpp
|
GCodeReader.cpp
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include "GCode/WipeTower.hpp"
|
#include "GCode/WipeTower.hpp"
|
||||||
#include "GCode/WipeTowerIntegration.hpp"
|
#include "GCode/WipeTowerIntegration.hpp"
|
||||||
#include "GCode/Travels.hpp"
|
#include "GCode/Travels.hpp"
|
||||||
|
#include "GCode/LayerChanges.hpp"
|
||||||
#include "Point.hpp"
|
#include "Point.hpp"
|
||||||
#include "Polygon.hpp"
|
#include "Polygon.hpp"
|
||||||
#include "PrintConfig.hpp"
|
#include "PrintConfig.hpp"
|
||||||
@ -2649,54 +2650,6 @@ std::string GCodeGenerator::preamble()
|
|||||||
return gcode;
|
return gcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace GCode::Impl {
|
|
||||||
Polygon generate_regular_polygon(
|
|
||||||
const Point& centroid,
|
|
||||||
const Point& start_point,
|
|
||||||
const unsigned points_count
|
|
||||||
) {
|
|
||||||
Points points;
|
|
||||||
points.reserve(points_count);
|
|
||||||
const double part_angle{2*M_PI / points_count};
|
|
||||||
for (unsigned i = 0; i < points_count; ++i) {
|
|
||||||
const double current_angle{i * part_angle};
|
|
||||||
points.emplace_back(scaled(std::cos(current_angle)), scaled(std::sin(current_angle)));
|
|
||||||
}
|
|
||||||
|
|
||||||
Polygon regular_polygon{points};
|
|
||||||
const Vec2d current_vector{unscaled(regular_polygon.points.front())};
|
|
||||||
const Vec2d expected_vector{unscaled(start_point) - unscaled(centroid)};
|
|
||||||
|
|
||||||
const double current_scale = current_vector.norm();
|
|
||||||
const double expected_scale = expected_vector.norm();
|
|
||||||
regular_polygon.scale(expected_scale / current_scale);
|
|
||||||
|
|
||||||
regular_polygon.rotate(angle(current_vector, expected_vector));
|
|
||||||
|
|
||||||
regular_polygon.translate(centroid);
|
|
||||||
|
|
||||||
return regular_polygon;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bed::Bed(const std::vector<Vec2d>& shape, const double padding):
|
|
||||||
inner_offset(get_inner_offset(shape, padding)),
|
|
||||||
centroid(unscaled(inner_offset.centroid()))
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool Bed::contains_within_padding(const Vec2d& point) const {
|
|
||||||
return inner_offset.contains(scaled(point));
|
|
||||||
}
|
|
||||||
|
|
||||||
Polygon Bed::get_inner_offset(const std::vector<Vec2d>& shape, const double padding) {
|
|
||||||
Points shape_scaled;
|
|
||||||
shape_scaled.reserve(shape.size());
|
|
||||||
using std::begin, std::end, std::back_inserter, std::transform;
|
|
||||||
transform(begin(shape), end(shape), back_inserter(shape_scaled), [](const Vec2d& point){
|
|
||||||
return scaled(point);
|
|
||||||
});
|
|
||||||
return shrink({Polygon{shape_scaled}}, scaled(padding)).front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::string> GCodeGenerator::get_helical_layer_change_gcode(
|
std::optional<std::string> GCodeGenerator::get_helical_layer_change_gcode(
|
||||||
const coordf_t previous_layer_z,
|
const coordf_t previous_layer_z,
|
||||||
@ -2713,7 +2666,7 @@ std::optional<std::string> GCodeGenerator::get_helical_layer_change_gcode(
|
|||||||
|
|
||||||
const Point n_gon_start_point{this->last_pos()};
|
const Point n_gon_start_point{this->last_pos()};
|
||||||
|
|
||||||
static GCode::Impl::Bed bed{
|
static GCode::Impl::LayerChanges::Bed bed{
|
||||||
this->m_config.bed_shape.values,
|
this->m_config.bed_shape.values,
|
||||||
circle_radius
|
circle_radius
|
||||||
};
|
};
|
||||||
@ -2729,7 +2682,7 @@ std::optional<std::string> GCodeGenerator::get_helical_layer_change_gcode(
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
const Polygon n_gon{GCode::Impl::generate_regular_polygon(
|
const Polygon n_gon{GCode::Impl::LayerChanges::generate_regular_polygon(
|
||||||
n_gon_centeroid,
|
n_gon_centeroid,
|
||||||
n_gon_start_point,
|
n_gon_start_point,
|
||||||
n_gon_points_count
|
n_gon_points_count
|
||||||
@ -3413,8 +3366,6 @@ std::string GCodeGenerator::travel_to(const Point &point, ExtrusionRole role, st
|
|||||||
|
|
||||||
const Point start_point = this->last_pos();
|
const Point start_point = this->last_pos();
|
||||||
|
|
||||||
using namespace GCode::Impl;
|
|
||||||
|
|
||||||
// check whether a straight travel move would need retraction
|
// check whether a straight travel move would need retraction
|
||||||
|
|
||||||
bool could_be_wipe_disabled {false};
|
bool could_be_wipe_disabled {false};
|
||||||
|
@ -89,43 +89,6 @@ struct LayerResult {
|
|||||||
static LayerResult make_nop_layer_result() { return {"", std::numeric_limits<coord_t>::max(), false, false, true}; }
|
static LayerResult make_nop_layer_result() { return {"", std::numeric_limits<coord_t>::max(), false, false, true}; }
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace GCode::Impl {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a regular polygon - all angles are the same (e.g. typical hexagon).
|
|
||||||
*
|
|
||||||
* @param centroid Central point.
|
|
||||||
* @param start_point The polygon point are ordered. This is the first point.
|
|
||||||
* @param points_count Amount of nodes of the polygon (e.g. 6 for haxagon).
|
|
||||||
*
|
|
||||||
* Distance between centroid and start point sets the scale of the polygon.
|
|
||||||
*/
|
|
||||||
Polygon generate_regular_polygon(
|
|
||||||
const Point& centroid,
|
|
||||||
const Point& start_point,
|
|
||||||
const unsigned points_count
|
|
||||||
);
|
|
||||||
|
|
||||||
class Bed {
|
|
||||||
private:
|
|
||||||
Polygon inner_offset;
|
|
||||||
static Polygon get_inner_offset(const std::vector<Vec2d>& shape, const double padding);
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Bed shape with inner padding.
|
|
||||||
*/
|
|
||||||
Bed(const std::vector<Vec2d>& shape, const double padding);
|
|
||||||
|
|
||||||
Vec2d centroid;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the point is within the bed shape including inner padding.
|
|
||||||
*/
|
|
||||||
bool contains_within_padding(const Vec2d& point) const;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
class GCodeGenerator {
|
class GCodeGenerator {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
48
src/libslic3r/GCode/LayerChanges.cpp
Normal file
48
src/libslic3r/GCode/LayerChanges.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "LayerChanges.hpp"
|
||||||
|
#include "libslic3r/ClipperUtils.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r::GCode::Impl::LayerChanges {
|
||||||
|
|
||||||
|
Polygon generate_regular_polygon(
|
||||||
|
const Point ¢roid, const Point &start_point, const unsigned points_count
|
||||||
|
) {
|
||||||
|
Points points;
|
||||||
|
points.reserve(points_count);
|
||||||
|
const double part_angle{2 * M_PI / points_count};
|
||||||
|
for (unsigned i = 0; i < points_count; ++i) {
|
||||||
|
const double current_angle{i * part_angle};
|
||||||
|
points.emplace_back(scaled(std::cos(current_angle)), scaled(std::sin(current_angle)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Polygon regular_polygon{points};
|
||||||
|
const Vec2d current_vector{unscaled(regular_polygon.points.front())};
|
||||||
|
const Vec2d expected_vector{unscaled(start_point) - unscaled(centroid)};
|
||||||
|
|
||||||
|
const double current_scale = current_vector.norm();
|
||||||
|
const double expected_scale = expected_vector.norm();
|
||||||
|
regular_polygon.scale(expected_scale / current_scale);
|
||||||
|
|
||||||
|
regular_polygon.rotate(angle(current_vector, expected_vector));
|
||||||
|
|
||||||
|
regular_polygon.translate(centroid);
|
||||||
|
|
||||||
|
return regular_polygon;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bed::Bed(const std::vector<Vec2d> &shape, const double padding)
|
||||||
|
: inner_offset(get_inner_offset(shape, padding)), centroid(unscaled(inner_offset.centroid())) {}
|
||||||
|
|
||||||
|
bool Bed::contains_within_padding(const Vec2d &point) const {
|
||||||
|
return inner_offset.contains(scaled(point));
|
||||||
|
}
|
||||||
|
|
||||||
|
Polygon Bed::get_inner_offset(const std::vector<Vec2d> &shape, const double padding) {
|
||||||
|
Points shape_scaled;
|
||||||
|
shape_scaled.reserve(shape.size());
|
||||||
|
using std::begin, std::end, std::back_inserter, std::transform;
|
||||||
|
transform(begin(shape), end(shape), back_inserter(shape_scaled), [](const Vec2d &point) {
|
||||||
|
return scaled(point);
|
||||||
|
});
|
||||||
|
return shrink({Polygon{shape_scaled}}, scaled(padding)).front();
|
||||||
|
}
|
||||||
|
} // namespace Slic3r::GCode::Impl::LayerChanges
|
52
src/libslic3r/GCode/LayerChanges.hpp
Normal file
52
src/libslic3r/GCode/LayerChanges.hpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Utility functions for layer change gcode generation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef slic3r_GCode_LayerChanges_hpp_
|
||||||
|
#define slic3r_GCode_LayerChanges_hpp_
|
||||||
|
|
||||||
|
#include "libslic3r/Point.hpp"
|
||||||
|
#include "libslic3r/Polygon.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r::GCode::Impl::LayerChanges {
|
||||||
|
/**
|
||||||
|
* Generates a regular polygon - all angles are the same (e.g. typical hexagon).
|
||||||
|
*
|
||||||
|
* @param centroid Central point.
|
||||||
|
* @param start_point The polygon point are ordered. This is the first point.
|
||||||
|
* @param points_count Amount of nodes of the polygon (e.g. 6 for haxagon).
|
||||||
|
*
|
||||||
|
* Distance between centroid and start point sets the scale of the polygon.
|
||||||
|
*/
|
||||||
|
Polygon generate_regular_polygon(
|
||||||
|
const Point ¢roid, const Point &start_point, const unsigned points_count
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A representation of the bed shape with inner padding.
|
||||||
|
*
|
||||||
|
* Its purpose is to facilitate the bed boundary checking.
|
||||||
|
*/
|
||||||
|
class Bed
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Polygon inner_offset;
|
||||||
|
static Polygon get_inner_offset(const std::vector<Vec2d> &shape, const double padding);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Bed shape with inner padding.
|
||||||
|
*/
|
||||||
|
Bed(const std::vector<Vec2d> &shape, const double padding);
|
||||||
|
|
||||||
|
Vec2d centroid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the point is within the bed shape including inner padding.
|
||||||
|
*/
|
||||||
|
bool contains_within_padding(const Vec2d &point) const;
|
||||||
|
};
|
||||||
|
} // namespace Slic3r::GCode::Impl::LayerChanges
|
||||||
|
|
||||||
|
#endif // slic3r_GCode_LayerChanges_hpp_
|
@ -14,6 +14,7 @@ add_executable(${_TEST_NAME}_tests
|
|||||||
test_gaps.cpp
|
test_gaps.cpp
|
||||||
test_gcode.cpp
|
test_gcode.cpp
|
||||||
test_gcode_travels.cpp
|
test_gcode_travels.cpp
|
||||||
|
test_gcode_layer_changes.cpp
|
||||||
test_gcodefindreplace.cpp
|
test_gcodefindreplace.cpp
|
||||||
test_gcodewriter.cpp
|
test_gcodewriter.cpp
|
||||||
test_model.cpp
|
test_model.cpp
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#include "libslic3r/GCode.hpp"
|
#include "libslic3r/GCode.hpp"
|
||||||
|
|
||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
using namespace Slic3r::GCode::Impl;
|
|
||||||
|
|
||||||
SCENARIO("Origin manipulation", "[GCode]") {
|
SCENARIO("Origin manipulation", "[GCode]") {
|
||||||
Slic3r::GCodeGenerator gcodegen;
|
Slic3r::GCodeGenerator gcodegen;
|
||||||
@ -21,53 +20,3 @@ SCENARIO("Origin manipulation", "[GCode]") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Generate regular polygon", "[GCode]") {
|
|
||||||
const unsigned points_count{32};
|
|
||||||
const Point centroid{scaled(Vec2d{5, -2})};
|
|
||||||
const Polygon result{generate_regular_polygon(centroid, scaled(Vec2d{0, 0}), points_count)};
|
|
||||||
const Point oposite_point{centroid * 2};
|
|
||||||
|
|
||||||
REQUIRE(result.size() == 32);
|
|
||||||
CHECK(result[16].x() == Approx(oposite_point.x()));
|
|
||||||
CHECK(result[16].y() == Approx(oposite_point.y()));
|
|
||||||
|
|
||||||
std::vector<double> angles;
|
|
||||||
angles.reserve(points_count);
|
|
||||||
for (unsigned index = 0; index < points_count; index++) {
|
|
||||||
const unsigned previous_index{index == 0 ? points_count - 1 : index - 1};
|
|
||||||
const unsigned next_index{index == points_count - 1 ? 0 : index + 1};
|
|
||||||
|
|
||||||
const Point previous_point = result.points[previous_index];
|
|
||||||
const Point current_point = result.points[index];
|
|
||||||
const Point next_point = result.points[next_index];
|
|
||||||
|
|
||||||
angles.emplace_back(angle(Vec2crd{previous_point - current_point}, Vec2crd{next_point - current_point}));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<double> expected;
|
|
||||||
angles.reserve(points_count);
|
|
||||||
std::generate_n(std::back_inserter(expected), points_count, [&](){
|
|
||||||
return angles.front();
|
|
||||||
});
|
|
||||||
|
|
||||||
CHECK_THAT(angles, Catch::Matchers::Approx(expected));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Square bed with padding", "[GCode]") {
|
|
||||||
const Bed bed{
|
|
||||||
{
|
|
||||||
Vec2d{0, 0},
|
|
||||||
Vec2d{100, 0},
|
|
||||||
Vec2d{100, 100},
|
|
||||||
Vec2d{0, 100}
|
|
||||||
},
|
|
||||||
10.0
|
|
||||||
};
|
|
||||||
|
|
||||||
CHECK(bed.centroid.x() == 50);
|
|
||||||
CHECK(bed.centroid.y() == 50);
|
|
||||||
CHECK(bed.contains_within_padding(Vec2d{10, 10}));
|
|
||||||
CHECK_FALSE(bed.contains_within_padding(Vec2d{9, 10}));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
55
tests/fff_print/test_gcode_layer_changes.cpp
Normal file
55
tests/fff_print/test_gcode_layer_changes.cpp
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#include <catch2/catch.hpp>
|
||||||
|
#include <libslic3r/GCode/LayerChanges.hpp>
|
||||||
|
|
||||||
|
using namespace Slic3r;
|
||||||
|
using namespace Slic3r::GCode::Impl::LayerChanges;
|
||||||
|
|
||||||
|
TEST_CASE("Generate regular polygon", "[GCode]") {
|
||||||
|
const unsigned points_count{32};
|
||||||
|
const Point centroid{scaled(Vec2d{5, -2})};
|
||||||
|
const Polygon result{generate_regular_polygon(centroid, scaled(Vec2d{0, 0}), points_count)};
|
||||||
|
const Point oposite_point{centroid * 2};
|
||||||
|
|
||||||
|
REQUIRE(result.size() == 32);
|
||||||
|
CHECK(result[16].x() == Approx(oposite_point.x()));
|
||||||
|
CHECK(result[16].y() == Approx(oposite_point.y()));
|
||||||
|
|
||||||
|
std::vector<double> angles;
|
||||||
|
angles.reserve(points_count);
|
||||||
|
for (unsigned index = 0; index < points_count; index++) {
|
||||||
|
const unsigned previous_index{index == 0 ? points_count - 1 : index - 1};
|
||||||
|
const unsigned next_index{index == points_count - 1 ? 0 : index + 1};
|
||||||
|
|
||||||
|
const Point previous_point = result.points[previous_index];
|
||||||
|
const Point current_point = result.points[index];
|
||||||
|
const Point next_point = result.points[next_index];
|
||||||
|
|
||||||
|
angles.emplace_back(angle(Vec2crd{previous_point - current_point}, Vec2crd{next_point - current_point}));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<double> expected;
|
||||||
|
angles.reserve(points_count);
|
||||||
|
std::generate_n(std::back_inserter(expected), points_count, [&](){
|
||||||
|
return angles.front();
|
||||||
|
});
|
||||||
|
|
||||||
|
CHECK_THAT(angles, Catch::Matchers::Approx(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Square bed with padding", "[GCode]") {
|
||||||
|
const Bed bed{
|
||||||
|
{
|
||||||
|
Vec2d{0, 0},
|
||||||
|
Vec2d{100, 0},
|
||||||
|
Vec2d{100, 100},
|
||||||
|
Vec2d{0, 100}
|
||||||
|
},
|
||||||
|
10.0
|
||||||
|
};
|
||||||
|
|
||||||
|
CHECK(bed.centroid.x() == 50);
|
||||||
|
CHECK(bed.centroid.y() == 50);
|
||||||
|
CHECK(bed.contains_within_padding(Vec2d{10, 10}));
|
||||||
|
CHECK_FALSE(bed.contains_within_padding(Vec2d{9, 10}));
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user