mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-27 10:41:15 -06:00
Fixed conflicts after merge with master
This commit is contained in:
commit
a1a4d49f15
249 changed files with 51509 additions and 33846 deletions
|
|
@ -577,7 +577,7 @@ void _arrange(
|
|||
std::function<bool()> stopfn)
|
||||
{
|
||||
// Integer ceiling the min distance from the bed perimeters
|
||||
coord_t md = minobjd - 2 * scaled(0.1 + EPSILON);
|
||||
coord_t md = minobjd;
|
||||
md = (md % 2) ? md / 2 + 1 : md / 2;
|
||||
|
||||
auto corrected_bin = bin;
|
||||
|
|
|
|||
|
|
@ -855,7 +855,12 @@ Polygons top_level_islands(const Slic3r::Polygons &polygons)
|
|||
}
|
||||
|
||||
// Outer offset shall not split the input contour into multiples. It is expected, that the solution will be non empty and it will contain just a single polygon.
|
||||
ClipperLib::Paths fix_after_outer_offset(const ClipperLib::Path &input, ClipperLib::PolyFillType filltype, bool reverse_result)
|
||||
ClipperLib::Paths fix_after_outer_offset(
|
||||
const ClipperLib::Path &input,
|
||||
// combination of default prameters to correspond to void ClipperOffset::Execute(Paths& solution, double delta)
|
||||
// to produce a CCW output contour from CCW input contour for a positive offset.
|
||||
ClipperLib::PolyFillType filltype, // = ClipperLib::pftPositive
|
||||
bool reverse_result) // = false
|
||||
{
|
||||
ClipperLib::Paths solution;
|
||||
if (! input.empty()) {
|
||||
|
|
@ -867,8 +872,13 @@ ClipperLib::Paths fix_after_outer_offset(const ClipperLib::Path &input, ClipperL
|
|||
return solution;
|
||||
}
|
||||
|
||||
// Inner offset may split the source contour into multiple contours, but one shall not be inside the other.
|
||||
ClipperLib::Paths fix_after_inner_offset(const ClipperLib::Path &input, ClipperLib::PolyFillType filltype, bool reverse_result)
|
||||
// Inner offset may split the source contour into multiple contours, but one resulting contour shall not lie inside the other.
|
||||
ClipperLib::Paths fix_after_inner_offset(
|
||||
const ClipperLib::Path &input,
|
||||
// combination of default prameters to correspond to void ClipperOffset::Execute(Paths& solution, double delta)
|
||||
// to produce a CCW output contour from CCW input contour for a negative offset.
|
||||
ClipperLib::PolyFillType filltype, // = ClipperLib::pftNegative
|
||||
bool reverse_result) // = true
|
||||
{
|
||||
ClipperLib::Paths solution;
|
||||
if (! input.empty()) {
|
||||
|
|
@ -1041,12 +1051,20 @@ Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::v
|
|||
|
||||
// 1) Offset the outer contour.
|
||||
ClipperLib::Paths contours = fix_after_inner_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftNegative, true);
|
||||
#ifndef NDEBUG
|
||||
for (auto &c : contours)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 2) Offset the holes one by one, collect the results.
|
||||
ClipperLib::Paths holes;
|
||||
holes.reserve(expoly.holes.size());
|
||||
for (const Polygon& hole : expoly.holes)
|
||||
append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, false));
|
||||
append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, false));
|
||||
#ifndef NDEBUG
|
||||
for (auto &c : holes)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 3) Subtract holes from the contours.
|
||||
ClipperLib::Paths output;
|
||||
|
|
@ -1077,12 +1095,20 @@ for (const std::vector<float>& ds : deltas)
|
|||
|
||||
// 1) Offset the outer contour.
|
||||
ClipperLib::Paths contours = fix_after_outer_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftPositive, false);
|
||||
#ifndef NDEBUG
|
||||
for (auto &c : contours)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 2) Offset the holes one by one, collect the results.
|
||||
ClipperLib::Paths holes;
|
||||
holes.reserve(expoly.holes.size());
|
||||
for (const Polygon& hole : expoly.holes)
|
||||
append(holes, fix_after_inner_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, true));
|
||||
#ifndef NDEBUG
|
||||
for (auto &c : holes)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 3) Subtract holes from the contours.
|
||||
ClipperLib::Paths output;
|
||||
|
|
@ -1113,12 +1139,20 @@ for (const std::vector<float>& ds : deltas)
|
|||
|
||||
// 1) Offset the outer contour.
|
||||
ClipperLib::Paths contours = fix_after_outer_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftPositive, false);
|
||||
#ifndef NDEBUG
|
||||
for (auto &c : contours)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 2) Offset the holes one by one, collect the results.
|
||||
ClipperLib::Paths holes;
|
||||
holes.reserve(expoly.holes.size());
|
||||
for (const Polygon& hole : expoly.holes)
|
||||
append(holes, fix_after_inner_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, true));
|
||||
#ifndef NDEBUG
|
||||
for (auto &c : holes)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 3) Subtract holes from the contours.
|
||||
unscaleClipperPolygons(contours);
|
||||
|
|
@ -1152,13 +1186,21 @@ ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<s
|
|||
#endif /* NDEBUG */
|
||||
|
||||
// 1) Offset the outer contour.
|
||||
ClipperLib::Paths contours = fix_after_inner_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftNegative, false);
|
||||
ClipperLib::Paths contours = fix_after_inner_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftNegative, true);
|
||||
#ifndef NDEBUG
|
||||
for (auto &c : contours)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 2) Offset the holes one by one, collect the results.
|
||||
ClipperLib::Paths holes;
|
||||
holes.reserve(expoly.holes.size());
|
||||
for (const Polygon& hole : expoly.holes)
|
||||
append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, true));
|
||||
append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, false));
|
||||
#ifndef NDEBUG
|
||||
for (auto &c : holes)
|
||||
assert(ClipperLib::Area(c) > 0.);
|
||||
#endif /* NDEBUG */
|
||||
|
||||
// 3) Subtract holes from the contours.
|
||||
unscaleClipperPolygons(contours);
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
#include "Point.hpp"
|
||||
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/format/format_fwd.hpp>
|
||||
#include <boost/property_tree/ptree_fwd.hpp>
|
||||
|
||||
#include <cereal/access.hpp>
|
||||
#include <cereal/types/base_class.hpp>
|
||||
|
|
@ -686,6 +686,7 @@ public:
|
|||
ConfigOption* clone() const override { return new ConfigOptionString(*this); }
|
||||
ConfigOptionString& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
|
||||
bool operator==(const ConfigOptionString &rhs) const { return this->value == rhs.value; }
|
||||
bool empty() const { return this->value.empty(); }
|
||||
|
||||
std::string serialize() const override
|
||||
{
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@ std::vector<std::pair<double, unsigned int>> custom_tool_changes(const Info& cus
|
|||
for (const Item& custom_gcode : custom_gcode_per_print_z.gcodes)
|
||||
if (custom_gcode.gcode == ToolChangeCode) {
|
||||
// If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders
|
||||
custom_tool_changes.emplace_back(custom_gcode.print_z, static_cast<unsigned int>(custom_gcode.extruder > num_extruders ? 1 : custom_gcode.extruder));
|
||||
assert(custom_gcode.extruder >= 0);
|
||||
custom_tool_changes.emplace_back(custom_gcode.print_z, static_cast<unsigned int>(size_t(custom_gcode.extruder) > num_extruders ? 1 : custom_gcode.extruder));
|
||||
}
|
||||
return custom_tool_changes;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,12 @@ static constexpr char ColorChangeCode[] = "M600";
|
|||
static constexpr char PausePrintCode[] = "M601";
|
||||
static constexpr char ToolChangeCode[] = "tool_change";
|
||||
|
||||
enum CustomGcodeType
|
||||
{
|
||||
cgtColorChange,
|
||||
cgtPausePrint,
|
||||
};
|
||||
|
||||
namespace CustomGCode {
|
||||
|
||||
struct Item
|
||||
|
|
|
|||
|
|
@ -1147,7 +1147,7 @@ EdgeGrid::Grid::ClosestPointResult EdgeGrid::Grid::closest_point(const Point &pt
|
|||
}
|
||||
}
|
||||
}
|
||||
if (result.contour_idx != -1 && d_min <= double(search_radius)) {
|
||||
if (result.contour_idx != size_t(-1) && d_min <= double(search_radius)) {
|
||||
result.distance = d_min * sign_min;
|
||||
result.t /= l2_seg_min;
|
||||
assert(result.t >= 0. && result.t < 1.);
|
||||
|
|
|
|||
|
|
@ -524,11 +524,22 @@ static inline void smooth_compensation_banded(const Points &contour, float band,
|
|||
}
|
||||
}
|
||||
|
||||
ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, const Flow &external_perimeter_flow, const double compensation)
|
||||
#ifndef NDEBUG
|
||||
static bool validate_expoly_orientation(const ExPolygon &expoly)
|
||||
{
|
||||
bool valid = expoly.contour.is_counter_clockwise();
|
||||
for (auto &h : expoly.holes)
|
||||
valid &= h.is_clockwise();
|
||||
return valid;
|
||||
}
|
||||
#endif /* NDEBUG */
|
||||
|
||||
ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, double min_contour_width, const double compensation)
|
||||
{
|
||||
// The contour shall be wide enough to apply the external perimeter plus compensation on both sides.
|
||||
double min_contour_width = double(external_perimeter_flow.scaled_width() + external_perimeter_flow.scaled_spacing());
|
||||
assert(validate_expoly_orientation(input_expoly));
|
||||
|
||||
double scaled_compensation = scale_(compensation);
|
||||
min_contour_width = scale_(min_contour_width);
|
||||
double min_contour_width_compensated = min_contour_width + 2. * scaled_compensation;
|
||||
// Make the search radius a bit larger for the averaging in contour_distance over a fan of rays to work.
|
||||
double search_radius = min_contour_width_compensated + min_contour_width * 0.5;
|
||||
|
|
@ -547,6 +558,7 @@ ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, const Flow &
|
|||
{
|
||||
EdgeGrid::Grid grid;
|
||||
ExPolygon simplified = input_expoly.simplify(SCALED_EPSILON).front();
|
||||
assert(validate_expoly_orientation(simplified));
|
||||
BoundingBox bbox = get_extents(simplified.contour);
|
||||
bbox.offset(SCALED_EPSILON);
|
||||
grid.set_bbox(bbox);
|
||||
|
|
@ -559,6 +571,7 @@ ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, const Flow &
|
|||
Polygon &poly = (idx_contour == 0) ? resampled.contour : resampled.holes[idx_contour - 1];
|
||||
std::vector<ResampledPoint> resampled_point_parameters;
|
||||
poly.points = resample_polygon(poly.points, resample_interval, resampled_point_parameters);
|
||||
assert(poly.is_counter_clockwise() == (idx_contour == 0));
|
||||
std::vector<float> dists = contour_distance2(grid, idx_contour, poly.points, resampled_point_parameters, scaled_compensation, search_radius);
|
||||
for (float &d : dists) {
|
||||
// printf("Point %d, Distance: %lf\n", int(&d - dists.data()), unscale<double>(d));
|
||||
|
|
@ -593,10 +606,18 @@ ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, const Flow &
|
|||
assert(out_vec.size() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
assert(validate_expoly_orientation(out));
|
||||
return out;
|
||||
}
|
||||
|
||||
ExPolygon elephant_foot_compensation(const ExPolygon &input, const Flow &external_perimeter_flow, const double compensation)
|
||||
{
|
||||
// The contour shall be wide enough to apply the external perimeter plus compensation on both sides.
|
||||
double min_contour_width = double(external_perimeter_flow.width + external_perimeter_flow.spacing());
|
||||
return elephant_foot_compensation(input, min_contour_width, compensation);
|
||||
}
|
||||
|
||||
ExPolygons elephant_foot_compensation(const ExPolygons &input, const Flow &external_perimeter_flow, const double compensation)
|
||||
{
|
||||
ExPolygons out;
|
||||
|
|
@ -606,4 +627,13 @@ ExPolygons elephant_foot_compensation(const ExPolygons &input, const Flow &exter
|
|||
return out;
|
||||
}
|
||||
|
||||
ExPolygons elephant_foot_compensation(const ExPolygons &input, double min_contour_width, const double compensation)
|
||||
{
|
||||
ExPolygons out;
|
||||
out.reserve(input.size());
|
||||
for (const ExPolygon &expoly : input)
|
||||
out.emplace_back(elephant_foot_compensation(expoly, min_contour_width, compensation));
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ namespace Slic3r {
|
|||
|
||||
class Flow;
|
||||
|
||||
ExPolygon elephant_foot_compensation(const ExPolygon &input, double min_countour_width, const double compensation);
|
||||
ExPolygons elephant_foot_compensation(const ExPolygons &input, double min_countour_width, const double compensation);
|
||||
ExPolygon elephant_foot_compensation(const ExPolygon &input, const Flow &external_perimeter_flow, const double compensation);
|
||||
ExPolygons elephant_foot_compensation(const ExPolygons &input, const Flow &external_perimeter_flow, const double compensation);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "Extruder.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@
|
|||
|
||||
#include "libslic3r.h"
|
||||
#include "Point.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class GCodeConfig;
|
||||
|
||||
class Extruder
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -11,18 +11,10 @@ void filter_by_extrusion_role_in_place(ExtrusionEntitiesPtr &extrusion_entities,
|
|||
if (role != erMixed) {
|
||||
auto first = extrusion_entities.begin();
|
||||
auto last = extrusion_entities.end();
|
||||
auto result = first;
|
||||
while (first != last) {
|
||||
// The caller wants only paths with a specific extrusion role.
|
||||
auto role2 = (*first)->role();
|
||||
if (role != role2) {
|
||||
// This extrusion entity does not match the role asked.
|
||||
assert(role2 != erMixed);
|
||||
*result = *first;
|
||||
++ result;
|
||||
}
|
||||
++ first;
|
||||
}
|
||||
extrusion_entities.erase(
|
||||
std::remove_if(first, last, [&role](const ExtrusionEntity* ee) {
|
||||
return ee->role() != role; }),
|
||||
last);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public:
|
|||
~ExtrusionEntityCollection() { clear(); }
|
||||
explicit operator ExtrusionPaths() const;
|
||||
|
||||
bool is_collection() const { return true; }
|
||||
bool is_collection() const override { return true; }
|
||||
ExtrusionRole role() const override {
|
||||
ExtrusionRole out = erNone;
|
||||
for (const ExtrusionEntity *ee : entities) {
|
||||
|
|
@ -49,7 +49,7 @@ public:
|
|||
}
|
||||
return out;
|
||||
}
|
||||
bool can_reverse() const { return !this->no_sort; }
|
||||
bool can_reverse() const override { return !this->no_sort; }
|
||||
bool empty() const { return this->entities.empty(); }
|
||||
void clear();
|
||||
void swap (ExtrusionEntityCollection &c);
|
||||
|
|
@ -83,9 +83,9 @@ public:
|
|||
static ExtrusionEntityCollection chained_path_from(const ExtrusionEntitiesPtr &extrusion_entities, const Point &start_near, ExtrusionRole role = erMixed);
|
||||
ExtrusionEntityCollection chained_path_from(const Point &start_near, ExtrusionRole role = erMixed) const
|
||||
{ return this->no_sort ? *this : chained_path_from(this->entities, start_near, role); }
|
||||
void reverse();
|
||||
const Point& first_point() const { return this->entities.front()->first_point(); }
|
||||
const Point& last_point() const { return this->entities.back()->last_point(); }
|
||||
void reverse() override;
|
||||
const Point& first_point() const override { return this->entities.front()->first_point(); }
|
||||
const Point& last_point() const override { return this->entities.back()->last_point(); }
|
||||
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width.
|
||||
// Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
|
||||
void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const override;
|
||||
|
|
@ -102,11 +102,11 @@ public:
|
|||
/// You should be iterating over flatten().entities if you are interested in the underlying ExtrusionEntities (and don't care about hierarchy).
|
||||
/// \param preserve_ordering Flag to method that will flatten if and only if the underlying collection is sortable when True (default: False).
|
||||
ExtrusionEntityCollection flatten(bool preserve_ordering = false) const;
|
||||
double min_mm3_per_mm() const;
|
||||
double min_mm3_per_mm() const override;
|
||||
double total_volume() const override { double volume=0.; for (const auto& ent : entities) volume+=ent->total_volume(); return volume; }
|
||||
|
||||
// Following methods shall never be called on an ExtrusionEntityCollection.
|
||||
Polyline as_polyline() const {
|
||||
Polyline as_polyline() const override {
|
||||
throw std::runtime_error("Calling as_polyline() on a ExtrusionEntityCollection");
|
||||
return Polyline();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
|||
if (surface.surface_type == stInternalVoid)
|
||||
has_internal_voids = true;
|
||||
else {
|
||||
FlowRole extrusion_role = (surface.surface_type == stTop) ? frTopSolidInfill : (surface.is_solid() ? frSolidInfill : frInfill);
|
||||
FlowRole extrusion_role = surface.is_top() ? frTopSolidInfill : (surface.is_solid() ? frSolidInfill : frInfill);
|
||||
bool is_bridge = layer.id() > 0 && surface.is_bridge();
|
||||
params.extruder = layerm.region()->extruder(extrusion_role);
|
||||
params.pattern = layerm.region()->config().fill_pattern.value;
|
||||
|
|
@ -132,7 +132,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
|||
is_bridge ?
|
||||
erBridgeInfill :
|
||||
(surface.is_solid() ?
|
||||
((surface.surface_type == stTop) ? erTopSolidInfill : erSolidInfill) :
|
||||
(surface.is_top() ? erTopSolidInfill : erSolidInfill) :
|
||||
erInternalInfill);
|
||||
params.bridge_angle = float(surface.bridge_angle);
|
||||
params.angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
|
||||
|
|
|
|||
|
|
@ -611,7 +611,7 @@ static inline SegmentPoint clip_start_segment_and_point(const Points &polyline,
|
|||
SegmentPoint out;
|
||||
if (polyline.size() >= 2) {
|
||||
Vec2d pt_prev = polyline.front().cast<double>();
|
||||
for (int i = 1; i < polyline.size(); ++ i) {
|
||||
for (size_t i = 1; i < polyline.size(); ++ i) {
|
||||
Vec2d pt = polyline[i].cast<double>();
|
||||
Vec2d v = pt - pt_prev;
|
||||
double l2 = v.squaredNorm();
|
||||
|
|
@ -674,7 +674,7 @@ static inline double segment_point_distance_squared(const Vec2d &p1a, const Vec2
|
|||
if (l2 < EPSILON)
|
||||
// p1a == p1b
|
||||
return (p2 - p1a).squaredNorm();
|
||||
return segment_point_distance_squared(p1a, p1b, v, v.squaredNorm(), p2);
|
||||
return segment_point_distance_squared(p1a, p1b, v, v.squaredNorm(), p2);
|
||||
}
|
||||
|
||||
// Distance to the closest point of line.
|
||||
|
|
@ -692,7 +692,7 @@ static inline double min_distance_of_segments(const Vec2d &p1a, const Vec2d &p1b
|
|||
// p2a == p2b: Return distance of p2a from the (p1a, p1b) segment.
|
||||
return segment_point_distance_squared(p1a, p1b, v1, l1_2, p2a);
|
||||
|
||||
return std::min(
|
||||
return std::min(
|
||||
std::min(segment_point_distance_squared(p1a, p1b, v1, l1_2, p2a), segment_point_distance_squared(p1a, p1b, v1, l1_2, p2b)),
|
||||
std::min(segment_point_distance_squared(p2a, p2b, v2, l2_2, p1a), segment_point_distance_squared(p2a, p2b, v2, l2_2, p1b)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ void FillGyroid::_fill_surface_single(
|
|||
Polylines &polylines_out)
|
||||
{
|
||||
float infill_angle = this->angle + (CorrectionAngle * 2*M_PI) / 360.;
|
||||
if(abs(infill_angle) >= EPSILON)
|
||||
if(std::abs(infill_angle) >= EPSILON)
|
||||
expolygon.rotate(-infill_angle);
|
||||
|
||||
BoundingBox bb = expolygon.contour.bounding_box();
|
||||
|
|
@ -197,8 +197,9 @@ void FillGyroid::_fill_surface_single(
|
|||
append(polylines_out, std::move(polylines));
|
||||
else
|
||||
this->connect_infill(std::move(polylines), expolygon, polylines_out, this->spacing, params);
|
||||
|
||||
// new paths must be rotated back
|
||||
if (abs(infill_angle) >= EPSILON) {
|
||||
if (std::abs(infill_angle) >= EPSILON) {
|
||||
for (auto it = polylines_out.begin() + polylines_out_first_idx; it != polylines_out.end(); ++ it)
|
||||
it->rotate(infill_angle);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,12 @@
|
|||
|
||||
namespace Slic3r {
|
||||
|
||||
FlowErrorNegativeSpacing::FlowErrorNegativeSpacing() :
|
||||
FlowError("Flow::spacing() produced negative spacing. Did you set some extrusion width too small?") {}
|
||||
|
||||
FlowErrorNegativeFlow::FlowErrorNegativeFlow() :
|
||||
FlowError("Flow::mm3_per_mm() produced negative flow. Did you set some extrusion width too small?") {}
|
||||
|
||||
// This static method returns a sane extrusion width default.
|
||||
float Flow::auto_extrusion_width(FlowRole role, float nozzle_diameter)
|
||||
{
|
||||
|
|
@ -52,7 +58,7 @@ static inline FlowRole opt_key_to_flow_role(const std::string &opt_key)
|
|||
|
||||
static inline void throw_on_missing_variable(const std::string &opt_key, const char *dependent_opt_key)
|
||||
{
|
||||
throw std::runtime_error((boost::format(L("Cannot calculate extrusion width for %1%: Variable \"%2%\" not accessible.")) % opt_key % dependent_opt_key).str());
|
||||
throw FlowErrorMissingVariable((boost::format(L("Cannot calculate extrusion width for %1%: Variable \"%2%\" not accessible.")) % opt_key % dependent_opt_key).str());
|
||||
}
|
||||
|
||||
// Used to provide hints to the user on default extrusion width values, and to provide reasonable values to the PlaceholderParser.
|
||||
|
|
@ -174,7 +180,7 @@ float Flow::spacing() const
|
|||
#endif
|
||||
// assert(res > 0.f);
|
||||
if (res <= 0.f)
|
||||
throw std::runtime_error("Flow::spacing() produced negative spacing. Did you set some extrusion width too small?");
|
||||
throw FlowErrorNegativeSpacing();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -190,7 +196,7 @@ float Flow::spacing(const Flow &other) const
|
|||
0.5 * this->spacing() + 0.5 * other.spacing());
|
||||
// assert(res > 0.f);
|
||||
if (res <= 0.f)
|
||||
throw std::runtime_error("Flow::spacing() produced negative spacing. Did you set some extrusion width too small?");
|
||||
throw FlowErrorNegativeSpacing();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -204,7 +210,7 @@ double Flow::mm3_per_mm() const
|
|||
float(this->height * (this->width - this->height * (1. - 0.25 * PI)));
|
||||
//assert(res > 0.);
|
||||
if (res <= 0.)
|
||||
throw std::runtime_error("Flow::mm3_per_mm() produced negative flow. Did you set some extrusion width too small?");
|
||||
throw FlowErrorNegativeFlow();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,31 @@ enum FlowRole {
|
|||
frSupportMaterialInterface,
|
||||
};
|
||||
|
||||
class FlowError : public std::invalid_argument
|
||||
{
|
||||
public:
|
||||
FlowError(const std::string& what_arg) : invalid_argument(what_arg) {}
|
||||
FlowError(const char* what_arg) : invalid_argument(what_arg) {}
|
||||
};
|
||||
|
||||
class FlowErrorNegativeSpacing : public FlowError
|
||||
{
|
||||
public:
|
||||
FlowErrorNegativeSpacing();
|
||||
};
|
||||
|
||||
class FlowErrorNegativeFlow : public FlowError
|
||||
{
|
||||
public:
|
||||
FlowErrorNegativeFlow();
|
||||
};
|
||||
|
||||
class FlowErrorMissingVariable : public FlowError
|
||||
{
|
||||
public:
|
||||
FlowErrorMissingVariable(const std::string& what_arg) : FlowError(what_arg) {}
|
||||
};
|
||||
|
||||
class Flow
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
#include "../Utils.hpp"
|
||||
#include "../GCode.hpp"
|
||||
#include "../Geometry.hpp"
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
#include "../GCode/ThumbnailData.hpp"
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
#include "../I18N.hpp"
|
||||
|
||||
|
|
@ -47,9 +45,7 @@ const std::string MODEL_EXTENSION = ".model";
|
|||
const std::string MODEL_FILE = "3D/3dmodel.model"; // << this is the only format of the string which works with CURA
|
||||
const std::string CONTENT_TYPES_FILE = "[Content_Types].xml";
|
||||
const std::string RELATIONSHIPS_FILE = "_rels/.rels";
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
const std::string THUMBNAIL_FILE = "Metadata/thumbnail.png";
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
const std::string PRINT_CONFIG_FILE = "Metadata/Slic3r_PE.config";
|
||||
const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_PE_model.config";
|
||||
const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights_profile.txt";
|
||||
|
|
@ -1722,7 +1718,7 @@ namespace Slic3r {
|
|||
}
|
||||
|
||||
// Added because of github #3435, currently not used by PrusaSlicer
|
||||
int instances_count_id = get_attribute_value_int(attributes, num_attributes, INSTANCESCOUNT_ATTR);
|
||||
// int instances_count_id = get_attribute_value_int(attributes, num_attributes, INSTANCESCOUNT_ATTR);
|
||||
|
||||
m_objects_metadata.insert(IdToMetadataMap::value_type(object_id, ObjectMetadata()));
|
||||
m_curr_config.object_id = object_id;
|
||||
|
|
@ -1969,22 +1965,12 @@ namespace Slic3r {
|
|||
bool m_fullpath_sources{ true };
|
||||
|
||||
public:
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data = nullptr);
|
||||
#else
|
||||
bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
private:
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data);
|
||||
#else
|
||||
bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
bool _add_content_types_file_to_archive(mz_zip_archive& archive);
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool _add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
bool _add_relationships_file_to_archive(mz_zip_archive& archive);
|
||||
bool _add_model_file_to_archive(mz_zip_archive& archive, const Model& model, IdToObjectDataMap &objects_data);
|
||||
bool _add_object_to_model_stream(std::stringstream& stream, unsigned int& object_id, ModelObject& object, BuildItemsList& build_items, VolumeToOffsetsMap& volumes_offsets);
|
||||
|
|
@ -1999,26 +1985,14 @@ namespace Slic3r {
|
|||
bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model);
|
||||
};
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data)
|
||||
{
|
||||
clear_errors();
|
||||
m_fullpath_sources = fullpath_sources;
|
||||
return _save_model_to_file(filename, model, config, thumbnail_data);
|
||||
}
|
||||
#else
|
||||
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources)
|
||||
{
|
||||
clear_errors();
|
||||
return _save_model_to_file(filename, model, config);
|
||||
}
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data)
|
||||
#else
|
||||
bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config)
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
{
|
||||
mz_zip_archive archive;
|
||||
mz_zip_zero_struct(&archive);
|
||||
|
|
@ -2037,7 +2011,6 @@ namespace Slic3r {
|
|||
return false;
|
||||
}
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
if ((thumbnail_data != nullptr) && thumbnail_data->is_valid())
|
||||
{
|
||||
// Adds the file Metadata/thumbnail.png.
|
||||
|
|
@ -2048,7 +2021,6 @@ namespace Slic3r {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
// Adds relationships file ("_rels/.rels").
|
||||
// The content of this file is the same for each PrusaSlicer 3mf.
|
||||
|
|
@ -2160,9 +2132,7 @@ namespace Slic3r {
|
|||
stream << "<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">\n";
|
||||
stream << " <Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\" />\n";
|
||||
stream << " <Default Extension=\"model\" ContentType=\"application/vnd.ms-package.3dmanufacturing-3dmodel+xml\" />\n";
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
stream << " <Default Extension=\"png\" ContentType=\"image/png\" />\n";
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
stream << "</Types>";
|
||||
|
||||
std::string out = stream.str();
|
||||
|
|
@ -2176,7 +2146,6 @@ namespace Slic3r {
|
|||
return true;
|
||||
}
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool _3MF_Exporter::_add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data)
|
||||
{
|
||||
bool res = false;
|
||||
|
|
@ -2194,7 +2163,6 @@ namespace Slic3r {
|
|||
|
||||
return res;
|
||||
}
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
bool _3MF_Exporter::_add_relationships_file_to_archive(mz_zip_archive& archive)
|
||||
{
|
||||
|
|
@ -2202,9 +2170,7 @@ namespace Slic3r {
|
|||
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
stream << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n";
|
||||
stream << " <Relationship Target=\"/" << MODEL_FILE << "\" Id=\"rel-1\" Type=\"http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel\" />\n";
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
stream << " <Relationship Target=\"/" << THUMBNAIL_FILE << "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\" />\n";
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
stream << "</Relationships>";
|
||||
|
||||
std::string out = stream.str();
|
||||
|
|
@ -2795,22 +2761,13 @@ bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model, bool c
|
|||
return res;
|
||||
}
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data)
|
||||
#else
|
||||
bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources)
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
{
|
||||
if ((path == nullptr) || (model == nullptr))
|
||||
return false;
|
||||
|
||||
_3MF_Exporter exporter;
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool res = exporter.save_model_to_file(path, *model, config, fullpath_sources, thumbnail_data);
|
||||
#else
|
||||
bool res = exporter.save_model_to_file(path, *model, config, fullpath_sources);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
if (!res)
|
||||
exporter.log_errors();
|
||||
|
||||
|
|
|
|||
|
|
@ -26,20 +26,14 @@ namespace Slic3r {
|
|||
|
||||
class Model;
|
||||
class DynamicPrintConfig;
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
struct ThumbnailData;
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
// Load the content of a 3mf file into the given model and preset bundle.
|
||||
extern bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model, bool check_version);
|
||||
|
||||
// Save the given model and the config data contained in the given Print into a 3mf file.
|
||||
// The model could be modified during the export process if meshes are not repaired or have no shared vertices
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data = nullptr);
|
||||
#else
|
||||
extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
|
|
|
|||
|
|
@ -20,9 +20,7 @@
|
|||
#include <boost/foreach.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
#include <boost/beast/core/detail/base64.hpp>
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
#include <boost/nowide/iostream.hpp>
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
|
|
@ -291,7 +289,7 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
|
|||
|
||||
std::string gcode;
|
||||
|
||||
// Toolchangeresult.gcode assumes the wipe tower corner is at the origin
|
||||
// Toolchangeresult.gcode assumes the wipe tower corner is at the origin (except for priming lines)
|
||||
// We want to rotate and shift all extrusions (gcode postprocessing) and starting and ending position
|
||||
float alpha = m_wipe_tower_rotation/180.f * float(M_PI);
|
||||
Vec2f start_pos = tcr.start_pos;
|
||||
|
|
@ -431,7 +429,6 @@ std::string WipeTowerIntegration::post_process_wipe_tower_moves(const WipeTower:
|
|||
Vec2f pos = tcr.start_pos;
|
||||
Vec2f transformed_pos = pos;
|
||||
Vec2f old_pos(-1000.1f, -1000.1f);
|
||||
std::string never_skip_tag = WipeTower::never_skip_tag();
|
||||
|
||||
while (gcode_str) {
|
||||
std::getline(gcode_str, line); // we read the gcode line by line
|
||||
|
|
@ -441,11 +438,11 @@ std::string WipeTowerIntegration::post_process_wipe_tower_moves(const WipeTower:
|
|||
// WT generator can override this by appending the never_skip_tag
|
||||
if (line.find("G1 ") == 0) {
|
||||
bool never_skip = false;
|
||||
auto it = line.find(never_skip_tag);
|
||||
auto it = line.find(WipeTower::never_skip_tag());
|
||||
if (it != std::string::npos) {
|
||||
// remove the tag and remember we saw it
|
||||
never_skip = true;
|
||||
line.erase(it, it+never_skip_tag.size());
|
||||
line.erase(it, it+WipeTower::never_skip_tag().size());
|
||||
}
|
||||
std::ostringstream line_out;
|
||||
std::istringstream line_str(line);
|
||||
|
|
@ -632,13 +629,16 @@ std::vector<GCode::LayerToPrint> GCode::collect_layers_to_print(const PrintObjec
|
|||
// Negative support_contact_z is not taken into account, it can result in false positives in cases
|
||||
// where previous layer has object extrusions too (https://github.com/prusa3d/PrusaSlicer/issues/2752)
|
||||
|
||||
// Only check this layer in case it has some extrusions.
|
||||
bool has_extrusions = (layer_to_print.object_layer && layer_to_print.object_layer->has_extrusions())
|
||||
|| (layer_to_print.support_layer && layer_to_print.support_layer->has_extrusions());
|
||||
|
||||
if (layer_to_print.print_z() > maximal_print_z + 2. * EPSILON)
|
||||
if (has_extrusions && layer_to_print.print_z() > maximal_print_z + 2. * EPSILON)
|
||||
throw std::runtime_error(_(L("Empty layers detected, the output would not be printable.")) + "\n\n" +
|
||||
_(L("Object name")) + ": " + object.model_object()->name + "\n" + _(L("Print z")) + ": " +
|
||||
std::to_string(layers_to_print.back().print_z()) + "\n\n" + _(L("This is "
|
||||
"usually caused by negligibly small extrusions or by a faulty model. Try to repair "
|
||||
" the model or change its orientation on the bed.")));
|
||||
"the model or change its orientation on the bed.")));
|
||||
// Remember last layer with extrusions.
|
||||
last_extrusion_layer = &layers_to_print.back();
|
||||
}
|
||||
|
|
@ -700,10 +700,8 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
|
|||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||
#elif ENABLE_THUMBNAIL_GENERATOR
|
||||
void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||
#else
|
||||
void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_data)
|
||||
void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
{
|
||||
PROFILE_CLEAR();
|
||||
|
|
@ -730,11 +728,7 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
|
|||
|
||||
try {
|
||||
m_placeholder_parser_failed_templates.clear();
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
this->_do_export(*print, file, thumbnail_cb);
|
||||
#else
|
||||
this->_do_export(*print, file);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
fflush(file);
|
||||
if (ferror(file)) {
|
||||
fclose(file);
|
||||
|
|
@ -999,7 +993,6 @@ namespace DoExport {
|
|||
}
|
||||
}
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
template<typename WriteToOutput, typename ThrowIfCanceledCallback>
|
||||
static void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb, const std::vector<Vec2d> &sizes, WriteToOutput output, ThrowIfCanceledCallback throw_if_canceled)
|
||||
{
|
||||
|
|
@ -1043,7 +1036,6 @@ namespace DoExport {
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
// Fill in print_statistics and return formatted string containing filament statistics to be inserted into G-code comment section.
|
||||
static std::string update_print_stats_and_format_filament_stats(
|
||||
|
|
@ -1060,9 +1052,9 @@ namespace DoExport {
|
|||
print_statistics.clear();
|
||||
print_statistics.estimated_normal_print_time = normal_time_estimator.get_time_dhm/*s*/();
|
||||
print_statistics.estimated_silent_print_time = silent_time_estimator_enabled ? silent_time_estimator.get_time_dhm/*s*/() : "N/A";
|
||||
print_statistics.estimated_normal_color_print_times = normal_time_estimator.get_color_times_dhms(true);
|
||||
print_statistics.estimated_normal_custom_gcode_print_times = normal_time_estimator.get_custom_gcode_times_dhm(true);
|
||||
if (silent_time_estimator_enabled)
|
||||
print_statistics.estimated_silent_color_print_times = silent_time_estimator.get_color_times_dhms(true);
|
||||
print_statistics.estimated_silent_custom_gcode_print_times = silent_time_estimator.get_custom_gcode_times_dhm(true);
|
||||
print_statistics.total_toolchanges = std::max(0, wipe_tower_data.number_of_toolchanges);
|
||||
if (! extruders.empty()) {
|
||||
std::pair<std::string, unsigned int> out_filament_used_mm ("; filament used [mm] = ", 0);
|
||||
|
|
@ -1104,11 +1096,11 @@ namespace DoExport {
|
|||
print_statistics.total_wipe_tower_cost += has_wipe_tower ? (extruded_volume - extruder.extruded_volume())* extruder.filament_density() * 0.001 * extruder.filament_cost() * 0.001 : 0.;
|
||||
}
|
||||
filament_stats_string_out += out_filament_used_mm.first;
|
||||
filament_stats_string_out += out_filament_used_cm3.first;
|
||||
filament_stats_string_out += "\n" + out_filament_used_cm3.first;
|
||||
if (out_filament_used_g.second)
|
||||
filament_stats_string_out += out_filament_used_g.first;
|
||||
filament_stats_string_out += "\n" + out_filament_used_g.first;
|
||||
if (out_filament_cost.second)
|
||||
filament_stats_string_out += out_filament_cost.first;
|
||||
filament_stats_string_out += "\n" + out_filament_cost.first;
|
||||
}
|
||||
return filament_stats_string_out;
|
||||
}
|
||||
|
|
@ -1149,11 +1141,7 @@ std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Pri
|
|||
return instances;
|
||||
}
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||
#else
|
||||
void GCode::_do_export(Print& print, FILE* file)
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
|
||||
|
|
@ -1550,6 +1538,7 @@ void GCode::_do_export(Print& print, FILE* file)
|
|||
m_writer.extruders(),
|
||||
// Modifies
|
||||
print.m_print_statistics));
|
||||
_write(file, "\n");
|
||||
_write_format(file, "; total filament used [g] = %.1lf\n", print.m_print_statistics.total_weight);
|
||||
_write_format(file, "; total filament cost = %.1lf\n", print.m_print_statistics.total_cost);
|
||||
if (print.m_print_statistics.total_toolchanges > 0)
|
||||
|
|
@ -1778,7 +1767,6 @@ std::vector<GCode::InstanceToPrint> GCode::sort_print_object_instances(
|
|||
std::sort(sorted.begin(), sorted.end());
|
||||
|
||||
if (! sorted.empty()) {
|
||||
const Print &print = *sorted.front().first->print();
|
||||
out.reserve(sorted.size());
|
||||
for (const PrintInstance *instance : *ordering) {
|
||||
const PrintObject &print_object = *instance->print_object;
|
||||
|
|
@ -1824,13 +1812,14 @@ namespace ProcessLayer
|
|||
// we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count
|
||||
if (color_change || tool_change)
|
||||
{
|
||||
assert(m600_extruder_before_layer >= 0);
|
||||
// Color Change or Tool Change as Color Change.
|
||||
// add tag for analyzer
|
||||
gcode += "; " + GCodeAnalyzer::Color_Change_Tag + ",T" + std::to_string(m600_extruder_before_layer) + "\n";
|
||||
// add tag for time estimator
|
||||
gcode += "; " + GCodeTimeEstimator::Color_Change_Tag + "\n";
|
||||
|
||||
if (!single_extruder_printer && m600_extruder_before_layer >= 0 && first_extruder_id != m600_extruder_before_layer
|
||||
if (!single_extruder_printer && m600_extruder_before_layer >= 0 && first_extruder_id != (unsigned)m600_extruder_before_layer
|
||||
// && !MMU1
|
||||
) {
|
||||
//! FIXME_in_fw show message during print pause
|
||||
|
|
@ -1852,7 +1841,7 @@ namespace ProcessLayer
|
|||
if (!pause_print_msg.empty())
|
||||
gcode += "M117 " + pause_print_msg + "\n";
|
||||
// add tag for time estimator
|
||||
//gcode += "; " + GCodeTimeEstimator::Pause_Print_Tag + "\n";
|
||||
gcode += "; " + GCodeTimeEstimator::Pause_Print_Tag + "\n";
|
||||
}
|
||||
else // custom Gcode
|
||||
{
|
||||
|
|
@ -2906,11 +2895,12 @@ std::string GCode::extrude_path(ExtrusionPath path, std::string description, dou
|
|||
std::string GCode::extrude_perimeters(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region, std::unique_ptr<EdgeGrid::Grid> &lower_layer_edge_grid)
|
||||
{
|
||||
std::string gcode;
|
||||
for (const ObjectByExtruder::Island::Region ®ion : by_region) {
|
||||
m_config.apply(print.regions()[®ion - &by_region.front()]->config());
|
||||
for (const ExtrusionEntity *ee : region.perimeters)
|
||||
gcode += this->extrude_entity(*ee, "perimeter", -1., &lower_layer_edge_grid);
|
||||
}
|
||||
for (const ObjectByExtruder::Island::Region ®ion : by_region)
|
||||
if (! region.perimeters.empty()) {
|
||||
m_config.apply(print.regions()[®ion - &by_region.front()]->config());
|
||||
for (const ExtrusionEntity *ee : region.perimeters)
|
||||
gcode += this->extrude_entity(*ee, "perimeter", -1., &lower_layer_edge_grid);
|
||||
}
|
||||
return gcode;
|
||||
}
|
||||
|
||||
|
|
@ -2918,19 +2908,20 @@ std::string GCode::extrude_perimeters(const Print &print, const std::vector<Obje
|
|||
std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region)
|
||||
{
|
||||
std::string gcode;
|
||||
for (const ObjectByExtruder::Island::Region ®ion : by_region) {
|
||||
m_config.apply(print.regions()[®ion - &by_region.front()]->config());
|
||||
ExtrusionEntitiesPtr extrusions { region.infills };
|
||||
chain_and_reorder_extrusion_entities(extrusions, &m_last_pos);
|
||||
for (const ExtrusionEntity *fill : extrusions) {
|
||||
auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(fill);
|
||||
if (eec) {
|
||||
for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos).entities)
|
||||
gcode += this->extrude_entity(*ee, "infill");
|
||||
} else
|
||||
gcode += this->extrude_entity(*fill, "infill");
|
||||
for (const ObjectByExtruder::Island::Region ®ion : by_region)
|
||||
if (! region.infills.empty()) {
|
||||
m_config.apply(print.regions()[®ion - &by_region.front()]->config());
|
||||
ExtrusionEntitiesPtr extrusions { region.infills };
|
||||
chain_and_reorder_extrusion_entities(extrusions, &m_last_pos);
|
||||
for (const ExtrusionEntity *fill : extrusions) {
|
||||
auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(fill);
|
||||
if (eec) {
|
||||
for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos).entities)
|
||||
gcode += this->extrude_entity(*ee, "infill");
|
||||
} else
|
||||
gcode += this->extrude_entity(*fill, "infill");
|
||||
}
|
||||
}
|
||||
}
|
||||
return gcode;
|
||||
}
|
||||
|
||||
|
|
@ -3396,17 +3387,18 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
|
|||
has_overrides = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Data is cleared, but the memory is not.
|
||||
by_region_per_copy_cache.clear();
|
||||
|
||||
if (! has_overrides)
|
||||
// Simple case. No need to copy the regions.
|
||||
return this->by_region;
|
||||
return wiping_entities ? by_region_per_copy_cache : this->by_region;
|
||||
|
||||
// Complex case. Some of the extrusions of some object instances are to be printed first - those are the wiping extrusions.
|
||||
// Some of the extrusions of some object instances are printed later - those are the clean print extrusions.
|
||||
// Filter out the extrusions based on the infill_overrides / perimeter_overrides:
|
||||
|
||||
// Data is cleared, but the memory is not.
|
||||
by_region_per_copy_cache.clear();
|
||||
|
||||
for (const auto& reg : by_region) {
|
||||
by_region_per_copy_cache.emplace_back(); // creates a region in the newly created Island
|
||||
|
||||
|
|
@ -3436,7 +3428,7 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
|
|||
if (this_override == nullptr || (*this_override)[copy] == -int(extruder)-1)
|
||||
target_eec.emplace_back(entities[i]);
|
||||
}
|
||||
for (; i < overrides.size(); ++ i)
|
||||
for (; i < entities.size(); ++ i)
|
||||
target_eec.emplace_back(entities[i]);
|
||||
}
|
||||
}
|
||||
|
|
@ -3467,15 +3459,17 @@ void GCode::ObjectByExtruder::Island::Region::append(const Type type, const Extr
|
|||
|
||||
// First we append the entities, there are eec->entities.size() of them:
|
||||
size_t old_size = perimeters_or_infills->size();
|
||||
perimeters_or_infills->reserve(perimeters_or_infills->size() + eec->entities.size());
|
||||
size_t new_size = old_size + eec->entities.size();
|
||||
perimeters_or_infills->reserve(new_size);
|
||||
for (auto* ee : eec->entities)
|
||||
perimeters_or_infills->emplace_back(ee);
|
||||
|
||||
if (copies_extruder != nullptr) {
|
||||
perimeters_or_infills_overrides->reserve(old_size + eec->entities.size());
|
||||
perimeters_or_infills_overrides->resize(old_size, nullptr);
|
||||
for (unsigned int i = 0; i < eec->entities.size(); ++ i)
|
||||
perimeters_or_infills_overrides->emplace_back(copies_extruder);
|
||||
// Don't reallocate overrides if not needed.
|
||||
// Missing overrides are implicitely considered non-overridden.
|
||||
perimeters_or_infills_overrides->reserve(new_size);
|
||||
perimeters_or_infills_overrides->resize(old_size, nullptr);
|
||||
perimeters_or_infills_overrides->resize(new_size, copies_extruder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,9 +20,7 @@
|
|||
#include "GCodeTimeEstimator.hpp"
|
||||
#include "EdgeGrid.hpp"
|
||||
#include "GCode/Analyzer.hpp"
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
#include "GCode/ThumbnailData.hpp"
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
|
@ -171,10 +169,8 @@ public:
|
|||
// throws CanceledException through print->throw_if_canceled().
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, GCodeProcessor::Result* result = nullptr, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
||||
#elif ENABLE_THUMBNAIL_GENERATOR
|
||||
void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
||||
#else
|
||||
void do_export(Print *print, const char *path, GCodePreviewData *preview_data = nullptr);
|
||||
void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
// Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.
|
||||
|
|
@ -215,11 +211,7 @@ public:
|
|||
};
|
||||
|
||||
private:
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
void _do_export(Print &print, FILE *file, ThumbnailsGeneratorCallback thumbnail_cb);
|
||||
#else
|
||||
void _do_export(Print &print, FILE *file);
|
||||
#endif //ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
static std::vector<LayerToPrint> collect_layers_to_print(const PrintObject &object);
|
||||
static std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> collect_layers_to_print(const Print &print);
|
||||
|
|
|
|||
|
|
@ -444,8 +444,10 @@ void GCodeAnalyzer::_processG92(const GCodeReader::GCodeLine& line)
|
|||
anyFound = true;
|
||||
}
|
||||
|
||||
if (!anyFound)
|
||||
if (!anyFound && ! line.has_unknown_axis())
|
||||
{
|
||||
// The G92 may be called for axes that PrusaSlicer does not recognize, for example see GH issue #3510,
|
||||
// where G92 A0 B0 is called although the extruder axis is till E.
|
||||
for (unsigned char a = X; a < Num_Axis; ++a)
|
||||
{
|
||||
_set_axis_origin((EAxis)a, _get_axis_position((EAxis)a));
|
||||
|
|
@ -470,7 +472,7 @@ void GCodeAnalyzer::_processM106(const GCodeReader::GCodeLine& line)
|
|||
// The absence of P means the print cooling fan, so ignore anything else.
|
||||
float new_fan_speed;
|
||||
if (line.has_value('S', new_fan_speed))
|
||||
_set_fan_speed((100.0f / 256.0f) * new_fan_speed);
|
||||
_set_fan_speed((100.0f / 255.0f) * new_fan_speed);
|
||||
else
|
||||
_set_fan_speed(100.0f);
|
||||
}
|
||||
|
|
@ -644,7 +646,7 @@ bool GCodeAnalyzer::_process_tags(const GCodeReader::GCodeLine& line)
|
|||
if (pos != comment.npos)
|
||||
{
|
||||
pos = comment.find_last_of(",T");
|
||||
int extruder = pos == comment.npos ? 0 : std::atoi(comment.substr(pos + 1, comment.npos).c_str());
|
||||
unsigned extruder = pos == comment.npos ? 0 : std::stoi(comment.substr(pos + 1, comment.npos));
|
||||
_process_color_change_tag(extruder);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -702,7 +704,7 @@ void GCodeAnalyzer::_process_height_tag(const std::string& comment, size_t pos)
|
|||
_set_height((float)::strtod(comment.substr(pos + Height_Tag.length()).c_str(), nullptr));
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_process_color_change_tag(int extruder)
|
||||
void GCodeAnalyzer::_process_color_change_tag(unsigned extruder)
|
||||
{
|
||||
m_extruder_color[extruder] = m_extruders_count + m_state.cp_color_counter; // color_change position in list of color for preview
|
||||
m_state.cp_color_counter++;
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ private:
|
|||
void _process_height_tag(const std::string& comment, size_t pos);
|
||||
|
||||
// Processes color change tag
|
||||
void _process_color_change_tag(int extruder);
|
||||
void _process_color_change_tag(unsigned extruder);
|
||||
|
||||
// Processes pause print and custom gcode tag
|
||||
void _process_pause_print_or_custom_code_tag();
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ Color GCodePreviewData::RangeBase::get_color_at(float value) const
|
|||
{
|
||||
// Input value scaled to the color range
|
||||
float step = step_size();
|
||||
const float global_t = (step != 0.0f) ? std::max(0.0f, value - min()) / step_size() : 0.0f; // lower limit of 0.0f
|
||||
const float global_t = (step != 0.0f) ? std::max(0.0f, value - min()) / step : 0.0f; // lower limit of 0.0f
|
||||
|
||||
constexpr std::size_t color_max_idx = range_rainbow_colors.size() - 1;
|
||||
|
||||
|
|
@ -241,6 +241,7 @@ void GCodePreviewData::reset()
|
|||
ranges.width.reset();
|
||||
ranges.height.reset();
|
||||
ranges.feedrate.reset();
|
||||
ranges.fan_speed.reset();
|
||||
ranges.volumetric_rate.reset();
|
||||
extrusion.layers.clear();
|
||||
travel.polylines.clear();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
#include "libslic3r/libslic3r.h"
|
||||
#include "ThumbnailData.hpp"
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
void ThumbnailData::set(unsigned int w, unsigned int h)
|
||||
|
|
@ -32,5 +30,3 @@ bool ThumbnailData::is_valid() const
|
|||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef slic3r_ThumbnailData_hpp_
|
||||
#define slic3r_ThumbnailData_hpp_
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
#include <vector>
|
||||
#include "libslic3r/Point.hpp"
|
||||
|
||||
|
|
@ -26,6 +24,4 @@ typedef std::function<void(ThumbnailsList & thumbnails, const Vec2ds & sizes, bo
|
|||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
#endif // slic3r_ThumbnailData_hpp_
|
||||
|
|
@ -212,10 +212,8 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
|
|||
if (m_print_config_ptr) { // in this case complete_objects is false (see ToolOrdering constructors)
|
||||
something_nonoverriddable = false;
|
||||
for (const auto& eec : layerm->perimeters.entities) // let's check if there are nonoverriddable entities
|
||||
if (!layer_tools.wiping_extrusions().is_overriddable_and_mark(dynamic_cast<const ExtrusionEntityCollection&>(*eec), *m_print_config_ptr, object, region)) {
|
||||
if (!layer_tools.wiping_extrusions().is_overriddable_and_mark(dynamic_cast<const ExtrusionEntityCollection&>(*eec), *m_print_config_ptr, object, region))
|
||||
something_nonoverriddable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (something_nonoverriddable)
|
||||
|
|
@ -237,7 +235,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
|
|||
has_infill = true;
|
||||
|
||||
if (m_print_config_ptr) {
|
||||
if (!something_nonoverriddable && !layer_tools.wiping_extrusions().is_overriddable_and_mark(*fill, *m_print_config_ptr, object, region))
|
||||
if (! layer_tools.wiping_extrusions().is_overriddable_and_mark(*fill, *m_print_config_ptr, object, region))
|
||||
something_nonoverriddable = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,14 +30,6 @@ public:
|
|||
// When allocating extruder overrides of an object's ExtrusionEntity, overrides for maximum 3 copies are allocated in place.
|
||||
typedef boost::container::small_vector<int32_t, 3> ExtruderPerCopy;
|
||||
|
||||
class ExtruderOverrides
|
||||
{
|
||||
public:
|
||||
ExtruderOverrides(const ExtruderPerCopy *overrides, const int correct_extruder_id) : m_overrides(overrides) {}
|
||||
private:
|
||||
const ExtruderPerCopy *m_overrides;
|
||||
};
|
||||
|
||||
// This is called from GCode::process_layer - see implementation for further comments:
|
||||
const ExtruderPerCopy* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, size_t num_of_copies);
|
||||
|
||||
|
|
@ -72,7 +64,7 @@ private:
|
|||
std::map<const ExtrusionEntity*, ExtruderPerCopy> entity_map; // to keep track of who prints what
|
||||
bool something_overridable = false;
|
||||
bool something_overridden = false;
|
||||
const LayerTools* m_layer_tools; // so we know which LayerTools object this belongs to
|
||||
const LayerTools* m_layer_tools = nullptr; // so we know which LayerTools object this belongs to
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -492,6 +492,9 @@ WipeTower::WipeTower(const PrintConfig& config, const std::vector<std::vector<fl
|
|||
const std::vector<Vec2d>& bed_points = config.bed_shape.values;
|
||||
m_bed_shape = (bed_points.size() == 4 ? RectangularBed : CircularBed);
|
||||
m_bed_width = float(BoundingBoxf(bed_points).size().x());
|
||||
m_bed_bottom_left = m_bed_shape == RectangularBed
|
||||
? Vec2f(bed_points.front().x(), bed_points.front().y())
|
||||
: Vec2f::Zero();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -566,6 +569,8 @@ std::vector<WipeTower::ToolChangeResult> WipeTower::prime(
|
|||
// In case of a circular bed, place it so it goes across the diameter and hope it will fit
|
||||
if (m_bed_shape == CircularBed)
|
||||
cleaning_box.translate(-m_bed_width/2 + m_bed_width * 0.03f, -m_bed_width * 0.12f);
|
||||
if (m_bed_shape == RectangularBed)
|
||||
cleaning_box.translate(m_bed_bottom_left);
|
||||
|
||||
std::vector<ToolChangeResult> results;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ enum GCodeFlavor : unsigned char;
|
|||
class WipeTower
|
||||
{
|
||||
public:
|
||||
static char const* never_skip_tag() { return "_GCODE_WIPE_TOWER_NEVER_SKIP_TAG"; }
|
||||
static const std::string never_skip_tag() { return "_GCODE_WIPE_TOWER_NEVER_SKIP_TAG"; }
|
||||
|
||||
struct Extrusion
|
||||
{
|
||||
|
|
@ -189,8 +189,6 @@ public:
|
|||
};
|
||||
|
||||
private:
|
||||
WipeTower();
|
||||
|
||||
enum wipe_shape // A fill-in direction
|
||||
{
|
||||
SHAPE_NORMAL = 1,
|
||||
|
|
@ -236,6 +234,7 @@ private:
|
|||
CircularBed
|
||||
} m_bed_shape;
|
||||
float m_bed_width; // width of the bed bounding box
|
||||
Vec2f m_bed_bottom_left; // bottom-left corner coordinates (for rectangular beds)
|
||||
|
||||
float m_perimeter_width = 0.4f * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill.
|
||||
float m_extrusion_flow = 0.038f; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter.
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ const char* GCodeReader::parse_line_internal(const char *ptr, GCodeLine &gline,
|
|||
if (is_end_of_gcode_line(*c))
|
||||
break;
|
||||
// Check the name of the axis.
|
||||
Axis axis = NUM_AXES;
|
||||
Axis axis = NUM_AXES_WITH_UNKNOWN;
|
||||
switch (*c) {
|
||||
case 'X': axis = X; break;
|
||||
case 'Y': axis = Y; break;
|
||||
|
|
@ -49,15 +49,19 @@ const char* GCodeReader::parse_line_internal(const char *ptr, GCodeLine &gline,
|
|||
default:
|
||||
if (*c == m_extrusion_axis)
|
||||
axis = E;
|
||||
else if (*c >= 'A' && *c <= 'Z')
|
||||
// Unknown axis, but we still want to remember that such a axis was seen.
|
||||
axis = UNKNOWN_AXIS;
|
||||
break;
|
||||
}
|
||||
if (axis != NUM_AXES) {
|
||||
if (axis != NUM_AXES_WITH_UNKNOWN) {
|
||||
// Try to parse the numeric value.
|
||||
char *pend = nullptr;
|
||||
double v = strtod(++ c, &pend);
|
||||
if (pend != nullptr && is_end_of_word(*pend)) {
|
||||
// The axis value has been parsed correctly.
|
||||
gline.m_axis[int(axis)] = float(v);
|
||||
if (axis != UNKNOWN_AXIS)
|
||||
gline.m_axis[int(axis)] = float(v);
|
||||
gline.m_mask |= 1 << int(axis);
|
||||
c = pend;
|
||||
} else
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ public:
|
|||
bool has_z() const { return this->has(Z); }
|
||||
bool has_e() const { return this->has(E); }
|
||||
bool has_f() const { return this->has(F); }
|
||||
bool has_unknown_axis() const { return this->has(UNKNOWN_AXIS); }
|
||||
float x() const { return m_axis[X]; }
|
||||
float y() const { return m_axis[Y]; }
|
||||
float z() const { return m_axis[Z]; }
|
||||
|
|
|
|||
|
|
@ -174,6 +174,7 @@ namespace Slic3r {
|
|||
const std::string GCodeTimeEstimator::Silent_Last_M73_Output_Placeholder_Tag = "; _TE_SILENT_LAST_M73_OUTPUT_PLACEHOLDER";
|
||||
|
||||
const std::string GCodeTimeEstimator::Color_Change_Tag = "PRINT_COLOR_CHANGE";
|
||||
const std::string GCodeTimeEstimator::Pause_Print_Tag = "PRINT_PAUSE";
|
||||
|
||||
GCodeTimeEstimator::GCodeTimeEstimator(EMode mode)
|
||||
: m_mode(mode)
|
||||
|
|
@ -212,8 +213,8 @@ namespace Slic3r {
|
|||
}
|
||||
_calculate_time();
|
||||
|
||||
if (m_needs_color_times && (m_color_time_cache != 0.0f))
|
||||
m_color_times.push_back(m_color_time_cache);
|
||||
if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f))
|
||||
m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache });
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
_log_moves_stats();
|
||||
|
|
@ -230,8 +231,8 @@ namespace Slic3r {
|
|||
|
||||
_calculate_time();
|
||||
|
||||
if (m_needs_color_times && (m_color_time_cache != 0.0f))
|
||||
m_color_times.push_back(m_color_time_cache);
|
||||
if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f))
|
||||
m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache });
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
_log_moves_stats();
|
||||
|
|
@ -245,8 +246,8 @@ namespace Slic3r {
|
|||
m_parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2));
|
||||
_calculate_time();
|
||||
|
||||
if (m_needs_color_times && (m_color_time_cache != 0.0f))
|
||||
m_color_times.push_back(m_color_time_cache);
|
||||
if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f))
|
||||
m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache });
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
_log_moves_stats();
|
||||
|
|
@ -263,8 +264,8 @@ namespace Slic3r {
|
|||
m_parser.parse_line(line, action);
|
||||
_calculate_time();
|
||||
|
||||
if (m_needs_color_times && (m_color_time_cache != 0.0f))
|
||||
m_color_times.push_back(m_color_time_cache);
|
||||
if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f))
|
||||
m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache});
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
_log_moves_stats();
|
||||
|
|
@ -351,8 +352,8 @@ namespace Slic3r {
|
|||
}
|
||||
|
||||
// check tags
|
||||
// remove color change tag
|
||||
if (gcode_line == "; " + Color_Change_Tag)
|
||||
// remove Color_Change_Tag and Pause_Print_Tag
|
||||
if (gcode_line == "; " + Color_Change_Tag || gcode_line == "; " + Pause_Print_Tag)
|
||||
continue;
|
||||
|
||||
// replaces placeholders for initial line M73 with the real lines
|
||||
|
|
@ -717,25 +718,26 @@ namespace Slic3r {
|
|||
return _get_time_minutes(get_time());
|
||||
}
|
||||
|
||||
std::vector<float> GCodeTimeEstimator::get_color_times() const
|
||||
std::vector<std::pair<CustomGcodeType, float>> GCodeTimeEstimator::get_custom_gcode_times() const
|
||||
{
|
||||
return m_color_times;
|
||||
return m_custom_gcode_times;
|
||||
}
|
||||
|
||||
std::vector<std::string> GCodeTimeEstimator::get_color_times_dhms(bool include_remaining) const
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
float total_time = 0.0f;
|
||||
for (float t : m_color_times)
|
||||
// for (float t : m_color_times)
|
||||
for (auto t : m_custom_gcode_times)
|
||||
{
|
||||
std::string time = _get_time_dhms(t);
|
||||
std::string time = _get_time_dhms(t.second);
|
||||
if (include_remaining)
|
||||
{
|
||||
time += " (";
|
||||
time += _get_time_dhms(m_time - total_time);
|
||||
time += ")";
|
||||
}
|
||||
total_time += t;
|
||||
total_time += t.second;
|
||||
ret.push_back(time);
|
||||
}
|
||||
return ret;
|
||||
|
|
@ -745,20 +747,42 @@ namespace Slic3r {
|
|||
{
|
||||
std::vector<std::string> ret;
|
||||
float total_time = 0.0f;
|
||||
for (float t : m_color_times)
|
||||
// for (float t : m_color_times)
|
||||
for (auto t : m_custom_gcode_times)
|
||||
{
|
||||
std::string time = _get_time_minutes(t);
|
||||
std::string time = _get_time_minutes(t.second);
|
||||
if (include_remaining)
|
||||
{
|
||||
time += " (";
|
||||
time += _get_time_minutes(m_time - total_time);
|
||||
time += ")";
|
||||
}
|
||||
total_time += t;
|
||||
total_time += t.second;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::pair<CustomGcodeType, std::string>> GCodeTimeEstimator::get_custom_gcode_times_dhm(bool include_remaining) const
|
||||
{
|
||||
std::vector<std::pair<CustomGcodeType, std::string>> ret;
|
||||
|
||||
float total_time = 0.0f;
|
||||
for (auto t : m_custom_gcode_times)
|
||||
{
|
||||
std::string time = _get_time_dhm(t.second);
|
||||
if (include_remaining)
|
||||
{
|
||||
time += " (";
|
||||
time += _get_time_dhm(m_time - total_time);
|
||||
time += ")";
|
||||
}
|
||||
total_time += t.second;
|
||||
ret.push_back({t.first, time});
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Return an estimate of the memory consumed by the time estimator.
|
||||
size_t GCodeTimeEstimator::memory_used() const
|
||||
{
|
||||
|
|
@ -791,9 +815,9 @@ namespace Slic3r {
|
|||
|
||||
m_last_st_synchronized_block_id = -1;
|
||||
|
||||
m_needs_color_times = false;
|
||||
m_color_times.clear();
|
||||
m_color_time_cache = 0.0f;
|
||||
m_needs_custom_gcode_times = false;
|
||||
m_custom_gcode_times.clear();
|
||||
m_custom_gcode_time_cache = 0.0f;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_reset_time()
|
||||
|
|
@ -814,7 +838,7 @@ namespace Slic3r {
|
|||
_recalculate_trapezoids();
|
||||
|
||||
m_time += get_additional_time();
|
||||
m_color_time_cache += get_additional_time();
|
||||
m_custom_gcode_time_cache += get_additional_time();
|
||||
|
||||
for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size(); ++i)
|
||||
{
|
||||
|
|
@ -835,7 +859,7 @@ namespace Slic3r {
|
|||
it->second.time += block_time;
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
|
||||
m_color_time_cache += block_time;
|
||||
m_custom_gcode_time_cache += block_time;
|
||||
}
|
||||
|
||||
m_last_st_synchronized_block_id = (int)m_blocks.size() - 1;
|
||||
|
|
@ -1466,26 +1490,34 @@ namespace Slic3r {
|
|||
{
|
||||
std::string comment = line.comment();
|
||||
|
||||
// color change tag
|
||||
// Color_Change_Tag
|
||||
size_t pos = comment.find(Color_Change_Tag);
|
||||
if (pos != comment.npos)
|
||||
{
|
||||
_process_color_change_tag();
|
||||
_process_custom_gcode_tag(cgtColorChange);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pause_Print_Tag
|
||||
pos = comment.find(Pause_Print_Tag);
|
||||
if (pos != comment.npos)
|
||||
{
|
||||
_process_custom_gcode_tag(cgtPausePrint);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_process_color_change_tag()
|
||||
void GCodeTimeEstimator::_process_custom_gcode_tag(CustomGcodeType code)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
m_needs_color_times = true;
|
||||
m_needs_custom_gcode_times = true;
|
||||
_calculate_time();
|
||||
if (m_color_time_cache != 0.0f)
|
||||
if (m_custom_gcode_time_cache != 0.0f)
|
||||
{
|
||||
m_color_times.push_back(m_color_time_cache);
|
||||
m_color_time_cache = 0.0f;
|
||||
m_custom_gcode_times.push_back({code, m_custom_gcode_time_cache});
|
||||
m_custom_gcode_time_cache = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "libslic3r.h"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "GCodeReader.hpp"
|
||||
#include "CustomGCode.hpp"
|
||||
|
||||
#define ENABLE_MOVE_STATS 0
|
||||
|
||||
|
|
@ -23,6 +24,7 @@ namespace Slic3r {
|
|||
static const std::string Silent_Last_M73_Output_Placeholder_Tag;
|
||||
|
||||
static const std::string Color_Change_Tag;
|
||||
static const std::string Pause_Print_Tag;
|
||||
|
||||
enum EMode : unsigned char
|
||||
{
|
||||
|
|
@ -240,10 +242,10 @@ namespace Slic3r {
|
|||
int m_last_st_synchronized_block_id;
|
||||
float m_time; // s
|
||||
|
||||
// data to calculate color print times
|
||||
bool m_needs_color_times;
|
||||
std::vector<float> m_color_times;
|
||||
float m_color_time_cache;
|
||||
// data to calculate custom code times
|
||||
bool m_needs_custom_gcode_times;
|
||||
std::vector<std::pair<CustomGcodeType, float>> m_custom_gcode_times;
|
||||
float m_custom_gcode_time_cache;
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
MovesStatsMap _moves_stats;
|
||||
|
|
@ -369,8 +371,8 @@ namespace Slic3r {
|
|||
// Returns the estimated time, in minutes (integer)
|
||||
std::string get_time_minutes() const;
|
||||
|
||||
// Returns the estimated time, in seconds, for each color
|
||||
std::vector<float> get_color_times() const;
|
||||
// Returns the estimated time, in seconds, for each custom gcode
|
||||
std::vector<std::pair<CustomGcodeType, float>> get_custom_gcode_times() const;
|
||||
|
||||
// Returns the estimated time, in format DDd HHh MMm SSs, for each color
|
||||
// If include_remaining==true the strings will be formatted as: "time for color (remaining time at color start)"
|
||||
|
|
@ -380,6 +382,10 @@ namespace Slic3r {
|
|||
// If include_remaining==true the strings will be formatted as: "time for color (remaining time at color start)"
|
||||
std::vector<std::string> get_color_times_minutes(bool include_remaining) const;
|
||||
|
||||
// Returns the estimated time, in format DDd HHh MMm, for each custom_gcode
|
||||
// If include_remaining==true the strings will be formatted as: "time for custom_gcode (remaining time at color start)"
|
||||
std::vector<std::pair<CustomGcodeType, std::string>> get_custom_gcode_times_dhm(bool include_remaining) const;
|
||||
|
||||
// Return an estimate of the memory consumed by the time estimator.
|
||||
size_t memory_used() const;
|
||||
|
||||
|
|
@ -460,8 +466,8 @@ namespace Slic3r {
|
|||
// Returns true if any tag has been processed
|
||||
bool _process_tags(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Processes color change tag
|
||||
void _process_color_change_tag();
|
||||
// Processes ColorChangeTag and PausePrintTag
|
||||
void _process_custom_gcode_tag(CustomGcodeType code);
|
||||
|
||||
// Simulates firmware st_synchronize() call
|
||||
void _simulate_st_synchronize();
|
||||
|
|
|
|||
|
|
@ -112,72 +112,82 @@ void Layer::make_perimeters()
|
|||
// keep track of regions whose perimeters we have already generated
|
||||
std::vector<unsigned char> done(m_regions.size(), false);
|
||||
|
||||
for (LayerRegionPtrs::iterator layerm = m_regions.begin(); layerm != m_regions.end(); ++ layerm) {
|
||||
size_t region_id = layerm - m_regions.begin();
|
||||
if (done[region_id])
|
||||
continue;
|
||||
BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << ", region " << region_id;
|
||||
done[region_id] = true;
|
||||
const PrintRegionConfig &config = (*layerm)->region()->config();
|
||||
|
||||
// find compatible regions
|
||||
LayerRegionPtrs layerms;
|
||||
layerms.push_back(*layerm);
|
||||
for (LayerRegionPtrs::const_iterator it = layerm + 1; it != m_regions.end(); ++it) {
|
||||
LayerRegion* other_layerm = *it;
|
||||
const PrintRegionConfig &other_config = other_layerm->region()->config();
|
||||
if (config.perimeter_extruder == other_config.perimeter_extruder
|
||||
&& config.perimeters == other_config.perimeters
|
||||
&& config.perimeter_speed == other_config.perimeter_speed
|
||||
&& config.external_perimeter_speed == other_config.external_perimeter_speed
|
||||
&& config.gap_fill_speed == other_config.gap_fill_speed
|
||||
&& config.overhangs == other_config.overhangs
|
||||
&& config.opt_serialize("perimeter_extrusion_width") == other_config.opt_serialize("perimeter_extrusion_width")
|
||||
&& config.thin_walls == other_config.thin_walls
|
||||
&& config.external_perimeters_first == other_config.external_perimeters_first
|
||||
&& config.infill_overlap == other_config.infill_overlap) {
|
||||
layerms.push_back(other_layerm);
|
||||
done[it - m_regions.begin()] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (layerms.size() == 1) { // optimization
|
||||
(*layerm)->fill_surfaces.surfaces.clear();
|
||||
(*layerm)->make_perimeters((*layerm)->slices, &(*layerm)->fill_surfaces);
|
||||
(*layerm)->fill_expolygons = to_expolygons((*layerm)->fill_surfaces.surfaces);
|
||||
} else {
|
||||
SurfaceCollection new_slices;
|
||||
// Use the region with highest infill rate, as the make_perimeters() function below decides on the gap fill based on the infill existence.
|
||||
LayerRegion *layerm_config = layerms.front();
|
||||
{
|
||||
// group slices (surfaces) according to number of extra perimeters
|
||||
std::map<unsigned short, Surfaces> slices; // extra_perimeters => [ surface, surface... ]
|
||||
for (LayerRegion *layerm : layerms) {
|
||||
for (Surface &surface : layerm->slices.surfaces)
|
||||
slices[surface.extra_perimeters].emplace_back(surface);
|
||||
if (layerm->region()->config().fill_density > layerm_config->region()->config().fill_density)
|
||||
layerm_config = layerm;
|
||||
}
|
||||
// merge the surfaces assigned to each group
|
||||
for (std::pair<const unsigned short,Surfaces> &surfaces_with_extra_perimeters : slices)
|
||||
new_slices.append(union_ex(surfaces_with_extra_perimeters.second, true), surfaces_with_extra_perimeters.second.front());
|
||||
}
|
||||
|
||||
// make perimeters
|
||||
SurfaceCollection fill_surfaces;
|
||||
layerm_config->make_perimeters(new_slices, &fill_surfaces);
|
||||
for (LayerRegionPtrs::iterator layerm = m_regions.begin(); layerm != m_regions.end(); ++ layerm)
|
||||
if ((*layerm)->slices.empty()) {
|
||||
(*layerm)->perimeters.clear();
|
||||
(*layerm)->fills.clear();
|
||||
(*layerm)->thin_fills.clear();
|
||||
} else {
|
||||
size_t region_id = layerm - m_regions.begin();
|
||||
if (done[region_id])
|
||||
continue;
|
||||
BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << ", region " << region_id;
|
||||
done[region_id] = true;
|
||||
const PrintRegionConfig &config = (*layerm)->region()->config();
|
||||
|
||||
// find compatible regions
|
||||
LayerRegionPtrs layerms;
|
||||
layerms.push_back(*layerm);
|
||||
for (LayerRegionPtrs::const_iterator it = layerm + 1; it != m_regions.end(); ++it)
|
||||
if (! (*it)->slices.empty()) {
|
||||
LayerRegion* other_layerm = *it;
|
||||
const PrintRegionConfig &other_config = other_layerm->region()->config();
|
||||
if (config.perimeter_extruder == other_config.perimeter_extruder
|
||||
&& config.perimeters == other_config.perimeters
|
||||
&& config.perimeter_speed == other_config.perimeter_speed
|
||||
&& config.external_perimeter_speed == other_config.external_perimeter_speed
|
||||
&& config.gap_fill_speed == other_config.gap_fill_speed
|
||||
&& config.overhangs == other_config.overhangs
|
||||
&& config.opt_serialize("perimeter_extrusion_width") == other_config.opt_serialize("perimeter_extrusion_width")
|
||||
&& config.thin_walls == other_config.thin_walls
|
||||
&& config.external_perimeters_first == other_config.external_perimeters_first
|
||||
&& config.infill_overlap == other_config.infill_overlap)
|
||||
{
|
||||
other_layerm->perimeters.clear();
|
||||
other_layerm->fills.clear();
|
||||
other_layerm->thin_fills.clear();
|
||||
layerms.push_back(other_layerm);
|
||||
done[it - m_regions.begin()] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (layerms.size() == 1) { // optimization
|
||||
(*layerm)->fill_surfaces.surfaces.clear();
|
||||
(*layerm)->make_perimeters((*layerm)->slices, &(*layerm)->fill_surfaces);
|
||||
(*layerm)->fill_expolygons = to_expolygons((*layerm)->fill_surfaces.surfaces);
|
||||
} else {
|
||||
SurfaceCollection new_slices;
|
||||
// Use the region with highest infill rate, as the make_perimeters() function below decides on the gap fill based on the infill existence.
|
||||
LayerRegion *layerm_config = layerms.front();
|
||||
{
|
||||
// group slices (surfaces) according to number of extra perimeters
|
||||
std::map<unsigned short, Surfaces> slices; // extra_perimeters => [ surface, surface... ]
|
||||
for (LayerRegion *layerm : layerms) {
|
||||
for (Surface &surface : layerm->slices.surfaces)
|
||||
slices[surface.extra_perimeters].emplace_back(surface);
|
||||
if (layerm->region()->config().fill_density > layerm_config->region()->config().fill_density)
|
||||
layerm_config = layerm;
|
||||
}
|
||||
// merge the surfaces assigned to each group
|
||||
for (std::pair<const unsigned short,Surfaces> &surfaces_with_extra_perimeters : slices)
|
||||
new_slices.append(union_ex(surfaces_with_extra_perimeters.second, true), surfaces_with_extra_perimeters.second.front());
|
||||
}
|
||||
|
||||
// make perimeters
|
||||
SurfaceCollection fill_surfaces;
|
||||
layerm_config->make_perimeters(new_slices, &fill_surfaces);
|
||||
|
||||
// assign fill_surfaces to each layer
|
||||
if (!fill_surfaces.surfaces.empty()) {
|
||||
for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) {
|
||||
// Separate the fill surfaces.
|
||||
ExPolygons expp = intersection_ex(to_polygons(fill_surfaces), (*l)->slices);
|
||||
(*l)->fill_expolygons = expp;
|
||||
(*l)->fill_surfaces.set(std::move(expp), fill_surfaces.surfaces.front());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// assign fill_surfaces to each layer
|
||||
if (!fill_surfaces.surfaces.empty()) {
|
||||
for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) {
|
||||
// Separate the fill surfaces.
|
||||
ExPolygons expp = intersection_ex(to_polygons(fill_surfaces), (*l)->slices);
|
||||
(*l)->fill_expolygons = expp;
|
||||
(*l)->fill_surfaces.set(std::move(expp), fill_surfaces.surfaces.front());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << " - Done";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
|
|||
// Voids are sparse infills if infill rate is zero.
|
||||
Polygons voids;
|
||||
for (const Surface &surface : this->fill_surfaces.surfaces) {
|
||||
if (surface.surface_type == stTop) {
|
||||
if (surface.is_top()) {
|
||||
// Collect the top surfaces, inflate them and trim them by the bottom surfaces.
|
||||
// This gives the priority to bottom surfaces.
|
||||
surfaces_append(top, offset_ex(surface.expolygon, margin, EXTERNAL_SURFACES_OFFSET_PARAMETERS), surface);
|
||||
|
|
@ -313,7 +313,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
|
|||
s2.clear();
|
||||
}
|
||||
}
|
||||
if (s1.surface_type == stTop)
|
||||
if (s1.is_top())
|
||||
// Trim the top surfaces by the bottom surfaces. This gives the priority to the bottom surfaces.
|
||||
polys = diff(polys, bottom_polygons);
|
||||
surfaces_append(
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public:
|
|||
// last point == first point for polygons
|
||||
const Point& last_point() const override { return this->points.front(); }
|
||||
|
||||
virtual Lines lines() const;
|
||||
Lines lines() const override;
|
||||
Polyline split_at_vertex(const Point &point) const;
|
||||
// Split a closed polygon into an open polyline, with the split point duplicated at both ends.
|
||||
Polyline split_at_index(int index) const;
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ public:
|
|||
const Point& last_point() const override { return this->points.back(); }
|
||||
|
||||
const Point& leftmost_point() const;
|
||||
virtual Lines lines() const;
|
||||
Lines lines() const override;
|
||||
void clip_end(double distance);
|
||||
void clip_start(double distance);
|
||||
void extend_end(double distance);
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|
|||
} else if (
|
||||
opt_key == "skirts"
|
||||
|| opt_key == "skirt_height"
|
||||
|| opt_key == "draft_shield"
|
||||
|| opt_key == "skirt_distance"
|
||||
|| opt_key == "min_skirt_length"
|
||||
|| opt_key == "ooze_prevention"
|
||||
|
|
@ -613,8 +614,12 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||
m_placeholder_parser.set("print_preset", new_full_config.option("print_settings_id")->clone());
|
||||
m_placeholder_parser.set("filament_preset", new_full_config.option("filament_settings_id")->clone());
|
||||
m_placeholder_parser.set("printer_preset", new_full_config.option("printer_settings_id")->clone());
|
||||
// We want the filament overrides to be applied over their respective extruder parameters by the PlaceholderParser.
|
||||
// see "Placeholders do not respect filament overrides." GH issue #3649
|
||||
m_placeholder_parser.apply_config(filament_overrides);
|
||||
// It is also safe to change m_config now after this->invalidate_state_by_config_options() call.
|
||||
m_config.apply_only(new_full_config, print_diff, true);
|
||||
//FIXME use move semantics once ConfigBase supports it.
|
||||
m_config.apply(filament_overrides);
|
||||
// Handle changes to object config defaults
|
||||
m_default_object_config.apply_only(new_full_config, object_diff, true);
|
||||
|
|
@ -1142,14 +1147,12 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||
|
||||
bool Print::has_infinite_skirt() const
|
||||
{
|
||||
return (m_config.skirt_height == -1 && m_config.skirts > 0)
|
||||
|| (m_config.ooze_prevention && this->extruders().size() > 1);
|
||||
return (m_config.draft_shield && m_config.skirts > 0) || (m_config.ooze_prevention && this->extruders().size() > 1);
|
||||
}
|
||||
|
||||
bool Print::has_skirt() const
|
||||
{
|
||||
return (m_config.skirt_height > 0 && m_config.skirts > 0)
|
||||
|| this->has_infinite_skirt();
|
||||
return (m_config.skirt_height > 0 && m_config.skirts > 0) || this->has_infinite_skirt();
|
||||
}
|
||||
|
||||
static inline bool sequential_print_horizontal_clearance_valid(const Print &print)
|
||||
|
|
@ -1621,10 +1624,8 @@ void Print::process()
|
|||
// It is up to the caller to show an error message.
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||
#elif ENABLE_THUMBNAIL_GENERATOR
|
||||
std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||
#else
|
||||
std::string Print::export_gcode(const std::string &path_template, GCodePreviewData *preview_data)
|
||||
std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
{
|
||||
// output everything to a G-code file
|
||||
|
|
@ -1644,10 +1645,8 @@ std::string Print::export_gcode(const std::string &path_template, GCodePreviewDa
|
|||
GCode gcode;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
gcode.do_export(this, path.c_str(), preview_data, result, thumbnail_cb);
|
||||
#elif ENABLE_THUMBNAIL_GENERATOR
|
||||
gcode.do_export(this, path.c_str(), preview_data, thumbnail_cb);
|
||||
#else
|
||||
gcode.do_export(this, path.c_str(), preview_data);
|
||||
gcode.do_export(this, path.c_str(), preview_data, thumbnail_cb);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
return path.c_str();
|
||||
}
|
||||
|
|
@ -1935,8 +1934,8 @@ void Print::_make_brim()
|
|||
for (size_t i = 0; i < loops_trimmed_order.size();) {
|
||||
// Find all pieces that the initial loop was split into.
|
||||
size_t j = i + 1;
|
||||
for (; j < loops_trimmed_order.size() && loops_trimmed_order[i].first == loops_trimmed_order[j].first; ++ j) ;
|
||||
const ClipperLib_Z::Path &first_path = *loops_trimmed_order[i].first;
|
||||
for (; j < loops_trimmed_order.size() && loops_trimmed_order[i].second == loops_trimmed_order[j].second; ++ j) ;
|
||||
const ClipperLib_Z::Path &first_path = *loops_trimmed_order[i].first;
|
||||
if (i + 1 == j && first_path.size() > 3 && first_path.front().X == first_path.back().X && first_path.front().Y == first_path.back().Y) {
|
||||
auto *loop = new ExtrusionLoop();
|
||||
m_brim.entities.emplace_back(loop);
|
||||
|
|
@ -2138,6 +2137,7 @@ std::string Print::output_filename(const std::string &filename_base) const
|
|||
// Set the placeholders for the data know first after the G-code export is finished.
|
||||
// These values will be just propagated into the output file name.
|
||||
DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders();
|
||||
config.set_key_value("num_extruders", new ConfigOptionInt((int)m_config.nozzle_diameter.size()));
|
||||
return this->PrintBase::output_filename(m_config.output_filename_format.value, ".gcode", filename_base, &config);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,9 +11,7 @@
|
|||
#include "Slicing.hpp"
|
||||
#include "GCode/ToolOrdering.hpp"
|
||||
#include "GCode/WipeTower.hpp"
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
#include "GCode/ThumbnailData.hpp"
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#include "GCode/GCodeProcessor.hpp"
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
|
@ -153,15 +151,15 @@ public:
|
|||
Layer* get_layer(int idx) { return m_layers[idx]; }
|
||||
// Get a layer exactly at print_z.
|
||||
const Layer* get_layer_at_printz(coordf_t print_z) const {
|
||||
auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [print_z](const Layer *layer) { return layer->print_z < print_z; });
|
||||
auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [print_z](const Layer *layer) { return layer->print_z < print_z; });
|
||||
return (it == m_layers.end() || (*it)->print_z != print_z) ? nullptr : *it;
|
||||
}
|
||||
Layer* get_layer_at_printz(coordf_t print_z) { return const_cast<Layer*>(std::as_const(*this).get_layer_at_printz(print_z)); }
|
||||
// Get a layer approximately at print_z.
|
||||
const Layer* get_layer_at_printz(coordf_t print_z, coordf_t epsilon) const {
|
||||
coordf_t limit = print_z + epsilon;
|
||||
auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [limit](const Layer *layer) { return layer->print_z < limit; });
|
||||
return (it == m_layers.end() || (*it)->print_z < print_z - epsilon) ? nullptr : *it;
|
||||
coordf_t limit = print_z - epsilon;
|
||||
auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [limit](const Layer *layer) { return layer->print_z < limit; });
|
||||
return (it == m_layers.end() || (*it)->print_z > print_z + epsilon) ? nullptr : *it;
|
||||
}
|
||||
Layer* get_layer_at_printz(coordf_t print_z, coordf_t epsilon) { return const_cast<Layer*>(std::as_const(*this).get_layer_at_printz(print_z, epsilon)); }
|
||||
|
||||
|
|
@ -305,8 +303,8 @@ struct PrintStatistics
|
|||
PrintStatistics() { clear(); }
|
||||
std::string estimated_normal_print_time;
|
||||
std::string estimated_silent_print_time;
|
||||
std::vector<std::string> estimated_normal_color_print_times;
|
||||
std::vector<std::string> estimated_silent_color_print_times;
|
||||
std::vector<std::pair<CustomGcodeType, std::string>> estimated_normal_custom_gcode_print_times;
|
||||
std::vector<std::pair<CustomGcodeType, std::string>> estimated_silent_custom_gcode_print_times;
|
||||
double total_used_filament;
|
||||
double total_extruded_volume;
|
||||
double total_cost;
|
||||
|
|
@ -326,8 +324,8 @@ struct PrintStatistics
|
|||
void clear() {
|
||||
estimated_normal_print_time.clear();
|
||||
estimated_silent_print_time.clear();
|
||||
estimated_normal_color_print_times.clear();
|
||||
estimated_silent_color_print_times.clear();
|
||||
estimated_normal_custom_gcode_print_times.clear();
|
||||
estimated_silent_custom_gcode_print_times.clear();
|
||||
total_used_filament = 0.;
|
||||
total_extruded_volume = 0.;
|
||||
total_cost = 0.;
|
||||
|
|
@ -352,7 +350,7 @@ public:
|
|||
Print() = default;
|
||||
virtual ~Print() { this->clear(); }
|
||||
|
||||
PrinterTechnology technology() const noexcept { return ptFFF; }
|
||||
PrinterTechnology technology() const noexcept override { return ptFFF; }
|
||||
|
||||
// Methods, which change the state of Print / PrintObject / PrintRegion.
|
||||
// The following methods are synchronized with process() and export_gcode(),
|
||||
|
|
@ -369,10 +367,8 @@ public:
|
|||
// If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r).
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
||||
#elif ENABLE_THUMBNAIL_GENERATOR
|
||||
std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
||||
#else
|
||||
std::string export_gcode(const std::string &path_template, GCodePreviewData *preview_data);
|
||||
std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
// methods for handling state
|
||||
|
|
|
|||
|
|
@ -113,6 +113,16 @@ void PrintConfigDef::init_common_params()
|
|||
"If left blank, the default OS CA certificate repository is used.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionString(""));
|
||||
|
||||
def = this->add("elefant_foot_compensation", coFloat);
|
||||
def->label = L("Elephant foot compensation");
|
||||
def->category = L("Advanced");
|
||||
def->tooltip = L("The first layer will be shrunk in the XY plane by the configured value "
|
||||
"to compensate for the 1st layer squish aka an Elephant Foot effect.");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0.2));
|
||||
}
|
||||
|
||||
void PrintConfigDef::init_fff_params()
|
||||
|
|
@ -244,7 +254,7 @@ void PrintConfigDef::init_fff_params()
|
|||
"to clip the overlapping object parts one by the other "
|
||||
"(2nd part will be clipped by the 1st, 3rd part will be clipped by the 1st and 2nd etc).");
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
def->set_default_value(new ConfigOptionBool(true));
|
||||
|
||||
def = this->add("colorprint_heights", coFloats);
|
||||
def->label = L("Colorprint height");
|
||||
|
|
@ -371,16 +381,6 @@ void PrintConfigDef::init_fff_params()
|
|||
def->min = 0;
|
||||
def->set_default_value(new ConfigOptionFloat(6));
|
||||
|
||||
def = this->add("elefant_foot_compensation", coFloat);
|
||||
def->label = L("Elephant foot compensation");
|
||||
def->category = L("Advanced");
|
||||
def->tooltip = L("The first layer will be shrunk in the XY plane by the configured value "
|
||||
"to compensate for the 1st layer squish aka an Elephant Foot effect.");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
|
||||
def = this->add("end_gcode", coString);
|
||||
def->label = L("End G-code");
|
||||
def->tooltip = L("This end procedure is inserted at the end of the output file. "
|
||||
|
|
@ -1691,6 +1691,13 @@ void PrintConfigDef::init_fff_params()
|
|||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionInt(1));
|
||||
|
||||
def = this->add("draft_shield", coBool);
|
||||
def->label = L("Draft shield");
|
||||
def->tooltip = L("If enabled, the skirt will be as tall as a highest printed object. "
|
||||
"This is useful to protect an ABS or ASA print from warping and detaching from print bed due to wind draft.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("skirts", coInt);
|
||||
def->label = L("Loops (minimum)");
|
||||
def->full_label = L("Skirt Loops");
|
||||
|
|
@ -2442,6 +2449,15 @@ void PrintConfigDef::init_sla_params()
|
|||
"to the sign of the correction.");
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionFloat(0.0));
|
||||
|
||||
def = this->add("elefant_foot_min_width", coFloat);
|
||||
def->label = L("Elephant foot minimum width");
|
||||
def->category = L("Advanced");
|
||||
def->tooltip = L("Minimum width of features to maintain when doing elephant foot compensation.");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0.2));
|
||||
|
||||
def = this->add("gamma_correction", coFloat);
|
||||
def->label = L("Printer gamma correction");
|
||||
|
|
@ -2644,6 +2660,16 @@ void PrintConfigDef::init_sla_params()
|
|||
def->max = 15;
|
||||
def->mode = comSimple;
|
||||
def->set_default_value(new ConfigOptionFloat(1.0));
|
||||
|
||||
def = this->add("support_max_bridges_on_pillar", coInt);
|
||||
def->label = L("Max bridges on a pillar");
|
||||
def->tooltip = L(
|
||||
"Maximum number of bridges that can be placed on a pillar. Bridges "
|
||||
"hold support point pinheads and connect to pillars as small branches.");
|
||||
def->min = 0;
|
||||
def->max = 50;
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionInt(3));
|
||||
|
||||
def = this->add("support_pillar_connection_mode", coEnum);
|
||||
def->label = L("Support pillar connection mode");
|
||||
|
|
@ -2840,7 +2866,7 @@ void PrintConfigDef::init_sla_params()
|
|||
def->min = 45;
|
||||
def->max = 90;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(45.0));
|
||||
def->set_default_value(new ConfigOptionFloat(90.0));
|
||||
|
||||
def = this->add("pad_around_object", coBool);
|
||||
def->label = L("Pad around object");
|
||||
|
|
@ -2979,6 +3005,11 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
|
|||
} else if (opt_key == "support_material_pattern" && value == "pillars") {
|
||||
// Slic3r PE does not support the pillars. They never worked well.
|
||||
value = "rectilinear";
|
||||
} else if (opt_key == "skirt_height" && value == "-1") {
|
||||
// PrusaSlicer no more accepts skirt_height == -1 to print a draft shield to the top of the highest object.
|
||||
// A new "draft_shield" boolean config value is used instead.
|
||||
opt_key = "draft_shield";
|
||||
value = "1";
|
||||
} else if (opt_key == "octoprint_host") {
|
||||
opt_key = "print_host";
|
||||
} else if (opt_key == "octoprint_cafile") {
|
||||
|
|
@ -3187,7 +3218,7 @@ std::string FullPrintConfig::validate()
|
|||
return "Invalid value for --infill-every-layers";
|
||||
|
||||
// --skirt-height
|
||||
if (this->skirt_height < -1) // -1 means as tall as the object
|
||||
if (this->skirt_height < 0)
|
||||
return "Invalid value for --skirt-height";
|
||||
|
||||
// --bridge-flow-ratio
|
||||
|
|
|
|||
|
|
@ -800,6 +800,7 @@ public:
|
|||
ConfigOptionBools retract_layer_change;
|
||||
ConfigOptionFloat skirt_distance;
|
||||
ConfigOptionInt skirt_height;
|
||||
ConfigOptionBool draft_shield;
|
||||
ConfigOptionInt skirts;
|
||||
ConfigOptionInts slowdown_below_layer_time;
|
||||
ConfigOptionBool spiral_vase;
|
||||
|
|
@ -872,6 +873,7 @@ protected:
|
|||
OPT_PTR(retract_layer_change);
|
||||
OPT_PTR(skirt_distance);
|
||||
OPT_PTR(skirt_height);
|
||||
OPT_PTR(draft_shield);
|
||||
OPT_PTR(skirts);
|
||||
OPT_PTR(slowdown_below_layer_time);
|
||||
OPT_PTR(spiral_vase);
|
||||
|
|
@ -980,6 +982,9 @@ public:
|
|||
|
||||
// Radius in mm of the support pillars.
|
||||
ConfigOptionFloat support_pillar_diameter /*= 0.8*/;
|
||||
|
||||
// How much bridge (supporting another pinhead) can be placed on a pillar.
|
||||
ConfigOptionInt support_max_bridges_on_pillar;
|
||||
|
||||
// How the pillars are bridged together
|
||||
ConfigOptionEnum<SLAPillarConnectionMode> support_pillar_connection_mode;
|
||||
|
|
@ -1101,6 +1106,7 @@ protected:
|
|||
OPT_PTR(support_head_penetration);
|
||||
OPT_PTR(support_head_width);
|
||||
OPT_PTR(support_pillar_diameter);
|
||||
OPT_PTR(support_max_bridges_on_pillar);
|
||||
OPT_PTR(support_pillar_connection_mode);
|
||||
OPT_PTR(support_buildplate_only);
|
||||
OPT_PTR(support_pillar_widening_factor);
|
||||
|
|
@ -1175,6 +1181,8 @@ public:
|
|||
ConfigOptionBool display_mirror_y;
|
||||
ConfigOptionFloats relative_correction;
|
||||
ConfigOptionFloat absolute_correction;
|
||||
ConfigOptionFloat elefant_foot_compensation;
|
||||
ConfigOptionFloat elefant_foot_min_width;
|
||||
ConfigOptionFloat gamma_correction;
|
||||
ConfigOptionFloat fast_tilt_time;
|
||||
ConfigOptionFloat slow_tilt_time;
|
||||
|
|
@ -1198,6 +1206,8 @@ protected:
|
|||
OPT_PTR(display_orientation);
|
||||
OPT_PTR(relative_correction);
|
||||
OPT_PTR(absolute_correction);
|
||||
OPT_PTR(elefant_foot_compensation);
|
||||
OPT_PTR(elefant_foot_min_width);
|
||||
OPT_PTR(gamma_correction);
|
||||
OPT_PTR(fast_tilt_time);
|
||||
OPT_PTR(slow_tilt_time);
|
||||
|
|
|
|||
|
|
@ -817,11 +817,12 @@ void PrintObject::detect_surfaces_type()
|
|||
m_layers[idx_layer]->m_regions[idx_region]->slices.surfaces = std::move(surfaces_new[idx_layer]);
|
||||
}
|
||||
|
||||
if (spiral_vase && num_layers > 1) {
|
||||
// Turn the last bottom layer infill to a top infill, so it will be extruded with a proper pattern.
|
||||
Surfaces &surfaces = m_layers[num_layers - 1]->m_regions[idx_region]->slices.surfaces;
|
||||
for (Surface &surface : surfaces)
|
||||
surface.surface_type = stTop;
|
||||
if (spiral_vase) {
|
||||
if (num_layers > 1)
|
||||
// Turn the last bottom layer infill to a top infill, so it will be extruded with a proper pattern.
|
||||
m_layers[num_layers - 1]->m_regions[idx_region]->slices.set_type(stTop);
|
||||
for (size_t i = num_layers; i < m_layers.size(); ++ i)
|
||||
m_layers[i]->m_regions[idx_region]->slices.set_type(stInternal);
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << idx_region << " - clipping in parallel - start";
|
||||
|
|
@ -1139,10 +1140,9 @@ void PrintObject::discover_vertical_shells()
|
|||
}
|
||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||
polygons_append(holes, cache_top_botom_regions[idx_layer].holes);
|
||||
{
|
||||
if (int n_top_layers = region_config.top_solid_layers.value; n_top_layers > 0) {
|
||||
// Gather top regions projected to this layer.
|
||||
coordf_t print_z = layer->print_z;
|
||||
int n_top_layers = region_config.top_solid_layers.value;
|
||||
coordf_t print_z = layer->print_z;
|
||||
for (int i = int(idx_layer) + 1;
|
||||
i < int(cache_top_botom_regions.size()) &&
|
||||
(i < int(idx_layer) + n_top_layers ||
|
||||
|
|
@ -1159,10 +1159,9 @@ void PrintObject::discover_vertical_shells()
|
|||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
if (int n_bottom_layers = region_config.bottom_solid_layers.value; n_bottom_layers > 0) {
|
||||
// Gather bottom regions projected to this layer.
|
||||
coordf_t bottom_z = layer->bottom_z();
|
||||
int n_bottom_layers = region_config.bottom_solid_layers.value;
|
||||
coordf_t bottom_z = layer->bottom_z();
|
||||
for (int i = int(idx_layer) - 1;
|
||||
i >= 0 &&
|
||||
(i > int(idx_layer) - n_bottom_layers ||
|
||||
|
|
@ -2356,6 +2355,9 @@ void PrintObject::discover_horizontal_shells()
|
|||
for (size_t idx_surface_type = 0; idx_surface_type < 3; ++ idx_surface_type) {
|
||||
m_print->throw_if_canceled();
|
||||
SurfaceType type = (idx_surface_type == 0) ? stTop : (idx_surface_type == 1) ? stBottom : stBottomBridge;
|
||||
int num_solid_layers = (type == stTop) ? region_config.top_solid_layers.value : region_config.bottom_solid_layers.value;
|
||||
if (num_solid_layers == 0)
|
||||
continue;
|
||||
// Find slices of current type for current layer.
|
||||
// Use slices instead of fill_surfaces, because they also include the perimeter area,
|
||||
// which needs to be propagated in shells; we need to grow slices like we did for
|
||||
|
|
@ -2384,9 +2386,9 @@ void PrintObject::discover_horizontal_shells()
|
|||
// Scatter top / bottom regions to other layers. Scattering process is inherently serial, it is difficult to parallelize without locking.
|
||||
for (int n = (type == stTop) ? int(i) - 1 : int(i) + 1;
|
||||
(type == stTop) ?
|
||||
(n >= 0 && (int(i) - n < region_config.top_solid_layers.value ||
|
||||
(n >= 0 && (int(i) - n < num_solid_layers ||
|
||||
print_z - m_layers[n]->print_z < region_config.top_solid_min_thickness.value - EPSILON)) :
|
||||
(n < int(m_layers.size()) && (n - int(i) < region_config.bottom_solid_layers.value ||
|
||||
(n < int(m_layers.size()) && (n - int(i) < num_solid_layers ||
|
||||
m_layers[n]->bottom_z() - bottom_z < region_config.bottom_solid_min_thickness.value - EPSILON));
|
||||
(type == stTop) ? -- n : ++ n)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -101,6 +101,9 @@ public:
|
|||
|
||||
// Iterates over hits and holes and returns the true hit, possibly
|
||||
// on the inside of a hole.
|
||||
// This function is currently not used anywhere, it was written when the
|
||||
// holes were subtracted on slices, that is, before we started using CGAL
|
||||
// to actually cut the holes into the mesh.
|
||||
hit_result filter_hits(const std::vector<EigenMesh3D::hit_result>& obj_hits) const;
|
||||
|
||||
class si_result {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ const double SupportConfig::max_dual_pillar_height_mm = 35.0;
|
|||
const double SupportConfig::optimizer_rel_score_diff = 1e-6;
|
||||
const unsigned SupportConfig::optimizer_max_iterations = 1000;
|
||||
const unsigned SupportConfig::pillar_cascade_neighbors = 3;
|
||||
const unsigned SupportConfig::max_bridges_on_pillar = 3;
|
||||
|
||||
void SupportTree::retrieve_full_mesh(TriangleMesh &outmesh) const {
|
||||
outmesh.merge(retrieve_mesh(MeshType::Support));
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ struct SupportConfig
|
|||
// body. This is only useful when elevation is set to zero.
|
||||
double pillar_base_safety_distance_mm = 0.5;
|
||||
|
||||
unsigned max_bridges_on_pillar = 3;
|
||||
|
||||
double head_fullwidth() const {
|
||||
return 2 * head_front_radius_mm + head_width_mm +
|
||||
2 * head_back_radius_mm - head_penetration_mm;
|
||||
|
|
@ -103,7 +105,7 @@ struct SupportConfig
|
|||
static const double optimizer_rel_score_diff;
|
||||
static const unsigned optimizer_max_iterations;
|
||||
static const unsigned pillar_cascade_neighbors;
|
||||
static const unsigned max_bridges_on_pillar;
|
||||
|
||||
};
|
||||
|
||||
enum class MeshType { Support, Pad };
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c)
|
|||
c.support_base_safety_distance.getFloat() < EPSILON ?
|
||||
scfg.safety_distance_mm : c.support_base_safety_distance.getFloat();
|
||||
|
||||
scfg.max_bridges_on_pillar = unsigned(c.support_max_bridges_on_pillar.getInt());
|
||||
|
||||
return scfg;
|
||||
}
|
||||
|
||||
|
|
@ -785,6 +787,8 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt
|
|||
"material_correction",
|
||||
"relative_correction",
|
||||
"absolute_correction",
|
||||
"elefant_foot_compensation",
|
||||
"elefant_foot_min_width",
|
||||
"gamma_correction"
|
||||
};
|
||||
|
||||
|
|
@ -944,6 +948,7 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
|
|||
|| opt_key == "support_head_penetration"
|
||||
|| opt_key == "support_head_width"
|
||||
|| opt_key == "support_pillar_diameter"
|
||||
|| opt_key == "support_max_bridges_on_pillar"
|
||||
|| opt_key == "support_pillar_connection_mode"
|
||||
|| opt_key == "support_buildplate_only"
|
||||
|| opt_key == "support_base_diameter"
|
||||
|
|
@ -1087,8 +1092,7 @@ const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
|
|||
|
||||
const ExPolygons &SliceRecord::get_slice(SliceOrigin o) const
|
||||
{
|
||||
size_t idx = o == soModel ? m_model_slices_idx :
|
||||
m_support_slices_idx;
|
||||
size_t idx = o == soModel ? m_model_slices_idx : m_support_slices_idx;
|
||||
|
||||
if(m_po == nullptr) return EMPTY_SLICE;
|
||||
|
||||
|
|
|
|||
|
|
@ -152,6 +152,10 @@ public:
|
|||
}
|
||||
|
||||
const ExPolygons& get_slice(SliceOrigin o) const;
|
||||
size_t get_slice_idx(SliceOrigin o) const
|
||||
{
|
||||
return o == soModel ? m_model_slices_idx : m_support_slices_idx;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
#include <libslic3r/SLA/Pad.hpp>
|
||||
#include <libslic3r/SLA/SupportPointGenerator.hpp>
|
||||
|
||||
#include <libslic3r/ElephantFootCompensation.hpp>
|
||||
|
||||
#include <libslic3r/ClipperUtils.hpp>
|
||||
|
||||
// For geometry algorithms with native Clipper types (no copies and conversions)
|
||||
|
|
@ -78,6 +80,40 @@ SLAPrint::Steps::Steps(SLAPrint *print)
|
|||
, objectstep_scale{(max_objstatus - min_objstatus) / (objcount * 100.0)}
|
||||
{}
|
||||
|
||||
void SLAPrint::Steps::apply_printer_corrections(SLAPrintObject &po, SliceOrigin o)
|
||||
{
|
||||
if (o == soSupport && !po.m_supportdata) return;
|
||||
|
||||
auto faded_lyrs = size_t(po.m_config.faded_layers.getInt());
|
||||
double min_w = m_print->m_printer_config.elefant_foot_min_width.getFloat() / 2.;
|
||||
double start_efc = m_print->m_printer_config.elefant_foot_compensation.getFloat();
|
||||
|
||||
double doffs = m_print->m_printer_config.absolute_correction.getFloat();
|
||||
coord_t clpr_offs = scaled(doffs);
|
||||
|
||||
faded_lyrs = std::min(po.m_slice_index.size(), faded_lyrs);
|
||||
|
||||
auto efc = [start_efc, faded_lyrs](size_t pos) {
|
||||
return (faded_lyrs - 1 - pos) * start_efc / (faded_lyrs - 1);
|
||||
};
|
||||
|
||||
std::vector<ExPolygons> &slices = o == soModel ?
|
||||
po.m_model_slices :
|
||||
po.m_supportdata->support_slices;
|
||||
|
||||
if (clpr_offs != 0) for (size_t i = 0; i < po.m_slice_index.size(); ++i) {
|
||||
size_t idx = po.m_slice_index[i].get_slice_idx(o);
|
||||
if (idx < slices.size())
|
||||
slices[idx] = offset_ex(slices[idx], float(clpr_offs));
|
||||
}
|
||||
|
||||
if (start_efc > 0.) for (size_t i = 0; i < faded_lyrs; ++i) {
|
||||
size_t idx = po.m_slice_index[i].get_slice_idx(o);
|
||||
if (idx < slices.size())
|
||||
slices[idx] = elephant_foot_compensation(slices[idx], min_w, efc(i));
|
||||
}
|
||||
}
|
||||
|
||||
void SLAPrint::Steps::hollow_model(SLAPrintObject &po)
|
||||
{
|
||||
po.m_hollowing_data.reset();
|
||||
|
|
@ -236,20 +272,15 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po)
|
|||
}
|
||||
|
||||
auto mit = slindex_it;
|
||||
double doffs = m_print->m_printer_config.absolute_correction.getFloat();
|
||||
coord_t clpr_offs = scaled(doffs);
|
||||
for(size_t id = 0;
|
||||
for (size_t id = 0;
|
||||
id < po.m_model_slices.size() && mit != po.m_slice_index.end();
|
||||
id++)
|
||||
{
|
||||
// We apply the printer correction offset here.
|
||||
if(clpr_offs != 0)
|
||||
po.m_model_slices[id] =
|
||||
offset_ex(po.m_model_slices[id], float(clpr_offs));
|
||||
|
||||
id++) {
|
||||
mit->set_model_slice_idx(po, id); ++mit;
|
||||
}
|
||||
|
||||
// We apply the printer correction offset here.
|
||||
apply_printer_corrections(po, soModel);
|
||||
|
||||
if(po.m_config.supports_enable.getBool() || po.m_config.pad_enable.getBool())
|
||||
{
|
||||
po.m_supportdata.reset(new SLAPrintObject::SupportData(mesh));
|
||||
|
|
@ -446,21 +477,15 @@ void SLAPrint::Steps::slice_supports(SLAPrintObject &po) {
|
|||
auto heights = reserve_vector<float>(po.m_slice_index.size());
|
||||
|
||||
for(auto& rec : po.m_slice_index) heights.emplace_back(rec.slice_level());
|
||||
|
||||
|
||||
sd->support_slices = sd->support_tree_ptr->slice(
|
||||
heights, float(po.config().slice_closing_radius.value));
|
||||
heights, float(po.config().slice_closing_radius.value));
|
||||
}
|
||||
|
||||
double doffs = m_print->m_printer_config.absolute_correction.getFloat();
|
||||
coord_t clpr_offs = scaled(doffs);
|
||||
|
||||
for (size_t i = 0; i < sd->support_slices.size() && i < po.m_slice_index.size(); ++i) {
|
||||
// We apply the printer correction offset here.
|
||||
if (clpr_offs != 0)
|
||||
sd->support_slices[i] = offset_ex(sd->support_slices[i], float(clpr_offs));
|
||||
|
||||
for (size_t i = 0; i < sd->support_slices.size() && i < po.m_slice_index.size(); ++i)
|
||||
po.m_slice_index[i].set_support_slice_idx(po, i);
|
||||
}
|
||||
|
||||
apply_printer_corrections(po, soSupport);
|
||||
|
||||
// Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update
|
||||
// status to the 3D preview to load the SLA slices.
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ private:
|
|||
bool canceled() const { return m_print->canceled(); }
|
||||
void initialize_printer_input();
|
||||
|
||||
void apply_printer_corrections(SLAPrintObject &po, SliceOrigin o);
|
||||
|
||||
public:
|
||||
Steps(SLAPrint *print);
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ public:
|
|||
void remove_type(const SurfaceType type);
|
||||
void remove_types(const SurfaceType *types, int ntypes);
|
||||
void filter_by_type(SurfaceType type, Polygons* polygons);
|
||||
void set_type(SurfaceType type) {
|
||||
for (Surface &surface : this->surfaces)
|
||||
surface.surface_type = type;
|
||||
}
|
||||
|
||||
void clear() { surfaces.clear(); }
|
||||
bool empty() const { return surfaces.empty(); }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef _technologies_h_
|
||||
#define _technologies_h_
|
||||
#ifndef _prusaslicer_technologies_h_
|
||||
#define _prusaslicer_technologies_h_
|
||||
|
||||
//============
|
||||
// debug techs
|
||||
|
|
@ -17,35 +17,32 @@
|
|||
#define ENABLE_CAMERA_STATISTICS 0
|
||||
// Render the picking pass instead of the main scene (use [T] key to toggle between regular rendering and picking pass only rendering)
|
||||
#define ENABLE_RENDER_PICKING_PASS 0
|
||||
|
||||
|
||||
//====================
|
||||
// 1.42.0.alpha1 techs
|
||||
//====================
|
||||
#define ENABLE_1_42_0_ALPHA1 1
|
||||
|
||||
// Enable extracting thumbnails from selected gcode and save them as png files
|
||||
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG 0
|
||||
// Disable synchronization of unselected instances
|
||||
#define DISABLE_INSTANCES_SYNCH (0 && ENABLE_1_42_0_ALPHA1)
|
||||
#define DISABLE_INSTANCES_SYNCH 0
|
||||
// Use wxDataViewRender instead of wxDataViewCustomRenderer
|
||||
#define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING (0 && ENABLE_1_42_0_ALPHA1)
|
||||
#define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING 0
|
||||
|
||||
|
||||
//====================
|
||||
// 2.2.0.alpha1 techs
|
||||
//====================
|
||||
#define ENABLE_2_2_0_ALPHA1 1
|
||||
//================
|
||||
// 2.2.0.rc1 techs
|
||||
//================
|
||||
#define ENABLE_2_2_0_RC1 1
|
||||
|
||||
// Enable thumbnail generator
|
||||
// When removing this technology, remove it also from stable branch,
|
||||
// where it has been partially copied for patch 2.1.1
|
||||
#define ENABLE_THUMBNAIL_GENERATOR (1 && ENABLE_2_2_0_ALPHA1)
|
||||
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG (0 && ENABLE_THUMBNAIL_GENERATOR)
|
||||
// Enable hack to remove crash when closing on OSX 10.9.5
|
||||
#define ENABLE_HACK_CLOSING_ON_OSX_10_9_5 (1 && ENABLE_2_2_0_RC1)
|
||||
|
||||
|
||||
//==================
|
||||
// 2.2.0.beta1 techs
|
||||
// 2.2.0.final techs
|
||||
//==================
|
||||
#define ENABLE_2_2_0_BETA1 1
|
||||
#define ENABLE_2_2_0_FINAL 1
|
||||
|
||||
// Enable tooltips for GLCanvas3D using ImGUI
|
||||
#define ENABLE_CANVAS_TOOLTIP_USING_IMGUI (1 && ENABLE_2_2_0_FINAL)
|
||||
// Enable fix for dragging mouse event handling for gizmobar
|
||||
#define ENABLE_GIZMO_TOOLBAR_DRAGGING_FIX (1 && ENABLE_2_2_0_FINAL)
|
||||
|
||||
|
||||
//==================
|
||||
|
|
@ -57,4 +54,4 @@
|
|||
#define ENABLE_GCODE_VIEWER (1 && ENABLE_2_3_0_ALPHA1)
|
||||
|
||||
|
||||
#endif // _technologies_h_
|
||||
#endif // _prusaslicer_technologies_h_
|
||||
|
|
|
|||
|
|
@ -64,15 +64,23 @@ extern std::string normalize_utf8_nfc(const char *src);
|
|||
// for a short while, so the file may not be movable. Retry while we see recoverable errors.
|
||||
extern std::error_code rename_file(const std::string &from, const std::string &to);
|
||||
|
||||
enum CopyFileResult {
|
||||
SUCCESS = 0,
|
||||
FAIL_COPY_FILE,
|
||||
FAIL_FILES_DIFFERENT,
|
||||
FAIL_RENAMING,
|
||||
FAIL_CHECK_ORIGIN_NOT_OPENED,
|
||||
FAIL_CHECK_TARGET_NOT_OPENED
|
||||
};
|
||||
// Copy a file, adjust the access attributes, so that the target is writable.
|
||||
int copy_file_inner(const std::string &from, const std::string &to);
|
||||
CopyFileResult copy_file_inner(const std::string &from, const std::string &to);
|
||||
// Copy file to a temp file first, then rename it to the final file name.
|
||||
// If with_check is true, then the content of the copied file is compared to the content
|
||||
// of the source file before renaming.
|
||||
extern int copy_file(const std::string &from, const std::string &to, const bool with_check = false);
|
||||
extern CopyFileResult copy_file(const std::string &from, const std::string &to, const bool with_check = false);
|
||||
|
||||
// Compares two files, returns 0 if identical, -1 if different.
|
||||
extern int check_copy(const std::string& origin, const std::string& copy);
|
||||
// Compares two files if identical.
|
||||
extern CopyFileResult check_copy(const std::string& origin, const std::string& copy);
|
||||
|
||||
// Ignore system and hidden files, which may be created by the DropBox synchronisation process.
|
||||
// https://github.com/prusa3d/PrusaSlicer/issues/1298
|
||||
|
|
|
|||
|
|
@ -98,7 +98,17 @@ extern Semver SEMVER;
|
|||
template<typename T, typename Q>
|
||||
inline T unscale(Q v) { return T(v) * T(SCALING_FACTOR); }
|
||||
|
||||
enum Axis { X=0, Y, Z, E, F, NUM_AXES };
|
||||
enum Axis {
|
||||
X=0,
|
||||
Y,
|
||||
Z,
|
||||
E,
|
||||
F,
|
||||
NUM_AXES,
|
||||
// For the GCodeReader to mark a parsed axis, which is not in "XYZEF", it was parsed correctly.
|
||||
UNKNOWN_AXIS = NUM_AXES,
|
||||
NUM_AXES_WITH_UNKNOWN,
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline void append_to(std::vector<T> &dst, const std::vector<T> &src)
|
||||
|
|
|
|||
|
|
@ -417,7 +417,7 @@ std::error_code rename_file(const std::string &from, const std::string &to)
|
|||
#endif
|
||||
}
|
||||
|
||||
int copy_file_inner(const std::string& from, const std::string& to)
|
||||
CopyFileResult copy_file_inner(const std::string& from, const std::string& to)
|
||||
{
|
||||
const boost::filesystem::path source(from);
|
||||
const boost::filesystem::path target(to);
|
||||
|
|
@ -433,38 +433,40 @@ int copy_file_inner(const std::string& from, const std::string& to)
|
|||
boost::filesystem::permissions(target, perms, ec);
|
||||
boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec);
|
||||
if (ec) {
|
||||
return -1;
|
||||
return FAIL_COPY_FILE;
|
||||
}
|
||||
boost::filesystem::permissions(target, perms, ec);
|
||||
return 0;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int copy_file(const std::string &from, const std::string &to, const bool with_check)
|
||||
CopyFileResult copy_file(const std::string &from, const std::string &to, const bool with_check)
|
||||
{
|
||||
std::string to_temp = to + ".tmp";
|
||||
int ret_val = copy_file_inner(from,to_temp);
|
||||
if(ret_val == 0)
|
||||
CopyFileResult ret_val = copy_file_inner(from,to_temp);
|
||||
if(ret_val == SUCCESS)
|
||||
{
|
||||
if (with_check)
|
||||
ret_val = check_copy(from, to_temp);
|
||||
|
||||
if (ret_val == 0 && rename_file(to_temp, to))
|
||||
ret_val = -3;
|
||||
ret_val = FAIL_RENAMING;
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
int check_copy(const std::string &origin, const std::string ©)
|
||||
CopyFileResult check_copy(const std::string &origin, const std::string ©)
|
||||
{
|
||||
std::ifstream f1(origin, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
|
||||
std::ifstream f2(copy, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
|
||||
boost::nowide::ifstream f1(origin, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
|
||||
boost::nowide::ifstream f2(copy, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
|
||||
|
||||
if (f1.fail() || f2.fail())
|
||||
return -2;
|
||||
if (f1.fail())
|
||||
return FAIL_CHECK_ORIGIN_NOT_OPENED;
|
||||
if (f2.fail())
|
||||
return FAIL_CHECK_TARGET_NOT_OPENED;
|
||||
|
||||
std::streampos fsize = f1.tellg();
|
||||
if (fsize != f2.tellg())
|
||||
return -2;
|
||||
return FAIL_FILES_DIFFERENT;
|
||||
|
||||
f1.seekg(0, std::ifstream::beg);
|
||||
f2.seekg(0, std::ifstream::beg);
|
||||
|
|
@ -481,12 +483,12 @@ int check_copy(const std::string &origin, const std::string ©)
|
|||
if (origin_cnt != copy_cnt ||
|
||||
(origin_cnt > 0 && std::memcmp(buffer_origin.data(), buffer_copy.data(), origin_cnt) != 0))
|
||||
// Files are different.
|
||||
return -2;
|
||||
return FAIL_FILES_DIFFERENT;
|
||||
fsize -= origin_cnt;
|
||||
} while (f1.good() && f2.good());
|
||||
|
||||
// All data has been read and compared equal.
|
||||
return (f1.eof() && f2.eof() && fsize == 0) ? 0 : -2;
|
||||
return (f1.eof() && f2.eof() && fsize == 0) ? SUCCESS : FAIL_FILES_DIFFERENT;
|
||||
}
|
||||
|
||||
// Ignore system and hidden files, which may be created by the DropBox synchronisation process.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue