mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-22 16:21:24 -06:00
Merge remote-tracking branch 'origin/master' into feature_arrange_with_libnest2d
This commit is contained in:
commit
c430f57187
40 changed files with 829 additions and 653 deletions
|
@ -103,6 +103,10 @@ public:
|
|||
bool contains(const BoundingBox3Base<PointClass>& other) const {
|
||||
return contains(other.min) && contains(other.max);
|
||||
}
|
||||
|
||||
bool intersects(const BoundingBox3Base<PointClass>& other) const {
|
||||
return (this->min.x < other.max.x) && (this->max.x > other.min.x) && (this->min.y < other.max.y) && (this->max.y > other.min.y) && (this->min.z < other.max.z) && (this->max.z > other.min.z);
|
||||
}
|
||||
};
|
||||
|
||||
class BoundingBox : public BoundingBoxBase<Point>
|
||||
|
|
|
@ -1989,7 +1989,7 @@ namespace Slic3r {
|
|||
|
||||
// stores object's name
|
||||
if (!obj->name.empty())
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << OBJECT_TYPE << "\" " << KEY_ATTR << "=\"name\" " << VALUE_ATTR << "=\"" << obj->name << "\"/>\n";
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << OBJECT_TYPE << "\" " << KEY_ATTR << "=\"name\" " << VALUE_ATTR << "=\"" << xml_escape(obj->name) << "\"/>\n";
|
||||
|
||||
// stores object's config data
|
||||
for (const std::string& key : obj->config.keys())
|
||||
|
@ -2012,7 +2012,7 @@ namespace Slic3r {
|
|||
|
||||
// stores volume's name
|
||||
if (!volume->name.empty())
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << NAME_KEY << "\" " << VALUE_ATTR << "=\"" << volume->name << "\"/>\n";
|
||||
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << NAME_KEY << "\" " << VALUE_ATTR << "=\"" << xml_escape(volume->name) << "\"/>\n";
|
||||
|
||||
// stores volume's modifier field
|
||||
if (volume->modifier)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "../libslic3r.h"
|
||||
#include "../Model.hpp"
|
||||
#include "../GCode.hpp"
|
||||
#include "../Utils.hpp"
|
||||
#include "../slic3r/GUI/PresetBundle.hpp"
|
||||
#include "AMF.hpp"
|
||||
|
||||
|
@ -686,33 +687,6 @@ bool load_amf(const char *path, PresetBundle* bundle, Model *model)
|
|||
return false;
|
||||
}
|
||||
|
||||
std::string xml_escape(std::string text)
|
||||
{
|
||||
std::string::size_type pos = 0;
|
||||
for (;;)
|
||||
{
|
||||
pos = text.find_first_of("\"\'&<>", pos);
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
|
||||
std::string replacement;
|
||||
switch (text[pos])
|
||||
{
|
||||
case '\"': replacement = """; break;
|
||||
case '\'': replacement = "'"; break;
|
||||
case '&': replacement = "&"; break;
|
||||
case '<': replacement = "<"; break;
|
||||
case '>': replacement = ">"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
text.replace(pos, 1, replacement);
|
||||
pos += replacement.size();
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
bool store_amf(const char *path, Model *model, Print* print, bool export_print_config)
|
||||
{
|
||||
if ((path == nullptr) || (model == nullptr) || (print == nullptr))
|
||||
|
@ -761,7 +735,7 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c
|
|||
for (const std::string &key : object->config.keys())
|
||||
stream << " <metadata type=\"slic3r." << key << "\">" << object->config.serialize(key) << "</metadata>\n";
|
||||
if (!object->name.empty())
|
||||
stream << " <metadata type=\"name\">" << object->name << "</metadata>\n";
|
||||
stream << " <metadata type=\"name\">" << xml_escape(object->name) << "</metadata>\n";
|
||||
std::vector<double> layer_height_profile = object->layer_height_profile_valid ? object->layer_height_profile : std::vector<double>();
|
||||
if (layer_height_profile.size() >= 4 && (layer_height_profile.size() % 2) == 0) {
|
||||
// Store the layer height profile as a single semicolon separated list.
|
||||
|
@ -805,7 +779,7 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c
|
|||
for (const std::string &key : volume->config.keys())
|
||||
stream << " <metadata type=\"slic3r." << key << "\">" << volume->config.serialize(key) << "</metadata>\n";
|
||||
if (!volume->name.empty())
|
||||
stream << " <metadata type=\"name\">" << volume->name << "</metadata>\n";
|
||||
stream << " <metadata type=\"name\">" << xml_escape(volume->name) << "</metadata>\n";
|
||||
if (volume->modifier)
|
||||
stream << " <metadata type=\"slic3r.modifier\">1</metadata>\n";
|
||||
for (int i = 0; i < volume->mesh.stl.stats.number_of_facets; ++i) {
|
||||
|
|
|
@ -309,10 +309,12 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
|
|||
size_t object_idx;
|
||||
size_t layer_idx;
|
||||
};
|
||||
std::vector<std::vector<LayerToPrint>> per_object(print.objects.size(), std::vector<LayerToPrint>());
|
||||
|
||||
PrintObjectPtrs printable_objects = print.get_printable_objects();
|
||||
std::vector<std::vector<LayerToPrint>> per_object(printable_objects.size(), std::vector<LayerToPrint>());
|
||||
std::vector<OrderingItem> ordering;
|
||||
for (size_t i = 0; i < print.objects.size(); ++ i) {
|
||||
per_object[i] = collect_layers_to_print(*print.objects[i]);
|
||||
for (size_t i = 0; i < printable_objects.size(); ++i) {
|
||||
per_object[i] = collect_layers_to_print(*printable_objects[i]);
|
||||
OrderingItem ordering_item;
|
||||
ordering_item.object_idx = i;
|
||||
ordering.reserve(ordering.size() + per_object[i].size());
|
||||
|
@ -337,8 +339,8 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
|
|||
std::pair<coordf_t, std::vector<LayerToPrint>> merged;
|
||||
// Assign an average print_z to the set of layers with nearly equal print_z.
|
||||
merged.first = 0.5 * (ordering[i].print_z + ordering[j-1].print_z);
|
||||
merged.second.assign(print.objects.size(), LayerToPrint());
|
||||
for (; i < j; ++ i) {
|
||||
merged.second.assign(printable_objects.size(), LayerToPrint());
|
||||
for (; i < j; ++i) {
|
||||
const OrderingItem &oi = ordering[i];
|
||||
assert(merged.second[oi.object_idx].layer() == nullptr);
|
||||
merged.second[oi.object_idx] = std::move(per_object[oi.object_idx][oi.layer_idx]);
|
||||
|
@ -375,10 +377,13 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
|
|||
}
|
||||
fclose(file);
|
||||
|
||||
m_normal_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
|
||||
if (print->config.gcode_flavor.value == gcfMarlin)
|
||||
{
|
||||
m_normal_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
|
||||
|
||||
if (m_silent_time_estimator_enabled)
|
||||
m_silent_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
|
||||
if (m_silent_time_estimator_enabled)
|
||||
m_silent_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
|
||||
}
|
||||
|
||||
if (! this->m_placeholder_parser_failed_templates.empty()) {
|
||||
// G-code export proceeded, but some of the PlaceholderParser substitutions failed.
|
||||
|
@ -472,9 +477,10 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
|||
// How many times will be change_layer() called?
|
||||
// change_layer() in turn increments the progress bar status.
|
||||
m_layer_count = 0;
|
||||
PrintObjectPtrs printable_objects = print.get_printable_objects();
|
||||
if (print.config.complete_objects.value) {
|
||||
// Add each of the object's layers separately.
|
||||
for (auto object : print.objects) {
|
||||
for (auto object : printable_objects) {
|
||||
std::vector<coordf_t> zs;
|
||||
zs.reserve(object->layers.size() + object->support_layers.size());
|
||||
for (auto layer : object->layers)
|
||||
|
@ -487,7 +493,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
|||
} else {
|
||||
// Print all objects with the same print_z together.
|
||||
std::vector<coordf_t> zs;
|
||||
for (auto object : print.objects) {
|
||||
for (auto object : printable_objects) {
|
||||
zs.reserve(zs.size() + object->layers.size() + object->support_layers.size());
|
||||
for (auto layer : object->layers)
|
||||
zs.push_back(layer->print_z);
|
||||
|
@ -506,8 +512,8 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
|||
{
|
||||
// get the minimum cross-section used in the print
|
||||
std::vector<double> mm3_per_mm;
|
||||
for (auto object : print.objects) {
|
||||
for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) {
|
||||
for (auto object : printable_objects) {
|
||||
for (size_t region_id = 0; region_id < print.regions.size(); ++region_id) {
|
||||
auto region = print.regions[region_id];
|
||||
for (auto layer : object->layers) {
|
||||
auto layerm = layer->regions[region_id];
|
||||
|
@ -567,7 +573,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
|||
_write(file, "\n");
|
||||
}
|
||||
// Write some terse information on the slicing parameters.
|
||||
const PrintObject *first_object = print.objects.front();
|
||||
const PrintObject *first_object = printable_objects.front();
|
||||
const double layer_height = first_object->config.layer_height.value;
|
||||
const double first_layer_height = first_object->config.first_layer_height.get_abs_value(layer_height);
|
||||
for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) {
|
||||
|
@ -596,13 +602,14 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
|||
size_t initial_print_object_id = 0;
|
||||
bool has_wipe_tower = false;
|
||||
if (print.config.complete_objects.value) {
|
||||
// Find the 1st printing object, find its tool ordering and the initial extruder ID.
|
||||
for (; initial_print_object_id < print.objects.size(); ++initial_print_object_id) {
|
||||
tool_ordering = ToolOrdering(*print.objects[initial_print_object_id], initial_extruder_id);
|
||||
if ((initial_extruder_id = tool_ordering.first_extruder()) != (unsigned int)-1)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Find the 1st printing object, find its tool ordering and the initial extruder ID.
|
||||
for (; initial_print_object_id < printable_objects.size(); ++initial_print_object_id) {
|
||||
tool_ordering = ToolOrdering(*printable_objects[initial_print_object_id], initial_extruder_id);
|
||||
if ((initial_extruder_id = tool_ordering.first_extruder()) != (unsigned int)-1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Find tool ordering for all the objects at once, and the initial extruder ID.
|
||||
// If the tool ordering has been pre-calculated by Print class for wipe tower already, reuse it.
|
||||
tool_ordering = print.m_tool_ordering.empty() ?
|
||||
|
@ -676,7 +683,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
|||
// Collect outer contours of all objects over all layers.
|
||||
// Discard objects only containing thin walls (offset would fail on an empty polygon).
|
||||
Polygons islands;
|
||||
for (const PrintObject *object : print.objects)
|
||||
for (const PrintObject *object : printable_objects)
|
||||
for (const Layer *layer : object->layers)
|
||||
for (const ExPolygon &expoly : layer->slices.expolygons)
|
||||
for (const Point © : object->_shifted_copies) {
|
||||
|
@ -724,7 +731,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
|||
if (print.config.complete_objects.value) {
|
||||
// Print objects from the smallest to the tallest to avoid collisions
|
||||
// when moving onto next object starting point.
|
||||
std::vector<PrintObject*> objects(print.objects);
|
||||
std::vector<PrintObject*> objects(printable_objects);
|
||||
std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->size.z < po2->size.z; });
|
||||
size_t finished_objects = 0;
|
||||
for (size_t object_id = initial_print_object_id; object_id < objects.size(); ++ object_id) {
|
||||
|
@ -785,7 +792,8 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
|||
// Order objects using a nearest neighbor search.
|
||||
std::vector<size_t> object_indices;
|
||||
Points object_reference_points;
|
||||
for (PrintObject *object : print.objects)
|
||||
PrintObjectPtrs printable_objects = print.get_printable_objects();
|
||||
for (PrintObject *object : printable_objects)
|
||||
object_reference_points.push_back(object->_shifted_copies.front());
|
||||
Slic3r::Geometry::chained_path(object_reference_points, object_indices);
|
||||
// Sort layers by Z.
|
||||
|
@ -799,7 +807,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
|||
// Verify, whether the print overaps the priming extrusions.
|
||||
BoundingBoxf bbox_print(get_print_extrusions_extents(print));
|
||||
coordf_t twolayers_printz = ((layers_to_print.size() == 1) ? layers_to_print.front() : layers_to_print[1]).first + EPSILON;
|
||||
for (const PrintObject *print_object : print.objects)
|
||||
for (const PrintObject *print_object : printable_objects)
|
||||
bbox_print.merge(get_print_object_extrusions_extents(*print_object, twolayers_printz));
|
||||
bbox_print.merge(get_wipe_tower_extrusions_extents(print, twolayers_printz));
|
||||
BoundingBoxf bbox_prime(get_wipe_tower_priming_extrusions_extents(print));
|
||||
|
@ -862,9 +870,9 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
|||
_write(file, m_writer.postamble());
|
||||
|
||||
// calculates estimated printing time
|
||||
m_normal_time_estimator.calculate_time();
|
||||
m_normal_time_estimator.calculate_time(false);
|
||||
if (m_silent_time_estimator_enabled)
|
||||
m_silent_time_estimator.calculate_time();
|
||||
m_silent_time_estimator.calculate_time(false);
|
||||
|
||||
// Get filament stats.
|
||||
print.filament_stats.clear();
|
||||
|
|
|
@ -67,11 +67,13 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
|
|||
ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material)
|
||||
{
|
||||
m_print_config_ptr = &print.config;
|
||||
|
||||
PrintObjectPtrs objects = print.get_printable_objects();
|
||||
// Initialize the print layers for all objects and all layers.
|
||||
coordf_t object_bottom_z = 0.;
|
||||
{
|
||||
std::vector<coordf_t> zs;
|
||||
for (auto object : print.objects) {
|
||||
for (auto object : objects) {
|
||||
zs.reserve(zs.size() + object->layers.size() + object->support_layers.size());
|
||||
for (auto layer : object->layers)
|
||||
zs.emplace_back(layer->print_z);
|
||||
|
@ -84,7 +86,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
|
|||
}
|
||||
|
||||
// Collect extruders reuqired to print the layers.
|
||||
for (auto object : print.objects)
|
||||
for (auto object : objects)
|
||||
this->collect_extruders(*object);
|
||||
|
||||
// Reorder the extruders to minimize tool switches.
|
||||
|
@ -449,10 +451,9 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
|
|||
return volume_to_wipe; // Soluble filament cannot be wiped in a random infill, neither the filament after it
|
||||
|
||||
// we will sort objects so that dedicated for wiping are at the beginning:
|
||||
PrintObjectPtrs object_list = print.objects;
|
||||
PrintObjectPtrs object_list = print.get_printable_objects();
|
||||
std::sort(object_list.begin(), object_list.end(), [](const PrintObject* a, const PrintObject* b) { return a->config.wipe_into_objects; });
|
||||
|
||||
|
||||
// We will now iterate through
|
||||
// - first the dedicated objects to mark perimeters or infills (depending on infill_first)
|
||||
// - second through the dedicated ones again to mark infills or perimeters (depending on infill_first)
|
||||
|
@ -546,7 +547,8 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
|
|||
unsigned int first_nonsoluble_extruder = first_nonsoluble_extruder_on_layer(print.config);
|
||||
unsigned int last_nonsoluble_extruder = last_nonsoluble_extruder_on_layer(print.config);
|
||||
|
||||
for (const PrintObject* object : print.objects) {
|
||||
PrintObjectPtrs printable_objects = print.get_printable_objects();
|
||||
for (const PrintObject* object : printable_objects) {
|
||||
// Finds this layer:
|
||||
auto this_layer_it = std::find_if(object->layers.begin(), object->layers.end(), [<](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)<EPSILON; });
|
||||
if (this_layer_it == object->layers.end())
|
||||
|
|
|
@ -66,8 +66,10 @@ public:
|
|||
wipe_tower_partitions(0),
|
||||
wipe_tower_layer_height(0.) {}
|
||||
|
||||
bool operator< (const LayerTools &rhs) const { return print_z - EPSILON < rhs.print_z; }
|
||||
bool operator==(const LayerTools &rhs) const { return std::abs(print_z - rhs.print_z) < EPSILON; }
|
||||
// Changing these operators to epsilon version can make a problem in cases where support and object layers get close to each other.
|
||||
// In case someone tries to do it, make sure you know what you're doing and test it properly (slice multiple objects at once with supports).
|
||||
bool operator< (const LayerTools &rhs) const { return print_z < rhs.print_z; }
|
||||
bool operator==(const LayerTools &rhs) const { return print_z == rhs.print_z; }
|
||||
|
||||
bool is_extruder_order(unsigned int a, unsigned int b) const;
|
||||
|
||||
|
|
|
@ -490,7 +490,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime(
|
|||
// box_coordinates cleaning_box(xy(0.5f, - 1.5f), m_wipe_tower_width, wipe_area);
|
||||
|
||||
const float prime_section_width = std::min(240.f / tools.size(), 60.f);
|
||||
box_coordinates cleaning_box(xy(5.f, 0.f), prime_section_width, 100.f);
|
||||
box_coordinates cleaning_box(xy(5.f, 0.01f + m_perimeter_width/2.f), prime_section_width, 100.f);
|
||||
|
||||
PrusaMultiMaterial::Writer writer(m_layer_height, m_perimeter_width);
|
||||
writer.set_extrusion_flow(m_extrusion_flow)
|
||||
|
|
|
@ -79,7 +79,6 @@ namespace Slic3r {
|
|||
}
|
||||
|
||||
GCodeTimeEstimator::Block::Block()
|
||||
: st_synchronized(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -196,11 +195,14 @@ namespace Slic3r {
|
|||
}
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::calculate_time()
|
||||
void GCodeTimeEstimator::calculate_time(bool start_from_beginning)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
_reset_time();
|
||||
_set_blocks_st_synchronize(false);
|
||||
if (start_from_beginning)
|
||||
{
|
||||
_reset_time();
|
||||
_last_st_synchronized_block_id = -1;
|
||||
}
|
||||
_calculate_time();
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
|
@ -484,6 +486,7 @@ namespace Slic3r {
|
|||
|
||||
GCodeFlavor GCodeTimeEstimator::get_dialect() const
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
return _state.dialect;
|
||||
}
|
||||
|
||||
|
@ -534,6 +537,7 @@ namespace Slic3r {
|
|||
|
||||
void GCodeTimeEstimator::add_additional_time(float timeSec)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
_state.additional_time += timeSec;
|
||||
}
|
||||
|
||||
|
@ -611,6 +615,8 @@ namespace Slic3r {
|
|||
|
||||
reset_g1_line_id();
|
||||
_g1_line_ids.clear();
|
||||
|
||||
_last_st_synchronized_block_id = -1;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_reset_time()
|
||||
|
@ -623,26 +629,19 @@ namespace Slic3r {
|
|||
_blocks.clear();
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_set_blocks_st_synchronize(bool state)
|
||||
{
|
||||
for (Block& block : _blocks)
|
||||
{
|
||||
block.st_synchronized = state;
|
||||
}
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_calculate_time()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
_forward_pass();
|
||||
_reverse_pass();
|
||||
_recalculate_trapezoids();
|
||||
|
||||
_time += get_additional_time();
|
||||
|
||||
for (Block& block : _blocks)
|
||||
for (int i = _last_st_synchronized_block_id + 1; i < (int)_blocks.size(); ++i)
|
||||
{
|
||||
if (block.st_synchronized)
|
||||
continue;
|
||||
Block& block = _blocks[i];
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
float block_time = 0.0f;
|
||||
|
@ -665,6 +664,8 @@ namespace Slic3r {
|
|||
block.elapsed_time = _time;
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
}
|
||||
|
||||
_last_st_synchronized_block_id = _blocks.size() - 1;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line)
|
||||
|
@ -800,6 +801,7 @@ namespace Slic3r {
|
|||
|
||||
void GCodeTimeEstimator::_processG1(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
increment_g1_line_id();
|
||||
|
||||
// updates axes positions from line
|
||||
|
@ -997,6 +999,7 @@ namespace Slic3r {
|
|||
|
||||
void GCodeTimeEstimator::_processG4(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
GCodeFlavor dialect = get_dialect();
|
||||
|
||||
float value;
|
||||
|
@ -1018,31 +1021,37 @@ namespace Slic3r {
|
|||
|
||||
void GCodeTimeEstimator::_processG20(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
set_units(Inches);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processG21(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
set_units(Millimeters);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processG28(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
// TODO
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processG90(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
set_global_positioning_type(Absolute);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processG91(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
set_global_positioning_type(Relative);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processG92(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
float lengthsScaleFactor = (get_units() == Inches) ? INCHES_TO_MM : 1.0f;
|
||||
bool anyFound = false;
|
||||
|
||||
|
@ -1083,26 +1092,31 @@ namespace Slic3r {
|
|||
|
||||
void GCodeTimeEstimator::_processM1(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
_simulate_st_synchronize();
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processM82(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
set_e_local_positioning_type(Absolute);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processM83(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
set_e_local_positioning_type(Relative);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processM109(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
// TODO
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processM201(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
GCodeFlavor dialect = get_dialect();
|
||||
|
||||
// see http://reprap.org/wiki/G-code#M201:_Set_max_printing_acceleration
|
||||
|
@ -1123,6 +1137,7 @@ namespace Slic3r {
|
|||
|
||||
void GCodeTimeEstimator::_processM203(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
GCodeFlavor dialect = get_dialect();
|
||||
|
||||
// see http://reprap.org/wiki/G-code#M203:_Set_maximum_feedrate
|
||||
|
@ -1147,6 +1162,7 @@ namespace Slic3r {
|
|||
|
||||
void GCodeTimeEstimator::_processM204(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
float value;
|
||||
if (line.has_value('S', value))
|
||||
set_acceleration(value);
|
||||
|
@ -1157,6 +1173,7 @@ namespace Slic3r {
|
|||
|
||||
void GCodeTimeEstimator::_processM205(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
if (line.has_x())
|
||||
{
|
||||
float max_jerk = line.x();
|
||||
|
@ -1183,6 +1200,7 @@ namespace Slic3r {
|
|||
|
||||
void GCodeTimeEstimator::_processM221(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
float value_s;
|
||||
float value_t;
|
||||
if (line.has_value('S', value_s) && !line.has_value('T', value_t))
|
||||
|
@ -1191,6 +1209,7 @@ namespace Slic3r {
|
|||
|
||||
void GCodeTimeEstimator::_processM566(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
if (line.has_x())
|
||||
set_axis_max_jerk(X, line.x() * MMMIN_TO_MMSEC);
|
||||
|
||||
|
@ -1206,19 +1225,17 @@ namespace Slic3r {
|
|||
|
||||
void GCodeTimeEstimator::_simulate_st_synchronize()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
_calculate_time();
|
||||
_set_blocks_st_synchronize(true);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_forward_pass()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
if (_blocks.size() > 1)
|
||||
{
|
||||
for (unsigned int i = 0; i < (unsigned int)_blocks.size() - 1; ++i)
|
||||
{
|
||||
if (_blocks[i].st_synchronized || _blocks[i + 1].st_synchronized)
|
||||
continue;
|
||||
|
||||
for (int i = _last_st_synchronized_block_id + 1; i < (int)_blocks.size() - 1; ++i)
|
||||
{
|
||||
_planner_forward_pass_kernel(_blocks[i], _blocks[i + 1]);
|
||||
}
|
||||
}
|
||||
|
@ -1226,13 +1243,11 @@ namespace Slic3r {
|
|||
|
||||
void GCodeTimeEstimator::_reverse_pass()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
if (_blocks.size() > 1)
|
||||
{
|
||||
for (int i = (int)_blocks.size() - 1; i >= 1; --i)
|
||||
for (int i = (int)_blocks.size() - 1; i >= _last_st_synchronized_block_id + 2; --i)
|
||||
{
|
||||
if (_blocks[i - 1].st_synchronized || _blocks[i].st_synchronized)
|
||||
continue;
|
||||
|
||||
_planner_reverse_pass_kernel(_blocks[i - 1], _blocks[i]);
|
||||
}
|
||||
}
|
||||
|
@ -1240,6 +1255,7 @@ namespace Slic3r {
|
|||
|
||||
void GCodeTimeEstimator::_planner_forward_pass_kernel(Block& prev, Block& curr)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
// If the previous block is an acceleration block, but it is not long enough to complete the
|
||||
// full speed change within the block, we need to adjust the entry speed accordingly. Entry
|
||||
// speeds have already been reset, maximized, and reverse planned by reverse planner.
|
||||
|
@ -1280,13 +1296,13 @@ namespace Slic3r {
|
|||
|
||||
void GCodeTimeEstimator::_recalculate_trapezoids()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
Block* curr = nullptr;
|
||||
Block* next = nullptr;
|
||||
|
||||
for (Block& b : _blocks)
|
||||
for (int i = _last_st_synchronized_block_id + 1; i < (int)_blocks.size(); ++i)
|
||||
{
|
||||
if (b.st_synchronized)
|
||||
continue;
|
||||
Block& b = _blocks[i];
|
||||
|
||||
curr = next;
|
||||
next = &b;
|
||||
|
|
|
@ -144,8 +144,6 @@ namespace Slic3r {
|
|||
Trapezoid trapezoid;
|
||||
float elapsed_time;
|
||||
|
||||
bool st_synchronized;
|
||||
|
||||
Block();
|
||||
|
||||
// Returns the length of the move covered by this block, in mm
|
||||
|
@ -211,6 +209,8 @@ namespace Slic3r {
|
|||
BlocksList _blocks;
|
||||
// Map between g1 line id and blocks id, used to speed up export of remaining times
|
||||
G1LineIdToBlockIdMap _g1_line_ids;
|
||||
// Index of the last block already st_synchronized
|
||||
int _last_st_synchronized_block_id;
|
||||
float _time; // s
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
|
@ -227,7 +227,10 @@ namespace Slic3r {
|
|||
void add_gcode_block(const std::string &str) { this->add_gcode_block(str.c_str()); }
|
||||
|
||||
// Calculates the time estimate from the gcode lines added using add_gcode_line() or add_gcode_block()
|
||||
void calculate_time();
|
||||
// start_from_beginning:
|
||||
// if set to true all blocks will be used to calculate the time estimate,
|
||||
// if set to false only the blocks not yet processed will be used and the calculated time will be added to the current calculated time
|
||||
void calculate_time(bool start_from_beginning);
|
||||
|
||||
// Calculates the time estimate from the given gcode in string format
|
||||
void calculate_time_from_text(const std::string& gcode);
|
||||
|
@ -320,8 +323,6 @@ namespace Slic3r {
|
|||
void _reset_time();
|
||||
void _reset_blocks();
|
||||
|
||||
void _set_blocks_st_synchronize(bool state);
|
||||
|
||||
// Calculates the time estimate
|
||||
void _calculate_time();
|
||||
|
||||
|
|
|
@ -1235,6 +1235,59 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
|
|||
return;
|
||||
}
|
||||
|
||||
void ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume)
|
||||
{
|
||||
for (ModelVolume* vol : this->volumes)
|
||||
{
|
||||
if (!vol->modifier)
|
||||
{
|
||||
for (ModelInstance* inst : this->instances)
|
||||
{
|
||||
BoundingBoxf3 bb;
|
||||
|
||||
double c = cos(inst->rotation);
|
||||
double s = sin(inst->rotation);
|
||||
|
||||
for (int f = 0; f < vol->mesh.stl.stats.number_of_facets; ++f)
|
||||
{
|
||||
const stl_facet& facet = vol->mesh.stl.facet_start[f];
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
// original point
|
||||
const stl_vertex& v = facet.vertex[i];
|
||||
Pointf3 p((double)v.x, (double)v.y, (double)v.z);
|
||||
|
||||
// scale
|
||||
p.x *= inst->scaling_factor;
|
||||
p.y *= inst->scaling_factor;
|
||||
p.z *= inst->scaling_factor;
|
||||
|
||||
// rotate Z
|
||||
double x = p.x;
|
||||
double y = p.y;
|
||||
p.x = c * x - s * y;
|
||||
p.y = s * x + c * y;
|
||||
|
||||
// translate
|
||||
p.x += inst->offset.x;
|
||||
p.y += inst->offset.y;
|
||||
|
||||
bb.merge(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (print_volume.contains(bb))
|
||||
inst->print_volume_state = ModelInstance::PVS_Inside;
|
||||
else if (print_volume.intersects(bb))
|
||||
inst->print_volume_state = ModelInstance::PVS_Partly_Outside;
|
||||
else
|
||||
inst->print_volume_state = ModelInstance::PVS_Fully_Outside;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelObject::print_info() const
|
||||
{
|
||||
using namespace std;
|
||||
|
|
|
@ -132,6 +132,8 @@ public:
|
|||
void cut(coordf_t z, Model* model) const;
|
||||
void split(ModelObjectPtrs* new_objects);
|
||||
|
||||
void check_instances_print_volume_state(const BoundingBoxf3& print_volume);
|
||||
|
||||
// Print object statistics to console.
|
||||
void print_info() const;
|
||||
|
||||
|
@ -197,12 +199,24 @@ private:
|
|||
// Knows the affine transformation of an object.
|
||||
class ModelInstance
|
||||
{
|
||||
friend class ModelObject;
|
||||
public:
|
||||
enum EPrintVolumeState : unsigned char
|
||||
{
|
||||
PVS_Inside,
|
||||
PVS_Partly_Outside,
|
||||
PVS_Fully_Outside,
|
||||
Num_BedStates
|
||||
};
|
||||
|
||||
friend class ModelObject;
|
||||
|
||||
double rotation; // Rotation around the Z axis, in radians around mesh center point
|
||||
double scaling_factor;
|
||||
Pointf offset; // in unscaled coordinates
|
||||
|
||||
// flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state())
|
||||
EPrintVolumeState print_volume_state;
|
||||
|
||||
ModelObject* get_object() const { return this->object; }
|
||||
|
||||
// To be called on an external mesh
|
||||
|
@ -213,14 +227,16 @@ public:
|
|||
BoundingBoxf3 transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate = false) const;
|
||||
// To be called on an external polygon. It does not translate the polygon, only rotates and scales.
|
||||
void transform_polygon(Polygon* polygon) const;
|
||||
|
||||
|
||||
bool is_printable() const { return print_volume_state == PVS_Inside; }
|
||||
|
||||
private:
|
||||
// Parent object, owning this instance.
|
||||
ModelObject* object;
|
||||
|
||||
ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), object(object) {}
|
||||
ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), object(object), print_volume_state(PVS_Inside) {}
|
||||
ModelInstance(ModelObject *object, const ModelInstance &other) :
|
||||
rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset), object(object) {}
|
||||
rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset), object(object), print_volume_state(PVS_Inside) {}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -71,6 +71,13 @@ bool Print::reload_model_instances()
|
|||
return invalidated;
|
||||
}
|
||||
|
||||
PrintObjectPtrs Print::get_printable_objects() const
|
||||
{
|
||||
PrintObjectPtrs printable_objects(this->objects);
|
||||
printable_objects.erase(std::remove_if(printable_objects.begin(), printable_objects.end(), [](PrintObject* o) { return !o->is_printable(); }), printable_objects.end());
|
||||
return printable_objects;
|
||||
}
|
||||
|
||||
PrintRegion* Print::add_region()
|
||||
{
|
||||
regions.push_back(new PrintRegion(this));
|
||||
|
@ -534,11 +541,17 @@ std::string Print::validate() const
|
|||
BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), config.max_print_height));
|
||||
// Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced.
|
||||
print_volume.min.z = -1e10;
|
||||
unsigned int printable_count = 0;
|
||||
for (PrintObject *po : this->objects) {
|
||||
if (!print_volume.contains(po->model_object()->tight_bounding_box(false)))
|
||||
return L("Some objects are outside of the print volume.");
|
||||
po->model_object()->check_instances_print_volume_state(print_volume);
|
||||
po->reload_model_instances();
|
||||
if (po->is_printable())
|
||||
++printable_count;
|
||||
}
|
||||
|
||||
if (printable_count == 0)
|
||||
return L("All objects are outside of the print volume.");
|
||||
|
||||
if (this->config.complete_objects) {
|
||||
// Check horizontal clearance.
|
||||
{
|
||||
|
@ -858,8 +871,9 @@ void Print::_make_skirt()
|
|||
// prepended to the first 'n' layers (with 'n' = skirt_height).
|
||||
// $skirt_height_z in this case is the highest possible skirt height for safety.
|
||||
coordf_t skirt_height_z = 0.;
|
||||
for (const PrintObject *object : this->objects) {
|
||||
size_t skirt_layers = this->has_infinite_skirt() ?
|
||||
PrintObjectPtrs printable_objects = get_printable_objects();
|
||||
for (const PrintObject *object : printable_objects) {
|
||||
size_t skirt_layers = this->has_infinite_skirt() ?
|
||||
object->layer_count() :
|
||||
std::min(size_t(this->config.skirt_height.value), object->layer_count());
|
||||
skirt_height_z = std::max(skirt_height_z, object->layers[skirt_layers-1]->print_z);
|
||||
|
@ -867,7 +881,7 @@ void Print::_make_skirt()
|
|||
|
||||
// Collect points from all layers contained in skirt height.
|
||||
Points points;
|
||||
for (const PrintObject *object : this->objects) {
|
||||
for (const PrintObject *object : printable_objects) {
|
||||
Points object_points;
|
||||
// Get object layers up to skirt_height_z.
|
||||
for (const Layer *layer : object->layers) {
|
||||
|
@ -980,7 +994,8 @@ void Print::_make_brim()
|
|||
// Brim is only printed on first layer and uses perimeter extruder.
|
||||
Flow flow = this->brim_flow();
|
||||
Polygons islands;
|
||||
for (PrintObject *object : this->objects) {
|
||||
PrintObjectPtrs printable_objects = get_printable_objects();
|
||||
for (PrintObject *object : printable_objects) {
|
||||
Polygons object_islands;
|
||||
for (ExPolygon &expoly : object->layers.front()->slices.expolygons)
|
||||
object_islands.push_back(expoly.contour);
|
||||
|
|
|
@ -209,6 +209,8 @@ public:
|
|||
void combine_infill();
|
||||
void _generate_support_material();
|
||||
|
||||
bool is_printable() const { return !this->_shifted_copies.empty(); }
|
||||
|
||||
private:
|
||||
Print* _print;
|
||||
ModelObject* _model_object;
|
||||
|
@ -257,6 +259,8 @@ public:
|
|||
void reload_object(size_t idx);
|
||||
bool reload_model_instances();
|
||||
|
||||
PrintObjectPtrs get_printable_objects() const;
|
||||
|
||||
// methods for handling regions
|
||||
PrintRegion* get_region(size_t idx) { return regions.at(idx); }
|
||||
const PrintRegion* get_region(size_t idx) const { return regions.at(idx); }
|
||||
|
|
|
@ -102,7 +102,10 @@ bool PrintObject::reload_model_instances()
|
|||
Points copies;
|
||||
copies.reserve(this->_model_object->instances.size());
|
||||
for (const ModelInstance *mi : this->_model_object->instances)
|
||||
copies.emplace_back(Point::new_scale(mi->offset.x, mi->offset.y));
|
||||
{
|
||||
if (mi->is_printable())
|
||||
copies.emplace_back(Point::new_scale(mi->offset.x, mi->offset.y));
|
||||
}
|
||||
return this->set_copies(copies);
|
||||
}
|
||||
|
||||
|
@ -291,6 +294,9 @@ bool PrintObject::has_support_material() const
|
|||
|
||||
void PrintObject::_prepare_infill()
|
||||
{
|
||||
if (!this->is_printable())
|
||||
return;
|
||||
|
||||
// This will assign a type (top/bottom/internal) to $layerm->slices.
|
||||
// Then the classifcation of $layerm->slices is transfered onto
|
||||
// the $layerm->fill_surfaces by clipping $layerm->fill_surfaces
|
||||
|
@ -1177,8 +1183,8 @@ void PrintObject::_slice()
|
|||
|
||||
this->typed_slices = false;
|
||||
|
||||
#if 0
|
||||
// Disable parallelization for debugging purposes.
|
||||
#ifdef SLIC3R_PROFILE
|
||||
// Disable parallelization so the Shiny profiler works
|
||||
static tbb::task_scheduler_init *tbb_init = nullptr;
|
||||
tbb_init = new tbb::task_scheduler_init(1);
|
||||
#endif
|
||||
|
@ -1442,6 +1448,9 @@ void PrintObject::_simplify_slices(double distance)
|
|||
|
||||
void PrintObject::_make_perimeters()
|
||||
{
|
||||
if (!this->is_printable())
|
||||
return;
|
||||
|
||||
if (this->state.is_done(posPerimeters)) return;
|
||||
this->state.set_started(posPerimeters);
|
||||
|
||||
|
@ -1550,6 +1559,9 @@ void PrintObject::_make_perimeters()
|
|||
|
||||
void PrintObject::_infill()
|
||||
{
|
||||
if (!this->is_printable())
|
||||
return;
|
||||
|
||||
if (this->state.is_done(posInfill)) return;
|
||||
this->state.set_started(posInfill);
|
||||
|
||||
|
@ -1954,6 +1966,9 @@ void PrintObject::combine_infill()
|
|||
|
||||
void PrintObject::_generate_support_material()
|
||||
{
|
||||
if (!this->is_printable())
|
||||
return;
|
||||
|
||||
PrintObjectSupportMaterial support_material(this, PrintObject::slicing_parameters());
|
||||
support_material.generate(*this);
|
||||
}
|
||||
|
|
|
@ -84,6 +84,8 @@ inline T next_highest_power_of_2(T v)
|
|||
return ++ v;
|
||||
}
|
||||
|
||||
extern std::string xml_escape(std::string text);
|
||||
|
||||
class PerlCallback {
|
||||
public:
|
||||
PerlCallback(void *sv) : m_callback(nullptr) { this->register_callback(sv); }
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <boost/thread.hpp>
|
||||
|
||||
#define SLIC3R_FORK_NAME "Slic3r Prusa Edition"
|
||||
#define SLIC3R_VERSION "1.41.0-alpha"
|
||||
#define SLIC3R_VERSION "1.41.0-alpha2"
|
||||
#define SLIC3R_BUILD "UNKNOWN"
|
||||
|
||||
typedef int32_t coord_t;
|
||||
|
|
|
@ -387,4 +387,31 @@ unsigned get_current_pid()
|
|||
#endif
|
||||
}
|
||||
|
||||
std::string xml_escape(std::string text)
|
||||
{
|
||||
std::string::size_type pos = 0;
|
||||
for (;;)
|
||||
{
|
||||
pos = text.find_first_of("\"\'&<>", pos);
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
|
||||
std::string replacement;
|
||||
switch (text[pos])
|
||||
{
|
||||
case '\"': replacement = """; break;
|
||||
case '\'': replacement = "'"; break;
|
||||
case '&': replacement = "&"; break;
|
||||
case '<': replacement = "<"; break;
|
||||
case '>': replacement = ">"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
text.replace(pos, 1, replacement);
|
||||
pos += replacement.size();
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue