Merge remote-tracking branch 'origin/dev_native' into tm_sla_supports_backend
This commit is contained in:
commit
4662fd0e73
25 changed files with 503 additions and 441 deletions
|
@ -26,6 +26,7 @@ option(SLIC3R_PROFILE "Compile Slic3r with an invasive Shiny profiler" 0)
|
|||
option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1)
|
||||
option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1)
|
||||
option(SLIC3R_PERL_XS "Compile XS Perl module and enable Perl unit and integration tests" 0)
|
||||
option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0)
|
||||
|
||||
# Proposal for C++ unit tests and sandboxes
|
||||
option(SLIC3R_BUILD_SANDBOXES "Build development sandboxes" OFF)
|
||||
|
@ -77,6 +78,13 @@ if(WIN32)
|
|||
message("STL fixing by the Netfabb service will not be compiled")
|
||||
unset(WIN10SDK_PATH)
|
||||
endif()
|
||||
if(WIN10SDK_PATH)
|
||||
message("Building with Win10 Netfabb STL fixing service support")
|
||||
add_definitions(-DHAS_WIN10SDK)
|
||||
include_directories("${WIN10SDK_PATH}/Include")
|
||||
else()
|
||||
message("Building without Win10 Netfabb STL fixing service support")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
|
@ -93,6 +101,13 @@ endif()
|
|||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
# On GCC and Clang, no return from a non-void function is a warning only. Here, we make it an error.
|
||||
add_compile_options(-Werror=return-type)
|
||||
|
||||
if (SLIC3R_ASAN)
|
||||
add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lasan")
|
||||
endif ()
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
# Where all the bundled libraries reside?
|
||||
|
|
|
@ -78,7 +78,7 @@ if (APPLE)
|
|||
target_link_libraries(slic3r "-liconv -framework IOKit" "-framework CoreFoundation" -lc++)
|
||||
elseif (MSVC)
|
||||
# Manifest is provided through slic3r.rc, don't generate your own.
|
||||
set(CMAKE_EXE_LINKER_FLAGS /MANIFEST:NO)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO")
|
||||
else ()
|
||||
target_link_libraries(slic3r -ldl -lstdc++)
|
||||
endif ()
|
||||
|
|
|
@ -127,6 +127,8 @@ add_library(libslic3r STATIC
|
|||
PolylineCollection.hpp
|
||||
Print.cpp
|
||||
Print.hpp
|
||||
PrintBase.cpp
|
||||
PrintBase.hpp
|
||||
PrintExport.hpp
|
||||
PrintConfig.cpp
|
||||
PrintConfig.hpp
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "libslic3r.h"
|
||||
#include "Point.hpp"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
|
|
@ -342,6 +342,7 @@ namespace Slic3r {
|
|||
IdToSlaSupportPointsMap m_sla_support_points;
|
||||
std::string m_curr_metadata_name;
|
||||
std::string m_curr_characters;
|
||||
std::string m_name;
|
||||
|
||||
public:
|
||||
_3MF_Importer();
|
||||
|
@ -444,6 +445,7 @@ namespace Slic3r {
|
|||
, m_unit_factor(1.0f)
|
||||
, m_curr_metadata_name("")
|
||||
, m_curr_characters("")
|
||||
, m_name("")
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -505,6 +507,8 @@ namespace Slic3r {
|
|||
|
||||
mz_zip_archive_file_stat stat;
|
||||
|
||||
m_name = boost::filesystem::path(filename).filename().stem().string();
|
||||
|
||||
// we first loop the entries to read from the archive the .model file only, in order to extract the version from it
|
||||
for (mz_uint i = 0; i < num_entries; ++i)
|
||||
{
|
||||
|
@ -1051,6 +1055,9 @@ namespace Slic3r {
|
|||
|
||||
// set object data
|
||||
m_curr_object.object->name = get_attribute_value_string(attributes, num_attributes, NAME_ATTR);
|
||||
if (m_curr_object.object->name.empty())
|
||||
m_curr_object.object->name = m_name + "_" + std::to_string(m_model->objects.size());
|
||||
|
||||
m_curr_object.id = get_attribute_value_int(attributes, num_attributes, ID_ATTR);
|
||||
}
|
||||
|
||||
|
|
|
@ -373,11 +373,10 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
|
|||
size_t layer_idx;
|
||||
};
|
||||
|
||||
PrintObjectPtrs printable_objects = print.get_printable_objects();
|
||||
std::vector<std::vector<LayerToPrint>> per_object(printable_objects.size(), std::vector<LayerToPrint>());
|
||||
std::vector<std::vector<LayerToPrint>> per_object(print.objects().size(), std::vector<LayerToPrint>());
|
||||
std::vector<OrderingItem> ordering;
|
||||
for (size_t i = 0; i < printable_objects.size(); ++i) {
|
||||
per_object[i] = collect_layers_to_print(*printable_objects[i]);
|
||||
for (size_t i = 0; i < print.objects().size(); ++i) {
|
||||
per_object[i] = collect_layers_to_print(*print.objects()[i]);
|
||||
OrderingItem ordering_item;
|
||||
ordering_item.object_idx = i;
|
||||
ordering.reserve(ordering.size() + per_object[i].size());
|
||||
|
@ -402,7 +401,7 @@ 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(printable_objects.size(), LayerToPrint());
|
||||
merged.second.assign(print.objects().size(), LayerToPrint());
|
||||
for (; i < j; ++i) {
|
||||
const OrderingItem &oi = ordering[i];
|
||||
assert(merged.second[oi.object_idx].layer() == nullptr);
|
||||
|
@ -569,10 +568,9 @@ 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 : printable_objects) {
|
||||
for (auto object : print.objects()) {
|
||||
std::vector<coordf_t> zs;
|
||||
zs.reserve(object->layers().size() + object->support_layers().size());
|
||||
for (auto layer : object->layers())
|
||||
|
@ -585,7 +583,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 : printable_objects) {
|
||||
for (auto object : print.objects()) {
|
||||
zs.reserve(zs.size() + object->layers().size() + object->support_layers().size());
|
||||
for (auto layer : object->layers())
|
||||
zs.push_back(layer->print_z);
|
||||
|
@ -608,7 +606,7 @@ 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 : printable_objects) {
|
||||
for (auto object : print.objects()) {
|
||||
for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) {
|
||||
const PrintRegion* region = print.regions()[region_id];
|
||||
for (auto layer : object->layers()) {
|
||||
|
@ -673,7 +671,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
|||
print.throw_if_canceled();
|
||||
|
||||
// Write some terse information on the slicing parameters.
|
||||
const PrintObject *first_object = printable_objects.front();
|
||||
const PrintObject *first_object = print.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 (const PrintRegion* region : print.regions()) {
|
||||
|
@ -711,8 +709,8 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
|||
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 < printable_objects.size(); ++initial_print_object_id) {
|
||||
tool_ordering = ToolOrdering(*printable_objects[initial_print_object_id], 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;
|
||||
}
|
||||
|
@ -796,7 +794,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 : printable_objects)
|
||||
for (const PrintObject *object : print.objects())
|
||||
for (const Layer *layer : object->layers())
|
||||
for (const ExPolygon &expoly : layer->slices.expolygons)
|
||||
for (const Point © : object->copies()) {
|
||||
|
@ -849,7 +847,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(printable_objects);
|
||||
std::vector<PrintObject*> objects(print.objects());
|
||||
std::sort(objects.begin(), objects.end(), [](const PrintObject* po1, const PrintObject* po2) { return po1->size(2) < po2->size(2); });
|
||||
size_t finished_objects = 0;
|
||||
for (size_t object_id = initial_print_object_id; object_id < objects.size(); ++ object_id) {
|
||||
|
@ -912,8 +910,7 @@ 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;
|
||||
PrintObjectPtrs printable_objects = print.get_printable_objects();
|
||||
for (PrintObject *object : printable_objects)
|
||||
for (PrintObject *object : print.objects())
|
||||
object_reference_points.push_back(object->copies().front());
|
||||
Slic3r::Geometry::chained_path(object_reference_points, object_indices);
|
||||
// Sort layers by Z.
|
||||
|
@ -928,7 +925,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 : printable_objects)
|
||||
for (const PrintObject *print_object : print.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));
|
||||
|
|
|
@ -68,12 +68,11 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
|
|||
{
|
||||
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 : objects) {
|
||||
for (auto object : print.objects()) {
|
||||
zs.reserve(zs.size() + object->layers().size() + object->support_layers().size());
|
||||
for (auto layer : object->layers())
|
||||
zs.emplace_back(layer->print_z);
|
||||
|
@ -86,7 +85,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
|
|||
}
|
||||
|
||||
// Collect extruders reuqired to print the layers.
|
||||
for (auto object : objects)
|
||||
for (auto object : print.objects())
|
||||
this->collect_extruders(*object);
|
||||
|
||||
// Reorder the extruders to minimize tool switches.
|
||||
|
@ -451,7 +450,7 @@ 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.get_printable_objects();
|
||||
PrintObjectPtrs object_list = print.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
|
||||
|
@ -547,8 +546,7 @@ 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());
|
||||
|
||||
PrintObjectPtrs printable_objects = print.get_printable_objects();
|
||||
for (const PrintObject* object : printable_objects) {
|
||||
for (const PrintObject* object : print.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())
|
||||
|
|
|
@ -188,8 +188,9 @@ public:
|
|||
when user expects that. */
|
||||
Vec3d origin_translation;
|
||||
|
||||
Model* get_model() const { return m_model; };
|
||||
|
||||
Model* get_model() { return m_model; };
|
||||
const Model* get_model() const { return m_model; };
|
||||
|
||||
ModelVolume* add_volume(const TriangleMesh &mesh);
|
||||
ModelVolume* add_volume(TriangleMesh &&mesh);
|
||||
ModelVolume* add_volume(const ModelVolume &volume);
|
||||
|
|
|
@ -25,33 +25,27 @@ namespace Slic3r {
|
|||
template class PrintState<PrintStep, psCount>;
|
||||
template class PrintState<PrintObjectStep, posCount>;
|
||||
|
||||
void Print::clear_objects()
|
||||
void Print::clear()
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(m_mutex);
|
||||
tbb::mutex::scoped_lock lock(this->cancel_mutex());
|
||||
// The following call should stop background processing if it is running.
|
||||
this->invalidate_all_steps();
|
||||
for (PrintObject *object : m_objects)
|
||||
delete object;
|
||||
m_objects.clear();
|
||||
for (PrintRegion *region : m_regions)
|
||||
delete region;
|
||||
m_regions.clear();
|
||||
this->invalidate_all_steps();
|
||||
}
|
||||
|
||||
void Print::delete_object(size_t idx)
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(m_mutex);
|
||||
// destroy object and remove it from our container
|
||||
delete m_objects[idx];
|
||||
m_objects.erase(m_objects.begin() + idx);
|
||||
this->invalidate_all_steps();
|
||||
// TODO: purge unused regions
|
||||
}
|
||||
|
||||
// Only used by the Perl test cases.
|
||||
void Print::reload_object(size_t /* idx */)
|
||||
{
|
||||
ModelObjectPtrs model_objects;
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(m_mutex);
|
||||
tbb::mutex::scoped_lock lock(this->cancel_mutex());
|
||||
// The following call should stop background processing if it is running.
|
||||
this->invalidate_all_steps();
|
||||
/* TODO: this method should check whether the per-object config and per-material configs
|
||||
have changed in such a way that regions need to be rearranged or we can just apply
|
||||
the diff and invalidate something. Same logic as apply_config()
|
||||
|
@ -68,33 +62,12 @@ void Print::reload_object(size_t /* idx */)
|
|||
for (PrintRegion *region : m_regions)
|
||||
delete region;
|
||||
m_regions.clear();
|
||||
this->invalidate_all_steps();
|
||||
}
|
||||
// re-add model objects
|
||||
for (ModelObject *mo : model_objects)
|
||||
this->add_model_object(mo);
|
||||
}
|
||||
|
||||
// Reloads the model instances into the print class.
|
||||
// The slicing shall not be running as the modified model instances at the print
|
||||
// are used for the brim & skirt calculation.
|
||||
// Returns true if the brim or skirt have been invalidated.
|
||||
bool Print::reload_model_instances()
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(m_mutex);
|
||||
bool invalidated = false;
|
||||
for (PrintObject *object : m_objects)
|
||||
invalidated |= object->reload_model_instances();
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
PrintObjectPtrs Print::get_printable_objects() const
|
||||
{
|
||||
PrintObjectPtrs printable_objects(m_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()
|
||||
{
|
||||
m_regions.emplace_back(new PrintRegion(this));
|
||||
|
@ -282,11 +255,11 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|
|||
|
||||
bool Print::invalidate_step(PrintStep step)
|
||||
{
|
||||
bool invalidated = m_state.invalidate(step, m_mutex, m_cancel_callback);
|
||||
bool invalidated = Inherited::invalidate_step(step);
|
||||
// Propagate to dependent steps.
|
||||
//FIXME Why should skirt invalidate brim? Shouldn't it be vice versa?
|
||||
if (step == psSkirt)
|
||||
invalidated |= m_state.invalidate(psBrim, m_mutex, m_cancel_callback);
|
||||
invalidated |= Inherited::invalidate_step(psBrim);
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
|
@ -399,9 +372,9 @@ static PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig
|
|||
// and have explicit instance positions.
|
||||
void Print::add_model_object(ModelObject* model_object, int idx)
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(m_mutex);
|
||||
tbb::mutex::scoped_lock lock(this->cancel_mutex());
|
||||
// Initialize a new print object and store it at the given position.
|
||||
PrintObject *object = new PrintObject(this, model_object, model_object->raw_bounding_box());
|
||||
PrintObject *object = new PrintObject(this, model_object);
|
||||
if (idx != -1) {
|
||||
delete m_objects[idx];
|
||||
m_objects[idx] = object;
|
||||
|
@ -460,7 +433,7 @@ void Print::add_model_object(ModelObject* model_object, int idx)
|
|||
|
||||
bool Print::apply_config(DynamicPrintConfig config)
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(m_mutex);
|
||||
tbb::mutex::scoped_lock lock(this->cancel_mutex());
|
||||
|
||||
// we get a copy of the config object so we can modify it safely
|
||||
config.normalize();
|
||||
|
@ -560,7 +533,7 @@ exit_for_rearrange_regions:
|
|||
model_objects.reserve(m_objects.size());
|
||||
for (PrintObject *object : m_objects)
|
||||
model_objects.push_back(object->model_object());
|
||||
this->clear_objects();
|
||||
this->clear();
|
||||
for (ModelObject *mo : model_objects)
|
||||
this->add_model_object(mo);
|
||||
invalidated = true;
|
||||
|
@ -786,7 +759,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||
update_apply_status(false);
|
||||
|
||||
// Grab the lock for the Print / PrintObject milestones.
|
||||
tbb::mutex::scoped_lock lock(m_mutex);
|
||||
tbb::mutex::scoped_lock lock(this->cancel_mutex());
|
||||
|
||||
// The following call may stop the background processing.
|
||||
update_apply_status(this->invalidate_state_by_config_options(print_diff));
|
||||
|
@ -823,7 +796,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||
if (model.id() != m_model.id()) {
|
||||
// Kill everything, initialize from scratch.
|
||||
// Stop background processing.
|
||||
m_cancel_callback();
|
||||
this->call_cancell_callback();
|
||||
update_apply_status(this->invalidate_all_steps());
|
||||
for (PrintObject *object : m_objects) {
|
||||
model_object_status.emplace(object->model_object()->id(), ModelObjectStatus::Deleted);
|
||||
|
@ -854,7 +827,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||
} else {
|
||||
// Reorder the objects, add new objects.
|
||||
// First stop background processing before shuffling or deleting the PrintObjects in the object list.
|
||||
m_cancel_callback();
|
||||
this->call_cancell_callback();
|
||||
this->invalidate_step(psGCodeExport);
|
||||
// Second create a new list of objects.
|
||||
std::vector<ModelObject*> model_objects_old(std::move(m_model.objects));
|
||||
|
@ -964,7 +937,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||
model_object.assign_copy(model_object_new);
|
||||
} else if (support_blockers_differ || support_enforcers_differ) {
|
||||
// First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list.
|
||||
m_cancel_callback();
|
||||
this->call_cancell_callback();
|
||||
// Invalidate just the supports step.
|
||||
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
|
||||
for (auto it = range.first; it != range.second; ++ it)
|
||||
|
@ -1024,7 +997,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||
if (old.empty()) {
|
||||
// Simple case, just generate new instances.
|
||||
for (const PrintInstances &print_instances : new_print_instances) {
|
||||
PrintObject *print_object = new PrintObject(this, model_object, model_object->raw_bounding_box());
|
||||
PrintObject *print_object = new PrintObject(this, model_object);
|
||||
print_object->set_trafo(print_instances.trafo);
|
||||
print_object->set_copies(print_instances.copies);
|
||||
print_object->config_apply(config);
|
||||
|
@ -1043,7 +1016,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||
for (; it_old != old.end() && transform3d_lower((*it_old)->trafo, new_instances.trafo); ++ it_old);
|
||||
if (it_old == old.end() || ! transform3d_equal((*it_old)->trafo, new_instances.trafo)) {
|
||||
// This is a new instance (or a set of instances with the same trafo). Just add it.
|
||||
PrintObject *print_object = new PrintObject(this, model_object, model_object->raw_bounding_box());
|
||||
PrintObject *print_object = new PrintObject(this, model_object);
|
||||
print_object->set_trafo(new_instances.trafo);
|
||||
print_object->set_copies(new_instances.copies);
|
||||
print_object->config_apply(config);
|
||||
|
@ -1066,7 +1039,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||
}
|
||||
}
|
||||
if (m_objects != print_objects_new) {
|
||||
m_cancel_callback();
|
||||
this->call_cancell_callback();
|
||||
m_objects = print_objects_new;
|
||||
// Delete the PrintObjects marked as Unknown or Deleted.
|
||||
bool deleted_objects = false;
|
||||
|
@ -1562,7 +1535,7 @@ void Print::process()
|
|||
for (PrintObject *obj : m_objects)
|
||||
obj->generate_support_material();
|
||||
this->throw_if_canceled();
|
||||
if (! m_state.is_done(psSkirt)) {
|
||||
if (! this->is_step_done(psSkirt)) {
|
||||
this->set_started(psSkirt);
|
||||
m_skirt.clear();
|
||||
if (this->has_skirt()) {
|
||||
|
@ -1572,7 +1545,7 @@ void Print::process()
|
|||
this->set_done(psSkirt);
|
||||
}
|
||||
this->throw_if_canceled();
|
||||
if (! m_state.is_done(psBrim)) {
|
||||
if (! this->is_step_done(psBrim)) {
|
||||
this->set_started(psBrim);
|
||||
m_brim.clear();
|
||||
if (m_config.brim_width > 0) {
|
||||
|
@ -1582,7 +1555,7 @@ void Print::process()
|
|||
this->set_done(psBrim);
|
||||
}
|
||||
this->throw_if_canceled();
|
||||
if (! m_state.is_done(psWipeTower)) {
|
||||
if (! this->is_step_done(psWipeTower)) {
|
||||
this->set_started(psWipeTower);
|
||||
m_wipe_tower_data.clear();
|
||||
if (this->has_wipe_tower()) {
|
||||
|
@ -1631,8 +1604,7 @@ 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.;
|
||||
PrintObjectPtrs printable_objects = get_printable_objects();
|
||||
for (const PrintObject *object : printable_objects) {
|
||||
for (const PrintObject *object : m_objects) {
|
||||
size_t skirt_layers = this->has_infinite_skirt() ?
|
||||
object->layer_count() :
|
||||
std::min(size_t(m_config.skirt_height.value), object->layer_count());
|
||||
|
@ -1641,7 +1613,7 @@ void Print::_make_skirt()
|
|||
|
||||
// Collect points from all layers contained in skirt height.
|
||||
Points points;
|
||||
for (const PrintObject *object : printable_objects) {
|
||||
for (const PrintObject *object : m_objects) {
|
||||
Points object_points;
|
||||
// Get object layers up to skirt_height_z.
|
||||
for (const Layer *layer : object->m_layers) {
|
||||
|
@ -1756,8 +1728,7 @@ void Print::_make_brim()
|
|||
// Brim is only printed on first layer and uses perimeter extruder.
|
||||
Flow flow = this->brim_flow();
|
||||
Polygons islands;
|
||||
PrintObjectPtrs printable_objects = get_printable_objects();
|
||||
for (PrintObject *object : printable_objects) {
|
||||
for (PrintObject *object : m_objects) {
|
||||
Polygons object_islands;
|
||||
for (ExPolygon &expoly : object->m_layers.front()->slices.expolygons)
|
||||
object_islands.push_back(expoly.contour);
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
#ifndef slic3r_Print_hpp_
|
||||
#define slic3r_Print_hpp_
|
||||
|
||||
#include "libslic3r.h"
|
||||
#include <atomic>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include "PrintBase.hpp"
|
||||
|
||||
#include "BoundingBox.hpp"
|
||||
#include "Flow.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "Layer.hpp"
|
||||
#include "Model.hpp"
|
||||
|
@ -18,13 +13,6 @@
|
|||
#include "GCode/ToolOrdering.hpp"
|
||||
#include "GCode/WipeTower.hpp"
|
||||
|
||||
#include "tbb/atomic.h"
|
||||
// tbb/mutex.h includes Windows, which in turn defines min/max macros. Convince Windows.h to not define these min/max macros.
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include "tbb/mutex.h"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Print;
|
||||
|
@ -42,116 +30,6 @@ enum PrintObjectStep {
|
|||
posInfill, posSupportMaterial, posCount,
|
||||
};
|
||||
|
||||
class CanceledException : public std::exception {
|
||||
public:
|
||||
const char* what() const throw() { return "Background processing has been canceled"; }
|
||||
};
|
||||
|
||||
// To be instantiated over PrintStep or PrintObjectStep enums.
|
||||
template <class StepType, size_t COUNT>
|
||||
class PrintState
|
||||
{
|
||||
public:
|
||||
PrintState() { for (size_t i = 0; i < COUNT; ++ i) m_state[i].store(INVALID, std::memory_order_relaxed); }
|
||||
|
||||
enum State {
|
||||
INVALID,
|
||||
STARTED,
|
||||
DONE,
|
||||
};
|
||||
|
||||
// With full memory barrier.
|
||||
bool is_done(StepType step) const { return m_state[step] == DONE; }
|
||||
|
||||
// Set the step as started. Block on mutex while the Print / PrintObject / PrintRegion objects are being
|
||||
// modified by the UI thread.
|
||||
// This is necessary to block until the Print::apply_config() updates its state, which may
|
||||
// influence the processing step being entered.
|
||||
void set_started(StepType step, tbb::mutex &mtx) {
|
||||
mtx.lock();
|
||||
m_state[step].store(STARTED, std::memory_order_relaxed);
|
||||
mtx.unlock();
|
||||
}
|
||||
|
||||
// Set the step as done. Block on mutex while the Print / PrintObject / PrintRegion objects are being
|
||||
// modified by the UI thread.
|
||||
void set_done(StepType step, tbb::mutex &mtx) {
|
||||
mtx.lock();
|
||||
m_state[step].store(DONE, std::memory_order_relaxed);
|
||||
mtx.unlock();
|
||||
}
|
||||
|
||||
// Make the step invalid.
|
||||
// The provided mutex should be locked at this point, guarding access to m_state.
|
||||
// In case the step has already been entered or finished, cancel the background
|
||||
// processing by calling the cancel callback.
|
||||
template<typename CancelationCallback>
|
||||
bool invalidate(StepType step, tbb::mutex &mtx, CancelationCallback cancel) {
|
||||
bool invalidated = m_state[step].load(std::memory_order_relaxed) != INVALID;
|
||||
if (invalidated) {
|
||||
#if 0
|
||||
if (mtx.state != mtx.HELD) {
|
||||
printf("Not held!\n");
|
||||
}
|
||||
#endif
|
||||
// Raise the mutex, so that the following cancel() callback could cancel
|
||||
// the background processing.
|
||||
mtx.unlock();
|
||||
cancel();
|
||||
m_state[step] = INVALID;
|
||||
mtx.lock();
|
||||
}
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
template<typename CancelationCallback, typename StepTypeIterator>
|
||||
bool invalidate_multiple(StepTypeIterator step_begin, StepTypeIterator step_end, tbb::mutex &mtx, CancelationCallback cancel) {
|
||||
bool invalidated = false;
|
||||
for (StepTypeIterator it = step_begin; ! invalidated && it != step_end; ++ it)
|
||||
invalidated = m_state[*it].load(std::memory_order_relaxed) != INVALID;
|
||||
if (invalidated) {
|
||||
#if 0
|
||||
if (mtx.state != mtx.HELD) {
|
||||
printf("Not held!\n");
|
||||
}
|
||||
#endif
|
||||
// Raise the mutex, so that the following cancel() callback could cancel
|
||||
// the background processing.
|
||||
mtx.unlock();
|
||||
cancel();
|
||||
for (StepTypeIterator it = step_begin; it != step_end; ++ it)
|
||||
m_state[*it] = INVALID;
|
||||
mtx.lock();
|
||||
}
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
// Make all steps invalid.
|
||||
// The provided mutex should be locked at this point, guarding access to m_state.
|
||||
// In case any step has already been entered or finished, cancel the background
|
||||
// processing by calling the cancel callback.
|
||||
template<typename CancelationCallback>
|
||||
bool invalidate_all(tbb::mutex &mtx, CancelationCallback cancel) {
|
||||
bool invalidated = false;
|
||||
for (size_t i = 0; i < COUNT; ++ i)
|
||||
if (m_state[i].load(std::memory_order_relaxed) != INVALID) {
|
||||
invalidated = true;
|
||||
break;
|
||||
}
|
||||
if (invalidated) {
|
||||
mtx.unlock();
|
||||
cancel();
|
||||
for (size_t i = 0; i < COUNT; ++ i)
|
||||
m_state[i].store(INVALID, std::memory_order_relaxed);
|
||||
mtx.lock();
|
||||
}
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<State> m_state[COUNT];
|
||||
};
|
||||
|
||||
// A PrintRegion object represents a group of volumes to print
|
||||
// sharing the same config (including the same assigned extruder(s))
|
||||
class PrintRegion
|
||||
|
@ -193,9 +71,10 @@ typedef std::vector<Layer*> LayerPtrs;
|
|||
typedef std::vector<SupportLayer*> SupportLayerPtrs;
|
||||
class BoundingBoxf3; // TODO: for temporary constructor parameter
|
||||
|
||||
class PrintObject
|
||||
class PrintObject : public PrintObjectBaseWithState<Print, PrintObjectStep, posCount>
|
||||
{
|
||||
friend class Print;
|
||||
private: // Prevents erroneous use by other classes.
|
||||
typedef PrintObjectBaseWithState<Print, PrintObjectStep, posCount> Inherited;
|
||||
|
||||
public:
|
||||
// vector of (vectors of volume ids), indexed by region_id
|
||||
|
@ -218,25 +97,13 @@ public:
|
|||
|
||||
Vec3crd size; // XYZ in scaled coordinates
|
||||
|
||||
Print* print() { return m_print; }
|
||||
const Print* print() const { return m_print; }
|
||||
ModelObject* model_object() { return m_model_object; }
|
||||
const ModelObject* model_object() const { return m_model_object; }
|
||||
ModelObject* model_object() { return m_model_object; }
|
||||
const PrintObjectConfig& config() const { return m_config; }
|
||||
void config_apply(const ConfigBase &other, bool ignore_nonexistent = false) { this->m_config.apply(other, ignore_nonexistent); }
|
||||
void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->m_config.apply_only(other, keys, ignore_nonexistent); }
|
||||
const LayerPtrs& layers() const { return m_layers; }
|
||||
const SupportLayerPtrs& support_layers() const { return m_support_layers; }
|
||||
|
||||
const Transform3d& trafo() const { return m_trafo; }
|
||||
void set_trafo(const Transform3d& trafo) { m_trafo = trafo; }
|
||||
|
||||
const Points& copies() const { return m_copies; }
|
||||
bool add_copy(const Vec2d &point);
|
||||
bool delete_last_copy();
|
||||
bool delete_all_copies() { return this->set_copies(Points()); }
|
||||
bool set_copies(const Points &points);
|
||||
bool reload_model_instances();
|
||||
|
||||
// since the object is aligned to origin, bounding box coincides with size
|
||||
BoundingBox bounding_box() const { return BoundingBox(Point(0,0), to_2d(this->size)); }
|
||||
|
@ -268,12 +135,6 @@ public:
|
|||
|
||||
// methods for handling state
|
||||
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
||||
bool invalidate_step(PrintObjectStep step);
|
||||
template<typename StepTypeIterator>
|
||||
bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end) { return m_state.invalidate_multiple(step_begin, step_end, this->cancel_mutex(), this->cancel_callback()); }
|
||||
bool invalidate_steps(std::initializer_list<PrintObjectStep> il) { return m_state.invalidate_multiple(il.begin(), il.end(), this->cancel_mutex(), this->cancel_callback()); }
|
||||
bool invalidate_all_steps() { return m_state.invalidate_all(this->cancel_mutex(), this->cancel_callback()); }
|
||||
bool is_step_done(PrintObjectStep step) const { return m_state.is_done(step); }
|
||||
|
||||
// To be used over the layer_height_profile of both the PrintObject and ModelObject
|
||||
// to initialize the height profile with the height ranges.
|
||||
|
@ -300,6 +161,20 @@ public:
|
|||
std::vector<ExPolygons> slice_support_enforcers() const;
|
||||
std::vector<ExPolygons> slice_support_blockers() const;
|
||||
|
||||
protected:
|
||||
// to be called from Print only.
|
||||
friend class Print;
|
||||
|
||||
PrintObject(Print* print, ModelObject* model_object);
|
||||
~PrintObject() {}
|
||||
|
||||
void config_apply(const ConfigBase &other, bool ignore_nonexistent = false) { this->m_config.apply(other, ignore_nonexistent); }
|
||||
void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false) { this->m_config.apply_only(other, keys, ignore_nonexistent); }
|
||||
void set_trafo(const Transform3d& trafo) { m_trafo = trafo; }
|
||||
bool set_copies(const Points &points);
|
||||
// Invalidates the step, and its depending steps in PrintObject and Print.
|
||||
bool invalidate_step(PrintObjectStep step);
|
||||
|
||||
private:
|
||||
void make_perimeters();
|
||||
void prepare_infill();
|
||||
|
@ -320,12 +195,6 @@ private:
|
|||
void combine_infill();
|
||||
void _generate_support_material();
|
||||
|
||||
bool is_printable() const { return ! m_copies.empty(); }
|
||||
// Implemented in cpp due to cyclic dependencies between Print and PrintObject.
|
||||
tbb::mutex& cancel_mutex();
|
||||
std::function<void()> cancel_callback();
|
||||
|
||||
Print *m_print;
|
||||
ModelObject *m_model_object;
|
||||
PrintObjectConfig m_config;
|
||||
// Translation in Z + Rotation + Scaling / Mirroring.
|
||||
|
@ -340,15 +209,6 @@ private:
|
|||
LayerPtrs m_layers;
|
||||
SupportLayerPtrs m_support_layers;
|
||||
|
||||
PrintState<PrintObjectStep, posCount> m_state;
|
||||
|
||||
// TODO: call model_object->get_bounding_box() instead of accepting
|
||||
// parameter
|
||||
PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox);
|
||||
~PrintObject() {}
|
||||
|
||||
void set_started(PrintObjectStep step);
|
||||
void set_done(PrintObjectStep step);
|
||||
std::vector<ExPolygons> _slice_region(size_t region_id, const std::vector<float> &z, bool modifier);
|
||||
std::vector<ExPolygons> _slice_volumes(const std::vector<float> &z, const std::vector<const ModelVolume*> &volumes) const;
|
||||
};
|
||||
|
@ -410,33 +270,30 @@ typedef std::vector<PrintObject*> PrintObjectPtrs;
|
|||
typedef std::vector<PrintRegion*> PrintRegionPtrs;
|
||||
|
||||
// The complete print tray with possibly multiple objects.
|
||||
class Print
|
||||
class Print : public PrintBaseWithState<PrintStep, psCount>
|
||||
{
|
||||
private: // Prevents erroneous use by other classes.
|
||||
typedef PrintBaseWithState<PrintStep, psCount> Inherited;
|
||||
|
||||
public:
|
||||
Print() { restart(); }
|
||||
~Print() { clear_objects(); }
|
||||
Print() {}
|
||||
virtual ~Print() { this->clear(); }
|
||||
|
||||
PrinterTechnology technology() const noexcept { return ptFFF; }
|
||||
|
||||
// Methods, which change the state of Print / PrintObject / PrintRegion.
|
||||
// The following methods are synchronized with process() and export_gcode(),
|
||||
// so that process() and export_gcode() may be called from a background thread.
|
||||
// In case the following methods need to modify data processed by process() or export_gcode(),
|
||||
// a cancellation callback is executed to stop the background processing before the operation.
|
||||
void clear_objects();
|
||||
void delete_object(size_t idx);
|
||||
void clear() override;
|
||||
|
||||
ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) override;
|
||||
|
||||
// The following three methods are used by the Perl tests only. Get rid of them!
|
||||
void reload_object(size_t idx);
|
||||
bool reload_model_instances();
|
||||
void add_model_object(ModelObject* model_object, int idx = -1);
|
||||
bool apply_config(DynamicPrintConfig config);
|
||||
enum ApplyStatus {
|
||||
// No change after the Print::apply() call.
|
||||
APPLY_STATUS_UNCHANGED,
|
||||
// Some of the Print / PrintObject / PrintObjectInstance data was changed,
|
||||
// but no result was invalidated (only data influencing not yet calculated results were changed).
|
||||
APPLY_STATUS_CHANGED,
|
||||
// Some data was changed, which in turn invalidated already calculated steps.
|
||||
APPLY_STATUS_INVALIDATED,
|
||||
};
|
||||
ApplyStatus apply(const Model &model, const DynamicPrintConfig &config);
|
||||
|
||||
void process();
|
||||
void export_gcode(const std::string &path_template, GCodePreviewData *preview_data);
|
||||
|
@ -444,12 +301,11 @@ public:
|
|||
void export_png(const std::string &dirpath);
|
||||
|
||||
// methods for handling state
|
||||
bool is_step_done(PrintStep step) const { return m_state.is_done(step); }
|
||||
bool is_step_done(PrintStep step) const { return Inherited::is_step_done(step); }
|
||||
bool is_step_done(PrintObjectStep step) const;
|
||||
|
||||
bool has_infinite_skirt() const;
|
||||
bool has_skirt() const;
|
||||
PrintObjectPtrs get_printable_objects() const;
|
||||
float get_wipe_tower_depth() const { return m_wipe_tower_data.depth; }
|
||||
|
||||
// Returns an empty string if valid, otherwise returns an error message.
|
||||
|
@ -482,7 +338,7 @@ public:
|
|||
unsigned int num_object_instances() const;
|
||||
|
||||
// Returns extruder this eec should be printed with, according to PrintRegion config:
|
||||
static int get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion ®ion);
|
||||
static int get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion ®ion);
|
||||
|
||||
const ExtrusionEntityCollection& skirt() const { return m_skirt; }
|
||||
const ExtrusionEntityCollection& brim() const { return m_brim; }
|
||||
|
@ -496,69 +352,24 @@ public:
|
|||
std::string output_filename() const;
|
||||
std::string output_filepath(const std::string &path) const;
|
||||
|
||||
typedef std::function<void(int, const std::string&)> status_callback_type;
|
||||
// Default status console print out in the form of percent => message.
|
||||
void set_status_default() { m_status_callback = nullptr; }
|
||||
// No status output or callback whatsoever, useful mostly for automatic tests.
|
||||
void set_status_silent() { m_status_callback = [](int, const std::string&){}; }
|
||||
// Register a custom status callback.
|
||||
void set_status_callback(status_callback_type cb) { m_status_callback = cb; }
|
||||
// Calls a registered callback to update the status, or print out the default message.
|
||||
void set_status(int percent, const std::string &message) {
|
||||
if (m_status_callback) m_status_callback(percent, message);
|
||||
else printf("%d => %s\n", percent, message.c_str());
|
||||
}
|
||||
|
||||
typedef std::function<void()> cancel_callback_type;
|
||||
// Various methods will call this callback to stop the background processing (the Print::process() call)
|
||||
// in case a successive change of the Print / PrintObject / PrintRegion instances changed
|
||||
// the state of the finished or running calculations.
|
||||
void set_cancel_callback(cancel_callback_type cancel_callback) { m_cancel_callback = cancel_callback; }
|
||||
// Has the calculation been canceled?
|
||||
enum CancelStatus {
|
||||
// No cancelation, background processing should run.
|
||||
NOT_CANCELED = 0,
|
||||
// Canceled by user from the user interface (user pressed the "Cancel" button or user closed the application).
|
||||
CANCELED_BY_USER = 1,
|
||||
// Canceled internally from Print::apply() through the Print/PrintObject::invalidate_step() or ::invalidate_all_steps().
|
||||
CANCELED_INTERNAL = 2
|
||||
};
|
||||
CancelStatus cancel_status() const { return m_cancel_status; }
|
||||
// Has the calculation been canceled?
|
||||
bool canceled() const { return m_cancel_status != NOT_CANCELED; }
|
||||
// Cancel the running computation. Stop execution of all the background threads.
|
||||
void cancel() { m_cancel_status = CANCELED_BY_USER; }
|
||||
void cancel_internal() { m_cancel_status = CANCELED_INTERNAL; }
|
||||
// Cancel the running computation. Stop execution of all the background threads.
|
||||
void restart() { m_cancel_status = NOT_CANCELED; }
|
||||
|
||||
// Accessed by SupportMaterial
|
||||
const PrintRegion* get_region(size_t idx) const { return m_regions[idx]; }
|
||||
|
||||
protected:
|
||||
void set_started(PrintStep step) { m_state.set_started(step, m_mutex); throw_if_canceled(); }
|
||||
void set_done(PrintStep step) { m_state.set_done(step, m_mutex); throw_if_canceled(); }
|
||||
bool invalidate_step(PrintStep step);
|
||||
template<typename StepTypeIterator>
|
||||
bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end) { return m_state.invalidate_multiple(step_begin, step_end, m_mutex, m_cancel_callback); }
|
||||
bool invalidate_steps(std::initializer_list<PrintStep> il) { return m_state.invalidate_multiple(il.begin(), il.end(), m_mutex, m_cancel_callback); }
|
||||
bool invalidate_all_steps() { return m_state.invalidate_all(m_mutex, m_cancel_callback); }
|
||||
|
||||
// methods for handling regions
|
||||
PrintRegion* get_region(size_t idx) { return m_regions[idx]; }
|
||||
PrintRegion* add_region();
|
||||
PrintRegion* add_region(const PrintRegionConfig &config);
|
||||
|
||||
// Invalidates the step, and its depending steps in Print.
|
||||
bool invalidate_step(PrintStep step);
|
||||
|
||||
private:
|
||||
// Update "scale", "input_filename", "input_filename_base" placeholders from the current m_objects.
|
||||
void update_object_placeholders();
|
||||
|
||||
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
||||
|
||||
// If the background processing stop was requested, throw CanceledException.
|
||||
// To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly.
|
||||
void throw_if_canceled() const { if (m_cancel_status) throw CanceledException(); }
|
||||
|
||||
void _make_skirt();
|
||||
void _make_brim();
|
||||
void _make_wipe_tower();
|
||||
|
@ -567,19 +378,6 @@ private:
|
|||
// Declared here to have access to Model / ModelObject / ModelInstance
|
||||
static void model_volume_list_update_supports(ModelObject &model_object_dst, const ModelObject &model_object_src);
|
||||
|
||||
PrintState<PrintStep, psCount> m_state;
|
||||
// Mutex used for synchronization of the worker thread with the UI thread:
|
||||
// The mutex will be used to guard the worker thread against entering a stage
|
||||
// while the data influencing the stage is modified.
|
||||
mutable tbb::mutex m_mutex;
|
||||
|
||||
tbb::atomic<CancelStatus> m_cancel_status;
|
||||
// Callback to be evoked regularly to update state of the UI thread.
|
||||
status_callback_type m_status_callback;
|
||||
|
||||
// Callback to be evoked to stop the background processing before a state is updated.
|
||||
cancel_callback_type m_cancel_callback = [](){};
|
||||
|
||||
Model m_model;
|
||||
PrintConfig m_config;
|
||||
PrintObjectConfig m_default_object_config;
|
||||
|
@ -604,6 +402,6 @@ private:
|
|||
friend class PrintObject;
|
||||
};
|
||||
|
||||
}
|
||||
} /* slic3r_Print_hpp_ */
|
||||
|
||||
#endif
|
||||
|
|
16
src/libslic3r/PrintBase.cpp
Normal file
16
src/libslic3r/PrintBase.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include "PrintBase.hpp"
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
|
||||
tbb::mutex& PrintObjectBase::cancel_mutex(PrintBase *print)
|
||||
{
|
||||
return print->cancel_mutex();
|
||||
}
|
||||
|
||||
std::function<void()> PrintObjectBase::cancel_callback(PrintBase *print)
|
||||
{
|
||||
return print->cancel_callback();
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
297
src/libslic3r/PrintBase.hpp
Normal file
297
src/libslic3r/PrintBase.hpp
Normal file
|
@ -0,0 +1,297 @@
|
|||
#ifndef slic3r_PrintBase_hpp_
|
||||
#define slic3r_PrintBase_hpp_
|
||||
|
||||
#include "libslic3r.h"
|
||||
#include <atomic>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
#include "tbb/atomic.h"
|
||||
// tbb/mutex.h includes Windows, which in turn defines min/max macros. Convince Windows.h to not define these min/max macros.
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include "tbb/mutex.h"
|
||||
|
||||
#include "Model.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class CanceledException : public std::exception {
|
||||
public:
|
||||
const char* what() const throw() { return "Background processing has been canceled"; }
|
||||
};
|
||||
|
||||
// To be instantiated over PrintStep or PrintObjectStep enums.
|
||||
template <class StepType, size_t COUNT>
|
||||
class PrintState
|
||||
{
|
||||
public:
|
||||
PrintState() { for (size_t i = 0; i < COUNT; ++ i) m_state[i].store(INVALID, std::memory_order_relaxed); }
|
||||
|
||||
enum State {
|
||||
INVALID,
|
||||
STARTED,
|
||||
DONE,
|
||||
};
|
||||
|
||||
// With full memory barrier.
|
||||
bool is_done(StepType step) const { return m_state[step] == DONE; }
|
||||
|
||||
// Set the step as started. Block on mutex while the Print / PrintObject / PrintRegion objects are being
|
||||
// modified by the UI thread.
|
||||
// This is necessary to block until the Print::apply_config() updates its state, which may
|
||||
// influence the processing step being entered.
|
||||
void set_started(StepType step, tbb::mutex &mtx) {
|
||||
mtx.lock();
|
||||
m_state[step].store(STARTED, std::memory_order_relaxed);
|
||||
mtx.unlock();
|
||||
}
|
||||
|
||||
// Set the step as done. Block on mutex while the Print / PrintObject / PrintRegion objects are being
|
||||
// modified by the UI thread.
|
||||
void set_done(StepType step, tbb::mutex &mtx) {
|
||||
mtx.lock();
|
||||
m_state[step].store(DONE, std::memory_order_relaxed);
|
||||
mtx.unlock();
|
||||
}
|
||||
|
||||
// Make the step invalid.
|
||||
// The provided mutex should be locked at this point, guarding access to m_state.
|
||||
// In case the step has already been entered or finished, cancel the background
|
||||
// processing by calling the cancel callback.
|
||||
template<typename CancelationCallback>
|
||||
bool invalidate(StepType step, tbb::mutex &mtx, CancelationCallback cancel) {
|
||||
bool invalidated = m_state[step].load(std::memory_order_relaxed) != INVALID;
|
||||
if (invalidated) {
|
||||
#if 0
|
||||
if (mtx.state != mtx.HELD) {
|
||||
printf("Not held!\n");
|
||||
}
|
||||
#endif
|
||||
// Raise the mutex, so that the following cancel() callback could cancel
|
||||
// the background processing.
|
||||
mtx.unlock();
|
||||
cancel();
|
||||
m_state[step] = INVALID;
|
||||
mtx.lock();
|
||||
}
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
template<typename CancelationCallback, typename StepTypeIterator>
|
||||
bool invalidate_multiple(StepTypeIterator step_begin, StepTypeIterator step_end, tbb::mutex &mtx, CancelationCallback cancel) {
|
||||
bool invalidated = false;
|
||||
for (StepTypeIterator it = step_begin; ! invalidated && it != step_end; ++ it)
|
||||
invalidated = m_state[*it].load(std::memory_order_relaxed) != INVALID;
|
||||
if (invalidated) {
|
||||
#if 0
|
||||
if (mtx.state != mtx.HELD) {
|
||||
printf("Not held!\n");
|
||||
}
|
||||
#endif
|
||||
// Raise the mutex, so that the following cancel() callback could cancel
|
||||
// the background processing.
|
||||
mtx.unlock();
|
||||
cancel();
|
||||
for (StepTypeIterator it = step_begin; it != step_end; ++ it)
|
||||
m_state[*it] = INVALID;
|
||||
mtx.lock();
|
||||
}
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
// Make all steps invalid.
|
||||
// The provided mutex should be locked at this point, guarding access to m_state.
|
||||
// In case any step has already been entered or finished, cancel the background
|
||||
// processing by calling the cancel callback.
|
||||
template<typename CancelationCallback>
|
||||
bool invalidate_all(tbb::mutex &mtx, CancelationCallback cancel) {
|
||||
bool invalidated = false;
|
||||
for (size_t i = 0; i < COUNT; ++ i)
|
||||
if (m_state[i].load(std::memory_order_relaxed) != INVALID) {
|
||||
invalidated = true;
|
||||
break;
|
||||
}
|
||||
if (invalidated) {
|
||||
mtx.unlock();
|
||||
cancel();
|
||||
for (size_t i = 0; i < COUNT; ++ i)
|
||||
m_state[i].store(INVALID, std::memory_order_relaxed);
|
||||
mtx.lock();
|
||||
}
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<State> m_state[COUNT];
|
||||
};
|
||||
|
||||
class PrintBase;
|
||||
|
||||
class PrintObjectBase
|
||||
{
|
||||
protected:
|
||||
virtual ~PrintObjectBase() {}
|
||||
// Declared here to allow access from PrintBase through friendship.
|
||||
static tbb::mutex& cancel_mutex(PrintBase *print);
|
||||
static std::function<void()> cancel_callback(PrintBase *print);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Printing involves slicing and export of device dependent instructions.
|
||||
*
|
||||
* Every technology has a potentially different set of requirements for
|
||||
* slicing, support structures and output print instructions. The pipeline
|
||||
* however remains roughly the same:
|
||||
* slice -> convert to instructions -> send to printer
|
||||
*
|
||||
* The PrintBase class will abstract this flow for different technologies.
|
||||
*
|
||||
*/
|
||||
class PrintBase
|
||||
{
|
||||
public:
|
||||
PrintBase() { this->restart(); }
|
||||
inline virtual ~PrintBase() {}
|
||||
|
||||
virtual PrinterTechnology technology() const noexcept = 0;
|
||||
|
||||
// Reset the print status including the copy of the Model / ModelObject hierarchy.
|
||||
virtual void clear() = 0;
|
||||
|
||||
enum ApplyStatus {
|
||||
// No change after the Print::apply() call.
|
||||
APPLY_STATUS_UNCHANGED,
|
||||
// Some of the Print / PrintObject / PrintObjectInstance data was changed,
|
||||
// but no result was invalidated (only data influencing not yet calculated results were changed).
|
||||
APPLY_STATUS_CHANGED,
|
||||
// Some data was changed, which in turn invalidated already calculated steps.
|
||||
APPLY_STATUS_INVALIDATED,
|
||||
};
|
||||
virtual ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) = 0;
|
||||
|
||||
virtual void process() = 0;
|
||||
|
||||
typedef std::function<void(int, const std::string&)> status_callback_type;
|
||||
// Default status console print out in the form of percent => message.
|
||||
void set_status_default() { m_status_callback = nullptr; }
|
||||
// No status output or callback whatsoever, useful mostly for automatic tests.
|
||||
void set_status_silent() { m_status_callback = [](int, const std::string&){}; }
|
||||
// Register a custom status callback.
|
||||
void set_status_callback(status_callback_type cb) { m_status_callback = cb; }
|
||||
// Calls a registered callback to update the status, or print out the default message.
|
||||
void set_status(int percent, const std::string &message) {
|
||||
if (m_status_callback) m_status_callback(percent, message);
|
||||
else printf("%d => %s\n", percent, message.c_str());
|
||||
}
|
||||
|
||||
typedef std::function<void()> cancel_callback_type;
|
||||
// Various methods will call this callback to stop the background processing (the Print::process() call)
|
||||
// in case a successive change of the Print / PrintObject / PrintRegion instances changed
|
||||
// the state of the finished or running calculations.
|
||||
void set_cancel_callback(cancel_callback_type cancel_callback) { m_cancel_callback = cancel_callback; }
|
||||
// Has the calculation been canceled?
|
||||
enum CancelStatus {
|
||||
// No cancelation, background processing should run.
|
||||
NOT_CANCELED = 0,
|
||||
// Canceled by user from the user interface (user pressed the "Cancel" button or user closed the application).
|
||||
CANCELED_BY_USER = 1,
|
||||
// Canceled internally from Print::apply() through the Print/PrintObject::invalidate_step() or ::invalidate_all_steps().
|
||||
CANCELED_INTERNAL = 2
|
||||
};
|
||||
CancelStatus cancel_status() const { return m_cancel_status; }
|
||||
// Has the calculation been canceled?
|
||||
bool canceled() const { return m_cancel_status != NOT_CANCELED; }
|
||||
// Cancel the running computation. Stop execution of all the background threads.
|
||||
void cancel() { m_cancel_status = CANCELED_BY_USER; }
|
||||
void cancel_internal() { m_cancel_status = CANCELED_INTERNAL; }
|
||||
// Cancel the running computation. Stop execution of all the background threads.
|
||||
void restart() { m_cancel_status = NOT_CANCELED; }
|
||||
|
||||
protected:
|
||||
friend class PrintObjectBase;
|
||||
|
||||
tbb::mutex& cancel_mutex() { return m_cancel_mutex; }
|
||||
std::function<void()> cancel_callback() { return m_cancel_callback; }
|
||||
void call_cancell_callback() { m_cancel_callback(); }
|
||||
|
||||
// If the background processing stop was requested, throw CanceledException.
|
||||
// To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly.
|
||||
void throw_if_canceled() const { if (m_cancel_status) throw CanceledException(); }
|
||||
|
||||
private:
|
||||
tbb::atomic<CancelStatus> m_cancel_status;
|
||||
// Callback to be evoked regularly to update state of the UI thread.
|
||||
status_callback_type m_status_callback;
|
||||
|
||||
// Callback to be evoked to stop the background processing before a state is updated.
|
||||
cancel_callback_type m_cancel_callback = [](){};
|
||||
|
||||
// Mutex used for synchronization of the worker thread with the UI thread:
|
||||
// The mutex will be used to guard the worker thread against entering a stage
|
||||
// while the data influencing the stage is modified.
|
||||
mutable tbb::mutex m_cancel_mutex;
|
||||
};
|
||||
|
||||
template<typename PrintStepEnum, const size_t COUNT>
|
||||
class PrintBaseWithState : public PrintBase
|
||||
{
|
||||
public:
|
||||
bool is_step_done(PrintStepEnum step) const { return m_state.is_done(step); }
|
||||
|
||||
protected:
|
||||
void set_started(PrintStepEnum step) { m_state.set_started(step, this->cancel_mutex()); throw_if_canceled(); }
|
||||
void set_done(PrintStepEnum step) { m_state.set_done(step, this->cancel_mutex()); throw_if_canceled(); }
|
||||
bool invalidate_step(PrintStepEnum step)
|
||||
{ return m_state.invalidate(step, this->cancel_mutex(), this->cancel_callback()); }
|
||||
template<typename StepTypeIterator>
|
||||
bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end)
|
||||
{ return m_state.invalidate_multiple(step_begin, step_end, this->cancel_mutex(), this->cancel_callback()); }
|
||||
bool invalidate_steps(std::initializer_list<PrintStepEnum> il)
|
||||
{ return m_state.invalidate_multiple(il.begin(), il.end(), this->cancel_mutex(), this->cancel_callback()); }
|
||||
bool invalidate_all_steps()
|
||||
{ return m_state.invalidate_all(this->cancel_mutex(), this->cancel_callback()); }
|
||||
|
||||
private:
|
||||
PrintState<PrintStepEnum, COUNT> m_state;
|
||||
};
|
||||
|
||||
template<typename PrintType, typename PrintObjectStepEnum, const size_t COUNT>
|
||||
class PrintObjectBaseWithState : public PrintObjectBase
|
||||
{
|
||||
public:
|
||||
Print* print() { return m_print; }
|
||||
const Print* print() const { return m_print; }
|
||||
|
||||
bool is_step_done(PrintObjectStepEnum step) const { return m_state.is_done(step); }
|
||||
|
||||
protected:
|
||||
PrintObjectBaseWithState(PrintType *print) : m_print(print) {}
|
||||
|
||||
void set_started(PrintObjectStepEnum step) { m_state.set_started(step, PrintObjectBase::cancel_mutex(m_print)); }
|
||||
void set_done(PrintObjectStepEnum step) { m_state.set_done(step, PrintObjectBase::cancel_mutex(m_print)); }
|
||||
|
||||
bool invalidate_step(PrintObjectStepEnum step)
|
||||
{ return m_state.invalidate(step, PrintObjectBase::cancel_mutex(m_print), PrintObjectBase::cancel_callback(m_print)); }
|
||||
template<typename StepTypeIterator>
|
||||
bool invalidate_steps(StepTypeIterator step_begin, StepTypeIterator step_end)
|
||||
{ return m_state.invalidate_multiple(step_begin, step_end, PrintObjectBase::cancel_mutex(m_print), PrintObjectBase::cancel_callback(m_print)); }
|
||||
bool invalidate_steps(std::initializer_list<PrintObjectStepEnum> il)
|
||||
{ return m_state.invalidate_multiple(il.begin(), il.end(), PrintObjectBase::cancel_mutex(m_print), PrintObjectBase::cancel_callback(m_print)); }
|
||||
bool invalidate_all_steps() { return m_state.invalidate_all(PrintObjectBase::cancel_mutex(m_print), PrintObjectBase::cancel_callback(m_print)); }
|
||||
|
||||
protected:
|
||||
friend PrintType;
|
||||
PrintType *m_print;
|
||||
|
||||
private:
|
||||
PrintState<PrintObjectStepEnum, COUNT> m_state;
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_PrintBase_hpp_ */
|
|
@ -34,9 +34,9 @@
|
|||
|
||||
namespace Slic3r {
|
||||
|
||||
PrintObject::PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox) :
|
||||
PrintObject::PrintObject(Print* print, ModelObject* model_object) :
|
||||
PrintObjectBaseWithState(print),
|
||||
typed_slices(false),
|
||||
m_print(print),
|
||||
m_model_object(model_object),
|
||||
size(Vec3crd::Zero()),
|
||||
layer_height_profile_valid(false)
|
||||
|
@ -49,42 +49,27 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Bounding
|
|||
// don't assume it's already aligned and we don't alter the original position in model.
|
||||
// We store the XY translation so that we can place copies correctly in the output G-code
|
||||
// (copies are expressed in G-code coordinates and this translation is not publicly exposed).
|
||||
const BoundingBoxf3 modobj_bbox = model_object->raw_bounding_box();
|
||||
m_copies_shift = Point::new_scale(modobj_bbox.min(0), modobj_bbox.min(1));
|
||||
// Scale the object size and store it
|
||||
this->size = (modobj_bbox.size() * (1. / SCALING_FACTOR)).cast<coord_t>();
|
||||
}
|
||||
|
||||
this->reload_model_instances();
|
||||
{
|
||||
Points copies;
|
||||
copies.reserve(m_model_object->instances.size());
|
||||
for (const ModelInstance *mi : m_model_object->instances) {
|
||||
assert(mi->is_printable());
|
||||
const Vec3d& offset = mi->get_offset();
|
||||
copies.emplace_back(Point::new_scale(offset(0), offset(1)));
|
||||
}
|
||||
this->set_copies(copies);
|
||||
}
|
||||
|
||||
this->layer_height_ranges = model_object->layer_height_ranges;
|
||||
this->layer_height_profile = model_object->layer_height_profile;
|
||||
}
|
||||
|
||||
void PrintObject::set_started(PrintObjectStep step)
|
||||
{
|
||||
m_state.set_started(step, m_print->m_mutex);
|
||||
}
|
||||
|
||||
void PrintObject::set_done(PrintObjectStep step)
|
||||
{
|
||||
m_state.set_done(step, m_print->m_mutex);
|
||||
}
|
||||
|
||||
bool PrintObject::add_copy(const Vec2d &point)
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(m_print->m_mutex);
|
||||
Points points = m_copies;
|
||||
points.push_back(Point::new_scale(point(0), point(1)));
|
||||
return this->set_copies(points);
|
||||
}
|
||||
|
||||
bool PrintObject::delete_last_copy()
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(m_print->m_mutex);
|
||||
Points points = m_copies;
|
||||
points.pop_back();
|
||||
return this->set_copies(points);
|
||||
}
|
||||
|
||||
bool PrintObject::set_copies(const Points &points)
|
||||
{
|
||||
// Order copies with a nearest-neighbor search.
|
||||
|
@ -107,21 +92,6 @@ bool PrintObject::set_copies(const Points &points)
|
|||
return invalidated;
|
||||
}
|
||||
|
||||
bool PrintObject::reload_model_instances()
|
||||
{
|
||||
Points copies;
|
||||
copies.reserve(m_model_object->instances.size());
|
||||
for (const ModelInstance *mi : m_model_object->instances)
|
||||
{
|
||||
if (mi->is_printable())
|
||||
{
|
||||
const Vec3d& offset = mi->get_offset();
|
||||
copies.emplace_back(Point::new_scale(offset(0), offset(1)));
|
||||
}
|
||||
}
|
||||
return this->set_copies(copies);
|
||||
}
|
||||
|
||||
// 1) Decides Z positions of the layers,
|
||||
// 2) Initializes layers and their regions
|
||||
// 3) Slices the object meshes
|
||||
|
@ -388,9 +358,6 @@ void PrintObject::prepare_infill()
|
|||
|
||||
void PrintObject::infill()
|
||||
{
|
||||
if (! this->is_printable())
|
||||
return;
|
||||
|
||||
// prerequisites
|
||||
this->prepare_infill();
|
||||
|
||||
|
@ -583,7 +550,7 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|
|||
|
||||
bool PrintObject::invalidate_step(PrintObjectStep step)
|
||||
{
|
||||
bool invalidated = m_state.invalidate(step, m_print->m_mutex, m_print->m_cancel_callback);
|
||||
bool invalidated = Inherited::invalidate_step(step);
|
||||
|
||||
// propagate to dependent steps
|
||||
if (step == posPerimeters) {
|
||||
|
@ -1732,9 +1699,6 @@ void PrintObject::_simplify_slices(double distance)
|
|||
|
||||
void PrintObject::_make_perimeters()
|
||||
{
|
||||
if (!this->is_printable())
|
||||
return;
|
||||
|
||||
if (this->is_step_done(posPerimeters))
|
||||
return;
|
||||
this->set_started(posPerimeters);
|
||||
|
@ -2226,9 +2190,6 @@ 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);
|
||||
}
|
||||
|
@ -2251,15 +2212,4 @@ void PrintObject::adjust_layer_height_profile(coordf_t z, coordf_t layer_thickne
|
|||
layer_height_profile_valid = false;
|
||||
}
|
||||
|
||||
tbb::mutex& PrintObject::cancel_mutex()
|
||||
{
|
||||
return m_print->m_mutex;
|
||||
}
|
||||
|
||||
std::function<void()> PrintObject::cancel_callback()
|
||||
{
|
||||
return m_print->m_cancel_callback;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -216,12 +216,10 @@ int main(int argc, char **argv)
|
|||
}
|
||||
if (outfile.empty())
|
||||
outfile = model.objects.front()->input_file + ".gcode";
|
||||
for (auto* mo : model.objects) {
|
||||
for (auto* mo : model.objects)
|
||||
print.auto_assign_extruders(mo);
|
||||
print.add_model_object(mo);
|
||||
}
|
||||
print_config.normalize();
|
||||
print.apply_config(print_config);
|
||||
print.apply(model, print_config);
|
||||
std::string err = print.validate();
|
||||
if (err.empty())
|
||||
print.export_gcode(outfile, nullptr);
|
||||
|
|
|
@ -178,6 +178,14 @@ bool BackgroundSlicingProcess::stop()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BackgroundSlicingProcess::reset()
|
||||
{
|
||||
bool stopped = this->stop();
|
||||
this->reset_export();
|
||||
m_print->clear();
|
||||
return stopped;
|
||||
}
|
||||
|
||||
// To be called by Print::apply() through the Print::m_cancel_callback to stop the background
|
||||
// processing before changing any data of running or finalized milestones.
|
||||
// This function shall not trigger any UI update through the wxWidgets event.
|
||||
|
|
|
@ -43,6 +43,9 @@ public:
|
|||
// Cancel the background processing. Returns false if the background processing was not running.
|
||||
// A stopped background processing may be restarted with start().
|
||||
bool stop();
|
||||
// Cancel the background processing and reset the print. Returns false if the background processing was not running.
|
||||
// Useful when the Model or configuration is being changed drastically.
|
||||
bool reset();
|
||||
|
||||
// Apply config over the print. Returns false, if the new config values caused any of the already
|
||||
// processed steps to be invalidated, therefore the task will need to be restarted.
|
||||
|
|
|
@ -489,7 +489,10 @@ public:
|
|||
bool is_wipe_tower() const { return m_type == WipeTower; }
|
||||
bool is_modifier() const { return (m_type == SingleModifier) || (m_type == MultipleModifier); }
|
||||
bool is_single_full_instance() const;
|
||||
bool is_multiple_full_instance() const { return m_type == MultipleFullInstance; }
|
||||
bool is_single_full_object() const { return m_type == SingleFullObject; }
|
||||
bool is_single_volume() const { return m_type == SingleVolume; }
|
||||
bool is_multiple_volume() const { return m_type == MultipleVolume; }
|
||||
bool is_mixed() const { return m_type == Mixed; }
|
||||
bool is_from_single_instance() const { return get_instance_idx() != -1; }
|
||||
bool is_from_single_object() const { return get_object_idx() != -1; }
|
||||
|
|
|
@ -1598,8 +1598,9 @@ void GLGizmoSlaSupports::update_mesh()
|
|||
{
|
||||
Eigen::MatrixXf& V = m_V;
|
||||
Eigen::MatrixXi& F = m_F;
|
||||
const stl_file& stl = m_model_object->mesh().stl;
|
||||
V.resize(3*stl.stats.number_of_facets, 3);
|
||||
TriangleMesh mesh(m_model_object->mesh());
|
||||
const stl_file& stl = mesh.stl;
|
||||
V.resize(3 * stl.stats.number_of_facets, 3);
|
||||
F.resize(stl.stats.number_of_facets, 3);
|
||||
for (unsigned int i=0; i<stl.stats.number_of_facets; ++i) {
|
||||
const stl_facet* facet = stl.facet_start+i;
|
||||
|
|
|
@ -286,8 +286,10 @@ void ObjectList::context_menu()
|
|||
else if (title == _("Name") && pt.x >15 &&
|
||||
m_objects_model->GetBitmap(item).GetRefData() == m_bmp_manifold_warning.GetRefData())
|
||||
{
|
||||
if (is_windows10())
|
||||
/*fix_through_netfabb()*/;// #ys_FIXME
|
||||
if (is_windows10()) {
|
||||
const auto obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
|
||||
wxGetApp().plater()->fix_through_netfabb(obj_idx);
|
||||
}
|
||||
}
|
||||
#ifndef __WXMSW__
|
||||
GetMainWindow()->SetToolTip(""); // hide tooltip
|
||||
|
@ -1093,7 +1095,7 @@ void ObjectList::add_object_to_list(size_t obj_idx)
|
|||
|
||||
// add settings to the object, if it has those
|
||||
auto opt_keys = model_object->config.keys();
|
||||
if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) {
|
||||
if (!opt_keys.empty() && !(opt_keys.size() == 1 && opt_keys[0] == "extruder")) {
|
||||
select_item(m_objects_model->AddSettingsChild(item));
|
||||
Collapse(item);
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
#include "BackgroundSlicingProcess.hpp"
|
||||
#include "ProgressStatusBar.hpp"
|
||||
#include "slic3r/Utils/ASCIIFolding.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
#include "../Utils/FixModelByWin10.hpp"
|
||||
|
||||
#include <wx/glcanvas.h> // Needs to be last because reasons :-/
|
||||
#include "WipeTowerDialog.hpp"
|
||||
|
@ -898,7 +898,7 @@ struct Plater::priv
|
|||
void start_background_process();
|
||||
void reload_from_disk();
|
||||
void export_object_stl();
|
||||
void fix_through_netfabb();
|
||||
void fix_through_netfabb(const int obj_idx);
|
||||
|
||||
void on_notebook_changed(wxBookCtrlEvent&);
|
||||
void on_select_preset(wxCommandEvent&);
|
||||
|
@ -1434,8 +1434,9 @@ void Plater::priv::reset()
|
|||
if (_3DScene::is_layers_editing_enabled(canvas3D))
|
||||
_3DScene::enable_layers_editing(canvas3D, false);
|
||||
|
||||
// Stop and reset the Print content.
|
||||
this->background_process.reset();
|
||||
model.clear_objects();
|
||||
// print.clear_objects();
|
||||
|
||||
// Delete all objects from list on c++ side
|
||||
sidebar->obj_list()->delete_all_objects_from_list();
|
||||
|
@ -1579,35 +1580,35 @@ void Plater::priv::export_object_stl()
|
|||
// TODO
|
||||
}
|
||||
|
||||
void Plater::priv::fix_through_netfabb()
|
||||
void Plater::priv::fix_through_netfabb(const int obj_idx)
|
||||
{
|
||||
/*
|
||||
my ($self) = @_;
|
||||
my ($obj_idx, $object) = $self->selected_object;
|
||||
return if !defined $obj_idx;
|
||||
my $model_object = $self->{model}->objects->[$obj_idx];
|
||||
my $model_fixed = Slic3r::Model->new;
|
||||
Slic3r::GUI::fix_model_by_win10_sdk_gui($model_object, $self->{print}, $model_fixed);
|
||||
if (obj_idx < 0)
|
||||
return;
|
||||
|
||||
my @new_obj_idx = $self->load_model_objects(@{$model_fixed->objects});
|
||||
return if !@new_obj_idx;
|
||||
const auto model_object = model.objects[obj_idx];
|
||||
Model model_fixed;// = new Model();
|
||||
fix_model_by_win10_sdk_gui(*model_object, print, model_fixed);
|
||||
|
||||
auto new_obj_idxs = load_model_objects(model_fixed.objects);
|
||||
if (new_obj_idxs.empty())
|
||||
return;
|
||||
|
||||
foreach my $new_obj_idx (@new_obj_idx) {
|
||||
my $o = $self->{model}->objects->[$new_obj_idx];
|
||||
$o->clear_instances;
|
||||
$o->add_instance($_) for @{$model_object->instances};
|
||||
#$o->invalidate_bounding_box;
|
||||
for(auto new_obj_idx : new_obj_idxs) {
|
||||
auto o = model.objects[new_obj_idx];
|
||||
o->clear_instances();
|
||||
for (auto instance: model_object->instances)
|
||||
o->add_instance(*instance);
|
||||
// o->invalidate_bounding_box();
|
||||
|
||||
if ($o->volumes_count == $model_object->volumes_count) {
|
||||
for my $i (0..($o->volumes_count-1)) {
|
||||
$o->get_volume($i)->config->apply($model_object->get_volume($i)->config);
|
||||
if (o->volumes.size() == model_object->volumes.size()) {
|
||||
for (int i = 0; i < o->volumes.size(); i++) {
|
||||
o->volumes[i]->config.apply(model_object->volumes[i]->config);
|
||||
}
|
||||
}
|
||||
#FIXME restore volumes and their configs, layer_height_ranges, layer_height_profile, layer_height_profile_valid,
|
||||
// FIXME restore volumes and their configs, layer_height_ranges, layer_height_profile, layer_height_profile_valid,
|
||||
}
|
||||
|
||||
$self->remove($obj_idx);
|
||||
*/
|
||||
remove(obj_idx);
|
||||
}
|
||||
|
||||
void Plater::priv::on_notebook_changed(wxBookCtrlEvent&)
|
||||
|
@ -1970,6 +1971,8 @@ void Plater::increase_instances(size_t num)
|
|||
ModelObject* model_object = p->model.objects[obj_idx];
|
||||
ModelInstance* model_instance = model_object->instances.back();
|
||||
|
||||
bool was_one_instance = model_object->instances.size()==1;
|
||||
|
||||
float offset = 10.0;
|
||||
for (size_t i = 0; i < num; i++, offset += 10.0) {
|
||||
Vec3d offset_vec = model_instance->get_offset() + Vec3d(offset, offset, 0.0);
|
||||
|
@ -1977,7 +1980,7 @@ void Plater::increase_instances(size_t num)
|
|||
// p->print.get_object(obj_idx)->add_copy(Slic3r::to_2d(offset_vec));
|
||||
}
|
||||
|
||||
sidebar().obj_list()->increase_object_instances(obj_idx, num);
|
||||
sidebar().obj_list()->increase_object_instances(obj_idx, was_one_instance ? num + 1 : num);
|
||||
|
||||
if (p->get_config("autocenter") == "1") {
|
||||
p->arrange();
|
||||
|
@ -2000,10 +2003,8 @@ void Plater::decrease_instances(size_t num)
|
|||
|
||||
ModelObject* model_object = p->model.objects[obj_idx];
|
||||
if (model_object->instances.size() > num) {
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
for (size_t i = 0; i < num; ++ i)
|
||||
model_object->delete_last_instance();
|
||||
// p->print.get_object(obj_idx)->delete_last_copy();
|
||||
}
|
||||
sidebar().obj_list()->decrease_object_instances(obj_idx, num);
|
||||
}
|
||||
else {
|
||||
|
@ -2287,5 +2288,6 @@ void Plater::changed_object(int obj_idx)
|
|||
|
||||
}
|
||||
|
||||
void Plater::fix_through_netfabb(const int obj_idx) { p->fix_through_netfabb(obj_idx); }
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
|
|
@ -124,6 +124,7 @@ public:
|
|||
void export_3mf();
|
||||
void reslice();
|
||||
void changed_object(int obj_idx);
|
||||
void fix_through_netfabb(const int obj_idx);
|
||||
void send_gcode();
|
||||
|
||||
void on_extruders_change(int extruders_count);
|
||||
|
|
|
@ -532,7 +532,7 @@ wxDataViewItem PrusaObjectDataViewModel::AddInstanceChild(const wxDataViewItem &
|
|||
parent_node->Append(inst_root_node);
|
||||
// notify control
|
||||
ItemAdded(parent_item, inst_root_item);
|
||||
if (num == 1) num++;
|
||||
// if (num == 1) num++;
|
||||
}
|
||||
|
||||
// Add instance nodes
|
||||
|
|
|
@ -347,8 +347,9 @@ void fix_model_by_win10_sdk_gui(const ModelObject &model_object, const Print &pr
|
|||
boost::filesystem::path path_src = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
path_src += ".3mf";
|
||||
Model model;
|
||||
DynamicPrintConfig config;
|
||||
model.add_object(model_object);
|
||||
if (! Slic3r::store_3mf(path_src.string().c_str(), &model, const_cast<Print*>(&print), false)) {
|
||||
if (! Slic3r::store_3mf(path_src.string().c_str(), &model, &config/*const_cast<Print*>(&print), false*/)) {
|
||||
boost::filesystem::remove(path_src);
|
||||
throw std::runtime_error(L("Export of a temporary 3mf file failed"));
|
||||
}
|
||||
|
@ -359,10 +360,11 @@ void fix_model_by_win10_sdk_gui(const ModelObject &model_object, const Print &pr
|
|||
fix_model_by_win10_sdk(path_src.string().c_str(), path_dst.string(), on_progress,
|
||||
[&canceled]() { if (canceled) throw RepairCanceledException(); });
|
||||
boost::filesystem::remove(path_src);
|
||||
PresetBundle bundle;
|
||||
// PresetBundle bundle;
|
||||
on_progress(L("Loading the repaired model"), 80);
|
||||
bool loaded = Slic3r::load_3mf(path_dst.string().c_str(), &bundle, &result);
|
||||
boost::filesystem::remove(path_dst);
|
||||
bool loaded = Slic3r::load_3mf(path_dst.string().c_str(), &config/*bundle*/, &result);
|
||||
result.objects[0]->name = boost::filesystem::path(model_object.name).filename().stem().string() + "_fixed";
|
||||
boost::filesystem::remove(path_dst);
|
||||
if (! loaded)
|
||||
throw std::runtime_error(L("Import of the repaired 3mf file failed"));
|
||||
success = true;
|
||||
|
|
|
@ -92,10 +92,6 @@
|
|||
|
||||
bool store_stl(char *path, bool binary)
|
||||
%code%{ TriangleMesh mesh = THIS->mesh(); RETVAL = Slic3r::store_stl(path, &mesh, binary); %};
|
||||
bool store_amf(char *path, Print* print, bool export_print_config)
|
||||
%code%{ RETVAL = Slic3r::store_amf(path, THIS, print, export_print_config); %};
|
||||
bool store_3mf(char *path, Print* print, bool export_print_config)
|
||||
%code%{ RETVAL = Slic3r::store_3mf(path, THIS, print, export_print_config); %};
|
||||
|
||||
%{
|
||||
|
||||
|
|
|
@ -58,10 +58,6 @@ _constant()
|
|||
Points _shifted_copies()
|
||||
%code%{ RETVAL = THIS->copies(); %};
|
||||
|
||||
bool add_copy(Vec2d* point)
|
||||
%code%{ RETVAL = THIS->add_copy(*point); %};
|
||||
bool delete_last_copy();
|
||||
bool reload_model_instances();
|
||||
void set_layer_height_ranges(t_layer_height_ranges layer_height_ranges)
|
||||
%code%{ THIS->layer_height_ranges = layer_height_ranges; %};
|
||||
|
||||
|
@ -109,12 +105,9 @@ _constant()
|
|||
%code%{ RETVAL = THIS->wipe_tower_data().number_of_toolchanges; %};
|
||||
PrintObjectPtrs* objects()
|
||||
%code%{ RETVAL = const_cast<PrintObjectPtrs*>(&THIS->objects()); %};
|
||||
void clear_objects();
|
||||
Ref<PrintObject> get_object(int idx)
|
||||
%code%{ RETVAL = THIS->objects()[idx]; %};
|
||||
void delete_object(int idx);
|
||||
void reload_object(int idx);
|
||||
bool reload_model_instances();
|
||||
size_t object_count()
|
||||
%code%{ RETVAL = THIS->objects().size(); %};
|
||||
|
||||
|
|
Loading…
Reference in a new issue