Merge remote-tracking branch 'origin/dev_native' into tm_sla_supports_backend

This commit is contained in:
tamasmeszaros 2018-11-08 16:19:22 +01:00
commit 4662fd0e73
25 changed files with 503 additions and 441 deletions

View file

@ -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?

View file

@ -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 ()

View file

@ -127,6 +127,8 @@ add_library(libslic3r STATIC
PolylineCollection.hpp
Print.cpp
Print.hpp
PrintBase.cpp
PrintBase.hpp
PrintExport.hpp
PrintConfig.cpp
PrintConfig.hpp

View file

@ -13,6 +13,7 @@
#include "libslic3r.h"
#include "Point.hpp"
#include <boost/format.hpp>
#include <boost/property_tree/ptree.hpp>
namespace Slic3r {

View file

@ -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);
}

View file

@ -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 &copy : 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));

View file

@ -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(), [&lt](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)<EPSILON; });
if (this_layer_it == object->layers().end())

View file

@ -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);

View file

@ -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);

View file

@ -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 &region);
static int get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion &region);
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

View 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
View 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_ */

View file

@ -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

View file

@ -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);

View file

@ -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.

View file

@ -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.

View file

@ -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; }

View file

@ -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;

View file

@ -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);
}

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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;

View file

@ -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); %};
%{

View file

@ -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(); %};