mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-19 18:19:09 +08:00
Merge remote-tracking branch 'remotes/remi/CI' into dev
in particular, move the repetier stuff to physicalprinter
This commit is contained in:
commit
160b509a46
13
.github/ISSUE_TEMPLATE.md
vendored
13
.github/ISSUE_TEMPLATE.md
vendored
@ -1,13 +1,8 @@
|
||||
### Version
|
||||
_Version of SupserSlicer used goes here_
|
||||
|
||||
_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`_
|
||||
_Version of SupserSlicer used goes here, Use `About->About SuperSlicer`_
|
||||
|
||||
### Operating system type + version
|
||||
_What OS are you using, and state any version #s_
|
||||
_In case of 3D rendering issues, please attach the content of menu Help -> System Info dialog_
|
||||
_What OS are you using (and version)_
|
||||
|
||||
### 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_
|
||||
@ -20,7 +15,5 @@ _What 3D printer brand / version are you printing on, is it a stock model or did
|
||||
* _Actual Results_
|
||||
* _Screenshots from __*SuperSlicer*__ preview are preferred_
|
||||
|
||||
_Is this a new feature request?_
|
||||
|
||||
#### 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`)_
|
||||
|
@ -35,7 +35,7 @@ This calibration will help you to choose the right retraction length for your ex
|
||||
<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").
|
||||
<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.
|
||||
<h2>Example</h2>
|
||||
<table width="100%">
|
||||
|
@ -40,9 +40,9 @@ group:Quality
|
||||
setting:thin_walls_merge
|
||||
end_line
|
||||
group:Overhangs
|
||||
line:On perimeters
|
||||
setting:sidetext_width$1:overhangs
|
||||
setting:width$5:overhangs_width
|
||||
line:threshold for
|
||||
setting:label$bridge speed and fan:width$5:overhangs_width_speed
|
||||
setting:label$bridge flow:width$5:overhangs_width
|
||||
end_line
|
||||
line:Extrusion direction
|
||||
setting:sidetext_width$1:overhangs_reverse
|
||||
@ -202,7 +202,6 @@ group:label_width$8:Speed for print moves
|
||||
line:Perimeter speed
|
||||
setting:width$4:perimeter_speed
|
||||
setting:width$4:external_perimeter_speed
|
||||
setting:width$4:small_perimeter_speed
|
||||
end_line
|
||||
line: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_infill_speed
|
||||
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)
|
||||
setting:perimeter_acceleration
|
||||
setting:infill_acceleration
|
||||
|
@ -598,7 +598,8 @@ Fill::do_gap_fill(const ExPolygons &gapfill_areas, const FillParams ¶ms, Ext
|
||||
// offset2_ex(gapfill_areas, double(-max / 2), double(+max / 2)),
|
||||
// true);
|
||||
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) {
|
||||
//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.
|
||||
@ -620,10 +621,10 @@ Fill::do_gap_fill(const ExPolygons &gapfill_areas, const FillParams ¶ms, Ext
|
||||
|
||||
ExtrusionEntityCollection gap_fill = thin_variable_width(polylines_gapfill, erGapFill, params.flow);
|
||||
//set role if needed
|
||||
if (params.role != erSolidInfill) {
|
||||
/*if (params.role != erSolidInfill) {
|
||||
ExtrusionSetRole set_good_role(params.role);
|
||||
gap_fill.visit(set_good_role);
|
||||
}
|
||||
}*/
|
||||
//move them into the collection
|
||||
if (!gap_fill.entities.empty()) {
|
||||
ExtrusionEntityCollection *coll_gapfill = new ExtrusionEntityCollection();
|
||||
|
@ -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()))));
|
||||
gapfill_areas = union_ex(gapfill_areas, true);
|
||||
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++) {
|
||||
if (gapfill_areas[i].area() < minarea) {
|
||||
gapfill_areas.erase(gapfill_areas.begin() + i);
|
||||
|
@ -1490,7 +1490,6 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
||||
print.throw_if_canceled();
|
||||
|
||||
m_cooling_buffer->set_current_extruder(initial_extruder_id);
|
||||
m_writer.toolchange(initial_extruder_id);
|
||||
|
||||
// Emit machine envelope limits for the Marlin firmware.
|
||||
this->print_machine_envelope(file, print);
|
||||
@ -1498,7 +1497,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
||||
// Disable fan.
|
||||
if ( print.config().disable_fan_first_layers.get_at(initial_extruder_id)
|
||||
&& 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.
|
||||
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_e.values.front() + 0.5));
|
||||
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));
|
||||
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.
|
||||
continue;
|
||||
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_bed_temperature(print.config().bed_temperature.get_at(first_extruder_id));
|
||||
@ -2698,6 +2696,9 @@ void GCode::process_layer(
|
||||
this->set_origin(unscale(offset));
|
||||
if (instance_to_print.object_by_extruder.support != nullptr && !print_wipe_extrusions) {
|
||||
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 += this->extrude_support(
|
||||
// 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",
|
||||
"print_host",
|
||||
"printhost_apikey",
|
||||
"printhost_cafile"
|
||||
"printhost_cafile",
|
||||
"printhost_slug"
|
||||
};
|
||||
assert(std::is_sorted(banned_keys.begin(), banned_keys.end()));
|
||||
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 "";
|
||||
|
||||
// apply the small/external? perimeter speed
|
||||
if (is_perimeter(paths.front().role()) && loop.length() <= SMALL_PERIMETER_LENGTH && speed == -1)
|
||||
speed = m_config.external_perimeter_speed.get_abs_value(m_config.perimeter_speed);
|
||||
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);
|
||||
} else {
|
||||
speed = - (loop.length() - min_length) / (max_length - min_length);
|
||||
}
|
||||
}
|
||||
|
||||
//get extrusion length
|
||||
coordf_t length = 0;
|
||||
@ -3295,8 +3305,16 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
|
||||
if (paths.empty()) return "";
|
||||
|
||||
// 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);
|
||||
} else {
|
||||
speed = -(loop.length() - min_length) / (max_length - min_length);
|
||||
}
|
||||
}
|
||||
|
||||
// extrude along the path
|
||||
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()[®ion - &by_region.front()]->config());
|
||||
if (m_config.print_temperature > 0)
|
||||
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
|
||||
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)
|
||||
@ -3600,6 +3620,8 @@ std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectBy
|
||||
m_writer.apply_print_region_config(print.regions()[®ion - &by_region.front()]->config());
|
||||
if (m_config.print_temperature > 0)
|
||||
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
|
||||
gcode += m_writer.set_temperature(m_config.temperature.get_at(m_writer.tool()->id()), false, m_writer.tool()->id());
|
||||
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
|
||||
* m_writer.tool()->e_per_mm3()
|
||||
* 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 (path.polyline.lines().size() > 0) {
|
||||
//get last direction //TODO: save it
|
||||
@ -3889,7 +3911,10 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string
|
||||
|
||||
|
||||
// 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) {
|
||||
speed = m_config.get_abs_value("perimeter_speed");
|
||||
} else if (path.role() == erExternalPerimeter) {
|
||||
@ -3915,6 +3940,12 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string
|
||||
} else {
|
||||
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)
|
||||
speed = m_volumetric_speed / path.mm3_per_mm;
|
||||
|
@ -31,6 +31,44 @@ void GCodeWriter::apply_print_region_config(const PrintRegionConfig& print_regio
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
//use m_tool if tool isn't set
|
||||
if (tool < 0 && m_tool != nullptr)
|
||||
tool = m_tool->id();
|
||||
|
||||
//add offset
|
||||
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));
|
||||
|
||||
if (m_last_temperature_with_offset == temp_w_offset)
|
||||
if (m_last_temperature_with_offset == temp_w_offset && !wait)
|
||||
return "";
|
||||
if (wait && (FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish)))
|
||||
return "";
|
||||
@ -177,13 +219,15 @@ std::string GCodeWriter::set_bed_temperature(unsigned int temperature, bool wait
|
||||
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;
|
||||
|
||||
const Tool *tool = m_tool == nullptr ? get_tool(default_tool) : m_tool;
|
||||
//add fan_offset
|
||||
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));
|
||||
|
||||
//test if it's useful to write it
|
||||
|
@ -34,41 +34,21 @@ public:
|
||||
// Extruders are expected to be sorted in an increasing order.
|
||||
void set_extruders(std::vector<uint16_t> extruder_ids);
|
||||
const std::vector<Extruder>& extruders() const { return m_extruders; }
|
||||
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;
|
||||
}
|
||||
std::vector<uint16_t> extruder_ids() const;
|
||||
void set_mills(std::vector<uint16_t> extruder_ids);
|
||||
const std::vector<Mill>& mills() const { return m_millers; }
|
||||
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;
|
||||
}
|
||||
std::vector<uint16_t> mill_ids() const;
|
||||
//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 {
|
||||
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 tool_is_extruder() const {
|
||||
return m_tool->id() < first_mill();
|
||||
}
|
||||
uint16_t first_mill() const;
|
||||
bool tool_is_extruder() const;
|
||||
const Tool* get_tool(uint16_t id) const;
|
||||
std::string preamble();
|
||||
std::string postamble() const;
|
||||
std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1);
|
||||
std::string set_bed_temperature(unsigned int temperature, bool wait = false);
|
||||
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);
|
||||
std::string write_acceleration();
|
||||
std::string reset_e(bool force = false);
|
||||
|
@ -153,7 +153,7 @@ void Layer::make_perimeters()
|
||||
&& config.infill_dense_algo == other_config.infill_dense_algo
|
||||
&& config.no_perimeter_unsupported_algo == other_config.no_perimeter_unsupported_algo
|
||||
&& 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_reverse == other_config.overhangs_reverse
|
||||
&& 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_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_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_min_width == other_config.thin_walls_min_width
|
||||
&& config.thin_walls_overlap == other_config.thin_walls_overlap
|
||||
|
@ -97,12 +97,16 @@ void PerimeterGenerator::process()
|
||||
coord_t ext_min_spacing = (coord_t)( ext_perimeter_spacing2 * (1 - 0.05/*INSET_OVERLAP_TOLERANCE*/) );
|
||||
|
||||
// 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
|
||||
// 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
|
||||
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
|
||||
@ -942,6 +946,69 @@ void PerimeterGenerator::process()
|
||||
} // 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(
|
||||
const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const
|
||||
{
|
||||
@ -971,31 +1038,9 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops(
|
||||
|
||||
// detect overhanging/bridging perimeters
|
||||
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)) {
|
||||
// get non-overhang paths by intersecting this loop with the grown lower slices
|
||||
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());
|
||||
paths = this->create_overhangs(loop.polygon, role, is_external);
|
||||
} else {
|
||||
ExtrusionPath path(role);
|
||||
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
|
||||
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)) {
|
||||
ExtrusionPaths paths;
|
||||
// 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());
|
||||
|
||||
ExtrusionPaths paths = this->create_overhangs(initial_polyline, role, is_external);
|
||||
|
||||
if (direction.length() > 0) {
|
||||
Polyline direction_polyline;
|
||||
|
@ -96,7 +96,11 @@ private:
|
||||
double _ext_mm3_per_mm;
|
||||
double _mm3_per_mm;
|
||||
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.
|
||||
ExtrusionEntityCollection _traverse_loops(const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const;
|
||||
|
@ -442,8 +442,9 @@ const std::vector<std::string>& Preset::print_options()
|
||||
"avoid_crossing_perimeters",
|
||||
"avoid_crossing_not_first_layer",
|
||||
"thin_perimeters", "thin_perimeters_all",
|
||||
"thin_walls", "overhangs",
|
||||
"thin_walls",
|
||||
"overhangs_width",
|
||||
"overhangs_width_speed",
|
||||
"overhangs_reverse",
|
||||
"overhangs_reverse_threshold",
|
||||
"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",
|
||||
#endif /* HAS_PRESSURE_EQUALIZER */
|
||||
"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",
|
||||
"bridge_speed",
|
||||
"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",
|
||||
"use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
|
||||
"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",
|
||||
|
||||
"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",
|
||||
"min_exposure_time", "max_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",
|
||||
"inherits",
|
||||
"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_printhost_apikey_old = cfg_old.option<ConfigOptionString>("printhost_apikey");
|
||||
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_printhost_apikey_new = cfg_new.option<ConfigOptionString>("printhost_apikey");
|
||||
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.
|
||||
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_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)
|
||||
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);
|
||||
};
|
||||
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)
|
||||
@ -938,7 +947,7 @@ static bool profile_print_params_same(const DynamicPrintConfig &cfg_old, const D
|
||||
"compatible_printers", "compatible_printers_condition", "inherits",
|
||||
"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",
|
||||
"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());
|
||||
// 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;
|
||||
@ -988,6 +997,7 @@ Preset& PresetCollection::load_external_preset(
|
||||
opt_update("print_host");
|
||||
opt_update("printhost_apikey");
|
||||
opt_update("printhost_cafile");
|
||||
opt_update("printhost_slug");
|
||||
}
|
||||
}
|
||||
// Update the "inherits" field.
|
||||
@ -1567,6 +1577,7 @@ const std::vector<std::string>& PhysicalPrinter::printer_options()
|
||||
"print_host",
|
||||
"printhost_apikey",
|
||||
"printhost_cafile",
|
||||
"printhost_slug",
|
||||
"printhost_authorization_type",
|
||||
// HTTP digest authentization (RFC 2617)
|
||||
"printhost_user",
|
||||
@ -1583,7 +1594,8 @@ const std::vector<std::string>& PhysicalPrinter::print_host_options()
|
||||
s_opts = {
|
||||
"print_host",
|
||||
"printhost_apikey",
|
||||
"printhost_cafile"
|
||||
"printhost_cafile",
|
||||
"printhost_slug"
|
||||
};
|
||||
}
|
||||
return s_opts;
|
||||
@ -1619,7 +1631,8 @@ bool PhysicalPrinter::has_empty_config() const
|
||||
config.opt_string("printhost_apikey" ).empty() &&
|
||||
config.opt_string("printhost_cafile" ).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()
|
||||
|
@ -499,6 +499,7 @@ DynamicPrintConfig PresetBundle::full_config_secure() const
|
||||
config.erase("print_host");
|
||||
config.erase("printhost_apikey");
|
||||
config.erase("printhost_cafile");
|
||||
config.erase("printhost_slug");
|
||||
return config;
|
||||
}
|
||||
|
||||
|
@ -151,6 +151,13 @@ void PrintConfigDef::init_common_params()
|
||||
def->mode = comAdvanced;
|
||||
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->label = L("HTTPS CA File");
|
||||
def->category = OptionCategory::general;
|
||||
@ -2380,10 +2387,12 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_values.push_back("duet");
|
||||
def->enum_values.push_back("flashair");
|
||||
def->enum_values.push_back("astrobox");
|
||||
def->enum_values.push_back("repetier");
|
||||
def->enum_labels.push_back("OctoPrint");
|
||||
def->enum_labels.push_back("Duet");
|
||||
def->enum_labels.push_back("FlashAir");
|
||||
def->enum_labels.push_back("AstroBox");
|
||||
def->enum_labels.push_back("Repetier");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionEnum<PrintHostType>(htOctoPrint));
|
||||
|
||||
@ -2448,24 +2457,30 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionString("[input_filename_base].gcode"));
|
||||
|
||||
def = this->add("overhangs", coBool);
|
||||
def->label = L("As bridge");
|
||||
def->full_label = L("Overhangs as bridge");
|
||||
def = this->add("overhangs_width_speed", coFloatOrPercent);
|
||||
def->label = L("'As bridge' speed threshold");
|
||||
def->full_label = L("Overhang bridge speed threshold");
|
||||
def->category = OptionCategory::perimeter;
|
||||
def->tooltip = L("Option to adjust flow for overhangs (bridge flow will be used), "
|
||||
"to apply bridge speed to them and enable fan.");
|
||||
def->mode = comExpert;
|
||||
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->tooltip = L("Minimum unsupported width for an extrusion to apply the bridge speed & fan 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(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->label = L("Reverse on odd");
|
||||
def->full_label = L("Overhang reversal");
|
||||
@ -2934,7 +2949,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionInts{ 5 });
|
||||
|
||||
def = this->add("small_perimeter_speed", coFloatOrPercent);
|
||||
def->label = L("Small");
|
||||
def->label = L("Speed");
|
||||
def->full_label = ("Small perimeters speed");
|
||||
def->category = OptionCategory::speed;
|
||||
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->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->label = L("Min convex angle");
|
||||
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";
|
||||
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:
|
||||
static std::set<std::string> ignore = {
|
||||
|
@ -71,7 +71,7 @@ enum class MachineLimitsUsage {
|
||||
};
|
||||
|
||||
enum PrintHostType {
|
||||
htOctoPrint, htDuet, htFlashAir, htAstroBox
|
||||
htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier
|
||||
};
|
||||
|
||||
enum AuthorizationType {
|
||||
@ -204,6 +204,7 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<PrintHostType>::g
|
||||
keys_map["duet"] = htDuet;
|
||||
keys_map["flashair"] = htFlashAir;
|
||||
keys_map["astrobox"] = htAstroBox;
|
||||
keys_map["repetier"] = htRepetier;
|
||||
}
|
||||
return keys_map;
|
||||
}
|
||||
@ -753,8 +754,8 @@ public:
|
||||
ConfigOptionFloat milling_speed;
|
||||
ConfigOptionFloatOrPercent min_width_top_surface;
|
||||
// Detect bridging perimeters
|
||||
ConfigOptionBool overhangs;
|
||||
ConfigOptionFloatOrPercent overhangs_width;
|
||||
ConfigOptionFloatOrPercent overhangs_width_speed;
|
||||
ConfigOptionBool overhangs_reverse;
|
||||
ConfigOptionFloatOrPercent overhangs_reverse_threshold;
|
||||
ConfigOptionEnum<NoPerimeterUnsupportedAlgo> no_perimeter_unsupported_algo;
|
||||
@ -769,6 +770,8 @@ public:
|
||||
ConfigOptionPercent print_extrusion_multiplier;
|
||||
ConfigOptionFloat print_retract_length;
|
||||
ConfigOptionFloatOrPercent small_perimeter_speed;
|
||||
ConfigOptionFloatOrPercent small_perimeter_min_length;
|
||||
ConfigOptionFloatOrPercent small_perimeter_max_length;
|
||||
ConfigOptionEnum<InfillPattern> solid_fill_pattern;
|
||||
ConfigOptionFloat solid_infill_below_area;
|
||||
ConfigOptionInt solid_infill_extruder;
|
||||
@ -850,8 +853,8 @@ protected:
|
||||
OPT_PTR(milling_post_process);
|
||||
OPT_PTR(milling_speed);
|
||||
OPT_PTR(min_width_top_surface);
|
||||
OPT_PTR(overhangs);
|
||||
OPT_PTR(overhangs_width);
|
||||
OPT_PTR(overhangs_width_speed);
|
||||
OPT_PTR(overhangs_reverse);
|
||||
OPT_PTR(overhangs_reverse_threshold);
|
||||
OPT_PTR(no_perimeter_unsupported_algo);
|
||||
@ -865,6 +868,8 @@ protected:
|
||||
OPT_PTR(print_extrusion_multiplier);
|
||||
OPT_PTR(print_retract_length);
|
||||
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_infill_below_area);
|
||||
OPT_PTR(solid_infill_extruder);
|
||||
@ -1349,6 +1354,7 @@ public:
|
||||
ConfigOptionString print_host;
|
||||
ConfigOptionString printhost_apikey;
|
||||
ConfigOptionString printhost_cafile;
|
||||
ConfigOptionString printhost_slug;
|
||||
ConfigOptionString serial_port;
|
||||
ConfigOptionInt serial_speed;
|
||||
|
||||
@ -1359,6 +1365,7 @@ protected:
|
||||
OPT_PTR(print_host);
|
||||
OPT_PTR(printhost_apikey);
|
||||
OPT_PTR(printhost_cafile);
|
||||
OPT_PTR(printhost_slug);
|
||||
OPT_PTR(serial_port);
|
||||
OPT_PTR(serial_speed);
|
||||
}
|
||||
|
@ -682,7 +682,7 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|
||||
opt_key == "gap_fill"
|
||||
|| opt_key == "gap_fill_min_area"
|
||||
|| opt_key == "only_one_perimeter_top"
|
||||
|| opt_key == "overhangs"
|
||||
|| opt_key == "overhangs_width_speed"
|
||||
|| opt_key == "overhangs_width"
|
||||
|| opt_key == "overhangs_reverse"
|
||||
|| 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_travel_cost"
|
||||
|| opt_key == "small_perimeter_speed"
|
||||
|| opt_key == "small_perimeter_min_length"
|
||||
|| opt_key == "small_perimeter_max_length"
|
||||
|| opt_key == "solid_infill_speed"
|
||||
|| opt_key == "support_material_interface_speed"
|
||||
|| opt_key == "support_material_speed"
|
||||
|
@ -2141,7 +2141,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object(
|
||||
polygons_append(polygons_trimming,
|
||||
offset(to_expolygons(region->fill_surfaces.filter_by_type(stPosBottom | stDensSolid | stModBridge)),
|
||||
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);
|
||||
}
|
||||
if (! some_region_overlaps)
|
||||
|
@ -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.
|
||||
static constexpr double LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER = 0.15;
|
||||
// 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;
|
||||
//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)); }
|
||||
|
@ -211,6 +211,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
Utils/FlashAir.hpp
|
||||
Utils/AstroBox.cpp
|
||||
Utils/AstroBox.hpp
|
||||
Utils/Repetier.cpp
|
||||
Utils/Repetier.hpp
|
||||
Utils/PrintHost.cpp
|
||||
Utils/PrintHost.hpp
|
||||
Utils/Bonjour.cpp
|
||||
|
@ -86,7 +86,7 @@ void CalibrationBridgeDialog::create_geometry(std::string setting_to_test, bool
|
||||
int start = bridge_flow_ratio->value;
|
||||
float zshift = 2.3 * (1 - z_scale);
|
||||
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 });
|
||||
}
|
||||
|
||||
|
@ -26,11 +26,11 @@ namespace GUI {
|
||||
void CalibrationRetractionDialog::create_buttons(wxStdDialogButtonSizer* buttons){
|
||||
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->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);
|
||||
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->SetToolTip(_(L("Select the number milimeters for the tower.")));
|
||||
nb_steps->SetToolTip(_L("Select the number milimeters for the tower."));
|
||||
nb_steps->SetSelection(5);
|
||||
//wxString choices_start[] = { "current","260","250","240","230","220","210" };
|
||||
//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;
|
||||
auto size = wxSize(4 * em_unit(), wxDefaultCoord);
|
||||
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->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);
|
||||
|
||||
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
|
||||
float zshift = (1 - scale) / 2 + 0.4 * scale;
|
||||
float zscale_number = (first_layer_height + layer_height) / 0.4;
|
||||
std::vector < std::vector<ModelObject*>> part_tower;
|
||||
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;
|
||||
if (mytemp > 285) mytemp = 285;
|
||||
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(1, 0, 0));
|
||||
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_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("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_min_width", new ConfigOptionFloatOrPercent(2,true));
|
||||
model.objects[objs_idx[i]]->config.set_key_value("gap_fill", new ConfigOptionBool(false));
|
||||
|
@ -275,9 +275,9 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
||||
// Ask only once.
|
||||
if (!support_material_overhangs_queried) {
|
||||
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"
|
||||
"- Detect bridging perimeters"));
|
||||
"- overhangs with bridge speed & fan"));
|
||||
if (is_global_config) {
|
||||
msg_text += "\n\n" + _(L("Shall I adjust those settings for supports?"));
|
||||
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();
|
||||
if (!is_global_config || answer == wxID_YES) {
|
||||
// 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) {
|
||||
// Do nothing, leave supports on and "detect bridging perimeters" off.
|
||||
} 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",
|
||||
"overhangs", "overhangs_reverse",
|
||||
"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("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("min_width_top_surface", config->opt_bool("only_one_perimeter_top"));
|
||||
toggle_field("thin_perimeters_all", config->opt_bool("thin_perimeters"));
|
||||
|
@ -862,9 +862,12 @@ void Choice::BUILD() {
|
||||
*
|
||||
* 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);
|
||||
empty_bmp.SetWidth(0);
|
||||
temp->SetItemBitmap(0, empty_bmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
// temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) { on_change_field(); }), temp->GetId());
|
||||
|
@ -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)
|
||||
config.set_key_value(opt_key, new ConfigOptionEnum<DenseInfillAlgo>(boost::any_cast<DenseInfillAlgo>(value)));
|
||||
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)
|
||||
config.set_key_value(opt_key, new ConfigOptionEnum<InfillConnection>(boost::any_cast<InfillConnection>(value)));
|
||||
else if (opt_key.compare("wipe_advanced_algo") == 0)
|
||||
|
@ -251,7 +251,7 @@ PhysicalPrinterDialog::~PhysicalPrinterDialog()
|
||||
void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgroup)
|
||||
{
|
||||
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();
|
||||
};
|
||||
|
||||
@ -302,6 +302,13 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr
|
||||
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
|
||||
Option option = m_optgroup->get_option("print_host");
|
||||
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();
|
||||
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.");
|
||||
|
||||
if (Http::ca_file_supported()) {
|
||||
@ -405,9 +418,61 @@ void PhysicalPrinterDialog::update()
|
||||
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();
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
|
@ -72,6 +72,7 @@ class PhysicalPrinterDialog : public DPIDialog
|
||||
ScalableButton* m_add_preset_btn {nullptr};
|
||||
ScalableButton* m_printhost_browse_btn {nullptr};
|
||||
ScalableButton* m_printhost_test_btn {nullptr};
|
||||
ScalableButton* m_printhost_slug_browse_btn {nullptr};
|
||||
ScalableButton* m_printhost_cafile_browse_btn {nullptr};
|
||||
|
||||
wxBoxSizer* m_presets_sizer {nullptr};
|
||||
@ -85,6 +86,7 @@ public:
|
||||
~PhysicalPrinterDialog();
|
||||
|
||||
void update();
|
||||
void update_printers();
|
||||
wxString get_printer_name();
|
||||
void update_full_printer_names();
|
||||
PhysicalPrinter* get_printer() {return &m_printer; }
|
||||
|
@ -1850,7 +1850,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
"complete_objects_one_skirt",
|
||||
"duplicate_distance", "extruder_clearance_radius", "skirts", "skirt_distance", "skirt_height",
|
||||
"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",
|
||||
"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.
|
||||
@ -5376,10 +5376,14 @@ void Plater::send_gcode()
|
||||
}
|
||||
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) {
|
||||
upload_job.upload_data.upload_path = dlg.filename();
|
||||
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));
|
||||
}
|
||||
|
@ -28,11 +28,13 @@ namespace GUI {
|
||||
|
||||
static const char *CONFIG_KEY_PATH = "printhost_path";
|
||||
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)
|
||||
, txt_filename(new wxTextCtrl(this, wxID_ANY))
|
||||
, 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__
|
||||
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");
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
|
||||
@ -86,6 +102,16 @@ bool PrintHostSendDialog::start_print() const
|
||||
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)
|
||||
{
|
||||
if (ret == wxID_OK) {
|
||||
@ -96,9 +122,15 @@ void PrintHostSendDialog::EndModal(int ret)
|
||||
path.clear();
|
||||
else
|
||||
path = path.SubString(0, last_slash);
|
||||
|
||||
AppConfig *app_config = wxGetApp().app_config;
|
||||
app_config->set("recent", CONFIG_KEY_PATH, into_u8(path));
|
||||
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);
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include <wx/string.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/combobox.h>
|
||||
#include <wx/arrstr.h>
|
||||
|
||||
#include "GUI.hpp"
|
||||
#include "GUI_Utils.hpp"
|
||||
@ -29,14 +31,16 @@ namespace GUI {
|
||||
class PrintHostSendDialog : public GUI::MsgDialog
|
||||
{
|
||||
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;
|
||||
bool start_print() const;
|
||||
std::string group() const;
|
||||
|
||||
virtual void EndModal(int ret) override;
|
||||
private:
|
||||
wxTextCtrl *txt_filename;
|
||||
wxCheckBox *box_print;
|
||||
wxComboBox *combo_groups;
|
||||
};
|
||||
|
||||
|
||||
|
@ -2312,6 +2312,7 @@ void TabPrinter::build_sla()
|
||||
|
||||
}
|
||||
|
||||
|
||||
void TabPrinter::extruders_count_changed(size_t extruders_count)
|
||||
{
|
||||
bool is_count_changed = false;
|
||||
|
@ -444,6 +444,8 @@ public:
|
||||
wxButton* m_serial_test_btn = nullptr;
|
||||
ScalableButton* m_print_host_test_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;
|
||||
|
||||
size_t m_extruders_count = 0;
|
||||
@ -476,6 +478,7 @@ public:
|
||||
void update_fff();
|
||||
void update_sla();
|
||||
void update_pages(); // update m_pages according to printer technology
|
||||
void update_printers();
|
||||
void extruders_count_changed(size_t extruders_count);
|
||||
void milling_count_changed(size_t extruders_count);
|
||||
PageShp build_kinematics_page();
|
||||
|
@ -27,8 +27,12 @@ public:
|
||||
bool has_auto_discovery() const override { return true; }
|
||||
bool can_test() 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; }
|
||||
|
||||
bool get_groups(wxArrayString &groups) const override { return false; }
|
||||
bool get_printers(wxArrayString &printers) const override { return false; }
|
||||
|
||||
protected:
|
||||
bool validate_version_text(const boost::optional<std::string> &version_text) const;
|
||||
|
||||
|
@ -26,8 +26,12 @@ public:
|
||||
bool has_auto_discovery() const override { return false; }
|
||||
bool can_test() 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; }
|
||||
|
||||
bool get_groups(wxArrayString &groups) const override { return false; }
|
||||
bool get_printers(wxArrayString &printers) const override { return false; }
|
||||
|
||||
private:
|
||||
enum class ConnectionType { rrf, dsf, error };
|
||||
std::string host;
|
||||
|
@ -27,8 +27,12 @@ public:
|
||||
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 false; }
|
||||
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:
|
||||
std::string host;
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <wx/string.h>
|
||||
#include <wx/arrstr.h>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include "PrintHost.hpp"
|
||||
@ -29,10 +30,14 @@ public:
|
||||
bool has_auto_discovery() const override { return true; }
|
||||
bool can_test() 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; }
|
||||
const std::string& get_apikey() const { return apikey; }
|
||||
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:
|
||||
virtual bool validate_version_text(const boost::optional<std::string> &version_text) const;
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "Duet.hpp"
|
||||
#include "FlashAir.hpp"
|
||||
#include "AstroBox.hpp"
|
||||
#include "Repetier.hpp"
|
||||
#include "../GUI/PrintHostDialogs.hpp"
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
@ -47,6 +48,7 @@ PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config)
|
||||
case htDuet: return new Duet(config);
|
||||
case htFlashAir: return new FlashAir(config);
|
||||
case htAstroBox: return new AstroBox(config);
|
||||
case htRepetier: return new Repetier(config);
|
||||
default: return nullptr;
|
||||
}
|
||||
} else {
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <wx/string.h>
|
||||
#include <wx/arrstr.h>
|
||||
|
||||
#include "Http.hpp"
|
||||
|
||||
@ -20,6 +21,9 @@ struct PrintHostUpload
|
||||
{
|
||||
boost::filesystem::path source_path;
|
||||
boost::filesystem::path upload_path;
|
||||
|
||||
std::string group;
|
||||
|
||||
bool start_print = false;
|
||||
};
|
||||
|
||||
@ -41,7 +45,10 @@ public:
|
||||
virtual bool has_auto_discovery() const = 0;
|
||||
virtual bool can_test() 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 bool get_groups(wxArrayString& groups) const = 0;
|
||||
virtual bool get_printers(wxArrayString &printers) const = 0;
|
||||
|
||||
static PrintHost* get_print_host(DynamicPrintConfig *config);
|
||||
|
||||
|
263
src/slic3r/Utils/Repetier.cpp
Normal file
263
src/slic3r/Utils/Repetier.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
52
src/slic3r/Utils/Repetier.hpp
Normal file
52
src/slic3r/Utils/Repetier.hpp
Normal 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
|
Loading…
x
Reference in New Issue
Block a user