Merge remote-tracking branch 'remotes/remi/CI' into dev

in particular, move the repetier stuff to physicalprinter
This commit is contained in:
supermerill 2020-10-27 17:52:46 +01:00
commit 160b509a46
39 changed files with 782 additions and 174 deletions

View File

@ -1,13 +1,8 @@
### Version ### Version
_Version of SupserSlicer used goes here_ _Version of SupserSlicer used goes here, Use `About->About SuperSlicer`_
_Use `About->About SuperSlicer` for release versions_
_For -dev versions, use `git describe --tag` or get the hash value for the version you downloaded or `git rev-parse HEAD`_
### Operating system type + version ### Operating system type + version
_What OS are you using, and state any version #s_ _What OS are you using (and version)_
_In case of 3D rendering issues, please attach the content of menu Help -> System Info dialog_
### 3D printer brand / version + firmware version (if known) ### 3D printer brand / version + firmware version (if known)
_What 3D printer brand / version are you printing on, is it a stock model or did you modify the printer, what firmware is running on your printer, version of the firmware #s_ _What 3D printer brand / version are you printing on, is it a stock model or did you modify the printer, what firmware is running on your printer, version of the firmware #s_
@ -20,7 +15,5 @@ _What 3D printer brand / version are you printing on, is it a stock model or did
* _Actual Results_ * _Actual Results_
* _Screenshots from __*SuperSlicer*__ preview are preferred_ * _Screenshots from __*SuperSlicer*__ preview are preferred_
_Is this a new feature request?_
#### Project File (.3MF) where problem occurs #### Project File (.3MF) where problem occurs
_Upload a SuperSlicer Project File (.3MF) (`Plater -> Export plate as 3MF` for Slic3r PE 1.41.2 and older, `File -> Save` / `Save Project` for SuperSlicer, Slic3r PE 1.42.0-alpha and newer)_ _Upload a SuperSlicer Project File (.3MF) (`File -> Save` / `Save Project`)_

View File

@ -35,7 +35,7 @@ This calibration will help you to choose the right retraction length for your ex
<h3>Remove filament slowdown</h3> <h3>Remove filament slowdown</h3>
This button will change your settings in filament/cooling to disable all features that trigger when a layer is too small to be able to cool down in time. With these algorithms disabled, your print will be more challenging in terms of retraction, so it's a good stress test. To re-enable them, remove all modifications from the filament tab (the little orange 'back arrow"). This button will change your settings in filament/cooling to disable all features that trigger when a layer is too small to be able to cool down in time. With these algorithms disabled, your print will be more challenging in terms of retraction, so it's a good stress test. To re-enable them, remove all modifications from the filament tab (the little orange 'back arrow").
<h3>Results</h3> <h3>Results</h3>
<p>When the test pieces are printed, you can count the millimetre with the ridges on the sides of the print towers. I count them with my nail. When you're at the height where there are no more strings, you can write down the millimetre number. Multiply it by your step parameter (0.2, 0.2, 0.5 or 1) and you have your retraction length number. You can add 20% more length to have a little margin.</p> <p>When the test pieces are printed, you can count the millimetre with the ridges on the sides of the print towers. I count them with my nail. When you're at the height where there are no more strings, you can write down the millimetre number. Multiply it by your step parameter (0.1, 0.2, 0.5 or 1) and you have your retraction length number. You can add 20% more length to have a little margin.</p>
<p>If you have multiple prints with different temperatures, you need to choose the best print, the one with the least amount of stringing, unless the decrease in stringing isn't big enough to warrant the decrease in temperature. <p>If you have multiple prints with different temperatures, you need to choose the best print, the one with the least amount of stringing, unless the decrease in stringing isn't big enough to warrant the decrease in temperature.
<h2>Example</h2> <h2>Example</h2>
<table width="100%"> <table width="100%">

View File

@ -40,9 +40,9 @@ group:Quality
setting:thin_walls_merge setting:thin_walls_merge
end_line end_line
group:Overhangs group:Overhangs
line:On perimeters line:threshold for
setting:sidetext_width$1:overhangs setting:label$bridge speed and fan:width$5:overhangs_width_speed
setting:width$5:overhangs_width setting:label$bridge flow:width$5:overhangs_width
end_line end_line
line:Extrusion direction line:Extrusion direction
setting:sidetext_width$1:overhangs_reverse setting:sidetext_width$1:overhangs_reverse
@ -202,7 +202,6 @@ group:label_width$8:Speed for print moves
line:Perimeter speed line:Perimeter speed
setting:width$4:perimeter_speed setting:width$4:perimeter_speed
setting:width$4:external_perimeter_speed setting:width$4:external_perimeter_speed
setting:width$4:small_perimeter_speed
end_line end_line
line:Infill speed line:Infill speed
setting:width$4:infill_speed setting:width$4:infill_speed
@ -228,6 +227,10 @@ group:Modifiers
setting:label_width$8:width$4:first_layer_speed setting:label_width$8:width$4:first_layer_speed
setting:label_width$8:width$4:first_layer_infill_speed setting:label_width$8:width$4:first_layer_infill_speed
end_line end_line
line:Small perimeter speed
setting:label_width$8:width$4:small_perimeter_min_length
setting:label_width$8:width$4:small_perimeter_max_length
setting:label_width$8:width$4:small_perimeter_speed
group:Acceleration control (advanced) group:Acceleration control (advanced)
setting:perimeter_acceleration setting:perimeter_acceleration
setting:infill_acceleration setting:infill_acceleration

View File

@ -598,7 +598,8 @@ Fill::do_gap_fill(const ExPolygons &gapfill_areas, const FillParams &params, Ext
// offset2_ex(gapfill_areas, double(-max / 2), double(+max / 2)), // offset2_ex(gapfill_areas, double(-max / 2), double(+max / 2)),
// true); // true);
ExPolygons gapfill_areas_collapsed = offset2_ex(gapfill_areas, double(-min / 2), double(+min / 2)); ExPolygons gapfill_areas_collapsed = offset2_ex(gapfill_areas, double(-min / 2), double(+min / 2));
const double minarea = scale_(params.config->gap_fill_min_area.get_abs_value(params.flow.width) ) * params.flow.scaled_width(); double minarea = params.flow.scaled_width() * params.flow.scaled_width();
if (params.config != nullptr) minarea = scale_(params.config->gap_fill_min_area.get_abs_value(params.flow.width)) * params.flow.scaled_width();
for (const ExPolygon &ex : gapfill_areas_collapsed) { for (const ExPolygon &ex : gapfill_areas_collapsed) {
//remove too small gaps that are too hard to fill. //remove too small gaps that are too hard to fill.
//ie one that are smaller than an extrusion with width of min and a length of max. //ie one that are smaller than an extrusion with width of min and a length of max.
@ -620,10 +621,10 @@ Fill::do_gap_fill(const ExPolygons &gapfill_areas, const FillParams &params, Ext
ExtrusionEntityCollection gap_fill = thin_variable_width(polylines_gapfill, erGapFill, params.flow); ExtrusionEntityCollection gap_fill = thin_variable_width(polylines_gapfill, erGapFill, params.flow);
//set role if needed //set role if needed
if (params.role != erSolidInfill) { /*if (params.role != erSolidInfill) {
ExtrusionSetRole set_good_role(params.role); ExtrusionSetRole set_good_role(params.role);
gap_fill.visit(set_good_role); gap_fill.visit(set_good_role);
} }*/
//move them into the collection //move them into the collection
if (!gap_fill.entities.empty()) { if (!gap_fill.entities.empty()) {
ExtrusionEntityCollection *coll_gapfill = new ExtrusionEntityCollection(); ExtrusionEntityCollection *coll_gapfill = new ExtrusionEntityCollection();

View File

@ -174,7 +174,8 @@ FillConcentricWGapFill::fill_surface_extrusion(
ExPolygons gapfill_areas = diff_ex({ surface->expolygon }, offset_ex(expp, double(scale_(0.5 * this->get_spacing())))); ExPolygons gapfill_areas = diff_ex({ surface->expolygon }, offset_ex(expp, double(scale_(0.5 * this->get_spacing()))));
gapfill_areas = union_ex(gapfill_areas, true); gapfill_areas = union_ex(gapfill_areas, true);
if (gapfill_areas.size() > 0) { if (gapfill_areas.size() > 0) {
const double minarea = scale_(params.config->gap_fill_min_area.get_abs_value(params.flow.width)) * params.flow.scaled_width(); double minarea = params.flow.scaled_width() * params.flow.scaled_width();
if (params.config != nullptr) minarea = scale_(params.config->gap_fill_min_area.get_abs_value(params.flow.width)) * params.flow.scaled_width();
for (int i = 0; i < gapfill_areas.size(); i++) { for (int i = 0; i < gapfill_areas.size(); i++) {
if (gapfill_areas[i].area() < minarea) { if (gapfill_areas[i].area() < minarea) {
gapfill_areas.erase(gapfill_areas.begin() + i); gapfill_areas.erase(gapfill_areas.begin() + i);

View File

@ -1490,7 +1490,6 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
print.throw_if_canceled(); print.throw_if_canceled();
m_cooling_buffer->set_current_extruder(initial_extruder_id); m_cooling_buffer->set_current_extruder(initial_extruder_id);
m_writer.toolchange(initial_extruder_id);
// Emit machine envelope limits for the Marlin firmware. // Emit machine envelope limits for the Marlin firmware.
this->print_machine_envelope(file, print); this->print_machine_envelope(file, print);
@ -1498,7 +1497,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
// Disable fan. // Disable fan.
if ( print.config().disable_fan_first_layers.get_at(initial_extruder_id) if ( print.config().disable_fan_first_layers.get_at(initial_extruder_id)
&& config().gcode_flavor != gcfKlipper) && config().gcode_flavor != gcfKlipper)
_write(file, m_writer.set_fan(0, true)); _write(file, m_writer.set_fan(0, true, initial_extruder_id));
// Let the start-up script prime the 1st printing tool. // Let the start-up script prime the 1st printing tool.
m_placeholder_parser.set("initial_tool", initial_extruder_id); m_placeholder_parser.set("initial_tool", initial_extruder_id);
@ -1946,7 +1945,7 @@ void GCode::print_machine_envelope(FILE *file, Print &print)
int(print.config().machine_max_acceleration_z.values.front() + 0.5), int(print.config().machine_max_acceleration_z.values.front() + 0.5),
int(print.config().machine_max_acceleration_e.values.front() + 0.5)); int(print.config().machine_max_acceleration_e.values.front() + 0.5));
if (std::set<uint8_t>{gcfRepetier}.count(print.config().gcode_flavor.value) > 0) if (std::set<uint8_t>{gcfRepetier}.count(print.config().gcode_flavor.value) > 0)
fprintf(file, "M202 X%d Y%d ; sets maximum travel speed\n", fprintf(file, "M202 X%d Y%d ; sets maximum travel acceleration\n",
int(print.config().machine_max_acceleration_travel.values.front() + 0.5), int(print.config().machine_max_acceleration_travel.values.front() + 0.5),
int(print.config().machine_max_acceleration_travel.values.front() + 0.5)); int(print.config().machine_max_acceleration_travel.values.front() + 0.5));
if (std::set<uint8_t>{gcfMarlin, gcfLerdge, gcfRepetier, gcfRepRap, gcfSmoothie, gcfSprinter}.count(print.config().gcode_flavor.value) > 0) if (std::set<uint8_t>{gcfMarlin, gcfLerdge, gcfRepetier, gcfRepRap, gcfSmoothie, gcfSprinter}.count(print.config().gcode_flavor.value) > 0)
@ -2400,7 +2399,6 @@ void GCode::process_layer(
// In single extruder multi material mode, set the temperature for the current extruder only. // In single extruder multi material mode, set the temperature for the current extruder only.
continue; continue;
int temperature = print.config().temperature.get_at(extruder.id()); int temperature = print.config().temperature.get_at(extruder.id());
if (temperature > 0 && temperature != print.config().first_layer_temperature.get_at(extruder.id()))
gcode += m_writer.set_temperature(temperature, false, extruder.id()); gcode += m_writer.set_temperature(temperature, false, extruder.id());
} }
gcode += m_writer.set_bed_temperature(print.config().bed_temperature.get_at(first_extruder_id)); gcode += m_writer.set_bed_temperature(print.config().bed_temperature.get_at(first_extruder_id));
@ -2698,6 +2696,9 @@ void GCode::process_layer(
this->set_origin(unscale(offset)); this->set_origin(unscale(offset));
if (instance_to_print.object_by_extruder.support != nullptr && !print_wipe_extrusions) { if (instance_to_print.object_by_extruder.support != nullptr && !print_wipe_extrusions) {
m_layer = layers[instance_to_print.layer_id].support_layer; m_layer = layers[instance_to_print.layer_id].support_layer;
if (m_layer != nullptr && m_layer->bottom_z() < EPSILON)
gcode += m_writer.set_temperature(m_config.first_layer_temperature.get_at(m_writer.tool()->id()), false, m_writer.tool()->id());
else
gcode += m_writer.set_temperature(m_config.temperature.get_at(m_writer.tool()->id()), false, m_writer.tool()->id()); gcode += m_writer.set_temperature(m_config.temperature.get_at(m_writer.tool()->id()), false, m_writer.tool()->id());
gcode += this->extrude_support( gcode += this->extrude_support(
// support_extrusion_role is erSupportMaterial, erSupportMaterialInterface or erMixed for all extrusion paths. // support_extrusion_role is erSupportMaterial, erSupportMaterialInterface or erMixed for all extrusion paths.
@ -2861,7 +2862,8 @@ void GCode::append_full_config(const Print &print, std::string &str)
"compatible_prints", "compatible_prints",
"print_host", "print_host",
"printhost_apikey", "printhost_apikey",
"printhost_cafile" "printhost_cafile",
"printhost_slug"
}; };
assert(std::is_sorted(banned_keys.begin(), banned_keys.end())); assert(std::is_sorted(banned_keys.begin(), banned_keys.end()));
auto is_banned = [banned_keys](const std::string &key) { auto is_banned = [banned_keys](const std::string &key) {
@ -2985,8 +2987,16 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s
if (paths.empty()) return ""; if (paths.empty()) return "";
// apply the small/external? perimeter speed // apply the small/external? perimeter speed
if (is_perimeter(paths.front().role()) && loop.length() <= SMALL_PERIMETER_LENGTH && speed == -1) if (speed == -1 && is_perimeter(paths.front().role()) && loop.length() <=
speed = m_config.external_perimeter_speed.get_abs_value(m_config.perimeter_speed); scale_(this->m_config.small_perimeter_max_length.get_abs_value(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)))) {
double min_length = scale_(this->m_config.small_perimeter_min_length.get_abs_value(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)));
double max_length = scale_(this->m_config.small_perimeter_max_length.get_abs_value(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)));
if (loop.length() <= min_length) {
speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed);
} else {
speed = - (loop.length() - min_length) / (max_length - min_length);
}
}
//get extrusion length //get extrusion length
coordf_t length = 0; coordf_t length = 0;
@ -3295,8 +3305,16 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
if (paths.empty()) return ""; if (paths.empty()) return "";
// apply the small perimeter speed // apply the small perimeter speed
if (is_perimeter(paths.front().role()) && loop.length() <= SMALL_PERIMETER_LENGTH && speed == -1) if (speed == -1 && is_perimeter(paths.front().role()) && loop.length() <=
scale_(this->m_config.small_perimeter_max_length.get_abs_value(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)))) {
double min_length = scale_(this->m_config.small_perimeter_min_length.get_abs_value(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)));
double max_length = scale_(this->m_config.small_perimeter_max_length.get_abs_value(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)));
if (loop.length() <= min_length) {
speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed); speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed);
} else {
speed = -(loop.length() - min_length) / (max_length - min_length);
}
}
// extrude along the path // extrude along the path
std::string gcode; std::string gcode;
@ -3574,6 +3592,8 @@ std::string GCode::extrude_perimeters(const Print &print, const std::vector<Obje
m_writer.apply_print_region_config(print.regions()[&region - &by_region.front()]->config()); m_writer.apply_print_region_config(print.regions()[&region - &by_region.front()]->config());
if (m_config.print_temperature > 0) if (m_config.print_temperature > 0)
gcode += m_writer.set_temperature(m_config.print_temperature.value, false, m_writer.tool()->id()); gcode += m_writer.set_temperature(m_config.print_temperature.value, false, m_writer.tool()->id());
else if (m_layer != nullptr && m_layer->bottom_z() < EPSILON)
gcode += m_writer.set_temperature(m_config.first_layer_temperature.get_at(m_writer.tool()->id()), false, m_writer.tool()->id());
else else
gcode += m_writer.set_temperature(m_config.temperature.get_at(m_writer.tool()->id()), false, m_writer.tool()->id()); gcode += m_writer.set_temperature(m_config.temperature.get_at(m_writer.tool()->id()), false, m_writer.tool()->id());
for (const ExtrusionEntity *ee : region.perimeters) for (const ExtrusionEntity *ee : region.perimeters)
@ -3600,6 +3620,8 @@ std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectBy
m_writer.apply_print_region_config(print.regions()[&region - &by_region.front()]->config()); m_writer.apply_print_region_config(print.regions()[&region - &by_region.front()]->config());
if (m_config.print_temperature > 0) if (m_config.print_temperature > 0)
gcode += m_writer.set_temperature(m_config.print_temperature.value, false, m_writer.tool()->id()); gcode += m_writer.set_temperature(m_config.print_temperature.value, false, m_writer.tool()->id());
else if(m_layer!=nullptr && m_layer->bottom_z() < EPSILON)
gcode += m_writer.set_temperature(m_config.first_layer_temperature.get_at(m_writer.tool()->id()), false, m_writer.tool()->id());
else else
gcode += m_writer.set_temperature(m_config.temperature.get_at(m_writer.tool()->id()), false, m_writer.tool()->id()); gcode += m_writer.set_temperature(m_config.temperature.get_at(m_writer.tool()->id()), false, m_writer.tool()->id());
ExtrusionEntitiesPtr extrusions { region.infills }; ExtrusionEntitiesPtr extrusions { region.infills };
@ -3745,7 +3767,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string &descri
double e_per_mm = path.mm3_per_mm double e_per_mm = path.mm3_per_mm
* m_writer.tool()->e_per_mm3() * m_writer.tool()->e_per_mm3()
* this->config().print_extrusion_multiplier.get_abs_value(1); * this->config().print_extrusion_multiplier.get_abs_value(1);
if (std::abs(this->m_layer->height - this->m_layer->print_z) < EPSILON) e_per_mm *= this->config().first_layer_flow_ratio.get_abs_value(1); if (m_layer->bottom_z() < EPSILON) e_per_mm *= this->config().first_layer_flow_ratio.get_abs_value(1);
if (m_writer.extrusion_axis().empty()) e_per_mm = 0; if (m_writer.extrusion_axis().empty()) e_per_mm = 0;
if (path.polyline.lines().size() > 0) { if (path.polyline.lines().size() > 0) {
//get last direction //TODO: save it //get last direction //TODO: save it
@ -3889,7 +3911,10 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string
// set speed // set speed
if (speed == -1) { if (speed < 0) {
//if speed == -1, then it's means "choose yourself, but if it's -1 < speed <0 , then it's a scaling from small_periemter.
//it's a bit hacky, so if you want to rework it, help yourself.
float factor = (-speed);
if (path.role() == erPerimeter) { if (path.role() == erPerimeter) {
speed = m_config.get_abs_value("perimeter_speed"); speed = m_config.get_abs_value("perimeter_speed");
} else if (path.role() == erExternalPerimeter) { } else if (path.role() == erExternalPerimeter) {
@ -3915,6 +3940,12 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string
} else { } else {
throw Slic3r::InvalidArgument("Invalid speed"); throw Slic3r::InvalidArgument("Invalid speed");
} }
//don't modify bridge speed
if (factor < 1 && !(path.role() == erOverhangPerimeter || path.role() == erBridgeInfill)) {
float small_speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed);
//apply factor between feature speed and small speed
speed = speed * factor + (1 - factor) * small_speed;
}
} }
if (m_volumetric_speed != 0. && speed == 0) if (m_volumetric_speed != 0. && speed == 0)
speed = m_volumetric_speed / path.mm3_per_mm; speed = m_volumetric_speed / path.mm3_per_mm;

View File

@ -31,6 +31,44 @@ void GCodeWriter::apply_print_region_config(const PrintRegionConfig& print_regio
config_region = &print_region_config; config_region = &print_region_config;
} }
std::vector<uint16_t> GCodeWriter::extruder_ids() const {
std::vector<uint16_t> out;
out.reserve(m_extruders.size());
for (const Extruder& e : m_extruders)
out.push_back(e.id());
return out;
}
std::vector<uint16_t> GCodeWriter::mill_ids() const {
std::vector<uint16_t> out;
out.reserve(m_millers.size());
for (const Tool& e : m_millers)
out.push_back(e.id());
return out;
}
uint16_t GCodeWriter::first_mill() const {
if (m_millers.empty()) {
uint16_t max = 0;
for (const Extruder& e : m_extruders)
max = std::max(max, e.id());
max++;
return (uint16_t)max;
} else return m_millers.front().id();
}
bool GCodeWriter::tool_is_extruder() const {
return m_tool->id() < first_mill();
}
const Tool* GCodeWriter::get_tool(uint16_t id) const{
for (const Extruder& e : m_extruders)
if (id == e.id())
return &e;
for (const Tool& e : m_millers)
if (id == e.id())
return &e;
return nullptr;
}
void GCodeWriter::set_extruders(std::vector<uint16_t> extruder_ids) void GCodeWriter::set_extruders(std::vector<uint16_t> extruder_ids)
{ {
std::sort(extruder_ids.begin(), extruder_ids.end()); std::sort(extruder_ids.begin(), extruder_ids.end());
@ -89,12 +127,16 @@ std::string GCodeWriter::postamble() const
std::string GCodeWriter::set_temperature(const unsigned int temperature, bool wait, int tool) std::string GCodeWriter::set_temperature(const unsigned int temperature, bool wait, int tool)
{ {
//use m_tool if tool isn't set
if (tool < 0 && m_tool != nullptr)
tool = m_tool->id();
//add offset //add offset
int16_t temp_w_offset = int16_t(temperature); int16_t temp_w_offset = int16_t(temperature);
temp_w_offset += int16_t(m_tool->temp_offset()); temp_w_offset += int16_t(get_tool(tool)->temp_offset());
temp_w_offset = std::max(int16_t(0), std::min(int16_t(2000), temp_w_offset)); temp_w_offset = std::max(int16_t(0), std::min(int16_t(2000), temp_w_offset));
if (m_last_temperature_with_offset == temp_w_offset) if (m_last_temperature_with_offset == temp_w_offset && !wait)
return ""; return "";
if (wait && (FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish))) if (wait && (FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish)))
return ""; return "";
@ -177,13 +219,15 @@ std::string GCodeWriter::set_bed_temperature(unsigned int temperature, bool wait
return gcode.str(); return gcode.str();
} }
std::string GCodeWriter::set_fan(const unsigned int speed, bool dont_save) std::string GCodeWriter::set_fan(const unsigned int speed, bool dont_save, uint16_t default_tool)
{ {
std::ostringstream gcode; std::ostringstream gcode;
const Tool *tool = m_tool == nullptr ? get_tool(default_tool) : m_tool;
//add fan_offset //add fan_offset
int16_t fan_speed = int16_t(speed); int16_t fan_speed = int16_t(speed);
fan_speed += int8_t(m_tool->fan_offset()); if (tool != nullptr)
fan_speed += int8_t(tool->fan_offset());
fan_speed = std::max(int16_t(0), std::min(int16_t(100), fan_speed)); fan_speed = std::max(int16_t(0), std::min(int16_t(100), fan_speed));
//test if it's useful to write it //test if it's useful to write it

View File

@ -34,41 +34,21 @@ public:
// Extruders are expected to be sorted in an increasing order. // Extruders are expected to be sorted in an increasing order.
void set_extruders(std::vector<uint16_t> extruder_ids); void set_extruders(std::vector<uint16_t> extruder_ids);
const std::vector<Extruder>& extruders() const { return m_extruders; } const std::vector<Extruder>& extruders() const { return m_extruders; }
std::vector<uint16_t> extruder_ids() const { std::vector<uint16_t> extruder_ids() const;
std::vector<uint16_t> out;
out.reserve(m_extruders.size());
for (const Extruder& e : m_extruders)
out.push_back(e.id());
return out;
}
void set_mills(std::vector<uint16_t> extruder_ids); void set_mills(std::vector<uint16_t> extruder_ids);
const std::vector<Mill>& mills() const { return m_millers; } const std::vector<Mill>& mills() const { return m_millers; }
std::vector<uint16_t> mill_ids() const { std::vector<uint16_t> mill_ids() const;
std::vector<uint16_t> out;
out.reserve(m_millers.size());
for (const Tool& e : m_millers)
out.push_back(e.id());
return out;
}
//give the first mill id or an id after the last extruder. Can be used to see if an id is an extruder or a mill //give the first mill id or an id after the last extruder. Can be used to see if an id is an extruder or a mill
uint16_t first_mill() const { uint16_t first_mill() const;
if (m_millers.empty()) { bool tool_is_extruder() const;
uint16_t max = 0; const Tool* get_tool(uint16_t id) const;
for (const Extruder& e : m_extruders)
max = std::max(max, e.id());
max++;
return (uint16_t)max;
}else return m_millers.front().id();
}
bool tool_is_extruder() const {
return m_tool->id() < first_mill();
}
std::string preamble(); std::string preamble();
std::string postamble() const; std::string postamble() const;
std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1); std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1);
std::string set_bed_temperature(unsigned int temperature, bool wait = false); std::string set_bed_temperature(unsigned int temperature, bool wait = false);
unsigned int get_fan() { return m_last_fan_speed; } unsigned int get_fan() { return m_last_fan_speed; }
std::string set_fan(unsigned int speed, bool dont_save = false); /// set fan at speed. Save it as current fan speed if !dont_save, and use tool default_tool if the internal m_tool is null (no toolchange done yet).
std::string set_fan(unsigned int speed, bool dont_save = false, uint16_t default_tool = 0);
void set_acceleration(unsigned int acceleration); void set_acceleration(unsigned int acceleration);
std::string write_acceleration(); std::string write_acceleration();
std::string reset_e(bool force = false); std::string reset_e(bool force = false);

View File

@ -153,7 +153,7 @@ void Layer::make_perimeters()
&& config.infill_dense_algo == other_config.infill_dense_algo && config.infill_dense_algo == other_config.infill_dense_algo
&& config.no_perimeter_unsupported_algo == other_config.no_perimeter_unsupported_algo && config.no_perimeter_unsupported_algo == other_config.no_perimeter_unsupported_algo
&& config.only_one_perimeter_top == other_config.only_one_perimeter_top && config.only_one_perimeter_top == other_config.only_one_perimeter_top
&& config.overhangs == other_config.overhangs && config.overhangs_width_speed == other_config.overhangs_width_speed
&& config.overhangs_width == other_config.overhangs_width && config.overhangs_width == other_config.overhangs_width
&& config.overhangs_reverse == other_config.overhangs_reverse && config.overhangs_reverse == other_config.overhangs_reverse
&& config.overhangs_reverse_threshold == other_config.overhangs_reverse_threshold && config.overhangs_reverse_threshold == other_config.overhangs_reverse_threshold
@ -163,6 +163,8 @@ void Layer::make_perimeters()
&& config.perimeter_overlap == other_config.perimeter_overlap && config.perimeter_overlap == other_config.perimeter_overlap
&& config.perimeter_speed == other_config.perimeter_speed // it os mandatory? can't this be set at gcode.cpp? && config.perimeter_speed == other_config.perimeter_speed // it os mandatory? can't this be set at gcode.cpp?
&& config.small_perimeter_speed == other_config.small_perimeter_speed && config.small_perimeter_speed == other_config.small_perimeter_speed
&& config.small_perimeter_min_length == other_config.small_perimeter_min_length
&& config.small_perimeter_max_length == other_config.small_perimeter_max_length
&& config.thin_walls == other_config.thin_walls && config.thin_walls == other_config.thin_walls
&& config.thin_walls_min_width == other_config.thin_walls_min_width && config.thin_walls_min_width == other_config.thin_walls_min_width
&& config.thin_walls_overlap == other_config.thin_walls_overlap && config.thin_walls_overlap == other_config.thin_walls_overlap

View File

@ -97,12 +97,16 @@ void PerimeterGenerator::process()
coord_t ext_min_spacing = (coord_t)( ext_perimeter_spacing2 * (1 - 0.05/*INSET_OVERLAP_TOLERANCE*/) ); coord_t ext_min_spacing = (coord_t)( ext_perimeter_spacing2 * (1 - 0.05/*INSET_OVERLAP_TOLERANCE*/) );
// prepare grown lower layer slices for overhang detection // prepare grown lower layer slices for overhang detection
if (this->lower_slices != NULL && this->config->overhangs) { if (this->lower_slices != NULL && this->config->overhangs_width > 0) {
// We consider overhang any part where the entire nozzle diameter is not supported by the // We consider overhang any part where the entire nozzle diameter is not supported by the
// lower layer, so we take lower slices and offset them by half the nozzle diameter used // lower layer, so we take lower slices and offset them by overhangs_width of the nozzle diameter used
// in the current layer // in the current layer
double offset_val = double(scale_(config->overhangs_width.get_abs_value(nozzle_diameter))) - (float)(ext_perimeter_width / 2); double offset_val = double(scale_(config->overhangs_width.get_abs_value(nozzle_diameter))) - (float)(ext_perimeter_width / 2);
this->_lower_slices_p = offset(*this->lower_slices, offset_val); this->_lower_slices_bridge_flow = offset(*this->lower_slices, offset_val);
}
if (this->lower_slices != NULL && this->config->overhangs_width_speed > 0) {
double offset_val = double(scale_(config->overhangs_width_speed.get_abs_value(nozzle_diameter))) - (float)(ext_perimeter_width / 2);
this->_lower_slices_bridge_speed = offset(*this->lower_slices, offset_val);
} }
// have to grown the perimeters if mill post-process // have to grown the perimeters if mill post-process
@ -942,6 +946,69 @@ void PerimeterGenerator::process()
} // for each island } // for each island
} }
template<typename LINE>
ExtrusionPaths PerimeterGenerator::create_overhangs(LINE loop_polygons, ExtrusionRole role, bool is_external) const {
ExtrusionPaths paths;
double nozzle_diameter = this->print_config->nozzle_diameter.get_at(this->config->perimeter_extruder - 1);
if (this->config->overhangs_width.get_abs_value(nozzle_diameter) > this->config->overhangs_width_speed.get_abs_value(nozzle_diameter)) {
// get non-overhang paths by intersecting this loop with the grown lower slices
extrusion_paths_append(
paths,
intersection_pl(loop_polygons, this->_lower_slices_bridge_speed),
role,
is_external ? this->_ext_mm3_per_mm : this->_mm3_per_mm,
is_external ? this->ext_perimeter_flow.width : this->perimeter_flow.width,
(float)this->layer->height);
// get overhang paths by checking what parts of this loop fall
// outside the grown lower slices
Polylines poly_speed = diff_pl(loop_polygons, this->_lower_slices_bridge_speed);
extrusion_paths_append(
paths,
intersection_pl(poly_speed, this->_lower_slices_bridge_flow),
erOverhangPerimeter,
is_external ? this->_ext_mm3_per_mm : this->_mm3_per_mm,
is_external ? this->ext_perimeter_flow.width : this->perimeter_flow.width,
(float)this->layer->height);
extrusion_paths_append(
paths,
diff_pl(poly_speed, this->_lower_slices_bridge_flow),
erOverhangPerimeter,
this->_mm3_per_mm_overhang,
this->overhang_flow.width,
this->overhang_flow.height);
} else {
// get non-overhang paths by intersecting this loop with the grown lower slices
extrusion_paths_append(
paths,
intersection_pl(loop_polygons, this->_lower_slices_bridge_flow),
role,
is_external ? this->_ext_mm3_per_mm : this->_mm3_per_mm,
is_external ? this->ext_perimeter_flow.width : this->perimeter_flow.width,
(float)this->layer->height);
// get overhang paths by checking what parts of this loop fall
// outside the grown lower slices
extrusion_paths_append(
paths,
diff_pl(loop_polygons, this->_lower_slices_bridge_flow),
erOverhangPerimeter,
this->_mm3_per_mm_overhang,
this->overhang_flow.width,
this->overhang_flow.height);
}
// reapply the nearest point search for starting point
// We allow polyline reversal because Clipper may have randomly reversed polylines during clipping.
if(!paths.empty())
chain_and_reorder_extrusion_paths(paths, &paths.front().first_point());
return paths;
}
ExtrusionEntityCollection PerimeterGenerator::_traverse_loops( ExtrusionEntityCollection PerimeterGenerator::_traverse_loops(
const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const
{ {
@ -971,31 +1038,9 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops(
// detect overhanging/bridging perimeters // detect overhanging/bridging perimeters
ExtrusionPaths paths; ExtrusionPaths paths;
if (this->config->overhangs && this->layer->id() > 0 if ( this->config->overhangs_width_speed > 0 && this->layer->id() > 0
&& !(this->object_config->support_material && this->object_config->support_material_contact_distance_type.value == zdNone)) { && !(this->object_config->support_material && this->object_config->support_material_contact_distance_type.value == zdNone)) {
// get non-overhang paths by intersecting this loop with the grown lower slices paths = this->create_overhangs(loop.polygon, role, is_external);
extrusion_paths_append(
paths,
intersection_pl(loop.polygon, this->_lower_slices_p),
role,
is_external ? this->_ext_mm3_per_mm : this->_mm3_per_mm,
is_external ? this->ext_perimeter_flow.width : this->perimeter_flow.width,
(float) this->layer->height);
// get overhang paths by checking what parts of this loop fall
// outside the grown lower slices (thus where the distance between
// the loop centerline and original lower slices is >= half nozzle diameter
extrusion_paths_append(
paths,
diff_pl(loop.polygon, this->_lower_slices_p),
erOverhangPerimeter,
this->_mm3_per_mm_overhang,
this->overhang_flow.width,
this->overhang_flow.height);
// reapply the nearest point search for starting point
// We allow polyline reversal because Clipper may have randomly reversed polylines during clipping.
chain_and_reorder_extrusion_paths(paths, &paths.front().first_point());
} else { } else {
ExtrusionPath path(role); ExtrusionPath path(role);
path.polyline = loop.polygon.split_at_first_point(); path.polyline = loop.polygon.split_at_first_point();
@ -1423,35 +1468,9 @@ PerimeterGenerator::_extrude_and_cut_loop(const PerimeterGeneratorLoop &loop, co
} }
// detect overhanging/bridging perimeters // detect overhanging/bridging perimeters
if (this->config->overhangs && this->layer->id() > 0 if ( this->config->overhangs_width_speed > 0 && this->layer->id() > 0
&& !(this->object_config->support_material && this->object_config->support_material_contact_distance_type.value == zdNone)) { && !(this->object_config->support_material && this->object_config->support_material_contact_distance_type.value == zdNone)) {
ExtrusionPaths paths; ExtrusionPaths paths = this->create_overhangs(initial_polyline, role, is_external);
// get non-overhang paths by intersecting this loop with the grown lower slices
extrusion_paths_append(
paths,
intersection_pl(initial_polyline, this->_lower_slices_p),
role,
is_external ? this->_ext_mm3_per_mm : this->_mm3_per_mm,
is_external ? this->ext_perimeter_flow.width : this->perimeter_flow.width,
(float) this->layer->height);
// get overhang paths by checking what parts of this loop fall
// outside the grown lower slices (thus where the distance between
// the loop centerline and original lower slices is >= half nozzle diameter
extrusion_paths_append(
paths,
diff_pl(initial_polyline, this->_lower_slices_p),
erOverhangPerimeter,
this->_mm3_per_mm_overhang,
this->overhang_flow.width,
this->overhang_flow.height);
// reapply the nearest point search for starting point
// We allow polyline reversal because Clipper may have randomly
// reversed polylines during clipping.
if (!paths.empty())
chain_and_reorder_extrusion_paths(paths, &paths.front().first_point());
if (direction.length() > 0) { if (direction.length() > 0) {
Polyline direction_polyline; Polyline direction_polyline;

View File

@ -96,7 +96,11 @@ private:
double _ext_mm3_per_mm; double _ext_mm3_per_mm;
double _mm3_per_mm; double _mm3_per_mm;
double _mm3_per_mm_overhang; double _mm3_per_mm_overhang;
Polygons _lower_slices_p; Polygons _lower_slices_bridge_flow;
Polygons _lower_slices_bridge_speed;
template<typename LINE>
ExtrusionPaths create_overhangs(LINE loop_polygons, ExtrusionRole role, bool is_external) const;
// transform loops into ExtrusionEntityCollection, adding also thin walls into it. // transform loops into ExtrusionEntityCollection, adding also thin walls into it.
ExtrusionEntityCollection _traverse_loops(const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const; ExtrusionEntityCollection _traverse_loops(const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const;

View File

@ -442,8 +442,9 @@ const std::vector<std::string>& Preset::print_options()
"avoid_crossing_perimeters", "avoid_crossing_perimeters",
"avoid_crossing_not_first_layer", "avoid_crossing_not_first_layer",
"thin_perimeters", "thin_perimeters_all", "thin_perimeters", "thin_perimeters_all",
"thin_walls", "overhangs", "thin_walls",
"overhangs_width", "overhangs_width",
"overhangs_width_speed",
"overhangs_reverse", "overhangs_reverse",
"overhangs_reverse_threshold", "overhangs_reverse_threshold",
"seam_position", "seam_position",
@ -475,7 +476,11 @@ const std::vector<std::string>& Preset::print_options()
"max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative", "max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative",
#endif /* HAS_PRESSURE_EQUALIZER */ #endif /* HAS_PRESSURE_EQUALIZER */
"min_width_top_surface", "min_width_top_surface",
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "infill_speed", "solid_infill_speed", "perimeter_speed",
"small_perimeter_speed",
"small_perimeter_min_length",
"small_perimeter_max_length",
"external_perimeter_speed", "infill_speed", "solid_infill_speed",
"top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed", "top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed",
"bridge_speed", "bridge_speed",
"gap_fill", "gap_fill",
@ -639,7 +644,7 @@ const std::vector<std::string>& Preset::printer_options()
"bed_shape", "bed_custom_texture", "bed_custom_model", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed", "bed_shape", "bed_custom_texture", "bed_custom_model", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed",
"use_firmware_retraction", "use_volumetric_e", "variable_layer_height", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
"min_length", "min_length",
"host_type", "print_host", "printhost_apikey", "printhost_cafile", "host_type", "print_host", "printhost_apikey", "printhost_cafile", "printhost_slug",
"single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode", "single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
"color_change_gcode", "pause_print_gcode", "template_custom_gcode", "feature_gcode", "color_change_gcode", "pause_print_gcode", "template_custom_gcode", "feature_gcode",
@ -776,7 +781,7 @@ const std::vector<std::string>& Preset::sla_printer_options()
"gamma_correction", "gamma_correction",
"min_exposure_time", "max_exposure_time", "min_exposure_time", "max_exposure_time",
"min_initial_exposure_time", "max_initial_exposure_time", "min_initial_exposure_time", "max_initial_exposure_time",
"print_host", "printhost_apikey", "printhost_cafile", "print_host", "printhost_apikey", "printhost_cafile", "printhost_slug",
"printer_notes", "printer_notes",
"inherits", "inherits",
"thumbnails", "thumbnails",
@ -909,15 +914,18 @@ static ProfileHostParams profile_host_params_same_or_anonymized(const DynamicPri
auto opt_print_host_old = cfg_old.option<ConfigOptionString>("print_host"); auto opt_print_host_old = cfg_old.option<ConfigOptionString>("print_host");
auto opt_printhost_apikey_old = cfg_old.option<ConfigOptionString>("printhost_apikey"); auto opt_printhost_apikey_old = cfg_old.option<ConfigOptionString>("printhost_apikey");
auto opt_printhost_cafile_old = cfg_old.option<ConfigOptionString>("printhost_cafile"); auto opt_printhost_cafile_old = cfg_old.option<ConfigOptionString>("printhost_cafile");
auto opt_printhost_slug_old = cfg_old.option<ConfigOptionString>("printhost_slug");
auto opt_print_host_new = cfg_new.option<ConfigOptionString>("print_host"); auto opt_print_host_new = cfg_new.option<ConfigOptionString>("print_host");
auto opt_printhost_apikey_new = cfg_new.option<ConfigOptionString>("printhost_apikey"); auto opt_printhost_apikey_new = cfg_new.option<ConfigOptionString>("printhost_apikey");
auto opt_printhost_cafile_new = cfg_new.option<ConfigOptionString>("printhost_cafile"); auto opt_printhost_cafile_new = cfg_new.option<ConfigOptionString>("printhost_cafile");
auto opt_printhost_slug_new = cfg_new.option<ConfigOptionString>("printhost_slug");
// If the new print host data is undefined, use the old data. // If the new print host data is undefined, use the old data.
bool new_print_host_undefined = (opt_print_host_new == nullptr || opt_print_host_new ->empty()) && bool new_print_host_undefined = (opt_print_host_new == nullptr || opt_print_host_new ->empty()) &&
(opt_printhost_apikey_new == nullptr || opt_printhost_apikey_new ->empty()) && (opt_printhost_apikey_new == nullptr || opt_printhost_apikey_new ->empty()) &&
(opt_printhost_cafile_new == nullptr || opt_printhost_cafile_new ->empty()); (opt_printhost_cafile_new == nullptr || opt_printhost_cafile_new ->empty()) &&
(opt_printhost_slug_new == nullptr || opt_printhost_slug_new ->empty());
if (new_print_host_undefined) if (new_print_host_undefined)
return ProfileHostParams::Anonymized; return ProfileHostParams::Anonymized;
@ -926,7 +934,8 @@ static ProfileHostParams profile_host_params_same_or_anonymized(const DynamicPri
(l != nullptr && r != nullptr && l->value == r->value); (l != nullptr && r != nullptr && l->value == r->value);
}; };
return (opt_same(opt_print_host_old, opt_print_host_new) && opt_same(opt_printhost_apikey_old, opt_printhost_apikey_new) && return (opt_same(opt_print_host_old, opt_print_host_new) && opt_same(opt_printhost_apikey_old, opt_printhost_apikey_new) &&
opt_same(opt_printhost_cafile_old, opt_printhost_cafile_new)) ? ProfileHostParams::Same : ProfileHostParams::Different; opt_same(opt_printhost_cafile_old, opt_printhost_cafile_new) && opt_same(opt_printhost_slug_old, opt_printhost_slug_new))
? ProfileHostParams::Same : ProfileHostParams::Different;
} }
static bool profile_print_params_same(const DynamicPrintConfig &cfg_old, const DynamicPrintConfig &cfg_new) static bool profile_print_params_same(const DynamicPrintConfig &cfg_old, const DynamicPrintConfig &cfg_new)
@ -938,7 +947,7 @@ static bool profile_print_params_same(const DynamicPrintConfig &cfg_old, const D
"compatible_printers", "compatible_printers_condition", "inherits", "compatible_printers", "compatible_printers_condition", "inherits",
"print_settings_id", "filament_settings_id", "sla_print_settings_id", "sla_material_settings_id", "printer_settings_id", "print_settings_id", "filament_settings_id", "sla_print_settings_id", "sla_material_settings_id", "printer_settings_id",
"printer_model", "printer_variant", "default_print_profile", "default_filament_profile", "default_sla_print_profile", "default_sla_material_profile", "printer_model", "printer_variant", "default_print_profile", "default_filament_profile", "default_sla_print_profile", "default_sla_material_profile",
"print_host", "printhost_apikey", "printhost_cafile" }) "print_host", "printhost_apikey", "printhost_slug", "printhost_cafile" })
diff.erase(std::remove(diff.begin(), diff.end(), key), diff.end()); diff.erase(std::remove(diff.begin(), diff.end(), key), diff.end());
// Preset with the same name as stored inside the config exists. // Preset with the same name as stored inside the config exists.
return diff.empty() && profile_host_params_same_or_anonymized(cfg_old, cfg_new) != ProfileHostParams::Different; return diff.empty() && profile_host_params_same_or_anonymized(cfg_old, cfg_new) != ProfileHostParams::Different;
@ -988,6 +997,7 @@ Preset& PresetCollection::load_external_preset(
opt_update("print_host"); opt_update("print_host");
opt_update("printhost_apikey"); opt_update("printhost_apikey");
opt_update("printhost_cafile"); opt_update("printhost_cafile");
opt_update("printhost_slug");
} }
} }
// Update the "inherits" field. // Update the "inherits" field.
@ -1567,6 +1577,7 @@ const std::vector<std::string>& PhysicalPrinter::printer_options()
"print_host", "print_host",
"printhost_apikey", "printhost_apikey",
"printhost_cafile", "printhost_cafile",
"printhost_slug",
"printhost_authorization_type", "printhost_authorization_type",
// HTTP digest authentization (RFC 2617) // HTTP digest authentization (RFC 2617)
"printhost_user", "printhost_user",
@ -1583,7 +1594,8 @@ const std::vector<std::string>& PhysicalPrinter::print_host_options()
s_opts = { s_opts = {
"print_host", "print_host",
"printhost_apikey", "printhost_apikey",
"printhost_cafile" "printhost_cafile",
"printhost_slug"
}; };
} }
return s_opts; return s_opts;
@ -1619,7 +1631,8 @@ bool PhysicalPrinter::has_empty_config() const
config.opt_string("printhost_apikey" ).empty() && config.opt_string("printhost_apikey" ).empty() &&
config.opt_string("printhost_cafile" ).empty() && config.opt_string("printhost_cafile" ).empty() &&
config.opt_string("printhost_user" ).empty() && config.opt_string("printhost_user" ).empty() &&
config.opt_string("printhost_password").empty(); config.opt_string("printhost_password").empty() &&
config.opt_string("printhost_slug" ).empty();
} }
void PhysicalPrinter::update_preset_names_in_config() void PhysicalPrinter::update_preset_names_in_config()

View File

@ -499,6 +499,7 @@ DynamicPrintConfig PresetBundle::full_config_secure() const
config.erase("print_host"); config.erase("print_host");
config.erase("printhost_apikey"); config.erase("printhost_apikey");
config.erase("printhost_cafile"); config.erase("printhost_cafile");
config.erase("printhost_slug");
return config; return config;
} }

View File

@ -151,6 +151,13 @@ void PrintConfigDef::init_common_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString("")); def->set_default_value(new ConfigOptionString(""));
def = this->add("printhost_slug", coString);
def->label = L("Printer");
def->tooltip = L("Name of the printer");
def->mode = comAdvanced;
def->gui_type = "select_open";
def->set_default_value(new ConfigOptionString(""));
def = this->add("printhost_cafile", coString); def = this->add("printhost_cafile", coString);
def->label = L("HTTPS CA File"); def->label = L("HTTPS CA File");
def->category = OptionCategory::general; def->category = OptionCategory::general;
@ -2380,10 +2387,12 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("duet"); def->enum_values.push_back("duet");
def->enum_values.push_back("flashair"); def->enum_values.push_back("flashair");
def->enum_values.push_back("astrobox"); def->enum_values.push_back("astrobox");
def->enum_values.push_back("repetier");
def->enum_labels.push_back("OctoPrint"); def->enum_labels.push_back("OctoPrint");
def->enum_labels.push_back("Duet"); def->enum_labels.push_back("Duet");
def->enum_labels.push_back("FlashAir"); def->enum_labels.push_back("FlashAir");
def->enum_labels.push_back("AstroBox"); def->enum_labels.push_back("AstroBox");
def->enum_labels.push_back("Repetier");
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<PrintHostType>(htOctoPrint)); def->set_default_value(new ConfigOptionEnum<PrintHostType>(htOctoPrint));
@ -2448,24 +2457,30 @@ void PrintConfigDef::init_fff_params()
def->mode = comExpert; def->mode = comExpert;
def->set_default_value(new ConfigOptionString("[input_filename_base].gcode")); def->set_default_value(new ConfigOptionString("[input_filename_base].gcode"));
def = this->add("overhangs", coBool); def = this->add("overhangs_width_speed", coFloatOrPercent);
def->label = L("As bridge"); def->label = L("'As bridge' speed threshold");
def->full_label = L("Overhangs as bridge"); def->full_label = L("Overhang bridge speed threshold");
def->category = OptionCategory::perimeter; def->category = OptionCategory::perimeter;
def->tooltip = L("Option to adjust flow for overhangs (bridge flow will be used), " def->tooltip = L("Minimum unsupported width for an extrusion to apply the bridge speed & fan to this overhang."
"to apply bridge speed to them and enable fan."); " Can be in mm or in a % of the nozzle diameter."
def->mode = comExpert; " Set to 0 to deactivate.");
def->set_default_value(new ConfigOptionBool(true));
def = this->add("overhangs_width", coFloatOrPercent);
def->label = L("'As bridge' threshold");
def->full_label = L("Overhang bridge threshold");
def->category = OptionCategory::perimeter;
def->tooltip = L("Minimum unsupported width for an extrusion to be considered an overhang. Can be in mm or in a % of the nozzle diameter.");
def->ratio_over = "nozzle_diameter"; def->ratio_over = "nozzle_diameter";
def->min = 0;
def->mode = comExpert; def->mode = comExpert;
def->set_default_value(new ConfigOptionFloatOrPercent(50,true)); def->set_default_value(new ConfigOptionFloatOrPercent(50,true));
def = this->add("overhangs_width", coFloatOrPercent);
def->label = L("'As bridge' flow threshold");
def->full_label = L("Overhang bridge flow threshold");
def->category = OptionCategory::perimeter;
def->tooltip = L("Minimum unsupported width for an extrusion to apply the bridge flow to this overhang."
" Can be in mm or in a % of the nozzle diameter."
" Set to 0 to deactivate.");
def->ratio_over = "nozzle_diameter";
def->min = 0;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloatOrPercent(75, true));
def = this->add("overhangs_reverse", coBool); def = this->add("overhangs_reverse", coBool);
def->label = L("Reverse on odd"); def->label = L("Reverse on odd");
def->full_label = L("Overhang reversal"); def->full_label = L("Overhang reversal");
@ -2934,7 +2949,7 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionInts{ 5 }); def->set_default_value(new ConfigOptionInts{ 5 });
def = this->add("small_perimeter_speed", coFloatOrPercent); def = this->add("small_perimeter_speed", coFloatOrPercent);
def->label = L("Small"); def->label = L("Speed");
def->full_label = ("Small perimeters speed"); def->full_label = ("Small perimeters speed");
def->category = OptionCategory::speed; def->category = OptionCategory::speed;
def->tooltip = L("This separate setting will affect the speed of perimeters having radius <= 6.5mm " def->tooltip = L("This separate setting will affect the speed of perimeters having radius <= 6.5mm "
@ -2946,6 +2961,32 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(15, false)); def->set_default_value(new ConfigOptionFloatOrPercent(15, false));
def = this->add("small_perimeter_min_length", coFloatOrPercent);
def->label = L("Min length");
def->full_label = ("Min small perimeters length");
def->category = OptionCategory::speed;
def->tooltip = L("This set the threshold for small periemter length. Every loop with a length lower than that will be printed at small perimeter speed"
"\nCan be a mm or a % of the nozzle diameter.");
def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(6, false));
def = this->add("small_perimeter_max_length", coFloatOrPercent);
def->label = L("Max length");
def->full_label = ("Max small perimeters length");
def->category = OptionCategory::speed;
def->tooltip = L("This set the end of the threshold for small periemter length."
" Every periemter loop lower than that will see their speed reduced a bit, from their normal spee at this length down to small perimeter speed."
"\nCan be a mm or a % of the nozzle diameter.");
def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(20, false));
def = this->add("curve_smoothing_angle_convex", coFloat); def = this->add("curve_smoothing_angle_convex", coFloat);
def->label = L("Min convex angle"); def->label = L("Min convex angle");
def->full_label = L("Curve smoothing minimum angle (convex)"); def->full_label = L("Curve smoothing minimum angle (convex)");
@ -4789,6 +4830,12 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
opt_key = "seam_travel_cost"; opt_key = "seam_travel_cost";
value = "20%"; value = "20%";
} }
} else if (opt_key == "overhangs") {
opt_key = "overhangs_width_speed";
if (value == "1")
value = "50%";
else
value = "0";
} }
// Ignore the following obsolete configuration keys: // Ignore the following obsolete configuration keys:
static std::set<std::string> ignore = { static std::set<std::string> ignore = {

View File

@ -71,7 +71,7 @@ enum class MachineLimitsUsage {
}; };
enum PrintHostType { enum PrintHostType {
htOctoPrint, htDuet, htFlashAir, htAstroBox htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier
}; };
enum AuthorizationType { enum AuthorizationType {
@ -204,6 +204,7 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<PrintHostType>::g
keys_map["duet"] = htDuet; keys_map["duet"] = htDuet;
keys_map["flashair"] = htFlashAir; keys_map["flashair"] = htFlashAir;
keys_map["astrobox"] = htAstroBox; keys_map["astrobox"] = htAstroBox;
keys_map["repetier"] = htRepetier;
} }
return keys_map; return keys_map;
} }
@ -753,8 +754,8 @@ public:
ConfigOptionFloat milling_speed; ConfigOptionFloat milling_speed;
ConfigOptionFloatOrPercent min_width_top_surface; ConfigOptionFloatOrPercent min_width_top_surface;
// Detect bridging perimeters // Detect bridging perimeters
ConfigOptionBool overhangs;
ConfigOptionFloatOrPercent overhangs_width; ConfigOptionFloatOrPercent overhangs_width;
ConfigOptionFloatOrPercent overhangs_width_speed;
ConfigOptionBool overhangs_reverse; ConfigOptionBool overhangs_reverse;
ConfigOptionFloatOrPercent overhangs_reverse_threshold; ConfigOptionFloatOrPercent overhangs_reverse_threshold;
ConfigOptionEnum<NoPerimeterUnsupportedAlgo> no_perimeter_unsupported_algo; ConfigOptionEnum<NoPerimeterUnsupportedAlgo> no_perimeter_unsupported_algo;
@ -769,6 +770,8 @@ public:
ConfigOptionPercent print_extrusion_multiplier; ConfigOptionPercent print_extrusion_multiplier;
ConfigOptionFloat print_retract_length; ConfigOptionFloat print_retract_length;
ConfigOptionFloatOrPercent small_perimeter_speed; ConfigOptionFloatOrPercent small_perimeter_speed;
ConfigOptionFloatOrPercent small_perimeter_min_length;
ConfigOptionFloatOrPercent small_perimeter_max_length;
ConfigOptionEnum<InfillPattern> solid_fill_pattern; ConfigOptionEnum<InfillPattern> solid_fill_pattern;
ConfigOptionFloat solid_infill_below_area; ConfigOptionFloat solid_infill_below_area;
ConfigOptionInt solid_infill_extruder; ConfigOptionInt solid_infill_extruder;
@ -850,8 +853,8 @@ protected:
OPT_PTR(milling_post_process); OPT_PTR(milling_post_process);
OPT_PTR(milling_speed); OPT_PTR(milling_speed);
OPT_PTR(min_width_top_surface); OPT_PTR(min_width_top_surface);
OPT_PTR(overhangs);
OPT_PTR(overhangs_width); OPT_PTR(overhangs_width);
OPT_PTR(overhangs_width_speed);
OPT_PTR(overhangs_reverse); OPT_PTR(overhangs_reverse);
OPT_PTR(overhangs_reverse_threshold); OPT_PTR(overhangs_reverse_threshold);
OPT_PTR(no_perimeter_unsupported_algo); OPT_PTR(no_perimeter_unsupported_algo);
@ -865,6 +868,8 @@ protected:
OPT_PTR(print_extrusion_multiplier); OPT_PTR(print_extrusion_multiplier);
OPT_PTR(print_retract_length); OPT_PTR(print_retract_length);
OPT_PTR(small_perimeter_speed); OPT_PTR(small_perimeter_speed);
OPT_PTR(small_perimeter_min_length);
OPT_PTR(small_perimeter_max_length);
OPT_PTR(solid_fill_pattern); OPT_PTR(solid_fill_pattern);
OPT_PTR(solid_infill_below_area); OPT_PTR(solid_infill_below_area);
OPT_PTR(solid_infill_extruder); OPT_PTR(solid_infill_extruder);
@ -1349,6 +1354,7 @@ public:
ConfigOptionString print_host; ConfigOptionString print_host;
ConfigOptionString printhost_apikey; ConfigOptionString printhost_apikey;
ConfigOptionString printhost_cafile; ConfigOptionString printhost_cafile;
ConfigOptionString printhost_slug;
ConfigOptionString serial_port; ConfigOptionString serial_port;
ConfigOptionInt serial_speed; ConfigOptionInt serial_speed;
@ -1359,6 +1365,7 @@ protected:
OPT_PTR(print_host); OPT_PTR(print_host);
OPT_PTR(printhost_apikey); OPT_PTR(printhost_apikey);
OPT_PTR(printhost_cafile); OPT_PTR(printhost_cafile);
OPT_PTR(printhost_slug);
OPT_PTR(serial_port); OPT_PTR(serial_port);
OPT_PTR(serial_speed); OPT_PTR(serial_speed);
} }

