mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-27 10:41:15 -06:00
Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_reload_from_disk_changes
This commit is contained in:
commit
a74f3e3fc0
66 changed files with 3959 additions and 633 deletions
|
|
@ -467,6 +467,8 @@ Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::Polygons
|
|||
{ return _clipper(ClipperLib::ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); }
|
||||
Slic3r::Polygons diff(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset)
|
||||
{ return _clipper(ClipperLib::ctDifference, ClipperUtils::ExPolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); }
|
||||
Slic3r::Polygons intersection(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
|
||||
{ return _clipper(ClipperLib::ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::SinglePathProvider(clip.points), do_safety_offset); }
|
||||
Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
|
||||
{ return _clipper(ClipperLib::ctIntersection, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); }
|
||||
Slic3r::Polygons intersection(const Slic3r::ExPolygon &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset)
|
||||
|
|
@ -496,6 +498,8 @@ Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Surfac
|
|||
{ return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::SurfacesProvider(clip), do_safety_offset); }
|
||||
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset)
|
||||
{ return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::ExPolygonsProvider(clip), do_safety_offset); }
|
||||
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
|
||||
{ return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::SinglePathProvider(clip.points), do_safety_offset); }
|
||||
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
|
||||
{ return _clipper_ex(ClipperLib::ctDifference, ClipperUtils::ExPolygonProvider(subject), ClipperUtils::PolygonsProvider(clip), do_safety_offset); }
|
||||
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
|
||||
|
|
@ -610,12 +614,18 @@ Polylines _clipper_pl_closed(ClipperLib::ClipType clipType, PathProvider1 &&subj
|
|||
|
||||
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip)
|
||||
{ return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::PolylinesProvider(subject), ClipperUtils::PolygonsProvider(clip)); }
|
||||
Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygon &clip)
|
||||
{ return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::ExPolygonProvider(clip)); }
|
||||
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygon &clip)
|
||||
{ return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::PolylinesProvider(subject), ClipperUtils::ExPolygonProvider(clip)); }
|
||||
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip)
|
||||
{ return _clipper_pl_open(ClipperLib::ctDifference, ClipperUtils::PolylinesProvider(subject), ClipperUtils::ExPolygonsProvider(clip)); }
|
||||
Slic3r::Polylines diff_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip)
|
||||
{ return _clipper_pl_closed(ClipperLib::ctDifference, ClipperUtils::PolygonsProvider(subject), ClipperUtils::PolygonsProvider(clip)); }
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip)
|
||||
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::SinglePathProvider(clip.points)); }
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip)
|
||||
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::SinglePathProvider(subject.points), ClipperUtils::PolygonsProvider(clip)); }
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip)
|
||||
{ return _clipper_pl_open(ClipperLib::ctIntersection, ClipperUtils::PolylinesProvider(subject), ClipperUtils::PolygonsProvider(clip)); }
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip)
|
||||
|
|
@ -637,7 +647,9 @@ Lines _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Pol
|
|||
// convert Polylines to Lines
|
||||
Lines retval;
|
||||
for (Polylines::const_iterator polyline = polylines.begin(); polyline != polylines.end(); ++polyline)
|
||||
retval.emplace_back(polyline->operator Line());
|
||||
if (polyline->size() >= 2)
|
||||
//FIXME It may happen, that Clipper produced a polyline with more than 2 collinear points by clipping a single line with polygons. It is a very rare issue, but it happens, see GH #6933.
|
||||
retval.push_back({ polyline->front(), polyline->back() });
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -303,6 +303,7 @@ Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygo
|
|||
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::ExPolygons diff_ex(const Slic3r::Polygon &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygon &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
|
|
@ -312,6 +313,7 @@ Slic3r::ExPolygons diff_ex(const Slic3r::ExPolygons &subject, const Slic3r::Surf
|
|||
Slic3r::ExPolygons diff_ex(const Slic3r::Surfaces &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::ExPolygons diff_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip);
|
||||
Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::ExPolygon &clip);
|
||||
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygon &clip);
|
||||
Slic3r::Polylines diff_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip);
|
||||
Slic3r::Polylines diff_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip);
|
||||
|
|
@ -322,6 +324,7 @@ inline Slic3r::Lines diff_ln(const Slic3r::Lines &subject, const Slic3r::Polygon
|
|||
}
|
||||
|
||||
// Safety offset is applied to the clipping polygons only.
|
||||
Slic3r::Polygons intersection(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::Polygons intersection(const Slic3r::ExPolygon &subject, const Slic3r::ExPolygon &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::Polygons intersection(const Slic3r::ExPolygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
|
|
@ -337,6 +340,8 @@ Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r
|
|||
Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::ExPolygons intersection_ex(const Slic3r::Surfaces &subject, const Slic3r::Surfaces &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::ExPolygons intersection_ex(const Slic3r::SurfacesPtr &subject, const Slic3r::ExPolygons &clip, ApplySafetyOffset do_safety_offset = ApplySafetyOffset::No);
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip);
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip);
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip);
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::ExPolygons &clip);
|
||||
Slic3r::Polylines intersection_pl(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip);
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ bool ExPolygon::contains(const Line &line) const
|
|||
|
||||
bool ExPolygon::contains(const Polyline &polyline) const
|
||||
{
|
||||
return diff_pl((Polylines)polyline, *this).empty();
|
||||
return diff_pl(polyline, *this).empty();
|
||||
}
|
||||
|
||||
bool ExPolygon::contains(const Polylines &polylines) const
|
||||
|
|
|
|||
|
|
@ -928,7 +928,9 @@ static Polylines connect_lines_using_hooks(Polylines &&lines, const ExPolygon &b
|
|||
Linef l { { bg::get<0, 0>(seg), bg::get<0, 1>(seg) }, { bg::get<1, 0>(seg), bg::get<1, 1>(seg) } };
|
||||
assert(line_alg::distance_to_squared(l, Vec2d(pt.cast<double>())) > 1000 * 1000);
|
||||
#endif // NDEBUG
|
||||
} else if (((Line)pl).distance_to_squared(pt) <= 1000 * 1000)
|
||||
} else if (pl.size() >= 2 &&
|
||||
//FIXME Hoping that pl is really a line, trimmed by a polygon using ClipperUtils. Sometimes Clipper leaves some additional collinear points on the polyline, let's hope it is all right.
|
||||
Line{ pl.front(), pl.back() }.distance_to_squared(pt) <= 1000 * 1000)
|
||||
out = closest.front().second;
|
||||
}
|
||||
return out;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "SVG.hpp"
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/pipeline.h>
|
||||
|
||||
#include <Shiny/Shiny.h>
|
||||
|
||||
|
|
@ -1099,7 +1100,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||
m_volumetric_speed = DoExport::autospeed_volumetric_limit(print);
|
||||
print.throw_if_canceled();
|
||||
|
||||
m_cooling_buffer = make_unique<CoolingBuffer>(*this);
|
||||
if (print.config().spiral_vase.value)
|
||||
m_spiral_vase = make_unique<SpiralVase>(print.config());
|
||||
#ifdef HAS_PRESSURE_EQUALIZER
|
||||
|
|
@ -1212,6 +1212,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||
}
|
||||
print.throw_if_canceled();
|
||||
|
||||
m_cooling_buffer = make_unique<CoolingBuffer>(*this);
|
||||
m_cooling_buffer->set_current_extruder(initial_extruder_id);
|
||||
|
||||
// Emit machine envelope limits for the Marlin firmware.
|
||||
|
|
@ -1219,7 +1220,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||
|
||||
// Disable fan.
|
||||
if (! print.config().cooling.get_at(initial_extruder_id) || print.config().disable_fan_first_layers.get_at(initial_extruder_id))
|
||||
file.write(m_writer.set_fan(0, true));
|
||||
file.write(m_writer.set_fan(0));
|
||||
|
||||
// Let the start-up script prime the 1st printing tool.
|
||||
m_placeholder_parser.set("initial_tool", initial_extruder_id);
|
||||
|
|
@ -1334,17 +1335,12 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||
file.writeln(between_objects_gcode);
|
||||
}
|
||||
// Reset the cooling buffer internal state (the current position, feed rate, accelerations).
|
||||
m_cooling_buffer->reset();
|
||||
m_cooling_buffer->reset(this->writer().get_position());
|
||||
m_cooling_buffer->set_current_extruder(initial_extruder_id);
|
||||
// Pair the object layers with the support layers by z, extrude them.
|
||||
std::vector<LayerToPrint> layers_to_print = collect_layers_to_print(object);
|
||||
for (const LayerToPrint <p : layers_to_print) {
|
||||
std::vector<LayerToPrint> lrs;
|
||||
lrs.emplace_back(std::move(ltp));
|
||||
this->process_layer(file, print, lrs, tool_ordering.tools_for_layer(ltp.print_z()), <p == &layers_to_print.back(),
|
||||
nullptr, *print_object_instance_sequential_active - object.instances().data());
|
||||
print.throw_if_canceled();
|
||||
}
|
||||
// Process all layers of a single object instance (sequential mode) with a parallel pipeline:
|
||||
// Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser
|
||||
// and export G-code into file.
|
||||
this->process_layers(print, tool_ordering, collect_layers_to_print(object), *print_object_instance_sequential_active - object.instances().data(), file);
|
||||
#ifdef HAS_PRESSURE_EQUALIZER
|
||||
if (m_pressure_equalizer)
|
||||
file.write(m_pressure_equalizer->process("", true));
|
||||
|
|
@ -1401,14 +1397,10 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||
}
|
||||
print.throw_if_canceled();
|
||||
}
|
||||
// Extrude the layers.
|
||||
for (auto &layer : layers_to_print) {
|
||||
const LayerTools &layer_tools = tool_ordering.tools_for_layer(layer.first);
|
||||
if (m_wipe_tower && layer_tools.has_wipe_tower)
|
||||
m_wipe_tower->next_layer();
|
||||
this->process_layer(file, print, layer.second, layer_tools, &layer == &layers_to_print.back(), &print_object_instances_ordering, size_t(-1));
|
||||
print.throw_if_canceled();
|
||||
}
|
||||
// Process all layers of all objects (non-sequential mode) with a parallel pipeline:
|
||||
// Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser
|
||||
// and export G-code into file.
|
||||
this->process_layers(print, tool_ordering, print_object_instances_ordering, layers_to_print, file);
|
||||
#ifdef HAS_PRESSURE_EQUALIZER
|
||||
if (m_pressure_equalizer)
|
||||
file.write(m_pressure_equalizer->process("", true));
|
||||
|
|
@ -1420,7 +1412,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||
|
||||
// Write end commands to file.
|
||||
file.write(this->retract());
|
||||
file.write(m_writer.set_fan(false));
|
||||
file.write(m_writer.set_fan(0));
|
||||
|
||||
// adds tag for processor
|
||||
file.write_format(";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
|
||||
|
|
@ -1481,6 +1473,88 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||
print.throw_if_canceled();
|
||||
}
|
||||
|
||||
// Process all layers of all objects (non-sequential mode) with a parallel pipeline:
|
||||
// Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser
|
||||
// and export G-code into file.
|
||||
void GCode::process_layers(
|
||||
const Print &print,
|
||||
const ToolOrdering &tool_ordering,
|
||||
const std::vector<const PrintInstance*> &print_object_instances_ordering,
|
||||
const std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> &layers_to_print,
|
||||
GCodeOutputStream &output_stream)
|
||||
{
|
||||
// The pipeline is variable: The vase mode filter is optional.
|
||||
size_t layer_to_print_idx = 0;
|
||||
const auto generator = tbb::make_filter<void, GCode::LayerResult>(tbb::filter::serial_in_order,
|
||||
[this, &print, &tool_ordering, &print_object_instances_ordering, &layers_to_print, &layer_to_print_idx](tbb::flow_control& fc) -> GCode::LayerResult {
|
||||
if (layer_to_print_idx == layers_to_print.size()) {
|
||||
fc.stop();
|
||||
return {};
|
||||
} else {
|
||||
const std::pair<coordf_t, std::vector<LayerToPrint>>& layer = layers_to_print[layer_to_print_idx++];
|
||||
const LayerTools& layer_tools = tool_ordering.tools_for_layer(layer.first);
|
||||
if (m_wipe_tower && layer_tools.has_wipe_tower)
|
||||
m_wipe_tower->next_layer();
|
||||
print.throw_if_canceled();
|
||||
return this->process_layer(print, layer.second, layer_tools, &layer == &layers_to_print.back(), &print_object_instances_ordering, size_t(-1));
|
||||
}
|
||||
});
|
||||
const auto spiral_vase = tbb::make_filter<GCode::LayerResult, GCode::LayerResult>(tbb::filter::serial_in_order,
|
||||
[&spiral_vase = *this->m_spiral_vase.get()](GCode::LayerResult in) -> GCode::LayerResult {
|
||||
spiral_vase.enable(in.spiral_vase_enable);
|
||||
return { spiral_vase.process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush };
|
||||
});
|
||||
const auto cooling = tbb::make_filter<GCode::LayerResult, std::string>(tbb::filter::serial_in_order,
|
||||
[&cooling_buffer = *this->m_cooling_buffer.get()](GCode::LayerResult in) -> std::string {
|
||||
return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush);
|
||||
});
|
||||
const auto output = tbb::make_filter<std::string, void>(tbb::filter::serial_in_order,
|
||||
[&output_stream](std::string s) { output_stream.write(s); }
|
||||
);
|
||||
|
||||
// The pipeline elements are joined using const references, thus no copying is performed.
|
||||
if (m_spiral_vase)
|
||||
tbb::parallel_pipeline(12, generator & spiral_vase & cooling & output);
|
||||
else
|
||||
tbb::parallel_pipeline(12, generator & cooling & output);
|
||||
}
|
||||
|
||||
// Process all layers of a single object instance (sequential mode) with a parallel pipeline:
|
||||
// Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser
|
||||
// and export G-code into file.
|
||||
void GCode::process_layers(
|
||||
const Print &print,
|
||||
const ToolOrdering &tool_ordering,
|
||||
std::vector<LayerToPrint> layers_to_print,
|
||||
const size_t single_object_idx,
|
||||
GCodeOutputStream &output_stream)
|
||||
{
|
||||
// The pipeline is fixed: Neither wipe tower nor vase mode are implemented for sequential print.
|
||||
size_t layer_to_print_idx = 0;
|
||||
tbb::parallel_pipeline(12,
|
||||
tbb::make_filter<void, GCode::LayerResult>(
|
||||
tbb::filter::serial_in_order,
|
||||
[this, &print, &tool_ordering, &layers_to_print, &layer_to_print_idx, single_object_idx](tbb::flow_control& fc) -> GCode::LayerResult {
|
||||
if (layer_to_print_idx == layers_to_print.size()) {
|
||||
fc.stop();
|
||||
return {};
|
||||
} else {
|
||||
LayerToPrint &layer = layers_to_print[layer_to_print_idx ++];
|
||||
print.throw_if_canceled();
|
||||
return this->process_layer(print, { std::move(layer) }, tool_ordering.tools_for_layer(layer.print_z()), &layer == &layers_to_print.back(), nullptr, single_object_idx);
|
||||
}
|
||||
}) &
|
||||
tbb::make_filter<GCode::LayerResult, std::string>(
|
||||
tbb::filter::serial_in_order,
|
||||
[&cooling_buffer = *this->m_cooling_buffer.get()](GCode::LayerResult in) -> std::string {
|
||||
return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush);
|
||||
}) &
|
||||
tbb::make_filter<std::string, void>(
|
||||
tbb::filter::serial_in_order,
|
||||
[&output_stream](std::string s) { output_stream.write(s); }
|
||||
));
|
||||
}
|
||||
|
||||
std::string GCode::placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override)
|
||||
{
|
||||
try {
|
||||
|
|
@ -1890,9 +1964,7 @@ namespace Skirt {
|
|||
// In non-sequential mode, process_layer is called per each print_z height with all object and support layers accumulated.
|
||||
// For multi-material prints, this routine minimizes extruder switches by gathering extruder specific extrusion paths
|
||||
// and performing the extruder specific extrusions together.
|
||||
void GCode::process_layer(
|
||||
// Write into the output file.
|
||||
GCodeOutputStream &file,
|
||||
GCode::LayerResult GCode::process_layer(
|
||||
const Print &print,
|
||||
// Set of object & print layers of the same PrintObject and with the same print_z.
|
||||
const std::vector<LayerToPrint> &layers,
|
||||
|
|
@ -1908,11 +1980,6 @@ void GCode::process_layer(
|
|||
// Either printing all copies of all objects, or just a single copy of a single object.
|
||||
assert(single_object_instance_idx == size_t(-1) || layers.size() == 1);
|
||||
|
||||
if (layer_tools.extruders.empty())
|
||||
// Nothing to extrude.
|
||||
return;
|
||||
|
||||
// Extract 1st object_layer and support_layer of this set of layers with an equal print_z.
|
||||
const Layer *object_layer = nullptr;
|
||||
const SupportLayer *support_layer = nullptr;
|
||||
for (const LayerToPrint &l : layers) {
|
||||
|
|
@ -1922,6 +1989,12 @@ void GCode::process_layer(
|
|||
support_layer = l.support_layer;
|
||||
}
|
||||
const Layer &layer = (object_layer != nullptr) ? *object_layer : *support_layer;
|
||||
GCode::LayerResult result { {}, layer.id(), false, last_layer };
|
||||
if (layer_tools.extruders.empty())
|
||||
// Nothing to extrude.
|
||||
return result;
|
||||
|
||||
// Extract 1st object_layer and support_layer of this set of layers with an equal print_z.
|
||||
coordf_t print_z = layer.print_z;
|
||||
bool first_layer = layer.id() == 0;
|
||||
unsigned int first_extruder_id = layer_tools.extruders.front();
|
||||
|
|
@ -1943,7 +2016,7 @@ void GCode::process_layer(
|
|||
break;
|
||||
}
|
||||
}
|
||||
m_spiral_vase->enable(enable);
|
||||
result.spiral_vase_enable = enable;
|
||||
// If we're going to apply spiralvase to this layer, disable loop clipping.
|
||||
m_enable_loop_clipping = !enable;
|
||||
}
|
||||
|
|
@ -2285,6 +2358,7 @@ void GCode::process_layer(
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Apply spiral vase post-processing if this layer contains suitable geometry
|
||||
// (we must feed all the G-code into the post-processor, including the first
|
||||
// bottom non-spiral layers otherwise it will mess with positions)
|
||||
|
|
@ -2308,8 +2382,14 @@ void GCode::process_layer(
|
|||
#endif /* HAS_PRESSURE_EQUALIZER */
|
||||
|
||||
file.write(gcode);
|
||||
#endif
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
|
||||
log_memory_info();
|
||||
|
||||
result.gcode = std::move(gcode);
|
||||
result.cooling_buffer_flush = object_layer || last_layer;
|
||||
return result;
|
||||
}
|
||||
|
||||
void GCode::apply_print_config(const PrintConfig &print_config)
|
||||
|
|
|
|||
|
|
@ -215,9 +215,16 @@ private:
|
|||
|
||||
static std::vector<LayerToPrint> collect_layers_to_print(const PrintObject &object);
|
||||
static std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> collect_layers_to_print(const Print &print);
|
||||
void process_layer(
|
||||
// Write into the output file.
|
||||
GCodeOutputStream &file,
|
||||
|
||||
struct LayerResult {
|
||||
std::string gcode;
|
||||
size_t layer_id;
|
||||
// Is spiral vase post processing enabled for this layer?
|
||||
bool spiral_vase_enable { false };
|
||||
// Should the cooling buffer content be flushed at the end of this layer?
|
||||
bool cooling_buffer_flush { false };
|
||||
};
|
||||
LayerResult process_layer(
|
||||
const Print &print,
|
||||
// Set of object & print layers of the same PrintObject and with the same print_z.
|
||||
const std::vector<LayerToPrint> &layers,
|
||||
|
|
@ -228,6 +235,24 @@ private:
|
|||
// If set to size_t(-1), then print all copies of all objects.
|
||||
// Otherwise print a single copy of a single object.
|
||||
const size_t single_object_idx = size_t(-1));
|
||||
// Process all layers of all objects (non-sequential mode) with a parallel pipeline:
|
||||
// Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser
|
||||
// and export G-code into file.
|
||||
void process_layers(
|
||||
const Print &print,
|
||||
const ToolOrdering &tool_ordering,
|
||||
const std::vector<const PrintInstance*> &print_object_instances_ordering,
|
||||
const std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> &layers_to_print,
|
||||
GCodeOutputStream &output_stream);
|
||||
// Process all layers of a single object instance (sequential mode) with a parallel pipeline:
|
||||
// Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser
|
||||
// and export G-code into file.
|
||||
void process_layers(
|
||||
const Print &print,
|
||||
const ToolOrdering &tool_ordering,
|
||||
std::vector<LayerToPrint> layers_to_print,
|
||||
const size_t single_object_idx,
|
||||
GCodeOutputStream &output_stream);
|
||||
|
||||
void set_last_pos(const Point &pos) { m_last_pos = pos; m_last_pos_defined = true; }
|
||||
bool last_pos_defined() const { return m_last_pos_defined; }
|
||||
|
|
|
|||
|
|
@ -16,19 +16,25 @@
|
|||
|
||||
namespace Slic3r {
|
||||
|
||||
CoolingBuffer::CoolingBuffer(GCode &gcodegen) : m_gcodegen(gcodegen), m_current_extruder(0)
|
||||
CoolingBuffer::CoolingBuffer(GCode &gcodegen) : m_config(gcodegen.config()), m_toolchange_prefix(gcodegen.writer().toolchange_prefix()), m_current_extruder(0)
|
||||
{
|
||||
this->reset();
|
||||
this->reset(gcodegen.writer().get_position());
|
||||
|
||||
const std::vector<Extruder> &extruders = gcodegen.writer().extruders();
|
||||
m_extruder_ids.reserve(extruders.size());
|
||||
for (const Extruder &ex : extruders) {
|
||||
m_num_extruders = std::max(ex.id() + 1, m_num_extruders);
|
||||
m_extruder_ids.emplace_back(ex.id());
|
||||
}
|
||||
}
|
||||
|
||||
void CoolingBuffer::reset()
|
||||
void CoolingBuffer::reset(const Vec3d &position)
|
||||
{
|
||||
m_current_pos.assign(5, 0.f);
|
||||
Vec3d pos = m_gcodegen.writer().get_position();
|
||||
m_current_pos[0] = float(pos(0));
|
||||
m_current_pos[1] = float(pos(1));
|
||||
m_current_pos[2] = float(pos(2));
|
||||
m_current_pos[4] = float(m_gcodegen.config().travel_speed.value);
|
||||
m_current_pos[0] = float(position.x());
|
||||
m_current_pos[1] = float(position.y());
|
||||
m_current_pos[2] = float(position.z());
|
||||
m_current_pos[4] = float(m_config.travel_speed.value);
|
||||
}
|
||||
|
||||
struct CoolingLine
|
||||
|
|
@ -303,30 +309,23 @@ std::string CoolingBuffer::process_layer(std::string &&gcode, size_t layer_id, b
|
|||
// Return the list of parsed lines, bucketed by an extruder.
|
||||
std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::string &gcode, std::vector<float> ¤t_pos) const
|
||||
{
|
||||
const FullPrintConfig &config = m_gcodegen.config();
|
||||
const std::vector<Extruder> &extruders = m_gcodegen.writer().extruders();
|
||||
unsigned int num_extruders = 0;
|
||||
for (const Extruder &ex : extruders)
|
||||
num_extruders = std::max(ex.id() + 1, num_extruders);
|
||||
|
||||
std::vector<PerExtruderAdjustments> per_extruder_adjustments(extruders.size());
|
||||
std::vector<size_t> map_extruder_to_per_extruder_adjustment(num_extruders, 0);
|
||||
for (size_t i = 0; i < extruders.size(); ++ i) {
|
||||
std::vector<PerExtruderAdjustments> per_extruder_adjustments(m_extruder_ids.size());
|
||||
std::vector<size_t> map_extruder_to_per_extruder_adjustment(m_num_extruders, 0);
|
||||
for (size_t i = 0; i < m_extruder_ids.size(); ++ i) {
|
||||
PerExtruderAdjustments &adj = per_extruder_adjustments[i];
|
||||
unsigned int extruder_id = extruders[i].id();
|
||||
unsigned int extruder_id = m_extruder_ids[i];
|
||||
adj.extruder_id = extruder_id;
|
||||
adj.cooling_slow_down_enabled = config.cooling.get_at(extruder_id);
|
||||
adj.slowdown_below_layer_time = float(config.slowdown_below_layer_time.get_at(extruder_id));
|
||||
adj.min_print_speed = float(config.min_print_speed.get_at(extruder_id));
|
||||
adj.cooling_slow_down_enabled = m_config.cooling.get_at(extruder_id);
|
||||
adj.slowdown_below_layer_time = float(m_config.slowdown_below_layer_time.get_at(extruder_id));
|
||||
adj.min_print_speed = float(m_config.min_print_speed.get_at(extruder_id));
|
||||
map_extruder_to_per_extruder_adjustment[extruder_id] = i;
|
||||
}
|
||||
|
||||
const std::string toolchange_prefix = m_gcodegen.writer().toolchange_prefix();
|
||||
unsigned int current_extruder = m_current_extruder;
|
||||
PerExtruderAdjustments *adjustment = &per_extruder_adjustments[map_extruder_to_per_extruder_adjustment[current_extruder]];
|
||||
const char *line_start = gcode.c_str();
|
||||
const char *line_end = line_start;
|
||||
const char extrusion_axis = get_extrusion_axis(config)[0];
|
||||
const char extrusion_axis = get_extrusion_axis(m_config)[0];
|
||||
// Index of an existing CoolingLine of the current adjustment, which holds the feedrate setting command
|
||||
// for a sequence of extrusion moves.
|
||||
size_t active_speed_modifier = size_t(-1);
|
||||
|
|
@ -387,7 +386,7 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
|
|||
}
|
||||
if ((line.type & CoolingLine::TYPE_G92) == 0) {
|
||||
// G0 or G1. Calculate the duration.
|
||||
if (config.use_relative_e_distances.value)
|
||||
if (m_config.use_relative_e_distances.value)
|
||||
// Reset extruder accumulator.
|
||||
current_pos[3] = 0.f;
|
||||
float dif[4];
|
||||
|
|
@ -430,8 +429,8 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
|
|||
} else if (boost::starts_with(sline, ";_EXTRUDE_END")) {
|
||||
line.type = CoolingLine::TYPE_EXTRUDE_END;
|
||||
active_speed_modifier = size_t(-1);
|
||||
} else if (boost::starts_with(sline, toolchange_prefix)) {
|
||||
unsigned int new_extruder = (unsigned int)atoi(sline.c_str() + toolchange_prefix.size());
|
||||
} else if (boost::starts_with(sline, m_toolchange_prefix)) {
|
||||
unsigned int new_extruder = (unsigned int)atoi(sline.c_str() + m_toolchange_prefix.size());
|
||||
// Only change extruder in case the number is meaningful. User could provide an out-of-range index through custom gcodes - those shall be ignored.
|
||||
if (new_extruder < map_extruder_to_per_extruder_adjustment.size()) {
|
||||
if (new_extruder != current_extruder) {
|
||||
|
|
@ -641,7 +640,7 @@ float CoolingBuffer::calculate_layer_slowdown(std::vector<PerExtruderAdjustments
|
|||
if (total > slowdown_below_layer_time) {
|
||||
// The current total time is above the minimum threshold of the rest of the extruders, don't adjust anything.
|
||||
} else {
|
||||
// Adjust this and all the following (higher config.slowdown_below_layer_time) extruders.
|
||||
// Adjust this and all the following (higher m_config.slowdown_below_layer_time) extruders.
|
||||
// Sum maximum slow down time as if everything was slowed down including the external perimeters.
|
||||
float max_time = elapsed_time_total0;
|
||||
for (auto it = cur_begin; it != by_slowdown_time.end(); ++ it)
|
||||
|
|
@ -694,8 +693,7 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
|||
bool bridge_fan_control = false;
|
||||
int bridge_fan_speed = 0;
|
||||
auto change_extruder_set_fan = [ this, layer_id, layer_time, &new_gcode, &fan_speed, &bridge_fan_control, &bridge_fan_speed ]() {
|
||||
const FullPrintConfig &config = m_gcodegen.config();
|
||||
#define EXTRUDER_CONFIG(OPT) config.OPT.get_at(m_current_extruder)
|
||||
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_current_extruder)
|
||||
int min_fan_speed = EXTRUDER_CONFIG(min_fan_speed);
|
||||
int fan_speed_new = EXTRUDER_CONFIG(fan_always_on) ? min_fan_speed : 0;
|
||||
int disable_fan_first_layers = EXTRUDER_CONFIG(disable_fan_first_layers);
|
||||
|
|
@ -737,13 +735,12 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
|||
}
|
||||
if (fan_speed_new != fan_speed) {
|
||||
fan_speed = fan_speed_new;
|
||||
new_gcode += m_gcodegen.writer().set_fan(fan_speed);
|
||||
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, fan_speed);
|
||||
}
|
||||
};
|
||||
|
||||
const char *pos = gcode.c_str();
|
||||
int current_feedrate = 0;
|
||||
const std::string toolchange_prefix = m_gcodegen.writer().toolchange_prefix();
|
||||
change_extruder_set_fan();
|
||||
for (const CoolingLine *line : lines) {
|
||||
const char *line_start = gcode.c_str() + line->line_start;
|
||||
|
|
@ -751,7 +748,7 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
|||
if (line_start > pos)
|
||||
new_gcode.append(pos, line_start - pos);
|
||||
if (line->type & CoolingLine::TYPE_SET_TOOL) {
|
||||
unsigned int new_extruder = (unsigned int)atoi(line_start + toolchange_prefix.size());
|
||||
unsigned int new_extruder = (unsigned int)atoi(line_start + m_toolchange_prefix.size());
|
||||
if (new_extruder != m_current_extruder) {
|
||||
m_current_extruder = new_extruder;
|
||||
change_extruder_set_fan();
|
||||
|
|
@ -759,10 +756,10 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
|||
new_gcode.append(line_start, line_end - line_start);
|
||||
} else if (line->type & CoolingLine::TYPE_BRIDGE_FAN_START) {
|
||||
if (bridge_fan_control)
|
||||
new_gcode += m_gcodegen.writer().set_fan(bridge_fan_speed, true);
|
||||
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, bridge_fan_speed);
|
||||
} else if (line->type & CoolingLine::TYPE_BRIDGE_FAN_END) {
|
||||
if (bridge_fan_control)
|
||||
new_gcode += m_gcodegen.writer().set_fan(fan_speed, true);
|
||||
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_config.gcode_comments, fan_speed);
|
||||
} else if (line->type & CoolingLine::TYPE_EXTRUDE_END) {
|
||||
// Just remove this comment.
|
||||
} else if (line->type & (CoolingLine::TYPE_ADJUSTABLE | CoolingLine::TYPE_EXTERNAL_PERIMETER | CoolingLine::TYPE_WIPE | CoolingLine::TYPE_HAS_F)) {
|
||||
|
|
|
|||
|
|
@ -23,10 +23,9 @@ struct PerExtruderAdjustments;
|
|||
class CoolingBuffer {
|
||||
public:
|
||||
CoolingBuffer(GCode &gcodegen);
|
||||
void reset();
|
||||
void reset(const Vec3d &position);
|
||||
void set_current_extruder(unsigned int extruder_id) { m_current_extruder = extruder_id; }
|
||||
std::string process_layer(std::string &&gcode, size_t layer_id, bool flush);
|
||||
GCode* gcodegen() { return &m_gcodegen; }
|
||||
|
||||
private:
|
||||
CoolingBuffer& operator=(const CoolingBuffer&) = delete;
|
||||
|
|
@ -36,17 +35,25 @@ private:
|
|||
// Returns the adjusted G-code.
|
||||
std::string apply_layer_cooldown(const std::string &gcode, size_t layer_id, float layer_time, std::vector<PerExtruderAdjustments> &per_extruder_adjustments);
|
||||
|
||||
GCode& m_gcodegen;
|
||||
// G-code snippet cached for the support layers preceding an object layer.
|
||||
std::string m_gcode;
|
||||
std::string m_gcode;
|
||||
// Internal data.
|
||||
// X,Y,Z,E,F
|
||||
std::vector<char> m_axis;
|
||||
std::vector<float> m_current_pos;
|
||||
unsigned int m_current_extruder;
|
||||
std::vector<char> m_axis;
|
||||
std::vector<float> m_current_pos;
|
||||
// Cached from GCodeWriter.
|
||||
// Printing extruder IDs, zero based.
|
||||
std::vector<unsigned int> m_extruder_ids;
|
||||
// Highest of m_extruder_ids plus 1.
|
||||
unsigned int m_num_extruders { 0 };
|
||||
const std::string m_toolchange_prefix;
|
||||
// Referencs GCode::m_config, which is FullPrintConfig. While the PrintObjectConfig slice of FullPrintConfig is being modified,
|
||||
// the PrintConfig slice of FullPrintConfig is constant, thus no thread synchronization is required.
|
||||
const PrintConfig &m_config;
|
||||
unsigned int m_current_extruder;
|
||||
|
||||
// Old logic: proportional.
|
||||
bool m_cooling_logic_proportional = false;
|
||||
bool m_cooling_logic_proportional = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ std::string SpiralVase::process_layer(const std::string &gcode)
|
|||
// For absolute extruder distances it will be switched off.
|
||||
// Tapering the absolute extruder distances requires to process every extrusion value after the first transition
|
||||
// layer.
|
||||
bool transition = m_transition_layer && m_config->use_relative_e_distances.value;
|
||||
bool transition = m_transition_layer && m_config.use_relative_e_distances.value;
|
||||
float layer_height_factor = layer_height / total_layer_length;
|
||||
float len = 0.f;
|
||||
m_reader.parse_buffer(gcode, [&new_gcode, &z, total_layer_length, layer_height_factor, transition, &len]
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ namespace Slic3r {
|
|||
|
||||
class SpiralVase {
|
||||
public:
|
||||
SpiralVase(const PrintConfig &config) : m_config(&config)
|
||||
SpiralVase(const PrintConfig &config) : m_config(config)
|
||||
{
|
||||
m_reader.z() = (float)m_config->z_offset;
|
||||
m_reader.apply_config(*m_config);
|
||||
m_reader.z() = (float)m_config.z_offset;
|
||||
m_reader.apply_config(m_config);
|
||||
};
|
||||
|
||||
void enable(bool en) {
|
||||
|
|
@ -22,7 +22,7 @@ public:
|
|||
std::string process_layer(const std::string &gcode);
|
||||
|
||||
private:
|
||||
const PrintConfig *m_config;
|
||||
const PrintConfig &m_config;
|
||||
GCodeReader m_reader;
|
||||
|
||||
bool m_enabled = false;
|
||||
|
|
@ -32,4 +32,4 @@ private:
|
|||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // slic3r_SpiralVase_hpp_
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <charconv>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
|
@ -10,6 +9,7 @@
|
|||
#include "LocalesUtils.hpp"
|
||||
|
||||
#include <Shiny/Shiny.h>
|
||||
#include <fast_float/fast_float.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
|
@ -71,16 +71,9 @@ const char* GCodeReader::parse_line_internal(const char *ptr, const char *end, G
|
|||
}
|
||||
if (axis != NUM_AXES_WITH_UNKNOWN) {
|
||||
// Try to parse the numeric value.
|
||||
#ifdef WIN32
|
||||
double v;
|
||||
auto [pend, ec] = std::from_chars(++ c, end, v);
|
||||
auto [pend, ec] = fast_float::from_chars(++ c, end, v);
|
||||
if (pend != c && is_end_of_word(*pend)) {
|
||||
#else
|
||||
// The older version of GCC and Clang support std::from_chars just for integers, so strtod we used it instead.
|
||||
char *pend = nullptr;
|
||||
double v = strtod(++ c, &pend);
|
||||
if (pend != nullptr && is_end_of_word(*pend)) {
|
||||
#endif
|
||||
// The axis value has been parsed correctly.
|
||||
if (axis != UNKNOWN_AXIS)
|
||||
gline.m_axis[int(axis)] = float(v);
|
||||
|
|
|
|||
|
|
@ -1,21 +1,17 @@
|
|||
#include "GCodeWriter.hpp"
|
||||
#include "CustomGCode.hpp"
|
||||
#include <algorithm>
|
||||
#include <charconv>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <assert.h>
|
||||
|
||||
#define XYZF_EXPORT_DIGITS 3
|
||||
#define E_EXPORT_DIGITS 5
|
||||
#ifdef __APPLE__
|
||||
#include <boost/spirit/include/karma.hpp>
|
||||
#endif
|
||||
|
||||
#define FLAVOR_IS(val) this->config.gcode_flavor == val
|
||||
#define FLAVOR_IS_NOT(val) this->config.gcode_flavor != val
|
||||
#define COMMENT(comment) if (this->config.gcode_comments && !comment.empty()) gcode << " ; " << comment;
|
||||
#define PRECISION(val, precision) std::fixed << std::setprecision(precision) << (val)
|
||||
#define XYZF_NUM(val) PRECISION(val, XYZF_EXPORT_DIGITS)
|
||||
#define E_NUM(val) PRECISION(val, E_EXPORT_DIGITS)
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
|
@ -156,41 +152,6 @@ std::string GCodeWriter::set_bed_temperature(unsigned int temperature, bool wait
|
|||
return gcode.str();
|
||||
}
|
||||
|
||||
std::string GCodeWriter::set_fan(unsigned int speed, bool dont_save)
|
||||
{
|
||||
std::ostringstream gcode;
|
||||
if (m_last_fan_speed != speed || dont_save) {
|
||||
if (!dont_save) m_last_fan_speed = speed;
|
||||
|
||||
if (speed == 0) {
|
||||
if (FLAVOR_IS(gcfTeacup)) {
|
||||
gcode << "M106 S0";
|
||||
} else if (FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish)) {
|
||||
gcode << "M127";
|
||||
} else {
|
||||
gcode << "M107";
|
||||
}
|
||||
if (this->config.gcode_comments) gcode << " ; disable fan";
|
||||
gcode << "\n";
|
||||
} else {
|
||||
if (FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish)) {
|
||||
gcode << "M126";
|
||||
} else {
|
||||
gcode << "M106 ";
|
||||
if (FLAVOR_IS(gcfMach3) || FLAVOR_IS(gcfMachinekit)) {
|
||||
gcode << "P";
|
||||
} else {
|
||||
gcode << "S";
|
||||
}
|
||||
gcode << (255.0 * speed / 100.0);
|
||||
}
|
||||
if (this->config.gcode_comments) gcode << " ; enable fan";
|
||||
gcode << "\n";
|
||||
}
|
||||
}
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
std::string GCodeWriter::set_acceleration(unsigned int acceleration)
|
||||
{
|
||||
// Clamp the acceleration to the allowed maximum.
|
||||
|
|
@ -292,85 +253,12 @@ std::string GCodeWriter::toolchange(unsigned int extruder_id)
|
|||
return gcode.str();
|
||||
}
|
||||
|
||||
class G1Writer {
|
||||
private:
|
||||
static constexpr const size_t buflen = 256;
|
||||
char buf[buflen];
|
||||
char *buf_end;
|
||||
std::to_chars_result ptr_err;
|
||||
|
||||
public:
|
||||
G1Writer() {
|
||||
this->buf[0] = 'G';
|
||||
this->buf[1] = '1';
|
||||
this->buf_end = this->buf + buflen;
|
||||
this->ptr_err.ptr = this->buf + 2;
|
||||
}
|
||||
|
||||
void emit_axis(const char axis, const double v, size_t digits) {
|
||||
*ptr_err.ptr ++ = ' '; *ptr_err.ptr ++ = axis;
|
||||
#ifdef WIN32
|
||||
this->ptr_err = std::to_chars(this->ptr_err.ptr, this->buf_end, v, std::chars_format::fixed, digits);
|
||||
#else
|
||||
int buf_capacity = int(this->buf_end - this->ptr_err.ptr);
|
||||
int ret = snprintf(this->ptr_err.ptr, buf_capacity, "%.*lf", int(digits), v);
|
||||
if (ret <= 0 || ret > buf_capacity)
|
||||
ptr_err.ec = std::errc::value_too_large;
|
||||
else
|
||||
this->ptr_err.ptr = this->ptr_err.ptr + ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
void emit_xy(const Vec2d &point) {
|
||||
this->emit_axis('X', point.x(), XYZF_EXPORT_DIGITS);
|
||||
this->emit_axis('Y', point.y(), XYZF_EXPORT_DIGITS);
|
||||
}
|
||||
|
||||
void emit_xyz(const Vec3d &point) {
|
||||
this->emit_axis('X', point.x(), XYZF_EXPORT_DIGITS);
|
||||
this->emit_axis('Y', point.y(), XYZF_EXPORT_DIGITS);
|
||||
this->emit_z(point.z());
|
||||
}
|
||||
|
||||
void emit_z(const double z) {
|
||||
this->emit_axis('Z', z, XYZF_EXPORT_DIGITS);
|
||||
}
|
||||
|
||||
void emit_e(const std::string &axis, double v) {
|
||||
if (! axis.empty()) {
|
||||
// not gcfNoExtrusion
|
||||
this->emit_axis(axis[0], v, E_EXPORT_DIGITS);
|
||||
}
|
||||
}
|
||||
|
||||
void emit_f(double speed) {
|
||||
this->emit_axis('F', speed, XYZF_EXPORT_DIGITS);
|
||||
}
|
||||
|
||||
void emit_string(const std::string &s) {
|
||||
strncpy(ptr_err.ptr, s.c_str(), s.size());
|
||||
ptr_err.ptr += s.size();
|
||||
}
|
||||
|
||||
void emit_comment(bool allow_comments, const std::string &comment) {
|
||||
if (allow_comments && ! comment.empty()) {
|
||||
*ptr_err.ptr ++ = ' '; *ptr_err.ptr ++ = ';'; *ptr_err.ptr ++ = ' ';
|
||||
this->emit_string(comment);
|
||||
}
|
||||
}
|
||||
|
||||
std::string string() {
|
||||
*ptr_err.ptr ++ = '\n';
|
||||
return std::string(this->buf, ptr_err.ptr - buf);
|
||||
}
|
||||
};
|
||||
|
||||
std::string GCodeWriter::set_speed(double F, const std::string &comment, const std::string &cooling_marker) const
|
||||
{
|
||||
assert(F > 0.);
|
||||
assert(F < 100000.);
|
||||
|
||||
G1Writer w;
|
||||
GCodeG1Formatter w;
|
||||
w.emit_f(F);
|
||||
w.emit_comment(this->config.gcode_comments, comment);
|
||||
w.emit_string(cooling_marker);
|
||||
|
|
@ -382,7 +270,7 @@ std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string &com
|
|||
m_pos(0) = point(0);
|
||||
m_pos(1) = point(1);
|
||||
|
||||
G1Writer w;
|
||||
GCodeG1Formatter w;
|
||||
w.emit_xy(point);
|
||||
w.emit_f(this->config.travel_speed.value * 60.0);
|
||||
w.emit_comment(this->config.gcode_comments, comment);
|
||||
|
|
@ -415,7 +303,7 @@ std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string &co
|
|||
m_lifted = 0;
|
||||
m_pos = point;
|
||||
|
||||
G1Writer w;
|
||||
GCodeG1Formatter w;
|
||||
w.emit_xyz(point);
|
||||
w.emit_f(this->config.travel_speed.value * 60.0);
|
||||
w.emit_comment(this->config.gcode_comments, comment);
|
||||
|
|
@ -449,7 +337,7 @@ std::string GCodeWriter::_travel_to_z(double z, const std::string &comment)
|
|||
if (speed == 0.)
|
||||
speed = this->config.travel_speed.value;
|
||||
|
||||
G1Writer w;
|
||||
GCodeG1Formatter w;
|
||||
w.emit_z(z);
|
||||
w.emit_f(speed * 60.0);
|
||||
w.emit_comment(this->config.gcode_comments, comment);
|
||||
|
|
@ -474,7 +362,7 @@ std::string GCodeWriter::extrude_to_xy(const Vec2d &point, double dE, const std:
|
|||
m_pos(1) = point(1);
|
||||
m_extruder->extrude(dE);
|
||||
|
||||
G1Writer w;
|
||||
GCodeG1Formatter w;
|
||||
w.emit_xy(point);
|
||||
w.emit_e(m_extrusion_axis, m_extruder->E());
|
||||
w.emit_comment(this->config.gcode_comments, comment);
|
||||
|
|
@ -487,7 +375,7 @@ std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std
|
|||
m_lifted = 0;
|
||||
m_extruder->extrude(dE);
|
||||
|
||||
G1Writer w;
|
||||
GCodeG1Formatter w;
|
||||
w.emit_xyz(point);
|
||||
w.emit_e(m_extrusion_axis, m_extruder->E());
|
||||
w.emit_comment(this->config.gcode_comments, comment);
|
||||
|
|
@ -518,12 +406,11 @@ std::string GCodeWriter::retract_for_toolchange(bool before_wipe)
|
|||
|
||||
std::string GCodeWriter::_retract(double length, double restart_extra, const std::string &comment)
|
||||
{
|
||||
std::ostringstream gcode;
|
||||
|
||||
/* If firmware retraction is enabled, we use a fake value of 1
|
||||
since we ignore the actual configured retract_length which
|
||||
might be 0, in which case the retraction logic gets skipped. */
|
||||
if (this->config.use_firmware_retraction) length = 1;
|
||||
if (this->config.use_firmware_retraction)
|
||||
length = 1;
|
||||
|
||||
// If we use volumetric E values we turn lengths into volumes */
|
||||
if (this->config.use_volumetric_e) {
|
||||
|
|
@ -533,52 +420,48 @@ std::string GCodeWriter::_retract(double length, double restart_extra, const std
|
|||
restart_extra = restart_extra * area;
|
||||
}
|
||||
|
||||
double dE = m_extruder->retract(length, restart_extra);
|
||||
if (dE != 0) {
|
||||
|
||||
std::string gcode;
|
||||
if (double dE = m_extruder->retract(length, restart_extra); dE != 0) {
|
||||
if (this->config.use_firmware_retraction) {
|
||||
if (FLAVOR_IS(gcfMachinekit))
|
||||
gcode << "G22 ; retract\n";
|
||||
else
|
||||
gcode << "G10 ; retract\n";
|
||||
gcode = FLAVOR_IS(gcfMachinekit) ? "G22 ; retract\n" : "G10 ; retract\n";
|
||||
} else if (! m_extrusion_axis.empty()) {
|
||||
gcode << "G1 " << m_extrusion_axis << E_NUM(m_extruder->E())
|
||||
<< " F" << XYZF_NUM(m_extruder->retract_speed() * 60.);
|
||||
COMMENT(comment);
|
||||
gcode << "\n";
|
||||
GCodeG1Formatter w;
|
||||
w.emit_e(m_extrusion_axis, m_extruder->E());
|
||||
w.emit_f(m_extruder->retract_speed() * 60.);
|
||||
w.emit_comment(this->config.gcode_comments, comment);
|
||||
gcode = w.string();
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAVOR_IS(gcfMakerWare))
|
||||
gcode << "M103 ; extruder off\n";
|
||||
|
||||
return gcode.str();
|
||||
gcode += "M103 ; extruder off\n";
|
||||
|
||||
return gcode;
|
||||
}
|
||||
|
||||
std::string GCodeWriter::unretract()
|
||||
{
|
||||
std::ostringstream gcode;
|
||||
std::string gcode;
|
||||
|
||||
if (FLAVOR_IS(gcfMakerWare))
|
||||
gcode << "M101 ; extruder on\n";
|
||||
gcode = "M101 ; extruder on\n";
|
||||
|
||||
double dE = m_extruder->unretract();
|
||||
if (dE != 0) {
|
||||
if (double dE = m_extruder->unretract(); dE != 0) {
|
||||
if (this->config.use_firmware_retraction) {
|
||||
if (FLAVOR_IS(gcfMachinekit))
|
||||
gcode << "G23 ; unretract\n";
|
||||
else
|
||||
gcode << "G11 ; unretract\n";
|
||||
gcode << this->reset_e();
|
||||
gcode += FLAVOR_IS(gcfMachinekit) ? "G23 ; unretract\n" : "G11 ; unretract\n";
|
||||
gcode += this->reset_e();
|
||||
} else if (! m_extrusion_axis.empty()) {
|
||||
// use G1 instead of G0 because G0 will blend the restart with the previous travel move
|
||||
gcode << "G1 " << m_extrusion_axis << E_NUM(m_extruder->E())
|
||||
<< " F" << XYZF_NUM(m_extruder->deretract_speed() * 60.);
|
||||
if (this->config.gcode_comments) gcode << " ; unretract";
|
||||
gcode << "\n";
|
||||
GCodeG1Formatter w;
|
||||
w.emit_e(m_extrusion_axis, m_extruder->E());
|
||||
w.emit_f(m_extruder->deretract_speed() * 60.);
|
||||
w.emit_comment(this->config.gcode_comments, " ; unretract");
|
||||
gcode += w.string();
|
||||
}
|
||||
}
|
||||
|
||||
return gcode.str();
|
||||
return gcode;
|
||||
}
|
||||
|
||||
/* If this method is called more than once before calling unlift(),
|
||||
|
|
@ -611,4 +494,88 @@ std::string GCodeWriter::unlift()
|
|||
return gcode;
|
||||
}
|
||||
|
||||
std::string GCodeWriter::set_fan(const GCodeFlavor gcode_flavor, bool gcode_comments, unsigned int speed)
|
||||
{
|
||||
std::ostringstream gcode;
|
||||
if (speed == 0) {
|
||||
switch (gcode_flavor) {
|
||||
case gcfTeacup:
|
||||
gcode << "M106 S0"; break;
|
||||
case gcfMakerWare:
|
||||
case gcfSailfish:
|
||||
gcode << "M127"; break;
|
||||
default:
|
||||
gcode << "M107"; break;
|
||||
}
|
||||
if (gcode_comments)
|
||||
gcode << " ; disable fan";
|
||||
gcode << "\n";
|
||||
} else {
|
||||
switch (gcode_flavor) {
|
||||
case gcfMakerWare:
|
||||
case gcfSailfish:
|
||||
gcode << "M126"; break;
|
||||
case gcfMach3:
|
||||
case gcfMachinekit:
|
||||
gcode << "M106 P" << 255.0 * speed / 100.0; break;
|
||||
default:
|
||||
gcode << "M106 S" << 255.0 * speed / 100.0; break;
|
||||
}
|
||||
if (gcode_comments)
|
||||
gcode << " ; enable fan";
|
||||
gcode << "\n";
|
||||
}
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
std::string GCodeWriter::set_fan(unsigned int speed) const
|
||||
{
|
||||
return GCodeWriter::set_fan(this->config.gcode_flavor, this->config.gcode_comments, speed);
|
||||
}
|
||||
|
||||
|
||||
void GCodeFormatter::emit_axis(const char axis, const double v, size_t digits) {
|
||||
assert(digits <= 6);
|
||||
static constexpr const std::array<int, 7> pow_10{1, 10, 100, 1000, 10000, 100000, 1000000};
|
||||
*ptr_err.ptr++ = ' '; *ptr_err.ptr++ = axis;
|
||||
|
||||
char *base_ptr = this->ptr_err.ptr;
|
||||
auto v_int = int64_t(std::round(v * pow_10[digits]));
|
||||
// Older stdlib on macOS doesn't support std::from_chars at all, so it is used boost::spirit::karma::generate instead of it.
|
||||
// That is a little bit slower than std::to_chars but not much.
|
||||
#ifdef __APPLE__
|
||||
boost::spirit::karma::generate(this->ptr_err.ptr, boost::spirit::karma::int_generator<int64_t>(), v_int);
|
||||
#else
|
||||
// this->buf_end minus 1 because we need space for adding the extra decimal point.
|
||||
this->ptr_err = std::to_chars(this->ptr_err.ptr, this->buf_end - 1, v_int);
|
||||
#endif
|
||||
size_t writen_digits = (this->ptr_err.ptr - base_ptr) - (v_int < 0 ? 1 : 0);
|
||||
if (writen_digits < digits) {
|
||||
// Number is smaller than 10^digits, so that we will pad it with zeros.
|
||||
size_t remaining_digits = digits - writen_digits;
|
||||
// Move all newly inserted chars by remaining_digits to allocate space for padding with zeros.
|
||||
for (char *from_ptr = this->ptr_err.ptr - 1, *to_ptr = from_ptr + remaining_digits; from_ptr >= this->ptr_err.ptr - writen_digits; --to_ptr, --from_ptr)
|
||||
*to_ptr = *from_ptr;
|
||||
|
||||
memset(this->ptr_err.ptr - writen_digits, '0', remaining_digits);
|
||||
this->ptr_err.ptr += remaining_digits;
|
||||
}
|
||||
|
||||
// Move all newly inserted chars by one to allocate space for a decimal point.
|
||||
for (char *to_ptr = this->ptr_err.ptr, *from_ptr = to_ptr - 1; from_ptr >= this->ptr_err.ptr - digits; --to_ptr, --from_ptr)
|
||||
*to_ptr = *from_ptr;
|
||||
|
||||
*(this->ptr_err.ptr - digits) = '.';
|
||||
for (size_t i = 0; i < digits; ++i) {
|
||||
if (*this->ptr_err.ptr != '0')
|
||||
break;
|
||||
this->ptr_err.ptr--;
|
||||
}
|
||||
if (*this->ptr_err.ptr == '.')
|
||||
this->ptr_err.ptr--;
|
||||
if ((this->ptr_err.ptr + 1) == base_ptr || *this->ptr_err.ptr == '-')
|
||||
*(++this->ptr_err.ptr) = '0';
|
||||
this->ptr_err.ptr++;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "libslic3r.h"
|
||||
#include <string>
|
||||
#include <charconv>
|
||||
#include "Extruder.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
|
|
@ -18,7 +19,7 @@ public:
|
|||
GCodeWriter() :
|
||||
multiple_extruders(false), m_extrusion_axis("E"), m_extruder(nullptr),
|
||||
m_single_extruder_multi_material(false),
|
||||
m_last_acceleration(0), m_max_acceleration(0), m_last_fan_speed(0),
|
||||
m_last_acceleration(0), m_max_acceleration(0),
|
||||
m_last_bed_temperature(0), m_last_bed_temperature_reached(true),
|
||||
m_lifted(0)
|
||||
{}
|
||||
|
|
@ -42,7 +43,6 @@ public:
|
|||
std::string postamble() const;
|
||||
std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1) const;
|
||||
std::string set_bed_temperature(unsigned int temperature, bool wait = false);
|
||||
std::string set_fan(unsigned int speed, bool dont_save = false);
|
||||
std::string set_acceleration(unsigned int acceleration);
|
||||
std::string reset_e(bool force = false);
|
||||
std::string update_progress(unsigned int num, unsigned int tot, bool allow_100 = false) const;
|
||||
|
|
@ -69,6 +69,12 @@ public:
|
|||
std::string unlift();
|
||||
Vec3d get_position() const { return m_pos; }
|
||||
|
||||
// To be called by the CoolingBuffer from another thread.
|
||||
static std::string set_fan(const GCodeFlavor gcode_flavor, bool gcode_comments, unsigned int speed);
|
||||
// To be called by the main thread. It always emits the G-code, it does not remember the previous state.
|
||||
// Keeping the state is left to the CoolingBuffer, which runs asynchronously on another thread.
|
||||
std::string set_fan(unsigned int speed) const;
|
||||
|
||||
private:
|
||||
// Extruders are sorted by their ID, so that binary search is possible.
|
||||
std::vector<Extruder> m_extruders;
|
||||
|
|
@ -79,7 +85,6 @@ private:
|
|||
// Limit for setting the acceleration, to respect the machine limits set for the Marlin firmware.
|
||||
// If set to zero, the limit is not in action.
|
||||
unsigned int m_max_acceleration;
|
||||
unsigned int m_last_fan_speed;
|
||||
unsigned int m_last_bed_temperature;
|
||||
bool m_last_bed_temperature_reached;
|
||||
double m_lifted;
|
||||
|
|
@ -89,6 +94,84 @@ private:
|
|||
std::string _retract(double length, double restart_extra, const std::string &comment);
|
||||
};
|
||||
|
||||
class GCodeFormatter {
|
||||
public:
|
||||
GCodeFormatter() {
|
||||
this->buf_end = buf + buflen;
|
||||
this->ptr_err.ptr = this->buf;
|
||||
}
|
||||
|
||||
GCodeFormatter(const GCodeFormatter&) = delete;
|
||||
GCodeFormatter& operator=(const GCodeFormatter&) = delete;
|
||||
|
||||
static constexpr const int XYZF_EXPORT_DIGITS = 3;
|
||||
static constexpr const int E_EXPORT_DIGITS = 5;
|
||||
|
||||
void emit_axis(const char axis, const double v, size_t digits);
|
||||
|
||||
void emit_xy(const Vec2d &point) {
|
||||
this->emit_axis('X', point.x(), XYZF_EXPORT_DIGITS);
|
||||
this->emit_axis('Y', point.y(), XYZF_EXPORT_DIGITS);
|
||||
}
|
||||
|
||||
void emit_xyz(const Vec3d &point) {
|
||||
this->emit_axis('X', point.x(), XYZF_EXPORT_DIGITS);
|
||||
this->emit_axis('Y', point.y(), XYZF_EXPORT_DIGITS);
|
||||
this->emit_z(point.z());
|
||||
}
|
||||
|
||||
void emit_z(const double z) {
|
||||
this->emit_axis('Z', z, XYZF_EXPORT_DIGITS);
|
||||
}
|
||||
|
||||
void emit_e(const std::string &axis, double v) {
|
||||
if (! axis.empty()) {
|
||||
// not gcfNoExtrusion
|
||||
this->emit_axis(axis[0], v, E_EXPORT_DIGITS);
|
||||
}
|
||||
}
|
||||
|
||||
void emit_f(double speed) {
|
||||
this->emit_axis('F', speed, XYZF_EXPORT_DIGITS);
|
||||
}
|
||||
|
||||
void emit_string(const std::string &s) {
|
||||
strncpy(ptr_err.ptr, s.c_str(), s.size());
|
||||
ptr_err.ptr += s.size();
|
||||
}
|
||||
|
||||
void emit_comment(bool allow_comments, const std::string &comment) {
|
||||
if (allow_comments && ! comment.empty()) {
|
||||
*ptr_err.ptr ++ = ' '; *ptr_err.ptr ++ = ';'; *ptr_err.ptr ++ = ' ';
|
||||
this->emit_string(comment);
|
||||
}
|
||||
}
|
||||
|
||||
std::string string() {
|
||||
*ptr_err.ptr ++ = '\n';
|
||||
return std::string(this->buf, ptr_err.ptr - buf);
|
||||
}
|
||||
|
||||
protected:
|
||||
static constexpr const size_t buflen = 256;
|
||||
char buf[buflen];
|
||||
char* buf_end;
|
||||
std::to_chars_result ptr_err;
|
||||
};
|
||||
|
||||
class GCodeG1Formatter : public GCodeFormatter {
|
||||
public:
|
||||
GCodeG1Formatter() {
|
||||
this->buf[0] = 'G';
|
||||
this->buf[1] = '1';
|
||||
this->buf_end = buf + buflen;
|
||||
this->ptr_err.ptr = this->buf + 2;
|
||||
}
|
||||
|
||||
GCodeG1Formatter(const GCodeG1Formatter&) = delete;
|
||||
GCodeG1Formatter& operator=(const GCodeG1Formatter&) = delete;
|
||||
};
|
||||
|
||||
} /* namespace Slic3r */
|
||||
|
||||
#endif /* slic3r_GCodeWriter_hpp_ */
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@ public:
|
|||
void rotate(double angle, const Point ¢er);
|
||||
void reverse() { std::reverse(this->points.begin(), this->points.end()); }
|
||||
|
||||
const Point& first_point() const { return this->points.front(); }
|
||||
const Point& front() const { return this->points.front(); }
|
||||
const Point& back() const { return this->points.back(); }
|
||||
const Point& first_point() const { return this->front(); }
|
||||
virtual const Point& last_point() const = 0;
|
||||
virtual Lines lines() const = 0;
|
||||
size_t size() const { return points.size(); }
|
||||
|
|
|
|||
|
|
@ -18,11 +18,6 @@ using ConstPolygonPtrs = std::vector<const Polygon*>;
|
|||
class Polygon : public MultiPoint
|
||||
{
|
||||
public:
|
||||
explicit operator Polygons() const { Polygons pp; pp.push_back(*this); return pp; }
|
||||
explicit operator Polyline() const { return this->split_at_first_point(); }
|
||||
Point& operator[](Points::size_type idx) { return this->points[idx]; }
|
||||
const Point& operator[](Points::size_type idx) const { return this->points[idx]; }
|
||||
|
||||
Polygon() = default;
|
||||
virtual ~Polygon() = default;
|
||||
explicit Polygon(const Points &points) : MultiPoint(points) {}
|
||||
|
|
@ -39,6 +34,9 @@ public:
|
|||
Polygon& operator=(const Polygon &other) { points = other.points; return *this; }
|
||||
Polygon& operator=(Polygon &&other) { points = std::move(other.points); return *this; }
|
||||
|
||||
Point& operator[](Points::size_type idx) { return this->points[idx]; }
|
||||
const Point& operator[](Points::size_type idx) const { return this->points[idx]; }
|
||||
|
||||
// last point == first point for polygons
|
||||
const Point& last_point() const override { return this->points.front(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -10,20 +10,6 @@
|
|||
|
||||
namespace Slic3r {
|
||||
|
||||
Polyline::operator Polylines() const
|
||||
{
|
||||
Polylines polylines;
|
||||
polylines.push_back(*this);
|
||||
return polylines;
|
||||
}
|
||||
|
||||
Polyline::operator Line() const
|
||||
{
|
||||
if (this->points.size() > 2)
|
||||
throw Slic3r::InvalidArgument("Can't convert polyline with more than two points to a line");
|
||||
return Line(this->points.front(), this->points.back());
|
||||
}
|
||||
|
||||
const Point& Polyline::leftmost_point() const
|
||||
{
|
||||
const Point *p = &this->points.front();
|
||||
|
|
|
|||
|
|
@ -59,13 +59,11 @@ public:
|
|||
src.points.clear();
|
||||
}
|
||||
}
|
||||
|
||||
explicit operator Polylines() const;
|
||||
explicit operator Line() const;
|
||||
|
||||
const Point& last_point() const override { return this->points.back(); }
|
||||
|
||||
const Point& leftmost_point() const;
|
||||
Lines lines() const override;
|
||||
|
||||
void clip_end(double distance);
|
||||
void clip_start(double distance);
|
||||
void extend_end(double distance);
|
||||
|
|
|
|||
|
|
@ -397,7 +397,7 @@ bool Print::sequential_print_horizontal_clearance_valid(const Print& print, Poly
|
|||
convex_hull.translate(instance.shift - print_object->center_offset());
|
||||
// if output needed, collect indices (inside convex_hulls_other) of intersecting hulls
|
||||
for (size_t i = 0; i < convex_hulls_other.size(); ++i) {
|
||||
if (!intersection((Polygons)convex_hulls_other[i], (Polygons)convex_hull).empty()) {
|
||||
if (! intersection(convex_hulls_other[i], convex_hull).empty()) {
|
||||
if (polygons == nullptr)
|
||||
return false;
|
||||
else {
|
||||
|
|
@ -812,7 +812,7 @@ void Print::auto_assign_extruders(ModelObject* model_object) const
|
|||
// Slicing process, running at a background thread.
|
||||
void Print::process()
|
||||
{
|
||||
name_tbb_thread_pool_threads();
|
||||
name_tbb_thread_pool_threads_set_locale();
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Starting the slicing process." << log_memory_info();
|
||||
for (PrintObject *obj : m_objects)
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ bool add_cavity(indexed_triangle_set &pad,
|
|||
|
||||
if (inner_base.empty() || middle_base.empty()) { logerr(); return false; }
|
||||
|
||||
ExPolygons pdiff = diff_ex((Polygons)top_poly, (Polygons)middle_base.contour);
|
||||
ExPolygons pdiff = diff_ex(top_poly, middle_base.contour);
|
||||
|
||||
if (pdiff.size() != 1) { logerr(); return false; }
|
||||
|
||||
|
|
|
|||
|
|
@ -693,7 +693,7 @@ void SLAPrint::process()
|
|||
if (m_objects.empty())
|
||||
return;
|
||||
|
||||
name_tbb_thread_pool_threads();
|
||||
name_tbb_thread_pool_threads_set_locale();
|
||||
|
||||
// Assumption: at this point the print objects should be populated only with
|
||||
// the model objects we have to process and the instances are also filtered
|
||||
|
|
|
|||
|
|
@ -3338,7 +3338,7 @@ void LoopInterfaceProcessor::generate(MyLayerExtruded &top_contact_layer, const
|
|||
Polygon &contour = (i_contour == 0) ? it_contact_expoly->contour : it_contact_expoly->holes[i_contour - 1];
|
||||
const Point *seg_current_pt = nullptr;
|
||||
coordf_t seg_current_t = 0.;
|
||||
if (! intersection_pl((Polylines)contour.split_at_first_point(), overhang_with_margin).empty()) {
|
||||
if (! intersection_pl(contour.split_at_first_point(), overhang_with_margin).empty()) {
|
||||
// The contour is below the overhang at least to some extent.
|
||||
//FIXME ideally one would place the circles below the overhang only.
|
||||
// Walk around the contour and place circles so their centers are not closer than circle_distance from each other.
|
||||
|
|
|
|||
|
|
@ -188,7 +188,8 @@ std::optional<std::string> get_current_thread_name()
|
|||
#endif // _WIN32
|
||||
|
||||
// Spawn (n - 1) worker threads on Intel TBB thread pool and name them by an index and a system thread ID.
|
||||
void name_tbb_thread_pool_threads()
|
||||
// Also it sets locale of the worker threads to "C" for the G-code generator to produce "." as a decimal separator.
|
||||
void name_tbb_thread_pool_threads_set_locale()
|
||||
{
|
||||
static bool initialized = false;
|
||||
if (initialized)
|
||||
|
|
@ -233,6 +234,21 @@ void name_tbb_thread_pool_threads()
|
|||
std::ostringstream name;
|
||||
name << "slic3r_tbb_" << range.begin();
|
||||
set_current_thread_name(name.str().c_str());
|
||||
// Set locales of the worker thread to "C".
|
||||
#ifdef _WIN32
|
||||
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
|
||||
std::setlocale(LC_ALL, "C");
|
||||
#else
|
||||
// We are leaking some memory here, because the newlocale() produced memory will never be released.
|
||||
// This is not a problem though, as there will be a maximum one worker thread created per physical thread.
|
||||
uselocale(newlocale(
|
||||
#ifdef __APPLE__
|
||||
LC_ALL_MASK
|
||||
#else // some Unix / Linux / BSD
|
||||
LC_ALL
|
||||
#endif
|
||||
, "C", nullptr));
|
||||
#endif
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ std::optional<std::string> get_current_thread_name();
|
|||
|
||||
// To be called somewhere before the TBB threads are spinned for the first time, to
|
||||
// give them names recognizible in the debugger.
|
||||
void name_tbb_thread_pool_threads();
|
||||
// Also it sets locale of the worker threads to "C" for the G-code generator to produce "." as a decimal separator.
|
||||
void name_tbb_thread_pool_threads_set_locale();
|
||||
|
||||
template<class Fn>
|
||||
inline boost::thread create_thread(boost::thread::attributes &attrs, Fn &&fn)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue