Skip to content

Commit

Permalink
fixes, fix overextrusion
Browse files Browse the repository at this point in the history
  • Loading branch information
supermerill committed Jan 15, 2024
2 parents 05af3be + b2c3f34 commit ba7290a
Show file tree
Hide file tree
Showing 48 changed files with 1,934 additions and 583 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.13)
project(Slic3r-native)

add_subdirectory(build-utils)
add_subdirectory(test-utils)
add_subdirectory(admesh)
add_subdirectory(avrdude)
# boost/nowide
Expand Down
18 changes: 10 additions & 8 deletions src/libslic3r/Config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1326,7 +1326,7 @@ class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVector<FloatOrPerce
{
if (idx < 0) {
for (const FloatOrPercent &v : this->values)
if (! std::isnan(v.value) || v != NIL_VALUE())
if (!(std::isnan(v.value) || v.value == NIL_VALUE().value || v.value > std::numeric_limits<float>::max()))
return false;
return true;
} else {
Expand All @@ -1344,7 +1344,9 @@ class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVector<FloatOrPerce
double get_float(size_t idx = 0) const override { return get_abs_value(idx, 1.); }

static inline bool is_nil(const boost::any &to_check) {
return std::isnan(boost::any_cast<FloatOrPercent>(to_check).value) || boost::any_cast<FloatOrPercent>(to_check).value == NIL_VALUE().value;
bool ok = std::isnan(boost::any_cast<FloatOrPercent>(to_check).value) || boost::any_cast<FloatOrPercent>(to_check).value == NIL_VALUE().value
|| boost::any_cast<FloatOrPercent>(to_check).value > std::numeric_limits<float>::max();
return ok;
}
// don't use it to compare, use is_nil() to check.
static inline boost::any create_nil() { return boost::any(NIL_VALUE()); }
Expand Down Expand Up @@ -1411,7 +1413,7 @@ class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVector<FloatOrPerce
ss << v.value;
if (v.percent)
ss << "%";
} else if (std::isnan(v.value) || v.value == NIL_VALUE().value) {
} else if (std::isnan(v.value) || v.value == NIL_VALUE().value || v.value > std::numeric_limits<float>::max()) {
if (NULLABLE)
ss << NIL_STR_VALUE;
else
Expand All @@ -1424,8 +1426,8 @@ class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVector<FloatOrPerce
if (v1.size() != v2.size())
return false;
for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end(); ++ it1, ++ it2)
if (!(((std::isnan(it1->value) || it1->value == NIL_VALUE().value) &&
(std::isnan(it2->value) || it2->value == NIL_VALUE().value)) ||
if (!(((std::isnan(it1->value) || it1->value == NIL_VALUE().value || it1->value > std::numeric_limits<float>::max()) &&
(std::isnan(it2->value) || it2->value == NIL_VALUE().value || it1->value > std::numeric_limits<float>::max())) ||
*it1 == *it2))
return false;
return true;
Expand All @@ -1436,8 +1438,8 @@ class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVector<FloatOrPerce
static bool vectors_lower(const std::vector<FloatOrPercent> &v1, const std::vector<FloatOrPercent> &v2) {
if (NULLABLE) {
for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end() && it2 != v2.end(); ++ it1, ++ it2) {
auto null1 = int(std::isnan(it1->value) || it1->value == NIL_VALUE().value);
auto null2 = int(std::isnan(it2->value) || it2->value == NIL_VALUE().value);
auto null1 = int(std::isnan(it1->value) || it1->value == NIL_VALUE().value || it1->value > std::numeric_limits<float>::max());
auto null2 = int(std::isnan(it2->value) || it2->value == NIL_VALUE().value || it1->value > std::numeric_limits<float>::max());
return (null1 < null2) || (null1 == null2 && *it1 < *it2);
}
return v1.size() < v2.size();
Expand Down Expand Up @@ -2320,7 +2322,7 @@ class ConfigBase : public ConfigOptionResolver
// to resolve renamed and removed configuration keys.
bool set_deserialize_nothrow(const t_config_option_key &opt_key_src, const std::string &value_src, ConfigSubstitutionContext& substitutions, bool append = false);
// May throw BadOptionTypeException() if the operation fails.
void set_deserialize(const t_config_option_key &opt_key, const std::string &str, ConfigSubstitutionContext& config_substitutions, bool append = false);
void set_deserialize(const t_config_option_key &opt_key, const std::string &str, ConfigSubstitutionContext& config_substitutions = ConfigSubstitutionContext(ForwardCompatibilitySubstitutionRule::Disable), bool append = false);
void set_deserialize_strict(const t_config_option_key &opt_key, const std::string &str, bool append = false)
{ ConfigSubstitutionContext ctxt{ ForwardCompatibilitySubstitutionRule::Disable }; this->set_deserialize(opt_key, str, ctxt, append); }
struct SetDeserializeItem {
Expand Down
2 changes: 2 additions & 0 deletions src/libslic3r/Extruder.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef slic3r_Extruder_hpp_
#define slic3r_Extruder_hpp_

#include <optional>

#include "libslic3r.h"
#include "Point.hpp"

Expand Down
75 changes: 64 additions & 11 deletions src/libslic3r/ExtrusionEntity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,58 +378,111 @@ ExtrusionRole ExtrusionEntity::string_to_role(const std::string_view role)
else
return erNone;
}


std::string role_to_code(ExtrusionRole role)
{
switch (role) {
case erNone : return L("None");
case erPerimeter : return L("IPeri");
case erExternalPerimeter : return L("EPeri");
case erOverhangPerimeter : return L("OPeri");
case erInternalInfill : return L("IFill");
case erSolidInfill : return L("SFill");
case erTopSolidInfill : return L("TFill");
case erIroning : return L("Iron");
case erBridgeInfill : return L("EBridge");
case erInternalBridgeInfill : return L("IBridge");
case erThinWall : return L("ThinW");
case erGapFill : return L("GFill");
case erSkirt : return L("Skirt");
case erSupportMaterial : return L("Supp");
case erSupportMaterialInterface : return L("SuppI");
case erWipeTower : return L("WTower");
case erMilling : return L("Mill");
case erCustom : return L("Custom");
case erMixed : return L("Mixed");
case erTravel : return L("Travel");
default : assert(false);
}

return "";
}


std::string looprole_to_code(ExtrusionLoopRole looprole)
{
std::string code;
if(elrDefault == (looprole & elrDefault))
code += std::string("D");
if(elrInternal == (looprole & elrInternal))
code += std::string("Int");
if(elrSkirt == (looprole & elrSkirt))
code += std::string("Skirt");
if(elrHole == (looprole & elrHole))
code += std::string("Hole");
if(elrVase == (looprole & elrVase))
code += std::string("Vase");
if(elrFirstLoop == (looprole & elrFirstLoop))
code += std::string("First");

return code;
}

void ExtrusionPrinter::use(const ExtrusionPath &path) {
ss << "ExtrusionPath:" << (uint16_t)path.role() << "{";
ss << (json?"\"":"") << "ExtrusionPath" << (path.can_reverse()?"":"Oriented") << (json?"_":":") << role_to_code(path.role()) << (json?"\":":"") << "[";
for (int i = 0; i < path.polyline.size(); i++) {
if (i != 0) ss << ",";
double x = (mult * (path.polyline.get_points()[i].x()));
double y = (mult * (path.polyline.get_points()[i].y()));
ss << std::fixed << "{"<<(trunc?(int)x:x) << "," << (trunc ? (int)y : y) <<"}";
ss << std::fixed << "["<<(trunc>0?(int(x*trunc))/double(trunc):x) << "," << (trunc>0?(int(y*trunc))/double(trunc):y) <<"]";
}
ss << "}";
ss << "]";
}
void ExtrusionPrinter::use(const ExtrusionPath3D &path3D) {
ss << "ExtrusionPath3D:" << (uint16_t)path3D.role() << "{";
ss << (json?"\"":"") << "ExtrusionPath3D" << (path3D.can_reverse()?"":"Oriented") << (json?"_":":") << role_to_code(path3D.role()) << (json?"\":":"") << "[";
for (int i = 0; i < path3D.polyline.size();i++){
if (i != 0) ss << ",";
double x = (mult * (path3D.polyline.get_points()[i].x()));
double y = (mult * (path3D.polyline.get_points()[i].y()));
double z = (path3D.z_offsets.size() > i ? mult * (path3D.z_offsets[i]) : -1);
ss << std::fixed << "{" << (trunc ? (int)x : x) << "," << (trunc ? (int)y : y) << "," << (trunc ? (int)z : z) << "}";
ss << std::fixed << "[" << (trunc>0?(int(x*trunc))/double(trunc):x) << "," << (trunc>0?(int(y*trunc))/double(trunc):y) << "," << (trunc>0?(int(z*trunc))/double(trunc):z) << "]";
}
ss << "}";
ss << "]";
}
void ExtrusionPrinter::use(const ExtrusionMultiPath &multipath) {
ss << "ExtrusionMultiPath:" << (uint16_t)multipath.role() << "{";
ss << (json?"\"":"") << "ExtrusionMultiPath" << (multipath.can_reverse()?"":"Oriented") << (json?"_":":") << role_to_code(multipath.role()) << (json?"\":":"") << "{";
for (int i = 0; i < multipath.paths.size(); i++) {
if (i != 0) ss << ",";
multipath.paths[i].visit(*this);
}
ss << "}";
}
void ExtrusionPrinter::use(const ExtrusionMultiPath3D &multipath3D) {
ss << "multipath3D:" << (uint16_t)multipath3D.role() << "{";
ss << (json?"\"":"") << "multipath3D" << (multipath3D.can_reverse()?"":"Oriented") << (json?"_":":") << role_to_code(multipath3D.role()) << (json?"\":":"") << "{";
for (int i = 0; i < multipath3D.paths.size(); i++) {
if (i != 0) ss << ",";
multipath3D.paths[i].visit(*this);
}
ss << "}";
}
void ExtrusionPrinter::use(const ExtrusionLoop &loop) {
ss << "ExtrusionLoop:" << (uint16_t)loop.role()<<":" <<(uint16_t)loop.loop_role()<<"{";
ss << (json?"\"":"") << "ExtrusionLoop" << (json?"_":":") << role_to_code(loop.role())<<"_" << looprole_to_code(loop.loop_role()) << (json?"\":":"") << "{";
if(!loop.can_reverse()) ss << (json?"\"":"") << "oriented" << (json?"\":":"=") << "true,";
for (int i = 0; i < loop.paths.size(); i++) {
if (i != 0) ss << ",";
loop.paths[i].visit(*this);
}
ss << "}";
}
void ExtrusionPrinter::use(const ExtrusionEntityCollection &collection) {
ss << "ExtrusionEntityCollection:" << (uint16_t)collection.role() << "{";
ss << (json?"\"":"") << "ExtrusionEntityCollection" << (json?"_":":") << role_to_code(collection.role()) << (json?"\":":"") << "{";
if(!collection.can_sort()) ss << (json?"\"":"") << "no_sort" << (json?"\":":"=") << "true,";
if(!collection.can_reverse()) ss << (json?"\"":"") << "oriented" << (json?"\":":"=") << "true,";
for (int i = 0; i < collection.entities().size(); i++) {
if (i != 0) ss << ",";
collection.entities()[i]->visit(*this);
}
if(!collection.can_sort()) ss<<", no_sort=true";
ss << "}";
}

Expand Down
5 changes: 3 additions & 2 deletions src/libslic3r/ExtrusionEntity.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,9 +628,10 @@ inline void extrusion_entities_append_loops_and_paths(ExtrusionEntitiesPtr &dst,
class ExtrusionPrinter : public ExtrusionVisitorConst {
std::stringstream ss;
double mult;
bool trunc;
int trunc;
bool json;
public:
ExtrusionPrinter(double mult = 0.0001, bool trunc = false) : mult(mult), trunc(trunc) { }
ExtrusionPrinter(double mult = 0.000001, int trunc = 0, bool json = false) : mult(mult), trunc(trunc), json(json) { }
virtual void use(const ExtrusionPath& path) override;
virtual void use(const ExtrusionPath3D& path3D) override;
virtual void use(const ExtrusionMultiPath& multipath) override;
Expand Down
9 changes: 8 additions & 1 deletion src/libslic3r/Fill/Fill.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,14 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:

//give the overlap size to let the infill do his overlap
//add overlap if at least one perimeter
const float perimeter_spacing = layerm->flow(frPerimeter).spacing();
float perimeter_spacing = 0;
if(layerm->region().config().perimeters == 1)
perimeter_spacing = layerm->flow(frExternalPerimeter).spacing();
else if(layerm->region().config().only_one_perimeter_top)
//note: use the min of the two to avoid overextrusion if only one perimeter top
perimeter_spacing = std::min(layerm->flow(frPerimeter).spacing(), layerm->flow(frExternalPerimeter).spacing());
else //if(layerm->region().config().perimeters > 1)
perimeter_spacing = layerm->flow(frPerimeter).spacing();

// Used by the concentric infill pattern to clip the loops to create extrusion paths.
f->loop_clipping = scale_t(layerm->region().config().get_computed_value("seam_gap", surface_fill.params.extruder - 1) * surface_fill.params.flow.nozzle_diameter());
Expand Down
12 changes: 1 addition & 11 deletions src/libslic3r/Fill/FillBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,17 +167,7 @@ double Fill::compute_unscaled_volume_to_fill(const Surface* surface, const FillP
} else {
for (const ExPolygon& poly : intersection_ex(ExPolygons{ surface->expolygon }, this->no_overlap_expolygons)) {
polyline_volume += params.flow.height() * unscaled(unscaled(poly.area()));
double perimeter_gap_usage = params.config->perimeter_overlap.get_abs_value(1);
// add external "perimeter gap"
//TODO: use filament_max_overlap to reduce it
//double filament_max_overlap = params.config->get_computed_value("filament_max_overlap", params.extruder - 1);
double perimeter_round_gap = unscaled(poly.contour.length()) * params.flow.height() * (1 - 0.25 * PI) * 0.5;
// add holes "perimeter gaps"
double holes_gaps = 0;
for (auto hole = poly.holes.begin(); hole != poly.holes.end(); ++hole) {
holes_gaps += unscaled(hole->length()) * params.flow.height() * (1 - 0.25 * PI) * 0.5;
}
polyline_volume += (perimeter_round_gap + holes_gaps) * perimeter_gap_usage;
//note: the no_overlap_expolygons is already at spacing from the centerline of the perimeter.
}
}
return polyline_volume;
Expand Down
2 changes: 2 additions & 0 deletions src/libslic3r/Fill/FillBase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ class Fill
ExPolygon /* expolygon */,
Polylines & /* polylines_out */) const {
BOOST_LOG_TRIVIAL(error)<<"Error, the fill isn't implemented";
assert(false);
};

// Used for concentric infill to generate ThickPolylines using Arachne.
Expand All @@ -182,6 +183,7 @@ class Fill
ExPolygon expolygon,
ThickPolylines &thick_polylines_out) const {
BOOST_LOG_TRIVIAL(error) << "Error, the arachne fill isn't implemented";
assert(false);
};

virtual float _layer_angle(size_t idx) const { return can_angle_cross && (idx & 1) ? float(M_PI/2.) : 0; }
Expand Down
4 changes: 2 additions & 2 deletions src/libslic3r/Flow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,12 +526,12 @@ float Flow::rounded_rectangle_extrusion_spacing(float width, float height, float
#endif
}

float Flow::rounded_rectangle_extrusion_width_from_spacing(float spacing, float height, float m_spacing_ratio)
float Flow::rounded_rectangle_extrusion_width_from_spacing(float spacing, float height, float spacing_ratio)
{
#ifdef HAS_PERIMETER_LINE_OVERLAP
return (spacing + PERIMETER_LINE_OVERLAP_FACTOR * height * (1. - 0.25 * PI) * spacing_ratio);
#else
return float(spacing + height * (1. - 0.25 * PI) * m_spacing_ratio);
return float(spacing + height * (1. - 0.25 * PI) * spacing_ratio);
#endif
}

Expand Down
1 change: 1 addition & 0 deletions src/libslic3r/Format/STL.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace Slic3r {

class TriangleMesh;
class ModelObject;
class Model;

// Load an STL file into a provided model.
extern bool load_stl(const char *path, Model *model, const char *object_name = nullptr);
Expand Down
Loading

0 comments on commit ba7290a

Please sign in to comment.