View File

@ -682,7 +682,7 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
opt_key == "gap_fill" opt_key == "gap_fill"
|| opt_key == "gap_fill_min_area" || opt_key == "gap_fill_min_area"
|| opt_key == "only_one_perimeter_top" || opt_key == "only_one_perimeter_top"
|| opt_key == "overhangs" || opt_key == "overhangs_width_speed"
|| opt_key == "overhangs_width" || opt_key == "overhangs_width"
|| opt_key == "overhangs_reverse" || opt_key == "overhangs_reverse"
|| opt_key == "overhangs_reverse_threshold" || opt_key == "overhangs_reverse_threshold"
@ -822,6 +822,8 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|| opt_key == "seam_angle_cost" || opt_key == "seam_angle_cost"
|| opt_key == "seam_travel_cost" || opt_key == "seam_travel_cost"
|| opt_key == "small_perimeter_speed" || opt_key == "small_perimeter_speed"
|| opt_key == "small_perimeter_min_length"
|| opt_key == "small_perimeter_max_length"
|| opt_key == "solid_infill_speed" || opt_key == "solid_infill_speed"
|| opt_key == "support_material_interface_speed" || opt_key == "support_material_interface_speed"
|| opt_key == "support_material_speed" || opt_key == "support_material_speed"

View File

