mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-14 00:52:04 +00:00
Various ZAA fixes.
- Handle z contouring in variable speed flow when emitting GCode - Add logic to restore nominnal z height for regular extrusions - preserve z_contoured flag when splitting extrusion paths
This commit is contained in:
@@ -161,10 +161,11 @@ namespace AABBTreeLines {
|
||||
// on centroids of the lines.
|
||||
// Epsilon is applied to the bounding boxes of the AABB Tree to cope with numeric inaccuracies
|
||||
// during tree traversal.
|
||||
template <typename LineType>
|
||||
inline AABBTreeIndirect::Tree<2, typename LineType::Scalar> build_aabb_tree_over_indexed_lines(const std::vector<LineType>& lines)
|
||||
template<typename LineType>
|
||||
inline AABBTreeIndirect::Tree<LineType::Dim, typename LineType::Scalar> build_aabb_tree_over_indexed_lines(
|
||||
const std::vector<LineType>& lines)
|
||||
{
|
||||
using TreeType = AABBTreeIndirect::Tree<2, typename LineType::Scalar>;
|
||||
using TreeType = AABBTreeIndirect::Tree<LineType::Dim, typename LineType::Scalar>;
|
||||
// using CoordType = typename TreeType::CoordType;
|
||||
using VectorType = typename TreeType::VectorType;
|
||||
using BoundingBox = typename TreeType::BoundingBox;
|
||||
@@ -303,7 +304,7 @@ namespace AABBTreeLines {
|
||||
|
||||
private:
|
||||
std::vector<LineType> lines;
|
||||
AABBTreeIndirect::Tree<2, Scalar> tree;
|
||||
AABBTreeIndirect::Tree<LineType::Dim, Scalar> tree;
|
||||
|
||||
public:
|
||||
explicit LinesDistancer(const std::vector<LineType>& lines)
|
||||
@@ -321,15 +322,15 @@ namespace AABBTreeLines {
|
||||
LinesDistancer() = default;
|
||||
|
||||
// 1 true, -1 false, 0 cannot determine
|
||||
int outside(const Vec<2, Scalar>& point) const { return point_outside_closed_contours(lines, tree, point); }
|
||||
int outside(const Vec<LineType::Dim, Scalar>& point) const { return point_outside_closed_contours(lines, tree, point); }
|
||||
|
||||
// negative sign means inside
|
||||
template <bool SIGNED_DISTANCE>
|
||||
std::tuple<Floating, size_t, Vec<2, Floating>> distance_from_lines_extra(const Vec<2, Scalar>& point) const
|
||||
template<bool SIGNED_DISTANCE>
|
||||
std::tuple<Floating, size_t, Vec<LineType::Dim, Floating>> distance_from_lines_extra(const Vec<LineType::Dim, Scalar>& point) const
|
||||
{
|
||||
size_t nearest_line_index_out = size_t(-1);
|
||||
Vec<2, Floating> nearest_point_out = Vec<2, Floating>::Zero();
|
||||
Vec<2, Floating> p = point.template cast<Floating>();
|
||||
Vec<LineType::Dim, Floating> nearest_point_out = Vec<LineType::Dim, Floating>::Zero();
|
||||
Vec<LineType::Dim, Floating> p = point.template cast<Floating>();
|
||||
auto distance = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, p, nearest_line_index_out, nearest_point_out);
|
||||
|
||||
if (distance < 0) {
|
||||
@@ -344,22 +345,20 @@ namespace AABBTreeLines {
|
||||
return { distance, nearest_line_index_out, nearest_point_out };
|
||||
}
|
||||
|
||||
template <bool SIGNED_DISTANCE>
|
||||
Floating distance_from_lines(const Vec<2, typename LineType::Scalar>& point) const
|
||||
template<bool SIGNED_DISTANCE> Floating distance_from_lines(const Vec<LineType::Dim, typename LineType::Scalar>& point) const
|
||||
{
|
||||
auto [dist, idx, np] = distance_from_lines_extra<SIGNED_DISTANCE>(point);
|
||||
return dist;
|
||||
}
|
||||
|
||||
std::vector<size_t> all_lines_in_radius(const Vec<2, Scalar> &point, Floating radius)
|
||||
{
|
||||
return AABBTreeLines::all_lines_in_radius(this->lines, this->tree, point.template cast<Floating>(), radius * radius);
|
||||
}
|
||||
|
||||
template <bool sorted>
|
||||
std::vector<std::pair<Vec<2, Scalar>, size_t>> intersections_with_line(const LineType& line) const
|
||||
std::vector<size_t> all_lines_in_radius(const Vec<LineType::Dim, Scalar>& point, Floating radius)
|
||||
{
|
||||
return get_intersections_with_line<sorted, Vec<2, Scalar>>(lines, tree, line);
|
||||
return AABBTreeLines::all_lines_in_radius(this->lines, this->tree, point.template cast<Floating>(), radius * radius);
|
||||
}
|
||||
|
||||
template<bool sorted> std::vector<std::pair<Vec<LineType::Dim, Scalar>, size_t>> intersections_with_line(const LineType& line) const
|
||||
{
|
||||
return get_intersections_with_line<sorted, Vec<LineType::Dim, Scalar>>(lines, tree, line);
|
||||
}
|
||||
|
||||
const LineType& get_line(size_t line_idx) const { return lines[line_idx]; }
|
||||
|
||||
@@ -225,8 +225,8 @@ static void handle_extrusion_collection(LayerRegion *region, const sla::IndexedM
|
||||
void Layer::make_contour_z(const sla::IndexedMesh &mesh)
|
||||
{
|
||||
for (LayerRegion *region : this->regions()) {
|
||||
handle_extrusion_collection(region, mesh, region->fills, {erTopSolidInfill, erIroning, erExternalPerimeter, erMixed});
|
||||
handle_extrusion_collection(region, mesh, region->perimeters, {erExternalPerimeter, erMixed});
|
||||
}
|
||||
handle_extrusion_collection(region, mesh, region->fills, {erTopSolidInfill, erIroning, erPerimeter, erExternalPerimeter, erMixed});
|
||||
handle_extrusion_collection(region, mesh, region->perimeters, {erPerimeter, erExternalPerimeter, erMixed});
|
||||
}
|
||||
}
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -192,6 +192,25 @@ inline Linesf to_unscaled_linesf(const ExPolygons &src)
|
||||
return lines;
|
||||
}
|
||||
|
||||
inline Linesf3 to_unscaled_linesf3(const ExPolygons& src)
|
||||
{
|
||||
Linesf3 lines;
|
||||
lines.reserve(count_points(src));
|
||||
for (ExPolygons::const_iterator it_expoly = src.begin(); it_expoly != src.end(); ++it_expoly) {
|
||||
for (size_t i = 0; i <= it_expoly->holes.size(); ++i) {
|
||||
const Points& points = ((i == 0) ? it_expoly->contour : it_expoly->holes[i - 1]).points;
|
||||
Vec2d unscaled_a = unscaled(points.front());
|
||||
Vec2d unscaled_b = unscaled_a;
|
||||
for (Points::const_iterator it = points.begin() + 1; it != points.end(); ++it) {
|
||||
unscaled_b = unscaled(*(it));
|
||||
lines.push_back(Linef3(unscaled_a, unscaled_b, 0));
|
||||
unscaled_a = unscaled_b;
|
||||
}
|
||||
lines.push_back(Linef3(unscaled_a, unscaled(points.front()), 0));
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
inline Points to_points(const ExPolygons &src)
|
||||
{
|
||||
|
||||
@@ -286,6 +286,7 @@ void ExtrusionLoop::split_at(const Point &point, bool prefer_non_overhang, const
|
||||
const ExtrusionPath &path = this->paths[path_idx];
|
||||
ExtrusionPath p1(path.role(), path.mm3_per_mm, path.width, path.height);
|
||||
ExtrusionPath p2(path.role(), path.mm3_per_mm, path.width, path.height);
|
||||
p1.z_contoured = p2.z_contoured = path.z_contoured;
|
||||
path.polyline.split_at(p, &p1.polyline, &p2.polyline);
|
||||
|
||||
if (this->paths.size() == 1) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "BoundingBox.hpp"
|
||||
#include "Config.hpp"
|
||||
#include "GCodeWriter.hpp"
|
||||
#include "Polygon.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "libslic3r.h"
|
||||
@@ -5817,7 +5818,7 @@ std::string GCode::extrude_loop(const ExtrusionLoop& loop_ref,
|
||||
const Point3 ¢er3 = paths.front().polyline.points.front();
|
||||
pt.rotate(angle, Point(center3.x(), center3.y()));
|
||||
// generate the travel move
|
||||
gcode += m_writer.extrude_to_xy(this->point_to_gcode(pt), 0,"move inwards before travel",true);
|
||||
gcode += m_writer.extrude_to_xy(this->point_to_gcode(pt), 0, "move inwards before travel", true);
|
||||
}
|
||||
|
||||
return gcode;
|
||||
@@ -6150,19 +6151,13 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
// Move to first point of extrusion path
|
||||
// path is 2D. But in slope lift case, lift z is done in travel_to function.
|
||||
// Add m_need_change_layer_lift_z when change_layer in case of no lift if m_last_pos is equal to path.first_point() by chance
|
||||
Point3 first_point = path.first_point3();
|
||||
if (!m_last_pos_defined || m_last_pos != first_point || m_need_change_layer_lift_z || slope_need_z_travel) {
|
||||
Point first_point = path.first_point();
|
||||
if (!m_last_pos_defined || m_last_pos.to_point() != first_point || m_need_change_layer_lift_z || slope_need_z_travel) {
|
||||
const bool _last_pos_undefined = !m_last_pos_defined;
|
||||
double z = DBL_MAX;
|
||||
if (sloped != nullptr) {
|
||||
z = get_sloped_z(sloped->slope_begin.z_ratio);
|
||||
} else if ((!m_last_pos_defined && first_point.z() != 0) || m_last_pos.z() != first_point.z()) {
|
||||
z = m_nominal_z + unscale_(first_point.z());
|
||||
if (z < 0.1) {
|
||||
throw RuntimeError("GCode: very low z");
|
||||
}
|
||||
}
|
||||
gcode += this->travel_to(path.first_point(), path.role(), "move to first " + description + " point", z);
|
||||
|
||||
gcode += this->travel_to(path.first_point(), path.role(), "move to first " + description + " point",
|
||||
sloped == nullptr ? DBL_MAX : get_sloped_z(sloped->slope_begin.z_ratio));
|
||||
|
||||
m_need_change_layer_lift_z = false;
|
||||
// Orca: ensure Z matches planned layer height
|
||||
if (_last_pos_undefined && !slope_need_z_travel) {
|
||||
@@ -6170,6 +6165,20 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
}
|
||||
}
|
||||
|
||||
if (path.z_contoured && !path.polyline.lines().empty()) {
|
||||
double current_z = m_writer.get_position().z();
|
||||
;
|
||||
double first_z = unscale_(path.polyline.lines().begin()->a.z()) + m_nominal_z;
|
||||
if (GCodeFormatter::quantize_xyzf(first_z) != GCodeFormatter::quantize_xyzf(current_z)) {
|
||||
gcode += m_writer.travel_to_z(first_z, "set Z for contouring", true);
|
||||
}
|
||||
}
|
||||
if (!path.z_contoured) {
|
||||
double current_z = m_writer.get_position().z();
|
||||
if (GCodeFormatter::quantize_xyzf(current_z) != GCodeFormatter::quantize_xyzf(m_nominal_z)) {
|
||||
gcode += this->writer().travel_to_z(m_nominal_z, "reset Z after contouring", true);
|
||||
}
|
||||
}
|
||||
|
||||
// if needed, write the gcode_label_objects_end then gcode_label_objects_start
|
||||
// should be already done by travel_to, but just in case
|
||||
@@ -6729,6 +6738,8 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
if (!m_config.enable_arc_fitting || path.polyline.fitting_result.empty() || m_config.spiral_mode || sloped != nullptr || path.z_contoured) {
|
||||
double path_length = 0.;
|
||||
double total_length = sloped == nullptr ? 0. : path.polyline.length() * SCALING_FACTOR;
|
||||
double saved_z = m_writer.get_position().z();
|
||||
|
||||
for (const Line3& line : path.polyline.lines()) {
|
||||
std::string tempDescription = description;
|
||||
const double line_length = line.length() * SCALING_FACTOR;
|
||||
@@ -6849,14 +6860,14 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
double total_length = 0;
|
||||
if (sloped != nullptr) {
|
||||
// Calculate total extrusion length
|
||||
Points p;
|
||||
Points3 p;
|
||||
p.reserve(new_points.size());
|
||||
std::transform(new_points.begin(), new_points.end(), std::back_inserter(p), [](const ProcessedPoint& pp) { return pp.p; });
|
||||
Polyline l(p);
|
||||
Polyline3 l(p);
|
||||
total_length = l.length() * SCALING_FACTOR;
|
||||
}
|
||||
gcode += m_writer.set_speed(last_set_speed, "", comment);
|
||||
Vec2d prev = this->point_to_gcode_quantized(new_points[0].p);
|
||||
Vec3d prev = this->point_to_gcode_quantized(new_points[0].p);
|
||||
bool pre_fan_enabled = false;
|
||||
bool cur_fan_enabled = false;
|
||||
if( m_enable_cooling_markers && enable_overhang_bridge_fan)
|
||||
@@ -6870,7 +6881,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
std::string tempDescription = description;
|
||||
const ProcessedPoint &processed_point = new_points[i];
|
||||
const ProcessedPoint &pre_processed_point = new_points[i-1];
|
||||
Vec2d p = this->point_to_gcode_quantized(processed_point.p);
|
||||
Vec3d p = this->point_to_gcode_quantized(processed_point.p);
|
||||
if (m_enable_cooling_markers) {
|
||||
if (enable_overhang_bridge_fan) {
|
||||
cur_fan_enabled = check_overhang_fan(processed_point.overlap, path.role());
|
||||
@@ -6952,9 +6963,26 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
tempDescription += Slic3r::format(" | Old Flow Value: %0.5f Length: %0.5f",oldE, line_length);
|
||||
}
|
||||
}
|
||||
if (sloped == nullptr) {
|
||||
if (path.z_contoured) {
|
||||
Vec2d dest2d = p.head<2>();
|
||||
coordf_t z_diff = unscale_(processed_point.p.z());
|
||||
|
||||
double extrusion_ratio = 1;
|
||||
if (path.role() != erIroning) {
|
||||
extrusion_ratio = (path.height + z_diff) / path.height;
|
||||
}
|
||||
|
||||
double e = dE * extrusion_ratio;
|
||||
|
||||
double z = m_nominal_z + z_diff;
|
||||
if (z < 0.1) {
|
||||
throw RuntimeError("GCode: very low z");
|
||||
}
|
||||
gcode += m_writer.extrude_to_xyz(Vec3d(dest2d.x(), dest2d.y(), z), e,
|
||||
GCodeWriter::full_gcode_comment ? tempDescription : "");
|
||||
} else if (sloped == nullptr) {
|
||||
// Normal extrusion
|
||||
gcode += m_writer.extrude_to_xy(p, dE, GCodeWriter::full_gcode_comment ? tempDescription : "");
|
||||
gcode += m_writer.extrude_to_xy(p.head<2>(), dE, GCodeWriter::full_gcode_comment ? tempDescription : "");
|
||||
} else {
|
||||
// Sloped extrusion
|
||||
const auto [z_ratio, e_ratio] = sloped->interpolate(path_length / total_length);
|
||||
@@ -7811,6 +7839,13 @@ Vec2d GCode::point_to_gcode(const Point &point) const
|
||||
return unscale(point) + m_origin - extruder_offset;
|
||||
}
|
||||
|
||||
Vec3d GCode::point_to_gcode(const Point3& point) const
|
||||
{
|
||||
Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset);
|
||||
Vec2d xy = unscale(point.to_point()) + m_origin - extruder_offset;
|
||||
return Vec3d(xy.x(), xy.y(), unscale_(point.z()));
|
||||
}
|
||||
|
||||
// convert a model-space scaled point into G-code coordinates
|
||||
Point GCode::gcode_to_point(const Vec2d &point) const
|
||||
{
|
||||
@@ -7828,6 +7863,11 @@ Vec2d GCode::point_to_gcode_quantized(const Point& point) const
|
||||
return { GCodeFormatter::quantize_xyzf(p.x()), GCodeFormatter::quantize_xyzf(p.y()) };
|
||||
}
|
||||
|
||||
Vec3d GCode::point_to_gcode_quantized(const Point3& point) const
|
||||
{
|
||||
Vec3d p = this->point_to_gcode(point);
|
||||
return {GCodeFormatter::quantize_xyzf(p.x()), GCodeFormatter::quantize_xyzf(p.y()), GCodeFormatter::quantize_xyzf(p.z())};
|
||||
}
|
||||
|
||||
// Goes through by_region std::vector and returns reference to a subvector of entities, that are to be printed
|
||||
// during infill/perimeter wiping, or normally (depends on wiping_entities parameter)
|
||||
|
||||
@@ -223,8 +223,10 @@ public:
|
||||
void set_origin(const coordf_t x, const coordf_t y) { this->set_origin(Vec2d(x, y)); }
|
||||
Point last_pos() const { return m_last_pos.to_point(); }
|
||||
Vec2d point_to_gcode(const Point &point) const;
|
||||
Vec3d point_to_gcode(const Point3& point) const;
|
||||
Point gcode_to_point(const Vec2d &point) const;
|
||||
Vec2d point_to_gcode_quantized(const Point& point) const;
|
||||
Vec3d point_to_gcode_quantized(const Point3& point) const;
|
||||
const FullPrintConfig &config() const { return m_config; }
|
||||
const Layer* layer() const { return m_layer; }
|
||||
GCodeWriter& writer() { return m_writer; }
|
||||
|
||||
@@ -27,19 +27,19 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
struct ExtendedPoint
|
||||
template<int Dim> struct ExtendedPoint
|
||||
{
|
||||
Vec2d position;
|
||||
Eigen::Matrix<double, Dim, 1, Eigen::DontAlign> position;
|
||||
float distance;
|
||||
float curvature;
|
||||
};
|
||||
|
||||
template<bool SCALED_INPUT, bool ADD_INTERSECTIONS, bool PREV_LAYER_BOUNDARY_OFFSET, bool SIGNED_DISTANCE, typename POINTS, typename L>
|
||||
std::vector<ExtendedPoint> estimate_points_properties(const POINTS &input_points,
|
||||
const AABBTreeLines::LinesDistancer<L> &unscaled_prev_layer,
|
||||
float flow_width,
|
||||
float max_line_length = -1.0f,
|
||||
float min_distance = -1.0f)
|
||||
std::vector<ExtendedPoint<L::Dim>> estimate_points_properties(const POINTS& input_points,
|
||||
const AABBTreeLines::LinesDistancer<L>& unscaled_prev_layer,
|
||||
float flow_width,
|
||||
float max_line_length = -1.0f,
|
||||
float min_distance = -1.0f)
|
||||
{
|
||||
bool looped = input_points.front() == input_points.back();
|
||||
std::function<size_t(size_t,size_t)> get_prev_index = [](size_t idx, size_t count) {
|
||||
@@ -78,47 +78,36 @@ std::vector<ExtendedPoint> estimate_points_properties(const POINTS
|
||||
double min_spacing = flow_width*0.25;
|
||||
|
||||
using AABBScalar = typename AABBTreeLines::LinesDistancer<L>::Scalar;
|
||||
using Vec = Eigen::Matrix<double, L::Dim, 1, Eigen::DontAlign>;
|
||||
if (input_points.empty())
|
||||
return {};
|
||||
float boundary_offset = PREV_LAYER_BOUNDARY_OFFSET ? 0.5 * flow_width : 0.0f;
|
||||
auto maybe_unscale = [](const P &p) -> Vec2d {
|
||||
if constexpr (P::RowsAtCompileTime == 3) {
|
||||
// 3D point - extract XY only
|
||||
if constexpr (SCALED_INPUT) {
|
||||
return unscaled(p).template head<2>();
|
||||
} else {
|
||||
return p.template head<2>().template cast<double>();
|
||||
}
|
||||
} else {
|
||||
// 2D point - use as is
|
||||
return SCALED_INPUT ? unscaled(p) : p.template cast<double>();
|
||||
}
|
||||
};
|
||||
auto maybe_unscale = [](const P& p) -> Vec { return SCALED_INPUT ? unscaled(p) : p.template cast<double>(); };
|
||||
|
||||
std::vector<ExtendedPoint> points;
|
||||
std::vector<ExtendedPoint<L::Dim>> points;
|
||||
points.reserve(input_points.size() * (ADD_INTERSECTIONS ? 1.5 : 1));
|
||||
|
||||
{
|
||||
ExtendedPoint start_point{maybe_unscale(input_points.front())};
|
||||
auto [distance, nearest_line,
|
||||
x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(start_point.position.cast<AABBScalar>());
|
||||
ExtendedPoint<L::Dim> start_point{maybe_unscale(input_points.front())};
|
||||
auto [distance, nearest_line, x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(
|
||||
start_point.position.template cast<AABBScalar>());
|
||||
start_point.distance = distance + boundary_offset;
|
||||
points.push_back(start_point);
|
||||
}
|
||||
for (size_t i = 1; i < input_points.size(); i++) {
|
||||
ExtendedPoint next_point{maybe_unscale(input_points[i])};
|
||||
ExtendedPoint<L::Dim> next_point{maybe_unscale(input_points[i])};
|
||||
auto [distance, nearest_line,
|
||||
x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(next_point.position.cast<AABBScalar>());
|
||||
x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(next_point.position.template cast<AABBScalar>());
|
||||
next_point.distance = distance + boundary_offset;
|
||||
|
||||
// Intersection handling
|
||||
if (ADD_INTERSECTIONS &&
|
||||
((points.back().distance > boundary_offset + EPSILON) != (next_point.distance > boundary_offset + EPSILON))) {
|
||||
const ExtendedPoint &prev_point = points.back();
|
||||
auto intersections = unscaled_prev_layer.template intersections_with_line<true>(
|
||||
L{prev_point.position.cast<AABBScalar>(), next_point.position.cast<AABBScalar>()});
|
||||
const ExtendedPoint<L::Dim>& prev_point = points.back();
|
||||
auto intersections = unscaled_prev_layer.template intersections_with_line<true>(
|
||||
L{prev_point.position.template cast<AABBScalar>(), next_point.position.template cast<AABBScalar>()});
|
||||
for (const auto &intersection : intersections) {
|
||||
ExtendedPoint p{};
|
||||
ExtendedPoint<L::Dim> p{};
|
||||
p.position = intersection.first.template cast<double>();
|
||||
p.distance = boundary_offset;
|
||||
// ORCA: Filter out points that are introduced at intersections if their distance from the previous or next point is not meaningful
|
||||
@@ -133,12 +122,12 @@ std::vector<ExtendedPoint> estimate_points_properties(const POINTS
|
||||
|
||||
// Segmentation handling
|
||||
if (PREV_LAYER_BOUNDARY_OFFSET && ADD_INTERSECTIONS) {
|
||||
std::vector<ExtendedPoint> new_points;
|
||||
std::vector<ExtendedPoint<L::Dim>> new_points;
|
||||
new_points.reserve(points.size() * 2);
|
||||
new_points.push_back(points.front());
|
||||
for (int point_idx = 0; point_idx < int(points.size()) - 1; ++point_idx) {
|
||||
const ExtendedPoint &curr = points[point_idx];
|
||||
const ExtendedPoint &next = points[point_idx + 1];
|
||||
const ExtendedPoint<L::Dim>& curr = points[point_idx];
|
||||
const ExtendedPoint<L::Dim>& next = points[point_idx + 1];
|
||||
|
||||
if ((curr.distance > -boundary_offset && curr.distance < boundary_offset + 2.0f) ||
|
||||
(next.distance > -boundary_offset && next.distance < boundary_offset + 2.0f)) {
|
||||
@@ -156,10 +145,10 @@ std::vector<ExtendedPoint> estimate_points_properties(const POINTS
|
||||
double t1 = std::max(a0, a1);
|
||||
|
||||
if (t0 < 1.0) {
|
||||
Vec2d p0 = curr.position + t0 * (next.position - curr.position);
|
||||
auto [p0_dist, p0_near_l,
|
||||
p0_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(p0.cast<AABBScalar>());
|
||||
ExtendedPoint new_p{};
|
||||
Vec p0 = curr.position + t0 * (next.position - curr.position);
|
||||
auto [p0_dist, p0_near_l, p0_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(
|
||||
p0.template cast<AABBScalar>());
|
||||
ExtendedPoint<L::Dim> new_p{};
|
||||
new_p.position = p0;
|
||||
new_p.distance = float(p0_dist + boundary_offset);
|
||||
// ORCA: only create a new point in the path if the new point overhang distance will be used to generate a speed change
|
||||
@@ -173,10 +162,10 @@ std::vector<ExtendedPoint> estimate_points_properties(const POINTS
|
||||
}
|
||||
}
|
||||
if (t1 > 0.0) {
|
||||
Vec2d p1 = curr.position + t1 * (next.position - curr.position);
|
||||
auto [p1_dist, p1_near_l,
|
||||
p1_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(p1.cast<AABBScalar>());
|
||||
ExtendedPoint new_p{};
|
||||
Vec p1 = curr.position + t1 * (next.position - curr.position);
|
||||
auto [p1_dist, p1_near_l, p1_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(
|
||||
p1.template cast<AABBScalar>());
|
||||
ExtendedPoint<L::Dim> new_p{};
|
||||
new_p.position = p1;
|
||||
new_p.distance = float(p1_dist + boundary_offset);
|
||||
// ORCA: only create a new point in the path if the new point overhang distance will be used to generate a speed change
|
||||
@@ -198,21 +187,21 @@ std::vector<ExtendedPoint> estimate_points_properties(const POINTS
|
||||
|
||||
// Maximum line length handling
|
||||
if (max_line_length > 0) {
|
||||
std::vector<ExtendedPoint> new_points;
|
||||
std::vector<ExtendedPoint<L::Dim>> new_points;
|
||||
new_points.reserve(points.size() * 2);
|
||||
{
|
||||
for (size_t i = 0; i + 1 < points.size(); i++) {
|
||||
const ExtendedPoint &curr = points[i];
|
||||
const ExtendedPoint &next = points[i + 1];
|
||||
const ExtendedPoint<L::Dim>& curr = points[i];
|
||||
const ExtendedPoint<L::Dim>& next = points[i + 1];
|
||||
new_points.push_back(curr);
|
||||
double len = (next.position - curr.position).squaredNorm();
|
||||
double t = sqrt((max_line_length * max_line_length) / len);
|
||||
size_t new_point_count = 1.0 / t;
|
||||
for (size_t j = 1; j < new_point_count + 1; j++) {
|
||||
Vec2d pos = curr.position * (1.0 - j * t) + next.position * (j * t);
|
||||
Vec pos = curr.position * (1.0 - j * t) + next.position * (j * t);
|
||||
auto [p_dist, p_near_l,
|
||||
p_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(pos.cast<AABBScalar>());
|
||||
ExtendedPoint new_p{};
|
||||
p_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(pos.template cast<AABBScalar>());
|
||||
ExtendedPoint<L::Dim> new_p{};
|
||||
new_p.position = pos;
|
||||
new_p.distance = float(p_dist + boundary_offset);
|
||||
|
||||
@@ -231,8 +220,8 @@ std::vector<ExtendedPoint> estimate_points_properties(const POINTS
|
||||
float accumulated_distance = 0;
|
||||
std::vector<float> distances_for_curvature(points.size());
|
||||
for (size_t point_idx = 0; point_idx < points.size(); ++point_idx) {
|
||||
const ExtendedPoint &a = points[point_idx];
|
||||
const ExtendedPoint &b = points[get_prev_index(point_idx, points.size())];
|
||||
const ExtendedPoint<L::Dim>& a = points[point_idx];
|
||||
const ExtendedPoint<L::Dim>& b = points[get_prev_index(point_idx, points.size())];
|
||||
|
||||
distances_for_curvature[point_idx] = (b.position - a.position).norm();
|
||||
accumulated_distance += distances_for_curvature[point_idx];
|
||||
@@ -241,9 +230,9 @@ std::vector<ExtendedPoint> estimate_points_properties(const POINTS
|
||||
if (accumulated_distance > EPSILON)
|
||||
for (float window_size : {3.0f, 9.0f, 16.0f}) {
|
||||
for (int point_idx = 0; point_idx < int(points.size()); ++point_idx) {
|
||||
ExtendedPoint ¤t = points[point_idx];
|
||||
ExtendedPoint<L::Dim>& current = points[point_idx];
|
||||
|
||||
Vec2d back_position = current.position;
|
||||
Vec back_position = current.position;
|
||||
{
|
||||
size_t back_point_index = point_idx;
|
||||
float dist_backwards = 0;
|
||||
@@ -263,7 +252,7 @@ std::vector<ExtendedPoint> estimate_points_properties(const POINTS
|
||||
}
|
||||
}
|
||||
|
||||
Vec2d front_position = current.position;
|
||||
Vec front_position = current.position;
|
||||
{
|
||||
size_t front_point_index = point_idx;
|
||||
float dist_forwards = 0;
|
||||
@@ -283,7 +272,9 @@ std::vector<ExtendedPoint> estimate_points_properties(const POINTS
|
||||
}
|
||||
}
|
||||
|
||||
float new_curvature = angle(current.position - back_position, front_position - current.position) / window_size;
|
||||
float new_curvature = angle((current.position - back_position).template head<2>(),
|
||||
(front_position - current.position).template head<2>()) /
|
||||
window_size;
|
||||
if (abs(current.curvature) < abs(new_curvature)) {
|
||||
current.curvature = new_curvature;
|
||||
}
|
||||
@@ -295,15 +286,15 @@ std::vector<ExtendedPoint> estimate_points_properties(const POINTS
|
||||
|
||||
struct ProcessedPoint
|
||||
{
|
||||
Point p;
|
||||
Point3 p;
|
||||
float speed = 1.0f;
|
||||
float overlap = 1.0f;
|
||||
};
|
||||
|
||||
class ExtrusionQualityEstimator
|
||||
{
|
||||
std::unordered_map<const PrintObject *, AABBTreeLines::LinesDistancer<Linef>> prev_layer_boundaries;
|
||||
std::unordered_map<const PrintObject *, AABBTreeLines::LinesDistancer<Linef>> next_layer_boundaries;
|
||||
std::unordered_map<const PrintObject*, AABBTreeLines::LinesDistancer<Linef3>> prev_layer_boundaries;
|
||||
std::unordered_map<const PrintObject*, AABBTreeLines::LinesDistancer<Linef3>> next_layer_boundaries;
|
||||
std::unordered_map<const PrintObject *, AABBTreeLines::LinesDistancer<CurledLine>> prev_curled_extrusions;
|
||||
std::unordered_map<const PrintObject *, AABBTreeLines::LinesDistancer<CurledLine>> next_curled_extrusions;
|
||||
const PrintObject *current_object;
|
||||
@@ -316,7 +307,7 @@ public:
|
||||
if (layer == nullptr) return;
|
||||
const PrintObject *object = obj;
|
||||
prev_layer_boundaries[object] = next_layer_boundaries[object];
|
||||
next_layer_boundaries[object] = AABBTreeLines::LinesDistancer<Linef>{to_unscaled_linesf(layer->lslices)};
|
||||
next_layer_boundaries[object] = AABBTreeLines::LinesDistancer<Linef3>{to_unscaled_linesf3(layer->lslices)};
|
||||
prev_curled_extrusions[object] = next_curled_extrusions[object];
|
||||
next_curled_extrusions[object] = AABBTreeLines::LinesDistancer<CurledLine>{layer->curled_lines};
|
||||
}
|
||||
@@ -371,56 +362,54 @@ public:
|
||||
smallest_distance_with_lower_speed=-1.f;
|
||||
|
||||
// Orca: Pass to the point properties estimator the smallest ovehang distance that triggers a slowdown (smallest_distance_with_lower_speed)
|
||||
std::vector<ExtendedPoint> extended_points = estimate_points_properties<true, true, true, true>
|
||||
(path.polyline.points,
|
||||
prev_layer_boundaries[current_object],
|
||||
path.width,
|
||||
-1,
|
||||
smallest_distance_with_lower_speed);
|
||||
std::vector<ExtendedPoint<3>> extended_points =
|
||||
estimate_points_properties<true, true, true, true>(path.polyline.points, prev_layer_boundaries[current_object], path.width, -1,
|
||||
smallest_distance_with_lower_speed);
|
||||
const auto width_inv = 1.0f / path.width;
|
||||
std::vector<ProcessedPoint> processed_points;
|
||||
processed_points.reserve(extended_points.size());
|
||||
for (size_t i = 0; i < extended_points.size(); i++) {
|
||||
const ExtendedPoint &curr = extended_points[i];
|
||||
const ExtendedPoint &next = extended_points[i + 1 < extended_points.size() ? i + 1 : i];
|
||||
|
||||
const ExtendedPoint<3>& curr = extended_points[i];
|
||||
const ExtendedPoint<3>& next = extended_points[i + 1 < extended_points.size() ? i + 1 : i];
|
||||
|
||||
float artificial_distance_to_curled_lines = 0.0;
|
||||
if(slowdown_for_curled_edges) {
|
||||
// The following code artifically increases the distance to provide slowdown for extrusions that are over curled lines
|
||||
const double dist_limit = 10.0 * path.width;
|
||||
{
|
||||
Vec2d middle = 0.5 * (curr.position + next.position);
|
||||
auto line_indices = prev_curled_extrusions[current_object].all_lines_in_radius(Point::new_scale(middle), scale_(dist_limit));
|
||||
if (!line_indices.empty()) {
|
||||
double len = (next.position - curr.position).norm();
|
||||
// For long lines, there is a problem with the additional slowdown. If by accident, there is small curled line near the middle of this long line
|
||||
Vec3d middle = 0.5 * (curr.position + next.position);
|
||||
auto line_indices = prev_curled_extrusions[current_object].all_lines_in_radius(Point::new_scale(middle),
|
||||
scale_(dist_limit));
|
||||
if (!line_indices.empty()) {
|
||||
double len = (next.position - curr.position).norm();
|
||||
// For long lines, there is a problem with the additional slowdown. If by accident, there is small curled line near the middle of this long line
|
||||
// The whole segment gets slower unnecesarily. For these long lines, we do additional check whether it is worth slowing down.
|
||||
// NOTE that this is still quite rough approximation, e.g. we are still checking lines only near the middle point
|
||||
// TODO maybe split the lines into smaller segments before running this alg? but can be demanding, and GCode will be huge
|
||||
if (len > 2) {
|
||||
Vec2d dir = Vec2d(next.position - curr.position) / len;
|
||||
Vec2d right = Vec2d(-dir.y(), dir.x());
|
||||
Vec2d dir = Vec2d(next.position.head<2>() - curr.position.head<2>()) / len;
|
||||
Vec2d right = Vec2d(-dir.y(), dir.x());
|
||||
|
||||
Polygon box_of_influence = {
|
||||
scaled(Vec2d(curr.position + right * dist_limit)),
|
||||
scaled(Vec2d(next.position + right * dist_limit)),
|
||||
scaled(Vec2d(next.position - right * dist_limit)),
|
||||
scaled(Vec2d(curr.position - right * dist_limit)),
|
||||
};
|
||||
Polygon box_of_influence = {
|
||||
scaled(Vec2d(curr.position.head<2>() + right * dist_limit)),
|
||||
scaled(Vec2d(next.position.head<2>() + right * dist_limit)),
|
||||
scaled(Vec2d(next.position.head<2>() - right * dist_limit)),
|
||||
scaled(Vec2d(curr.position.head<2>() - right * dist_limit)),
|
||||
};
|
||||
|
||||
double projected_lengths_sum = 0;
|
||||
for (size_t idx : line_indices) {
|
||||
const CurledLine &line = prev_curled_extrusions[current_object].get_line(idx);
|
||||
Lines inside = intersection_ln({{line.a, line.b}}, {box_of_influence});
|
||||
double projected_lengths_sum = 0;
|
||||
for (size_t idx : line_indices) {
|
||||
const CurledLine& line = prev_curled_extrusions[current_object].get_line(idx);
|
||||
Lines inside = intersection_ln({{line.a, line.b}}, {box_of_influence});
|
||||
if (inside.empty())
|
||||
continue;
|
||||
double projected_length = abs(dir.dot(unscaled(Vec2d((inside.back().b - inside.back().a).cast<double>()))));
|
||||
projected_lengths_sum += projected_length;
|
||||
}
|
||||
if (projected_lengths_sum < 0.4 * len) {
|
||||
line_indices.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (projected_lengths_sum < 0.4 * len) {
|
||||
line_indices.clear();
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t idx : line_indices) {
|
||||
const CurledLine &line = prev_curled_extrusions[current_object].get_line(idx);
|
||||
@@ -430,9 +419,9 @@ public:
|
||||
(line.curled_height / (path.height * 10.0f)); // max_curled_height_factor from SupportSpotGenerator
|
||||
artificial_distance_to_curled_lines = std::max(artificial_distance_to_curled_lines, dist);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto calculate_speed = [&speed_sections, &original_speed](float distance) {
|
||||
float final_speed;
|
||||
@@ -464,8 +453,8 @@ public:
|
||||
}
|
||||
|
||||
float overlap = std::min(1 - (curr.distance+artificial_distance_to_curled_lines) * width_inv, 1 - (next.distance+artificial_distance_to_curled_lines) * width_inv);
|
||||
|
||||
processed_points.push_back({ scaled(curr.position), extrusion_speed, overlap });
|
||||
|
||||
processed_points.push_back({Point3(scaled(curr.position)), extrusion_speed, overlap});
|
||||
}
|
||||
return processed_points;
|
||||
}
|
||||
|
||||
@@ -271,6 +271,7 @@ class Linef3
|
||||
public:
|
||||
Linef3() : a(Vec3d::Zero()), b(Vec3d::Zero()) {}
|
||||
Linef3(const Vec3d& _a, const Vec3d& _b) : a(_a), b(_b) {}
|
||||
Linef3(const Vec2d& _a, const Vec2d& _b, double z) : a(Vec3d(_a.x(), _a.y(), z)), b(Vec3d(_b.x(), _b.y(), z)) {}
|
||||
|
||||
Vec3d intersect_plane(double z) const;
|
||||
void scale(double factor) { this->a *= factor; this->b *= factor; }
|
||||
@@ -311,6 +312,8 @@ public:
|
||||
using Scalar = Vec3d::Scalar;
|
||||
};
|
||||
|
||||
using Linesf3 = std::vector<Linef3>;
|
||||
|
||||
BoundingBox get_extents(const Lines &lines);
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -279,7 +279,7 @@ public:
|
||||
Point3(int64_t x, int64_t y, int64_t z = 0) : Vec3crd(coord_t(x), coord_t(y), coord_t(z)) {}
|
||||
Point3(double x, double y, double z = 0.0) : Vec3crd(coord_t(std::round(x)), coord_t(std::round(y)), coord_t(std::round(z))) {}
|
||||
Point3(const Point3 &rhs) { *this = rhs; }
|
||||
explicit Point3(const Point &rhs, coord_t z = 0) : Vec3crd(rhs.x(), rhs.y(), z) {}
|
||||
explicit Point3(const Vec2crd& vec2crd, coord_t z = 0) : Vec3crd(vec2crd.x(), vec2crd.y(), z) {}
|
||||
explicit Point3(const Vec3crd &vec3crd) : Vec3crd(vec3crd) {}
|
||||
// This constructor allows you to construct Point from Eigen expressions
|
||||
template<typename OtherDerived>
|
||||
|
||||
@@ -165,8 +165,8 @@ void estimate_malformations(LayerPtrs &layers, const Params ¶ms)
|
||||
flow_width,
|
||||
params.bridge_distance);
|
||||
for (size_t i = 0; i < annotated_points.size(); ++i) {
|
||||
const ExtendedPoint &a = i > 0 ? annotated_points[i - 1] : annotated_points[i];
|
||||
const ExtendedPoint &b = annotated_points[i];
|
||||
const ExtendedPoint<2>& a = i > 0 ? annotated_points[i - 1] : annotated_points[i];
|
||||
const ExtendedPoint<2>& b = annotated_points[i];
|
||||
ExtrusionLine line_out{a.position.cast<float>(), b.position.cast<float>(), float((a.position - b.position).norm()),
|
||||
extrusion};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user