Skip to content

Commit

Permalink
fixes, fix overextrusion, arachne with brim
Browse files Browse the repository at this point in the history
  • Loading branch information
supermerill committed Jan 15, 2024
2 parents dcada9f + dee60bb commit b6d41ca
Show file tree
Hide file tree
Showing 62 changed files with 2,236 additions and 722 deletions.
10 changes: 5 additions & 5 deletions resources/data/hints.ini
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
# Settings highlight (like search feature)
# hypertext_type = settings
# hypertext_settings_opt = name_of_settings (hover over settings value and copy last line of hover text)
# hypertext_settings_type = 1 (1 - 5 according to settings tab - to be channged to name of tabs instead of numbers)
# hypertext_settings_type = print ( {print, filament, sla_print, sla_material, printer} according to settings tab)
# hypertext_settings_category = Infill (name of panel - written on left in settings)
#
# Plater top toolbar highlight
Expand Down Expand Up @@ -67,7 +67,7 @@
text = Fuzzy skin\nDid you know that you can create rough fibre-like texture on the sides of your models using the<a>Fuzzy skin</a>feature? You can also use modifiers to apply fuzzy-skin only to a portion of your model.
hypertext_type = settings
hypertext_settings_opt = fuzzy_skin
hypertext_settings_type = 1
hypertext_settings_type = print
hypertext_settings_category = Layers and perimeters
disabled_tags = SLA

Expand Down Expand Up @@ -118,7 +118,7 @@ text = Set number of instances\nDid you know that you can right-click a model an
text = Combine infill\nDid you know that you can print the infill with a higher layer height compared to perimeters to save print time using the setting<a>Combine infill every</a>.
hypertext_type = settings
hypertext_settings_opt = infill_every_layers
hypertext_settings_type = 1
hypertext_settings_type = print
hypertext_settings_category = Infill
disabled_tags = SLA; simple

Expand All @@ -142,7 +142,7 @@ disabled_tags = SLA
text = Solid infill threshold area\nDid you know that you can make parts of your model with a small cross-section be filled with solid infill automatically? Set the<a>Solid infill threshold area</a>. (Expert mode only.)
hypertext_type = settings
hypertext_settings_opt = solid_infill_below_area
hypertext_settings_type = 1
hypertext_settings_type = print
hypertext_settings_category = Infill
enabled_tags = FFF; expert

Expand Down Expand Up @@ -207,7 +207,7 @@ hypertext_menubar_item_name = &Configuration Snapshots
text = Minimum shell thickness\nDid you know that instead of the number of top and bottom layers, you can define the<a>Minimum shell thickness</a>in millimeters? This feature is especially useful when using the variable layer height function.
hypertext_type = settings
hypertext_settings_opt = top_solid_min_thickness
hypertext_settings_type = 1
hypertext_settings_type = print
hypertext_settings_category = Layers and perimeters
disabled_tags = SLA

Expand Down
2 changes: 1 addition & 1 deletion resources/ui_layout/default/print.ui
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ group:sidetext_width$5:Infill angle
end_line
line:Modifiers
setting:label_width$6:width$5:label$increment:fill_angle_increment
setting:label_width$6:width$5:label$increment:fill_angle_cross
setting:width$5:fill_angle_cross
vector_line:fill_angle_template
# setting:fill_angle_template
group:sidetext_width$5:Advanced
Expand Down
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
4 changes: 4 additions & 0 deletions src/libslic3r/Arachne/utils/ExtrusionLine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,10 @@ static inline Slic3r::ThickPolyline to_thick_polyline(const ClipperLib_Z::Path &
out.points_width.emplace_back(it->z());
}
}
assert(out.points.front().x() == path.front().x());
assert(out.points.front().y() == path.front().y());
assert(out.points.back().x() == path.back().x());
assert(out.points.back().y() == path.back().y());
return out;
}

Expand Down
20 changes: 13 additions & 7 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 @@ -2321,6 +2323,10 @@ class ConfigBase : public ConfigOptionResolver
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){ //for tests
ConfigSubstitutionContext no_context(ForwardCompatibilitySubstitutionRule::Disable);
set_deserialize(opt_key, str, no_context);
}
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
5 changes: 5 additions & 0 deletions src/libslic3r/ExtrusionEntityCollection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ class ExtrusionEntityCollection : public ExtrusionEntity
return *this;
}
~ExtrusionEntityCollection() override { clear(); }
// move all entitites from src into this
void append_move_from(ExtrusionEntityCollection &src) {
m_entities.insert(m_entities.end(), src.m_entities.begin(), src.m_entities.end());
src.m_entities.clear();
}

/// Operator to convert and flatten this collection to a single vector of ExtrusionPaths.
explicit operator ExtrusionPaths() const;
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
Loading

0 comments on commit b6d41ca

Please sign in to comment.