@ -2141,7 +2141,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object(
polygons_append(polygons_trimming, polygons_append(polygons_trimming,
offset(to_expolygons(region->fill_surfaces.filter_by_type(stPosBottom | stDensSolid | stModBridge)), offset(to_expolygons(region->fill_surfaces.filter_by_type(stPosBottom | stDensSolid | stModBridge)),
gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS)); gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS));
if (region->region()->config().overhangs.value) if (region->region()->config().overhangs_width.value > 0)
SupportMaterialInternal::collect_bridging_perimeter_areas(region->perimeters.entities, gap_xy_scaled, polygons_trimming); SupportMaterialInternal::collect_bridging_perimeter_areas(region->perimeters.entities, gap_xy_scaled, polygons_trimming);
} }
if (! some_region_overlaps) if (! some_region_overlaps)

View File

@ -56,7 +56,7 @@ static constexpr double SCALING_FACTOR = 0.000001;
// When extruding a closed loop, the loop is interrupted and shortened a bit to reduce the seam. // When extruding a closed loop, the loop is interrupted and shortened a bit to reduce the seam.
static constexpr double LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER = 0.15; static constexpr double LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER = 0.15;
// Maximum perimeter length for the loop to apply the small perimeter speed. // Maximum perimeter length for the loop to apply the small perimeter speed.
#define SMALL_PERIMETER_LENGTH ((6.5 / SCALING_FACTOR) * 2 * PI) //#define SMALL_PERIMETER_LENGTH ((6.5 / SCALING_FACTOR) * 2 * PI)
static constexpr double INSET_OVERLAP_TOLERANCE = 0.4; static constexpr double INSET_OVERLAP_TOLERANCE = 0.4;
//FIXME Better to use an inline function with an explicit return type. //FIXME Better to use an inline function with an explicit return type.
//inline coord_t scale_(coordf_t v) { return coord_t(floor(v / SCALING_FACTOR + 0.5f)); } //inline coord_t scale_(coordf_t v) { return coord_t(floor(v / SCALING_FACTOR + 0.5f)); }

View File

@ -211,6 +211,8 @@ set(SLIC3R_GUI_SOURCES
Utils/FlashAir.hpp Utils/FlashAir.hpp
Utils/AstroBox.cpp Utils/AstroBox.cpp
Utils/AstroBox.hpp Utils/AstroBox.hpp
Utils/Repetier.cpp
Utils/Repetier.hpp
Utils/PrintHost.cpp Utils/PrintHost.cpp
Utils/PrintHost.hpp Utils/PrintHost.hpp
Utils/Bonjour.cpp Utils/Bonjour.cpp

View File

@ -86,7 +86,7 @@ void CalibrationBridgeDialog::create_geometry(std::string setting_to_test, bool
int start = bridge_flow_ratio->value; int start = bridge_flow_ratio->value;
float zshift = 2.3 * (1 - z_scale); float zshift = 2.3 * (1 - z_scale);
for (size_t i = 0; i < nb_items; i++) { for (size_t i = 0; i < nb_items; i++) {
if((start + (add ? 1 : -1) * i * step) < 180 && start + (start + (add ? 1 : -1) * i * step) > 20) if((start + (add ? 1 : -1) * i * step) < 180 && (start + (add ? 1 : -1) * i * step) > 20)
add_part(model.objects[objs_idx[i]], Slic3r::resources_dir() + "/calibration/bridge_flow/f"+std::to_string(start + (add ? 1 : -1) * i * step)+".amf", Vec3d{ -10,0, zshift + 4.6 * z_scale }, Vec3d{ 1,1,z_scale }); add_part(model.objects[objs_idx[i]], Slic3r::resources_dir() + "/calibration/bridge_flow/f"+std::to_string(start + (add ? 1 : -1) * i * step)+".amf", Vec3d{ -10,0, zshift + 4.6 * z_scale }, Vec3d{ 1,1,z_scale });
} }

View File

@ -26,11 +26,11 @@ namespace GUI {
void CalibrationRetractionDialog::create_buttons(wxStdDialogButtonSizer* buttons){ void CalibrationRetractionDialog::create_buttons(wxStdDialogButtonSizer* buttons){
wxString choices_steps[] = { "0.1","0.2","0.5","1" }; wxString choices_steps[] = { "0.1","0.2","0.5","1" };
steps = new wxComboBox(this, wxID_ANY, wxString{ "0.2" }, wxDefaultPosition, wxDefaultSize, 4, choices_steps); steps = new wxComboBox(this, wxID_ANY, wxString{ "0.2" }, wxDefaultPosition, wxDefaultSize, 4, choices_steps);
steps->SetToolTip(_(L("Each militer add this value to the retraction value. "))); steps->SetToolTip(_L("Each militer add this value to the retraction value. "));
steps->SetSelection(1); steps->SetSelection(1);
wxString choices_nb[] = { "2","4","6","8","10","15","20","25" }; wxString choices_nb[] = { "2","4","6","8","10","15","20","25" };
nb_steps = new wxComboBox(this, wxID_ANY, wxString{ "15" }, wxDefaultPosition, wxDefaultSize, 8, choices_nb); nb_steps = new wxComboBox(this, wxID_ANY, wxString{ "15" }, wxDefaultPosition, wxDefaultSize, 8, choices_nb);
nb_steps->SetToolTip(_(L("Select the number milimeters for the tower."))); nb_steps->SetToolTip(_L("Select the number milimeters for the tower."));
nb_steps->SetSelection(5); nb_steps->SetSelection(5);
//wxString choices_start[] = { "current","260","250","240","230","220","210" }; //wxString choices_start[] = { "current","260","250","240","230","220","210" };
//start_step = new wxComboBox(this, wxID_ANY, wxString{ "current" }, wxDefaultPosition, wxDefaultSize, 7, choices_start); //start_step = new wxComboBox(this, wxID_ANY, wxString{ "current" }, wxDefaultPosition, wxDefaultSize, 7, choices_start);
@ -40,9 +40,10 @@ void CalibrationRetractionDialog::create_buttons(wxStdDialogButtonSizer* buttons
int temp = int((2 + filament_config->option<ConfigOptionInts>("temperature")->get_at(0)) / 5) * 5; int temp = int((2 + filament_config->option<ConfigOptionInts>("temperature")->get_at(0)) / 5) * 5;
auto size = wxSize(4 * em_unit(), wxDefaultCoord); auto size = wxSize(4 * em_unit(), wxDefaultCoord);
temp_start = new wxTextCtrl(this, wxID_ANY, std::to_string(temp), wxDefaultPosition, size); temp_start = new wxTextCtrl(this, wxID_ANY, std::to_string(temp), wxDefaultPosition, size);
wxString choices_decr[] = { "one test","2x10°","3x10°","4x10°","3x5°","5x5°" }; wxString degree = L'°' ;
wxString choices_decr[] = { "one test","2x10"+ degree,"3x10"+ degree, L"4x10°", _("3x50°"), _L("5x5°") };
decr_temp = new wxComboBox(this, wxID_ANY, wxString{ "current" }, wxDefaultPosition, wxDefaultSize, 6, choices_decr); decr_temp = new wxComboBox(this, wxID_ANY, wxString{ "current" }, wxDefaultPosition, wxDefaultSize, 6, choices_decr);
decr_temp->SetToolTip(_(L("Select the number tower to print, and by how many degrees C to decrease each time."))); decr_temp->SetToolTip(_L("Select the number tower to print, and by how many degrees C to decrease each time."));
decr_temp->SetSelection(0); decr_temp->SetSelection(0);
buttons->Add(new wxStaticText(this, wxID_ANY, wxString{ "step:" })); buttons->Add(new wxStaticText(this, wxID_ANY, wxString{ "step:" }));
@ -163,7 +164,6 @@ void CalibrationRetractionDialog::create_geometry(wxCommandEvent& event_args) {
} }
//add sub-part after scale //add sub-part after scale
float zshift = (1 - scale) / 2 + 0.4 * scale;
float zscale_number = (first_layer_height + layer_height) / 0.4; float zscale_number = (first_layer_height + layer_height) / 0.4;
std::vector < std::vector<ModelObject*>> part_tower; std::vector < std::vector<ModelObject*>> part_tower;
for (size_t id_item = 0; id_item < nb_items; id_item++) { for (size_t id_item = 0; id_item < nb_items; id_item++) {
@ -171,11 +171,14 @@ void CalibrationRetractionDialog::create_geometry(wxCommandEvent& event_args) {
int mytemp = temp - temp_decr * id_item; int mytemp = temp - temp_decr * id_item;
if (mytemp > 285) mytemp = 285; if (mytemp > 285) mytemp = 285;
if (mytemp < 180) mytemp = 180; if (mytemp < 180) mytemp = 180;
add_part(model.objects[objs_idx[id_item]], Slic3r::resources_dir() + "/calibration/filament_temp/t"+ std::to_string(mytemp) + ".amf", Vec3d{ 0,0,zshift - 5.2 * scale }, Vec3d{ scale,scale,scale }); add_part(model.objects[objs_idx[id_item]], Slic3r::resources_dir() + "/calibration/filament_temp/t"+ std::to_string(mytemp) + ".amf",
Vec3d{ 0,0, scale * 0.2 -4.8 }, Vec3d{ scale,scale,scale });
model.objects[objs_idx[id_item]]->volumes[1]->rotate(PI / 2, Vec3d(0, 0, 1)); model.objects[objs_idx[id_item]]->volumes[1]->rotate(PI / 2, Vec3d(0, 0, 1));
model.objects[objs_idx[id_item]]->volumes[1]->rotate(-PI / 2, Vec3d(1, 0, 0)); model.objects[objs_idx[id_item]]->volumes[1]->rotate(-PI / 2, Vec3d(1, 0, 0));
for (int num_retract = 0; num_retract < nb_retract; num_retract++) { for (int num_retract = 0; num_retract < nb_retract; num_retract++) {
part_tower.back().push_back(add_part(model.objects[objs_idx[id_item]], Slic3r::resources_dir() + "/calibration/retraction/retraction_calibration_pillar.amf", Vec3d{ 0,0,zshift + scale * num_retract }, Vec3d{ scale,scale,scale })); part_tower.back().push_back(add_part(model.objects[objs_idx[id_item]],
Slic3r::resources_dir() + "/calibration/retraction/retraction_calibration_pillar.amf",
Vec3d{ 0,0,scale * 0.7 - 0.3 + scale * num_retract }, Vec3d{ scale,scale,scale }));
} }
} }
@ -212,7 +215,7 @@ void CalibrationRetractionDialog::create_geometry(wxCommandEvent& event_args) {
model.objects[objs_idx[i]]->config.set_key_value("fill_density", new ConfigOptionPercent(0)); model.objects[objs_idx[i]]->config.set_key_value("fill_density", new ConfigOptionPercent(0));
//model.objects[objs_idx[i]]->config.set_key_value("fill_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinear)); //model.objects[objs_idx[i]]->config.set_key_value("fill_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinear));
model.objects[objs_idx[i]]->config.set_key_value("only_one_perimeter_top", new ConfigOptionBool(false)); model.objects[objs_idx[i]]->config.set_key_value("only_one_perimeter_top", new ConfigOptionBool(false));
model.objects[objs_idx[i]]->config.set_key_value("overhangs", new ConfigOptionBool(false)); model.objects[objs_idx[i]]->config.set_key_value("overhangs_width_speed", new ConfigOptionFloatOrPercent(0,false));
model.objects[objs_idx[i]]->config.set_key_value("thin_walls", new ConfigOptionBool(true)); model.objects[objs_idx[i]]->config.set_key_value("thin_walls", new ConfigOptionBool(true));
model.objects[objs_idx[i]]->config.set_key_value("thin_walls_min_width", new ConfigOptionFloatOrPercent(2,true)); model.objects[objs_idx[i]]->config.set_key_value("thin_walls_min_width", new ConfigOptionFloatOrPercent(2,true));
model.objects[objs_idx[i]]->config.set_key_value("gap_fill", new ConfigOptionBool(false)); model.objects[objs_idx[i]]->config.set_key_value("gap_fill", new ConfigOptionBool(false));

View File

@ -275,9 +275,9 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
// Ask only once. // Ask only once.
if (!support_material_overhangs_queried) { if (!support_material_overhangs_queried) {
support_material_overhangs_queried = true; support_material_overhangs_queried = true;
if (!config->opt_bool("overhangs")/* != 1*/) { if (config->option<ConfigOptionFloatOrPercent>("overhangs_width_speed") == 0) {
wxString msg_text = _(L("Supports work better, if the following feature is enabled:\n" wxString msg_text = _(L("Supports work better, if the following feature is enabled:\n"
"- Detect bridging perimeters")); "- overhangs with bridge speed & fan"));
if (is_global_config) { if (is_global_config) {
msg_text += "\n\n" + _(L("Shall I adjust those settings for supports?")); msg_text += "\n\n" + _(L("Shall I adjust those settings for supports?"));
wxMessageDialog dialog(nullptr, msg_text, _(L("Support Generator")), wxMessageDialog dialog(nullptr, msg_text, _(L("Support Generator")),
@ -286,7 +286,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
auto answer = dialog.ShowModal(); auto answer = dialog.ShowModal();
if (!is_global_config || answer == wxID_YES) { if (!is_global_config || answer == wxID_YES) {
// Enable "detect bridging perimeters". // Enable "detect bridging perimeters".
new_conf.set_key_value("overhangs", new ConfigOptionBool(true)); new_conf.set_key_value("overhangs_width_speed", new ConfigOptionFloatOrPercent(50, true));
} else if (answer == wxID_NO) { } else if (answer == wxID_NO) {
// Do nothing, leave supports on and "detect bridging perimeters" off. // Do nothing, leave supports on and "detect bridging perimeters" off.
} else if (answer == wxID_CANCEL) { } else if (answer == wxID_CANCEL) {
@ -358,10 +358,10 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
"only_one_perimeter_top", "ensure_vertical_shell_thickness", "thin_walls", "only_one_perimeter_top", "ensure_vertical_shell_thickness", "thin_walls",
"overhangs", "overhangs_reverse", "overhangs", "overhangs_reverse",
"seam_position", "external_perimeters_first", "external_perimeters_vase", "external_perimeter_extrusion_width", "seam_position", "external_perimeters_first", "external_perimeters_vase", "external_perimeter_extrusion_width",
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "perimeter_loop", "perimeter_loop_seam" }) "perimeter_speed", "small_perimeter_speed", "small_perimeter_min_length", " small_perimeter_max_length", "external_perimeter_speed", "perimeter_loop", "perimeter_loop_seam" })
toggle_field(el, have_perimeters); toggle_field(el, have_perimeters);
toggle_field("overhangs_width", config->opt_bool("overhangs")); toggle_field("overhangs_width", config->option<ConfigOptionFloatOrPercent>("overhangs_width_speed")->value > 0);
toggle_field("overhangs_reverse_threshold", config->opt_bool("overhangs_reverse")); toggle_field("overhangs_reverse_threshold", config->opt_bool("overhangs_reverse"));
toggle_field("min_width_top_surface", config->opt_bool("only_one_perimeter_top")); toggle_field("min_width_top_surface", config->opt_bool("only_one_perimeter_top"));
toggle_field("thin_perimeters_all", config->opt_bool("thin_perimeters")); toggle_field("thin_perimeters_all", config->opt_bool("thin_perimeters"));

View File

@ -862,9 +862,12 @@ void Choice::BUILD() {
* *
* Note: Set bitmap height to the Font size because of OSX rendering. * Note: Set bitmap height to the Font size because of OSX rendering.
*/ */
// Welll, it makes wx freak out... (in debug) if select_open
if (m_opt.gui_type != "select_open") {
wxBitmap empty_bmp(1, temp->GetFont().GetPixelSize().y + 2); wxBitmap empty_bmp(1, temp->GetFont().GetPixelSize().y + 2);
empty_bmp.SetWidth(0); empty_bmp.SetWidth(0);
temp->SetItemBitmap(0, empty_bmp); temp->SetItemBitmap(0, empty_bmp);
}
#endif #endif
// temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), temp->GetId()); // temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), temp->GetId());

View File

@ -201,7 +201,7 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
else if (opt_key.compare("infill_dense_algo") == 0) else if (opt_key.compare("infill_dense_algo") == 0)
config.set_key_value(opt_key, new ConfigOptionEnum<DenseInfillAlgo>(boost::any_cast<DenseInfillAlgo>(value))); config.set_key_value(opt_key, new ConfigOptionEnum<DenseInfillAlgo>(boost::any_cast<DenseInfillAlgo>(value)));
else if (opt_key.compare("no_perimeter_unsupported_algo") == 0) else if (opt_key.compare("no_perimeter_unsupported_algo") == 0)
config.set_key_value(opt_key, new ConfigOptionEnum<DenseInfillAlgo>(boost::any_cast<DenseInfillAlgo>(value))); config.set_key_value(opt_key, new ConfigOptionEnum<NoPerimeterUnsupportedAlgo>(boost::any_cast<NoPerimeterUnsupportedAlgo>(value)));
else if (opt_key.compare("infill_connection") == 0) else if (opt_key.compare("infill_connection") == 0)
config.set_key_value(opt_key, new ConfigOptionEnum<InfillConnection>(boost::any_cast<InfillConnection>(value))); config.set_key_value(opt_key, new ConfigOptionEnum<InfillConnection>(boost::any_cast<InfillConnection>(value)));
else if (opt_key.compare("wipe_advanced_algo") == 0) else if (opt_key.compare("wipe_advanced_algo") == 0)

View File

@ -251,7 +251,7 @@ PhysicalPrinterDialog::~PhysicalPrinterDialog()
void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgroup) void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgroup)
{ {
m_optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) { m_optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
if (opt_key == "printhost_authorization_type") if (opt_key == "printhost_authorization_type" || opt_key == "host_type")
this->update(); this->update();
}; };
@ -302,6 +302,13 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr
return sizer; return sizer;
}; };
auto print_host_printers = [=](wxWindow* parent) {
auto sizer = create_sizer_with_btn(parent, &m_printhost_slug_browse_btn, "browse", _L("Refresh Printers"));
m_printhost_slug_browse_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent e) { update_printers(); });
return sizer;
};
// Set a wider width for a better alignment // Set a wider width for a better alignment
Option option = m_optgroup->get_option("print_host"); Option option = m_optgroup->get_option("print_host");
option.opt.width = Field::def_width_wider(); option.opt.width = Field::def_width_wider();
@ -316,6 +323,12 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr
option.opt.width = Field::def_width_wider(); option.opt.width = Field::def_width_wider();
m_optgroup->append_single_option_line(option); m_optgroup->append_single_option_line(option);
option = m_optgroup->get_option("printhost_slug");
option.opt.width = Field::def_width_wider();
Line slug_line = m_optgroup->create_single_option_line(option);
slug_line.append_widget(print_host_printers);
m_optgroup->append_line(slug_line);
const auto ca_file_hint = _u8L("HTTPS CA file is optional. It is only needed if you use HTTPS with a self-signed certificate."); const auto ca_file_hint = _u8L("HTTPS CA file is optional. It is only needed if you use HTTPS with a self-signed certificate.");
if (Http::ca_file_supported()) { if (Http::ca_file_supported()) {
@ -405,9 +418,61 @@ void PhysicalPrinterDialog::update()
m_optgroup->show_field(opt_key, auth_type == AuthorizationType::atUserPassword); m_optgroup->show_field(opt_key, auth_type == AuthorizationType::atUserPassword);
} }
{
std::unique_ptr<PrintHost> host(PrintHost::get_print_host(m_config));
if (m_printhost_test_btn)
m_printhost_test_btn->Enable(host->can_test());
if (m_printhost_browse_btn)
m_printhost_browse_btn->Enable(host->has_auto_discovery());
m_printhost_slug_browse_btn->Enable(host->can_support_multiple_printers());
Field* rs = m_optgroup->get_field("printhost_slug");
if (host->can_support_multiple_printers()) {
update_printers();
rs->enable();
} else {
rs->disable();
}
}
this->Layout(); this->Layout();
} }
void PhysicalPrinterDialog::update_printers()
{
std::unique_ptr<PrintHost> host(PrintHost::get_print_host(m_config));
wxArrayString printers;
Field* rs = m_optgroup->get_field("printhost_slug");
if (!host->get_printers(printers)) {
std::vector<std::string> slugs;
Choice* choice = dynamic_cast<Choice*>(rs);
choice->set_values(slugs);
rs->disable();
} else {
std::vector<std::string> slugs;
for (int i = 0; i < printers.size(); i++) {
slugs.push_back(printers[i].ToStdString());
}
Choice* choice = dynamic_cast<Choice*>(rs);
choice->set_values(slugs);
boost::any val = choice->get_value();
boost::any any_string_type = std::string("");
auto value_idx = std::find(slugs.begin(), slugs.end(), m_config->opt<ConfigOptionString>("printhost_slug")->value);
if ((val.empty() || (any_string_type.type() == val.type() && boost::any_cast<std::string>(val) == "")) && !slugs.empty() && value_idx == slugs.end()) {
change_opt_value(*m_config, "printhost_slug", slugs[0]);
choice->set_value(slugs[0],false);
} else if(value_idx != slugs.end() ){
choice->set_value(m_config->option<ConfigOptionString>("printhost_slug")->value, false);
}
rs->enable();
}
}
wxString PhysicalPrinterDialog::get_printer_name() wxString PhysicalPrinterDialog::get_printer_name()
{ {

View File

@ -72,6 +72,7 @@ class PhysicalPrinterDialog : public DPIDialog
ScalableButton* m_add_preset_btn {nullptr}; ScalableButton* m_add_preset_btn {nullptr};
ScalableButton* m_printhost_browse_btn {nullptr}; ScalableButton* m_printhost_browse_btn {nullptr};
ScalableButton* m_printhost_test_btn {nullptr}; ScalableButton* m_printhost_test_btn {nullptr};
ScalableButton* m_printhost_slug_browse_btn {nullptr};
ScalableButton* m_printhost_cafile_browse_btn {nullptr}; ScalableButton* m_printhost_cafile_browse_btn {nullptr};
wxBoxSizer* m_presets_sizer {nullptr}; wxBoxSizer* m_presets_sizer {nullptr};
@ -85,6 +86,7 @@ public:
~PhysicalPrinterDialog(); ~PhysicalPrinterDialog();
void update(); void update();
void update_printers();
wxString get_printer_name(); wxString get_printer_name();
void update_full_printer_names(); void update_full_printer_names();
PhysicalPrinter* get_printer() {return &m_printer; } PhysicalPrinter* get_printer() {return &m_printer; }

View File

@ -1850,7 +1850,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
"complete_objects_one_skirt", "complete_objects_one_skirt",
"duplicate_distance", "extruder_clearance_radius", "skirts", "skirt_distance", "skirt_height", "duplicate_distance", "extruder_clearance_radius", "skirts", "skirt_distance", "skirt_height",
"brim_width", "variable_layer_height", "serial_port", "serial_speed", "host_type", "print_host", "brim_width", "variable_layer_height", "serial_port", "serial_speed", "host_type", "print_host",
"printhost_apikey", "printhost_cafile", "nozzle_diameter", "single_extruder_multi_material", "printhost_apikey", "printhost_cafile", "printhost_slug", "nozzle_diameter", "single_extruder_multi_material",
"wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim", "wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim",
"extruder_colour", "filament_colour", "max_print_height", "printer_model", "printer_technology", "extruder_colour", "filament_colour", "max_print_height", "printer_model", "printer_technology",
// These values are necessary to construct SlicingParameters by the Canvas3D variable layer height editor. // These values are necessary to construct SlicingParameters by the Canvas3D variable layer height editor.
@ -5376,10 +5376,14 @@ void Plater::send_gcode()
} }
default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string()));
PrintHostSendDialog dlg(default_output_file, upload_job.printhost->can_start_print()); wxArrayString groups;
upload_job.printhost->get_groups(groups);
PrintHostSendDialog dlg(default_output_file, upload_job.printhost->can_start_print(), groups);
if (dlg.ShowModal() == wxID_OK) { if (dlg.ShowModal() == wxID_OK) {
upload_job.upload_data.upload_path = dlg.filename(); upload_job.upload_data.upload_path = dlg.filename();
upload_job.upload_data.start_print = dlg.start_print(); upload_job.upload_data.start_print = dlg.start_print();
upload_job.upload_data.group = dlg.group();
p->export_gcode(fs::path(), false, std::move(upload_job)); p->export_gcode(fs::path(), false, std::move(upload_job));
} }

View File

@ -28,11 +28,13 @@ namespace GUI {
static const char *CONFIG_KEY_PATH = "printhost_path"; static const char *CONFIG_KEY_PATH = "printhost_path";
static const char *CONFIG_KEY_PRINT = "printhost_print"; static const char *CONFIG_KEY_PRINT = "printhost_print";
static const char *CONFIG_KEY_GROUP = "printhost_group";
PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_print) PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_print, wxArrayString& groups)
: MsgDialog(nullptr, _(L("Send G-Code to printer host")), _(L("Upload to Printer Host with the following filename:")), wxID_NONE) : MsgDialog(nullptr, _(L("Send G-Code to printer host")), _(L("Upload to Printer Host with the following filename:")), wxID_NONE)
, txt_filename(new wxTextCtrl(this, wxID_ANY)) , txt_filename(new wxTextCtrl(this, wxID_ANY))
, box_print(can_start_print ? new wxCheckBox(this, wxID_ANY, _(L("Start printing after upload"))) : nullptr) , box_print(can_start_print ? new wxCheckBox(this, wxID_ANY, _(L("Start printing after upload"))) : nullptr)
, combo_groups(!groups.IsEmpty() ? new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, groups, wxCB_READONLY) : nullptr)
{ {
#ifdef __APPLE__ #ifdef __APPLE__
txt_filename->OSXDisableAllSmartSubstitutions(); txt_filename->OSXDisableAllSmartSubstitutions();
@ -50,6 +52,20 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_pr
box_print->SetValue(app_config->get("recent", CONFIG_KEY_PRINT) == "1"); box_print->SetValue(app_config->get("recent", CONFIG_KEY_PRINT) == "1");
} }
if (combo_groups != nullptr) {
auto *label_group = new wxStaticText(this, wxID_ANY, _(L("Group")));
content_sizer->Add(label_group);
content_sizer->Add(combo_groups, 0, wxBOTTOM, 2*VERT_SPACING);
wxString recent_group = from_u8(app_config->get("recent", CONFIG_KEY_GROUP));
if (recent_group.Length() > 0) {
combo_groups->SetValue(recent_group);
} else {
combo_groups->SetSelection(0);
}
}
btn_sizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL)); btn_sizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL));
@ -86,6 +102,16 @@ bool PrintHostSendDialog::start_print() const
return box_print != nullptr ? box_print->GetValue() : false; return box_print != nullptr ? box_print->GetValue() : false;
} }
std::string PrintHostSendDialog::group() const
{
if (combo_groups == nullptr) {
return "";
} else {
wxString group = combo_groups->GetValue();
return into_u8(group);
}
}
void PrintHostSendDialog::EndModal(int ret) void PrintHostSendDialog::EndModal(int ret)
{ {
if (ret == wxID_OK) { if (ret == wxID_OK) {
@ -96,9 +122,15 @@ void PrintHostSendDialog::EndModal(int ret)
path.clear(); path.clear();
else else
path = path.SubString(0, last_slash); path = path.SubString(0, last_slash);
AppConfig *app_config = wxGetApp().app_config; AppConfig *app_config = wxGetApp().app_config;
app_config->set("recent", CONFIG_KEY_PATH, into_u8(path)); app_config->set("recent", CONFIG_KEY_PATH, into_u8(path));
app_config->set("recent", CONFIG_KEY_PRINT, start_print() ? "1" : "0"); app_config->set("recent", CONFIG_KEY_PRINT, start_print() ? "1" : "0");
if (combo_groups != nullptr) {
wxString group = combo_groups->GetValue();
app_config->set("recent", CONFIG_KEY_GROUP, into_u8(group));
}
} }
MsgDialog::EndModal(ret); MsgDialog::EndModal(ret);

View File

@ -7,6 +7,8 @@
#include <wx/string.h> #include <wx/string.h>
#include <wx/event.h> #include <wx/event.h>
#include <wx/dialog.h> #include <wx/dialog.h>
#include <wx/combobox.h>
#include <wx/arrstr.h>
#include "GUI.hpp" #include "GUI.hpp"
#include "GUI_Utils.hpp" #include "GUI_Utils.hpp"
@ -29,14 +31,16 @@ namespace GUI {
class PrintHostSendDialog : public GUI::MsgDialog class PrintHostSendDialog : public GUI::MsgDialog
{ {
public: public:
PrintHostSendDialog(const boost::filesystem::path &path, bool can_start_print); PrintHostSendDialog(const boost::filesystem::path &path, bool can_start_print, wxArrayString& groups);
boost::filesystem::path filename() const; boost::filesystem::path filename() const;
bool start_print() const; bool start_print() const;
std::string group() const;
virtual void EndModal(int ret) override; virtual void EndModal(int ret) override;
private: private:
wxTextCtrl *txt_filename; wxTextCtrl *txt_filename;
wxCheckBox *box_print; wxCheckBox *box_print;
wxComboBox *combo_groups;
}; };

View File

@ -2312,6 +2312,7 @@ void TabPrinter::build_sla()
} }
void TabPrinter::extruders_count_changed(size_t extruders_count) void TabPrinter::extruders_count_changed(size_t extruders_count)
{ {
bool is_count_changed = false; bool is_count_changed = false;

View File

@ -444,6 +444,8 @@ public:
wxButton* m_serial_test_btn = nullptr; wxButton* m_serial_test_btn = nullptr;
ScalableButton* m_print_host_test_btn = nullptr; ScalableButton* m_print_host_test_btn = nullptr;
ScalableButton* m_printhost_browse_btn = nullptr; ScalableButton* m_printhost_browse_btn = nullptr;
ScalableButton* m_printhost_browse_printer_btn = nullptr;
ScalableButton* m_printhost_slug_browse_btn = nullptr;
ScalableButton* m_reset_to_filament_color = nullptr; ScalableButton* m_reset_to_filament_color = nullptr;
size_t m_extruders_count = 0; size_t m_extruders_count = 0;
@ -476,6 +478,7 @@ public:
void update_fff(); void update_fff();
void update_sla(); void update_sla();
void update_pages(); // update m_pages according to printer technology void update_pages(); // update m_pages according to printer technology
void update_printers();
void extruders_count_changed(size_t extruders_count); void extruders_count_changed(size_t extruders_count);
void milling_count_changed(size_t extruders_count); void milling_count_changed(size_t extruders_count);
PageShp build_kinematics_page(); PageShp build_kinematics_page();

View File

@ -27,8 +27,12 @@ public:
bool has_auto_discovery() const override { return true; } bool has_auto_discovery() const override { return true; }
bool can_test() const override { return true; } bool can_test() const override { return true; }
bool can_start_print() const override { return true; } bool can_start_print() const override { return true; }
bool can_support_multiple_printers() const override { return false; }
std::string get_host() const override { return host; } std::string get_host() const override { return host; }
bool get_groups(wxArrayString &groups) const override { return false; }
bool get_printers(wxArrayString &printers) const override { return false; }
protected: protected:
bool validate_version_text(const boost::optional<std::string> &version_text) const; bool validate_version_text(const boost::optional<std::string> &version_text) const;

View File

@ -26,8 +26,12 @@ public:
bool has_auto_discovery() const override { return false; } bool has_auto_discovery() const override { return false; }
bool can_test() const override { return true; } bool can_test() const override { return true; }
bool can_start_print() const override { return true; } bool can_start_print() const override { return true; }
bool can_support_multiple_printers() const override { return false; }
std::string get_host() const override { return host; } std::string get_host() const override { return host; }
bool get_groups(wxArrayString &groups) const override { return false; }
bool get_printers(wxArrayString &printers) const override { return false; }
private: private:
enum class ConnectionType { rrf, dsf, error }; enum class ConnectionType { rrf, dsf, error };
std::string host; std::string host;

View File

@ -27,8 +27,12 @@ public:
bool has_auto_discovery() const override { return false; } bool has_auto_discovery() const override { return false; }
bool can_test() const override { return true; } bool can_test() const override { return true; }
bool can_start_print() const override { return false; } bool can_start_print() const override { return false; }
bool can_support_multiple_printers() const override { return false; }
std::string get_host() const override { return host; } std::string get_host() const override { return host; }
bool get_groups(wxArrayString &groups) const override { return false; }
bool get_printers(wxArrayString &printers) const override { return false; }
private: private:
std::string host; std::string host;

View File

@ -3,6 +3,7 @@
#include <string> #include <string>
#include <wx/string.h> #include <wx/string.h>
#include <wx/arrstr.h>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include "PrintHost.hpp" #include "PrintHost.hpp"
@ -29,10 +30,14 @@ public:
bool has_auto_discovery() const override { return true; } bool has_auto_discovery() const override { return true; }
bool can_test() const override { return true; } bool can_test() const override { return true; }
bool can_start_print() const override { return true; } bool can_start_print() const override { return true; }
bool can_support_multiple_printers() const override { return false; }
std::string get_host() const override { return host; } std::string get_host() const override { return host; }
const std::string& get_apikey() const { return apikey; } const std::string& get_apikey() const { return apikey; }
const std::string& get_cafile() const { return cafile; } const std::string& get_cafile() const { return cafile; }
bool get_groups(wxArrayString &groups) const override { return false; }
bool get_printers(wxArrayString &printers) const override { return false; }
protected: protected:
virtual bool validate_version_text(const boost::optional<std::string> &version_text) const; virtual bool validate_version_text(const boost::optional<std::string> &version_text) const;

View File

@ -16,6 +16,7 @@
#include "Duet.hpp" #include "Duet.hpp"
#include "FlashAir.hpp" #include "FlashAir.hpp"
#include "AstroBox.hpp" #include "AstroBox.hpp"
#include "Repetier.hpp"
#include "../GUI/PrintHostDialogs.hpp" #include "../GUI/PrintHostDialogs.hpp"
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
@ -47,6 +48,7 @@ PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config)
case htDuet: return new Duet(config); case htDuet: return new Duet(config);
case htFlashAir: return new FlashAir(config); case htFlashAir: return new FlashAir(config);
case htAstroBox: return new AstroBox(config); case htAstroBox: return new AstroBox(config);
case htRepetier: return new Repetier(config);
default: return nullptr; default: return nullptr;
} }
} else { } else {

View File

@ -7,6 +7,7 @@
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <wx/string.h> #include <wx/string.h>
#include <wx/arrstr.h>
#include "Http.hpp" #include "Http.hpp"
@ -20,6 +21,9 @@ struct PrintHostUpload
{ {
boost::filesystem::path source_path; boost::filesystem::path source_path;
boost::filesystem::path upload_path; boost::filesystem::path upload_path;
std::string group;
bool start_print = false; bool start_print = false;
}; };
@ -41,7 +45,10 @@ public:
virtual bool has_auto_discovery() const = 0; virtual bool has_auto_discovery() const = 0;
virtual bool can_test() const = 0; virtual bool can_test() const = 0;
virtual bool can_start_print() const = 0; virtual bool can_start_print() const = 0;
virtual bool can_support_multiple_printers() const = 0;
virtual std::string get_host() const = 0; virtual std::string get_host() const = 0;
virtual bool get_groups(wxArrayString& groups) const = 0;
virtual bool get_printers(wxArrayString &printers) const = 0;
static PrintHost* get_print_host(DynamicPrintConfig *config); static PrintHost* get_print_host(DynamicPrintConfig *config);

View File

@ -0,0 +1,263 @@
#include "Repetier.hpp"
#include <algorithm>
#include <sstream>
#include <exception>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <boost/log/trivial.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <wx/progdlg.h>
#include "libslic3r/PrintConfig.hpp"
#include "slic3r/GUI/I18N.hpp"
#include "slic3r/GUI/GUI.hpp"
#include "Http.hpp"
namespace fs = boost::filesystem;
namespace pt = boost::property_tree;
namespace Slic3r {
Repetier::Repetier(DynamicPrintConfig *config) :
host(config->opt_string("print_host")),
apikey(config->opt_string("printhost_apikey")),
cafile(config->opt_string("printhost_cafile")),
slug(config->opt_string("printhost_slug"))
{}
const char* Repetier::get_name() const { return "Repetier"; }
bool Repetier::test(wxString &msg) const
{
// Since the request is performed synchronously here,
// it is ok to refer to `msg` from within the closure
const char *name = get_name();
bool res = true;
auto url = make_url("printer/info");
BOOST_LOG_TRIVIAL(info) << boost::format("%1%: List version at: %2%") % name % url;
auto http = Http::get(std::move(url));
set_auth(http);
http.on_error([&](std::string body, std::string error, unsigned status) {
BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error getting version: %2%, HTTP %3%, body: `%4%`") % name % error % status % body;
res = false;
msg = format_error(body, error, status);
})
.on_complete([&, this](std::string body, unsigned) {
BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got version: %2%") % name % body;
try {
std::stringstream ss(body);
pt::ptree ptree;
pt::read_json(ss, ptree);
const auto text = ptree.get_optional<std::string>("name");
res = validate_version_text(text);
if (! res) {
msg = GUI::from_u8((boost::format(_utf8(L("Mismatched type of print host: %s"))) % (text ? *text : "Repetier")).str());
}
}
catch (const std::exception &) {
res = false;
msg = "Could not parse server response";
}
})
.perform_sync();
return res;
}
wxString Repetier::get_test_ok_msg () const
{
return _(L("Connection to Repetier works correctly."));
}
wxString Repetier::get_test_failed_msg (wxString &msg) const
{
return GUI::from_u8((boost::format("%s: %s\n\n%s")
% _utf8(L("Could not connect to Repetier"))
% std::string(msg.ToUTF8())
% _utf8(L("Note: Repetier version at least 0.90.0 is required."))).str());
}
bool Repetier::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const
{
const char *name = get_name();
const auto upload_filename = upload_data.upload_path.filename();
const auto upload_parent_path = upload_data.upload_path.parent_path();
wxString test_msg;
if (! test(test_msg)) {
error_fn(std::move(test_msg));
return false;
}
bool res = true;
auto url = make_url((boost::format("printer/model/%1%") % slug).str());
BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Uploading file %2% at %3%, filename: %4%, path: %5%, print: %6%, group: %7%")
% name
% upload_data.source_path
% url
% upload_filename.string()
% upload_parent_path.string()
% upload_data.start_print
% upload_data.group;
auto http = Http::post(std::move(url));
set_auth(http);
if (! upload_data.group.empty() && upload_data.group != _utf8(L("Default"))) {
http.form_add("group", upload_data.group);
}
http.form_add("a", "upload")
.form_add_file("filename", upload_data.source_path.string(), upload_filename.string())
.on_complete([&](std::string body, unsigned status) {
BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: File uploaded: HTTP %2%: %3%") % name % status % body;
})
.on_error([&](std::string body, std::string error, unsigned status) {
BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error uploading file: %2%, HTTP %3%, body: `%4%`") % name % error % status % body;
error_fn(format_error(body, error, status));
res = false;
})
.on_progress([&](Http::Progress progress, bool &cancel) {
prorgess_fn(std::move(progress), cancel);
if (cancel) {
// Upload was canceled
BOOST_LOG_TRIVIAL(info) << "Repetier: Upload canceled";
res = false;
}
})
.perform_sync();
return res;
}
bool Repetier::validate_version_text(const boost::optional<std::string> &version_text) const
{
return version_text ? boost::starts_with(*version_text, "Repetier") : true;
}
void Repetier::set_auth(Http &http) const
{
http.header("X-Api-Key", apikey);
if (! cafile.empty()) {
http.ca_file(cafile);
}
}
std::string Repetier::make_url(const std::string &path) const
{
if (host.find("http://") == 0 || host.find("https://") == 0) {
if (host.back() == '/') {
return (boost::format("%1%%2%") % host % path).str();
} else {
return (boost::format("%1%/%2%") % host % path).str();
}
} else {
return (boost::format("http://%1%/%2%") % host % path).str();
}
}
bool Repetier::get_groups(wxArrayString& groups) const
{
bool res = true;
const char *name = get_name();
auto url = make_url((boost::format("printer/api/%1%") % slug).str());
BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Get groups at: %2%") % name % url;
auto http = Http::get(std::move(url));
set_auth(http);
http.form_add("a", "listModelGroups");
http.on_error([&](std::string body, std::string error, unsigned status) {
BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error getting version: %2%, HTTP %3%, body: `%4%`") % name % error % status % body;
})
.on_complete([&, this](std::string body, unsigned) {
BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got groups: %2%") % name % body;
try {
std::stringstream ss(body);
pt::ptree ptree;
pt::read_json(ss, ptree);
BOOST_FOREACH(boost::property_tree::ptree::value_type &v, ptree.get_child("groupNames.")) {
if (v.second.data() == "#") {
groups.push_back(_utf8(L("Default")));
} else {
groups.push_back(v.second.data());
}
}
}
catch (const std::exception &) {
//msg = "Could not parse server response";
res = false;
}
})
.perform_sync();
return res;
}
bool Repetier::get_printers(wxArrayString& printers) const
{
const char *name = get_name();
bool res = true;
auto url = make_url("printer/list");
BOOST_LOG_TRIVIAL(info) << boost::format("%1%: List printers at: %2%") % name % url;
auto http = Http::get(std::move(url));
set_auth(http);
auto &slugs = printers;
http.on_error([&](std::string body, std::string error, unsigned status) {
BOOST_LOG_TRIVIAL(error) << boost::format("%1%: Error listing printers: %2%, HTTP %3%, body: `%4%`") % name % error % status % body;
res = false;
})
.on_complete([&, this](std::string body, unsigned) {
BOOST_LOG_TRIVIAL(debug) << boost::format("%1%: Got printers: %2%") % name % body;
try {
std::stringstream ss(body);
pt::ptree ptree;
pt::read_json(ss, ptree);
const auto error = ptree.get_optional<std::string>("error");
if (error) {
res = false;
} else {
BOOST_FOREACH(boost::property_tree::ptree::value_type &v, ptree.get_child("data.")) {
const auto slug = v.second.get<std::string>("slug");
printers.push_back(slug);
}
//res = !printers.empty();
}
}
catch (const std::exception &) {
res = false;
}
})
.perform_sync();
return res;
}
}

View File

@ -0,0 +1,52 @@
#ifndef slic3r_Repetier_hpp_
#define slic3r_Repetier_hpp_
#include <string>
#include <wx/string.h>
#include <boost/optional.hpp>
#include "PrintHost.hpp"
namespace Slic3r {
class DynamicPrintConfig;
class Http;
class Repetier : public PrintHost
{
public:
Repetier(DynamicPrintConfig *config);
~Repetier() override = default;
const char* get_name() const;
bool test(wxString &curl_msg) const override;
wxString get_test_ok_msg () const override;
wxString get_test_failed_msg (wxString &msg) const override;
bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const override;
bool has_auto_discovery() const override { return false; }
bool can_test() const override { return true; }
bool can_start_print() const override { return false; }
bool can_support_multiple_printers() const override { return true; }
std::string get_host() const override { return host; }
bool get_groups(wxArrayString &groups) const override;
bool get_printers(wxArrayString &printers) const override;
protected:
virtual bool validate_version_text(const boost::optional<std::string> &version_text) const;
private:
std::string host;
std::string apikey;
std::string cafile;
std::string slug;
void set_auth(Http &http) const;
std::string make_url(const std::string &path) const;
};
}
#endif