diff --git a/src/BambuStudio.cpp b/src/BambuStudio.cpp index 9e4bbd4c91..04acfb4046 100644 --- a/src/BambuStudio.cpp +++ b/src/BambuStudio.cpp @@ -91,29 +91,6 @@ using namespace Slic3r; std::string message; }error_message;*/ -#define CLI_SUCCESS 0 -#define CLI_ENVIRONMENT_ERROR -1 -#define CLI_INVALID_PARAMS -2 -#define CLI_FILE_NOTFOUND -3 -#define CLI_FILELIST_INVALID_ORDER -4 -#define CLI_CONFIG_FILE_ERROR -5 -#define CLI_DATA_FILE_ERROR -6 -#define CLI_INVALID_PRINTER_TECH -7 -#define CLI_UNSUPPORTED_OPERATION -8 - -#define CLI_COPY_OBJECTS_ERROR -9 -#define CLI_SCALE_TO_FIT_ERROR -10 -#define CLI_EXPORT_STL_ERROR -11 -#define CLI_EXPORT_OBJ_ERROR -12 -#define CLI_EXPORT_3MF_ERROR -13 - -#define CLI_NO_SUITABLE_OBJECTS -50 -#define CLI_VALIDATE_ERROR -51 -#define CLI_OBJECTS_PARTLY_INSIDE -52 - -#define CLI_SLICING_ERROR -100 - - std::map cli_errors = { {CLI_SUCCESS, "Success"}, @@ -130,9 +107,15 @@ std::map cli_errors = { {CLI_EXPORT_STL_ERROR, "Export stl error"}, {CLI_EXPORT_OBJ_ERROR, "Export obj error"}, {CLI_EXPORT_3MF_ERROR, "Export 3mf error"}, + {CLI_OUT_OF_MEMORY, "Out of memory"}, {CLI_NO_SUITABLE_OBJECTS, "Found no objects in print volume to slice"}, {CLI_VALIDATE_ERROR, "Validate print error"}, {CLI_OBJECTS_PARTLY_INSIDE, "Objects partly inside"}, + {CLI_EXPORT_CACHE_DIRECTORY_CREATE_FAILED, "Objects partly inside"}, + {CLI_EXPORT_CACHE_WRITE_FAILED, "export cached slicedata failed"}, + {CLI_IMPORT_CACHE_NOT_FOUND, "cached slicedata can not be found"}, + {CLI_IMPORT_CACHE_DATA_CAN_NOT_USE, "cached slicedata can not be used"}, + {CLI_IMPORT_CACHE_LOAD_FAILED, "load cached slicedata failed"}, {CLI_SLICING_ERROR, "Slice error"} }; @@ -374,12 +357,12 @@ int CLI::run(int argc, char **argv) int debug_argc = 7; char *debug_argv[] = { "E:\work\projects\bambu_release\bamboo_slicer\build_debug\src\Debug\bambu-studio.exe", + "--load-slicedata", + "cached_data", "--slice", - "2", + "0", "--export-3mf=output.3mf", - "--load-filaments", - "GFSA05.json;GFSA04.json;;GFSA05.json;GFSL23.json", - "majiang.3mf" + "test.3mf" }; if (! this->setup(debug_argc, debug_argv))*/ if (!this->setup(argc, argv)) @@ -1345,8 +1328,8 @@ int CLI::run(int argc, char **argv) o->ensure_on_bed(); // loop through action options - bool export_to_3mf = false; - std::string export_3mf_file; + bool export_to_3mf = false, load_slicedata = false, export_slicedata = false, export_slicedata_error = false; + std::string export_3mf_file, load_slice_data_dir, export_slice_data_dir; std::string outfile_dir = m_config.opt_string("outputdir"); std::vector calibration_thumbnails; for (auto const &opt_key : m_actions) { @@ -1361,6 +1344,13 @@ int CLI::run(int argc, char **argv) std::string pipe_name = m_config.option("pipe")->value; g_cli_callback_mgr.start(pipe_name); #endif + } else if (opt_key == "load_slicedata") { + load_slicedata = true; + load_slice_data_dir = m_config.opt_string(opt_key); + if (export_slicedata) { + BOOST_LOG_TRIVIAL(error) << "should not set load_slicedata and export_slicedata together." << std::endl; + flush_and_exit(CLI_INVALID_PARAMS); + } } else if (opt_key == "export_settings") { //FIXME check for mixing the FFF / SLA parameters. // or better save fff_print_config vs. sla_print_config @@ -1377,7 +1367,7 @@ int CLI::run(int argc, char **argv) model.add_default_instances(); if (! this->export_models(IO::STL)) flush_and_exit(CLI_EXPORT_STL_ERROR); - } else if (opt_key == "expor1t_obj") { + } else if (opt_key == "export_obj") { for (auto &model : m_models) model.add_default_instances(); if (! this->export_models(IO::OBJ)) @@ -1389,6 +1379,13 @@ int CLI::run(int argc, char **argv) export_to_3mf = true; export_3mf_file = m_config.opt_string(opt_key); //} else if (opt_key == "export_gcode" || opt_key == "export_sla" || opt_key == "slice") { + } else if (opt_key == "export_slicedata") { + export_slicedata = true; + export_slice_data_dir = m_config.opt_string(opt_key); + if (load_slicedata) { + BOOST_LOG_TRIVIAL(error) << "should not set load_slicedata and export_slicedata together." << std::endl; + flush_and_exit(CLI_INVALID_PARAMS); + } } else if (opt_key == "slice") { //BBS: slice 0 means all plates, i means plate i; plate_to_slice = m_config.option("slice")->value; @@ -1530,7 +1527,23 @@ int CLI::run(int argc, char **argv) } } #endif - print->process(); + if (load_slicedata) { + std::string plate_dir = load_slice_data_dir+"/"+std::to_string(index+1); + int ret = print->load_cached_data(plate_dir); + if (ret) { + BOOST_LOG_TRIVIAL(warning) << "plate "<< index+1<< ": load Slicing data error, ret=" << ret; + BOOST_LOG_TRIVIAL(warning) << "plate "<< index+1<< ": switch normal slicing"; + print->process(); + } + else { + BOOST_LOG_TRIVIAL(info) << "plate "<< index+1<< ": load cached data success, go on."; + print->process(true); + BOOST_LOG_TRIVIAL(info) << "plate "<< index+1<< ": finished print::process."; + } + } + else { + print->process(); + } if (printer_technology == ptFFF) { // The outfile is processed by a PlaceholderParser. //outfile = part_plate->get_tmp_gcode_path(); @@ -1569,6 +1582,18 @@ int CLI::run(int argc, char **argv) cli_status_callback(slicing_status); } #endif + if (export_slicedata) { + BOOST_LOG_TRIVIAL(info) << "plate "<< index+1<< ":will export Slicing data to " << export_slice_data_dir; + std::string plate_dir = export_slice_data_dir+"/"+std::to_string(index+1); + bool with_space = (get_logging_level() >= 4)?true:false; + int ret = print->export_cached_data(plate_dir, with_space); + if (ret) { + BOOST_LOG_TRIVIAL(error) << "plate "<< index+1<< ": export Slicing data error, ret=" << ret; + export_slicedata_error = true; + if (fs::exists(plate_dir)) + fs::remove_all(plate_dir); + } + } } catch (const std::exception &ex) { BOOST_LOG_TRIVIAL(info) << "found slicing or export error for partplate "<("debug"); - if (opt_loglevel != 0) + if (opt_loglevel != 0) { set_logging_level(opt_loglevel->value); + } } #endif diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp index 6863a0df3b..dc34ef5004 100644 --- a/src/libslic3r/ExtrusionEntity.hpp +++ b/src/libslic3r/ExtrusionEntity.hpp @@ -137,6 +137,7 @@ public: // Height of the extrusion, used for visualization purposes. float height; + ExtrusionPath() : mm3_per_mm(-1), width(-1), height(-1), m_role(erNone), m_no_extrusion(false) {} ExtrusionPath(ExtrusionRole role) : mm3_per_mm(-1), width(-1), height(-1), m_role(role), m_no_extrusion(false) {} ExtrusionPath(ExtrusionRole role, double mm3_per_mm, float width, float height, bool no_extrusion = false) : mm3_per_mm(mm3_per_mm), width(width), height(height), m_role(role), m_no_extrusion(no_extrusion) {} ExtrusionPath(int overhang_degree, int curve_degree, ExtrusionRole role, double mm3_per_mm, float width, float height) : overhang_degree(overhang_degree), curve_degree(curve_degree), mm3_per_mm(mm3_per_mm), width(width), height(height), m_role(role) {} @@ -225,6 +226,8 @@ public: void simplify_by_fitting_arc(double tolerance); //BBS: bool is_force_no_extrusion() const { return m_no_extrusion; } + void set_force_no_extrusion(bool no_extrusion) { m_no_extrusion = no_extrusion; } + void set_extrusion_role(ExtrusionRole extrusion_role) { m_role = extrusion_role; } private: void _inflate_collection(const Polylines &polylines, ExtrusionEntityCollection* collection) const; @@ -241,7 +244,7 @@ class ExtrusionMultiPath : public ExtrusionEntity { public: ExtrusionPaths paths; - + ExtrusionMultiPath() {} ExtrusionMultiPath(const ExtrusionMultiPath &rhs) : paths(rhs.paths) {} ExtrusionMultiPath(ExtrusionMultiPath &&rhs) : paths(std::move(rhs.paths)) {} @@ -278,7 +281,7 @@ public: double min_mm3_per_mm() const override; Polyline as_polyline() const override; void collect_polylines(Polylines &dst) const override { Polyline pl = this->as_polyline(); if (! pl.empty()) dst.emplace_back(std::move(pl)); } - void collect_points(Points &dst) const override { + void collect_points(Points &dst) const override { size_t n = std::accumulate(paths.begin(), paths.end(), 0, [](const size_t n, const ExtrusionPath &p){ return n + p.polyline.size(); }); dst.reserve(dst.size() + n); for (const ExtrusionPath &p : this->paths) @@ -292,11 +295,11 @@ class ExtrusionLoop : public ExtrusionEntity { public: ExtrusionPaths paths; - + ExtrusionLoop(ExtrusionLoopRole role = elrDefault) : m_loop_role(role) {} ExtrusionLoop(const ExtrusionPaths &paths, ExtrusionLoopRole role = elrDefault) : paths(paths), m_loop_role(role) {} ExtrusionLoop(ExtrusionPaths &&paths, ExtrusionLoopRole role = elrDefault) : paths(std::move(paths)), m_loop_role(role) {} - ExtrusionLoop(const ExtrusionPath &path, ExtrusionLoopRole role = elrDefault) : m_loop_role(role) + ExtrusionLoop(const ExtrusionPath &path, ExtrusionLoopRole role = elrDefault) : m_loop_role(role) { this->paths.push_back(path); } ExtrusionLoop(const ExtrusionPath &&path, ExtrusionLoopRole role = elrDefault) : m_loop_role(role) { this->paths.emplace_back(std::move(path)); } @@ -329,6 +332,7 @@ public: bool has_overhang_point(const Point &point) const; ExtrusionRole role() const override { return this->paths.empty() ? erNone : this->paths.front().role(); } ExtrusionLoopRole loop_role() const { return m_loop_role; } + void set_loop_role(ExtrusionLoopRole role) { m_loop_role = role; } // Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width. // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps. void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const override; @@ -344,7 +348,7 @@ public: double min_mm3_per_mm() const override; Polyline as_polyline() const override { return this->polygon().split_at_first_point(); } void collect_polylines(Polylines &dst) const override { Polyline pl = this->as_polyline(); if (! pl.empty()) dst.emplace_back(std::move(pl)); } - void collect_points(Points &dst) const override { + void collect_points(Points &dst) const override { size_t n = std::accumulate(paths.begin(), paths.end(), 0, [](const size_t n, const ExtrusionPath &p){ return n + p.polyline.size(); }); dst.reserve(dst.size() + n); for (const ExtrusionPath &p : this->paths) diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index 5dee58242b..dc95ad21f0 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -245,6 +245,7 @@ static constexpr const char* PATTERN_FILE_ATTR = "pattern_file"; static constexpr const char* PATTERN_BBOX_FILE_ATTR = "pattern_bbox_file"; static constexpr const char* OBJECT_ID_ATTR = "object_id"; static constexpr const char* INSTANCEID_ATTR = "instance_id"; +static constexpr const char* ARRANGE_ORDER_ATTR = "arrange_order"; static constexpr const char* PLATERID_ATTR = "plater_id"; static constexpr const char* PLATE_IDX_ATTR = "index"; static constexpr const char* SLICE_PREDICTION_ATTR = "prediction"; @@ -604,6 +605,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) { int object_id; int instance_id; + int arrange_order; }; struct Instance @@ -1123,6 +1125,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) m_plater_data.clear(); m_curr_instance.object_id = -1; m_curr_instance.instance_id = -1; + m_curr_instance.arrange_order = 0; clear_errors(); // restore @@ -1570,7 +1573,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) return false; } if (current_plate_data) { - std::map::iterator it = current_plate_data->obj_inst_map.find(object.first.second); + std::map>::iterator it = current_plate_data->obj_inst_map.find(object.first.second); if (it == current_plate_data->obj_inst_map.end()) { //not in current plate, skip BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", could not find object %1% in plate %2%, skip it\n")%object.first.second %plate_id; @@ -1769,8 +1772,46 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) plate_data_list[it->first-1]->pattern_file = (m_load_restore || it->second->pattern_file.empty()) ? it->second->pattern_file : m_backup_path + "/" + it->second->pattern_file; plate_data_list[it->first-1]->pattern_bbox_file = (m_load_restore || it->second->pattern_bbox_file.empty()) ? it->second->pattern_bbox_file : m_backup_path + "/" + it->second->pattern_bbox_file; plate_data_list[it->first-1]->config = it->second->config; + current_plate_data = plate_data_list[it->first - 1]; BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", plate %1%, thumbnail_file=%2%")%it->first %plate_data_list[it->first-1]->thumbnail_file; it++; + + //update the arrange order + std::map>::iterator map_it = current_plate_data->obj_inst_map.begin(); + while (map_it != current_plate_data->obj_inst_map.end()) { + int obj_index, obj_id = map_it->first, inst_index = map_it->second.first; + IndexToPathMap::iterator index_iter = m_index_paths.find(obj_id); + if (index_iter == m_index_paths.end()) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ + << boost::format(", can not find object from plate's obj_map, id=%1%, skip this object")%obj_id; + map_it++; + continue; + } + Id temp_id = std::make_pair(index_iter->second, index_iter->first); + IdToModelObjectMap::iterator object_item = m_objects.find(temp_id); + if (object_item == m_objects.end()) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ + << boost::format(", can not find object from plate's obj_map, ID <%1%, %2%>, skip this object")%index_iter->second %index_iter->first; + map_it++; + continue; + } + obj_index = object_item->second; + + if (obj_index >= m_model->objects.size()) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ << boost::format("invalid object id %1%\n")%obj_index; + map_it++; + continue; + } + ModelObject* obj = m_model->objects[obj_index]; + if (inst_index >= obj->instances.size()) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ << boost::format("invalid instance id %1%\n")%inst_index; + map_it++; + continue; + } + ModelInstance* inst = obj->instances[inst_index]; + inst->arrange_order = map_it->second.second; + map_it++; + } } if ((plate_id > 0) && (plate_id <= m_plater_data.size())) { @@ -3417,6 +3458,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) { m_curr_instance.instance_id = atoi(value.c_str()); } + else if (key == ARRANGE_ORDER_ATTR) + { + m_curr_instance.arrange_order = atoi(value.c_str()); + } else if (key == OBJECT_ID_ATTR) { m_curr_instance.object_id = atoi(value.c_str()); @@ -3570,11 +3615,13 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) //add_error("invalid object id/instance id"); //skip this instance m_curr_instance.object_id = m_curr_instance.instance_id = -1; + m_curr_instance.arrange_order = 0; return true; } - m_curr_plater->obj_inst_map.emplace(m_curr_instance.object_id, m_curr_instance.instance_id); + m_curr_plater->obj_inst_map.emplace(m_curr_instance.object_id, std::make_pair(m_curr_instance.instance_id, m_curr_instance.arrange_order)); m_curr_instance.object_id = m_curr_instance.instance_id = -1; + m_curr_instance.arrange_order = 0; return true; } @@ -6360,14 +6407,32 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) stream << " <" << INSTANCE_TAG << ">\n"; int obj_id = plate_data->objects_and_instances[j].first; int inst_id = plate_data->objects_and_instances[j].second; - if (m_skip_static) { - obj_id = model.objects[obj_id]->get_backup_id(); + int arrange_o = 0; + ModelObject* obj = NULL; + ModelInstance* inst = NULL; + if (obj_id >= model.objects.size()) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ << boost::format("invalid object id %1%\n")%obj_id; + } + else + obj = model.objects[obj_id]; + + if (obj && (inst_id >= obj->instances.size())) { + BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ":" << __LINE__ << boost::format("invalid instance id %1%\n")%inst_id; + } + else if (obj){ + inst = obj->instances[inst_id]; + arrange_o = inst->arrange_order; + } + if (m_skip_static && obj) { + obj_id = obj->get_backup_id(); } else { //inst_id = convert_instance_id_to_resource_id(model, obj_id, inst_id); obj_id = convert_instance_id_to_resource_id(model, obj_id, 0); } + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << OBJECT_ID_ATTR << "\" " << VALUE_ATTR << "=\"" << obj_id << "\"/>\n"; stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << INSTANCEID_ATTR << "\" " << VALUE_ATTR << "=\"" << inst_id << "\"/>\n"; + stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << ARRANGE_ORDER_ATTR << "\" " << VALUE_ATTR << "=\"" << arrange_o << "\"/>\n"; stream << " \n"; } } diff --git a/src/libslic3r/Format/bbs_3mf.hpp b/src/libslic3r/Format/bbs_3mf.hpp index 620468eccf..3652709116 100644 --- a/src/libslic3r/Format/bbs_3mf.hpp +++ b/src/libslic3r/Format/bbs_3mf.hpp @@ -57,7 +57,7 @@ struct PlateData int plate_index; std::vector> objects_and_instances; - std::map obj_inst_map; + std::map> obj_inst_map; std::string gcode_file; std::string gcode_file_md5; std::string thumbnail_file; diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index 0c2193330e..91a7e981ba 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -65,7 +65,7 @@ public: // ordered collection of extrusion paths to fill surfaces // (this collection contains only ExtrusionEntityCollection objects) ExtrusionEntityCollection fills; - + Flow flow(FlowRole role) const; Flow flow(FlowRole role, double layer_height) const; Flow bridging_flow(FlowRole role, bool thick_bridge = false) const; @@ -110,7 +110,7 @@ private: const PrintRegion *m_region; }; -class Layer +class Layer { public: // Sequential index of this layer in PrintObject::m_layers, offsetted by the number of raft layers. @@ -132,7 +132,7 @@ public: mutable ExPolygons cantilevers; mutable std::map sharp_tails_height; - // Collection of expolygons generated by slicing the possibly multiple meshes of the source geometry + // Collection of expolygons generated by slicing the possibly multiple meshes of the source geometry // (with possibly differing extruder ID and slicing parameters) and merged. // For the first layer, if the Elephant foot compensation is applied, this lslice is uncompensated, therefore // it includes the Elephant foot effect, thus it corresponds to the shape of the printed 1st layer. @@ -149,7 +149,7 @@ public: LayerRegion* add_region(const PrintRegion *print_region); const LayerRegionPtrs& regions() const { return m_regions; } // Test whether whether there are any slices assigned to this layer. - bool empty() const; + bool empty() const; void make_slices(); // Backup and restore raw sliced regions if needed. //FIXME Review whether not to simplify the code by keeping the raw_slices all the time. @@ -209,7 +209,7 @@ private: LayerRegionPtrs m_regions; }; -class SupportLayer : public Layer +class SupportLayer : public Layer { public: // Polygons covered by the supports: base, interface and contact areas. diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index ebce884262..ad3cafcb10 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -24,6 +24,11 @@ #include #include +//BBS: add json support +#include "nlohmann/json.hpp" + +using namespace nlohmann; + // Mark string for localization and translate. #define L(s) Slic3r::I18N::translate(s) @@ -131,7 +136,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "wipe_distance", "curr_bed_type", "nozzle_volume", - "nozzle_hrc", + "nozzle_hrc", "required_nozzle_HRC" }; @@ -506,17 +511,17 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print } }; std::unordered_set left_right_pair; // pairs in this vector must strictly obey the left-right order - for (size_t i = 0; i < print_instance_with_bounding_box.size();i++) { + for (size_t i = 0; i < print_instance_with_bounding_box.size();i++) { auto &inst = print_instance_with_bounding_box[i]; inst.index = i; Point pt = inst.bounding_box.center(); inst.arrange_score = pt.x() / 2 + pt.y(); // we prefer print row-by-row, so cost on x-direction is smaller } for (size_t i = 0; i < print_instance_with_bounding_box.size(); i++) { - auto &inst = print_instance_with_bounding_box[i]; + auto &inst = print_instance_with_bounding_box[i]; auto &l = print_instance_with_bounding_box[i]; for (size_t j = 0; j < print_instance_with_bounding_box.size(); j++) { - if (j != i) { + if (j != i) { auto &r = print_instance_with_bounding_box[j]; auto ly1 = l.bounding_box.min.y(); auto ly2 = l.bounding_box.max.y(); @@ -543,7 +548,7 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print << " -> " << r.print_instance->model_instance->get_object()->name << "(" << r.arrange_score << ")"; } } - } + } if (l.height > hc1 && r.height < hc1) { // 当前物体超过了顶盖高度,必须后打 left_right_pair.insert({j, i}); @@ -570,7 +575,7 @@ StringObjectException Print::sequential_print_clearance_valid(const Print &print if(r.arrange_score layer_height_profiles[idx_object][layer_height_profiles[idx_object].size() - 2]) // break; if (std::abs(layer_height_profiles[idx_object][i] - layer_height_profiles[tallest_object_idx][i]) > eps) @@ -1098,7 +1103,7 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons* break; } } - + StringObjectException except; except.string = format(L("Plate %d: %s does not support filament %s\n"), this->get_plate_index() + 1, L(bed_type_name), extruder_id + 1); except.type = STRING_EXCEPT_FILAMENT_NOT_MATCH_BED_TYPE; @@ -1324,12 +1329,12 @@ std::map getObjectExtruderMap(const Print& print) { } // Slicing process, running at a background thread. -void Print::process() +void Print::process(bool use_cache) { name_tbb_thread_pool_threads_set_locale(); //compute the PrintObject with the same geometries - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": this=%1%, enter")%this; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": this=%1%, enter, use_cache=%2%")%this%use_cache; for (PrintObject *obj : m_objects) obj->clear_shared_object(); @@ -1375,74 +1380,116 @@ void Print::process() }; int object_count = m_objects.size(); std::set need_slicing_objects; - for (int index = 0; index < object_count; index++) - { - PrintObject *obj = m_objects[index]; - for (PrintObject *slicing_obj : need_slicing_objects) + if (!use_cache) { + for (int index = 0; index < object_count; index++) { - if (is_print_object_the_same(obj, slicing_obj)) { - obj->set_shared_object(slicing_obj); - break; + PrintObject *obj = m_objects[index]; + for (PrintObject *slicing_obj : need_slicing_objects) + { + if (is_print_object_the_same(obj, slicing_obj)) { + obj->set_shared_object(slicing_obj); + break; + } + } + if (!obj->get_shared_object()) + need_slicing_objects.insert(obj); + } + } + else { + for (int index = 0; index < object_count; index++) + { + PrintObject *obj = m_objects[index]; + if (obj->layer_count() > 0) + need_slicing_objects.insert(obj); + } + for (int index = 0; index < object_count; index++) + { + PrintObject *obj = m_objects[index]; + if (need_slicing_objects.find(obj) == need_slicing_objects.end()) { + for (PrintObject *slicing_obj : need_slicing_objects) + { + if (is_print_object_the_same(obj, slicing_obj)) { + obj->set_shared_object(slicing_obj); + break; + } + } } } - if (!obj->get_shared_object()) - need_slicing_objects.insert(obj); } BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": total object counts %1% in current print, need to slice %2%")%m_objects.size()%need_slicing_objects.size(); BOOST_LOG_TRIVIAL(info) << "Starting the slicing process." << log_memory_info(); - for (PrintObject *obj : m_objects) { - if (need_slicing_objects.count(obj) != 0) { - obj->make_perimeters(); + if (!use_cache) { + for (PrintObject *obj : m_objects) { + if (need_slicing_objects.count(obj) != 0) { + obj->make_perimeters(); + } + else { + if (obj->set_started(posSlice)) + obj->set_done(posSlice); + if (obj->set_started(posPerimeters)) + obj->set_done(posPerimeters); + } } - else { + for (PrintObject *obj : m_objects) { + if (need_slicing_objects.count(obj) != 0) { + obj->infill(); + } + else { + if (obj->set_started(posPrepareInfill)) + obj->set_done(posPrepareInfill); + if (obj->set_started(posInfill)) + obj->set_done(posInfill); + } + } + for (PrintObject *obj : m_objects) { + if (need_slicing_objects.count(obj) != 0) { + obj->ironing(); + } + else { + if (obj->set_started(posIroning)) + obj->set_done(posIroning); + } + } + + tbb::parallel_for(tbb::blocked_range(0, int(m_objects.size())), + [this, need_slicing_objects](const tbb::blocked_range& range) { + for (int i = range.begin(); i < range.end(); i++) { + PrintObject* obj = m_objects[i]; + if (need_slicing_objects.count(obj) != 0) { + obj->generate_support_material(); + } + else { + if (obj->set_started(posSupportMaterial)) + obj->set_done(posSupportMaterial); + } + } + } + ); + } + else { + for (PrintObject *obj : m_objects) { if (obj->set_started(posSlice)) obj->set_done(posSlice); if (obj->set_started(posPerimeters)) obj->set_done(posPerimeters); - } - } - for (PrintObject *obj : m_objects) { - if (need_slicing_objects.count(obj) != 0) { - obj->infill(); - } - else { if (obj->set_started(posPrepareInfill)) obj->set_done(posPrepareInfill); if (obj->set_started(posInfill)) obj->set_done(posInfill); - } - } - for (PrintObject *obj : m_objects) { - if (need_slicing_objects.count(obj) != 0) { - obj->ironing(); - } - else { if (obj->set_started(posIroning)) obj->set_done(posIroning); + if (obj->set_started(posSupportMaterial)) + obj->set_done(posSupportMaterial); } } - tbb::parallel_for(tbb::blocked_range(0, int(m_objects.size())), - [this, need_slicing_objects](const tbb::blocked_range& range) { - for (int i = range.begin(); i < range.end(); i++) { - PrintObject* obj = m_objects[i]; - if (need_slicing_objects.count(obj) != 0) { - obj->generate_support_material(); - } - else { - if (obj->set_started(posSupportMaterial)) - obj->set_done(posSupportMaterial); - } - } - } - ); - for (PrintObject *obj : m_objects) { if (need_slicing_objects.count(obj) == 0) obj->copy_layers_from_shared_object(); } + if (this->set_started(psWipeTower)) { m_wipe_tower_data.clear(); m_tool_ordering.clear(); @@ -1546,7 +1593,7 @@ void Print::process() } //BBS for (PrintObject *obj : m_objects) { - if (need_slicing_objects.count(obj) != 0) { + if ((!use_cache)&&(need_slicing_objects.count(obj) != 0)) { obj->simplify_extrusion_path(); } else { @@ -2113,4 +2160,1087 @@ std::string PrintStatistics::finalize_output_path(const std::string &path_in) co return final_path; } +/*add json export/import related functions */ +#define JSON_POLYGON_CONTOUR "contour" +#define JSON_POLYGON_HOLES "holes" +#define JSON_POINTS "points" +#define JSON_EXPOLYGON "expolygon" +#define JSON_ARC_FITTING "arc_fitting" +#define JSON_OBJECT_NAME "name" +#define JSON_ARRANGE_ORDER "arrange_order" + + +#define JSON_LAYERS "layers" +#define JSON_SUPPORT_LAYERS "support_layers" +#define JSON_TREE_SUPPORT_LAYERS "tree_support_layers" +#define JSON_LAYER_REGIONS "layer_regions" + + +#define JSON_LAYER_PRINT_Z "print_z" +#define JSON_LAYER_SLICE_Z "slice_z" +#define JSON_LAYER_HEIGHT "height" +#define JSON_LAYER_ID "layer_id" +#define JSON_LAYER_SLICED_POLYGONS "sliced_polygons" +#define JSON_LAYER_SLLICED_BBOXES "sliced_bboxes" + +#define JSON_SUPPORT_LAYER_ISLANDS "support_islands" +#define JSON_SUPPORT_LAYER_FILLS "support_fills" +#define JSON_SUPPORT_LAYER_INTERFACE_ID "interface_id" + + +#define JSON_LAYER_REGION_CONFIG_HASH "config_hash" +#define JSON_LAYER_REGION_SLICES "slices" +#define JSON_LAYER_REGION_RAW_SLICES "raw_slices" +//#define JSON_LAYER_REGION_ENTITIES "entities" +#define JSON_LAYER_REGION_THIN_FILLS "thin_fills" +#define JSON_LAYER_REGION_FILL_EXPOLYGONS "fill_expolygons" +#define JSON_LAYER_REGION_FILL_SURFACES "fill_surfaces" +#define JSON_LAYER_REGION_FILL_NO_OVERLAP "fill_no_overlap_expolygons" +#define JSON_LAYER_REGION_UNSUPPORTED_BRIDGE_EDGES "unsupported_bridge_edges" +#define JSON_LAYER_REGION_PERIMETERS "perimeters" +#define JSON_LAYER_REGION_FILLS "fills" + + + +#define JSON_SURF_TYPE "surface_type" +#define JSON_SURF_THICKNESS "thickness" +#define JSON_SURF_THICKNESS_LAYER "thickness_layers" +#define JSON_SURF_BRIDGE_ANGLE "bridge_angle" +#define JSON_SURF_EXTRA_PERIMETERS "extra_perimeters" + +#define JSON_ARC_DATA "arc_data" +#define JSON_ARC_START_INDEX "start_index" +#define JSON_ARC_END_INDEX "end_index" +#define JSON_ARC_PATH_TYPE "path_type" + +#define JSON_IS_ARC "is_arc" +#define JSON_ARC_LENGTH "length" +#define JSON_ARC_ANGLE_RADIUS "angle_radians" +#define JSON_ARC_POLAY_START_THETA "polar_start_theta" +#define JSON_ARC_POLAY_END_THETA "polar_end_theta" +#define JSON_ARC_START_POINT "start_point" +#define JSON_ARC_END_POINT "end_point" +#define JSON_ARC_DIRECTION "direction" +#define JSON_ARC_RADIUS "radius" +#define JSON_ARC_CENTER "center" + +//extrusions +#define JSON_EXTRUSION_ENTITY_TYPE "entity_type" +#define JSON_EXTRUSION_NO_SORT "no_sort" +#define JSON_EXTRUSION_PATHS "paths" +#define JSON_EXTRUSION_ENTITIES "entities" +#define JSON_EXTRUSION_TYPE_PATH "path" +#define JSON_EXTRUSION_TYPE_MULTIPATH "multipath" +#define JSON_EXTRUSION_TYPE_LOOP "loop" +#define JSON_EXTRUSION_TYPE_COLLECTION "collection" +#define JSON_EXTRUSION_POLYLINE "polyline" +#define JSON_EXTRUSION_OVERHANG_DEGREE "overhang_degree" +#define JSON_EXTRUSION_CURVE_DEGREE "curve_degree" +#define JSON_EXTRUSION_MM3_PER_MM "mm3_per_mm" +#define JSON_EXTRUSION_WIDTH "width" +#define JSON_EXTRUSION_HEIGHT "height" +#define JSON_EXTRUSION_ROLE "role" +#define JSON_EXTRUSION_NO_EXTRUSION "no_extrusion" +#define JSON_EXTRUSION_LOOP_ROLE "loop_role" + + +static void to_json(json& j, const Points& p_s) { + for (const Point& p : p_s) + { + j.push_back(p.x()); + j.push_back(p.y()); + } +} + +static void to_json(json& j, const BoundingBox& bb) { + j.push_back(bb.min.x()); + j.push_back(bb.min.y()); + j.push_back(bb.max.x()); + j.push_back(bb.max.y()); +} + +static void to_json(json& j, const ExPolygon& polygon) { + json contour_json = json::array(), holes_json = json::array(); + + //contour + const Polygon& slice_contour = polygon.contour; + contour_json = slice_contour.points; + j[JSON_POLYGON_CONTOUR] = std::move(contour_json); + + //holes + const Polygons& slice_holes = polygon.holes; + for (const Polygon& hole_polyon : slice_holes) + { + json hole_json = json::array(); + hole_json = hole_polyon.points; + holes_json.push_back(std::move(hole_json)); + } + j[JSON_POLYGON_HOLES] = std::move(holes_json); +} + +static void to_json(json& j, const Surface& surf) { + j[JSON_EXPOLYGON] = surf.expolygon; + j[JSON_SURF_TYPE] = surf.surface_type; + j[JSON_SURF_THICKNESS] = surf.thickness; + j[JSON_SURF_THICKNESS_LAYER] = surf.thickness_layers; + j[JSON_SURF_BRIDGE_ANGLE] = surf.bridge_angle; + j[JSON_SURF_EXTRA_PERIMETERS] = surf.extra_perimeters; +} + +static void to_json(json& j, const ArcSegment& arc_seg) { + json start_point_json = json::array(), end_point_json = json::array(), center_point_json = json::array(); + j[JSON_IS_ARC] = arc_seg.is_arc; + j[JSON_ARC_LENGTH] = arc_seg.length; + j[JSON_ARC_ANGLE_RADIUS] = arc_seg.angle_radians; + j[JSON_ARC_POLAY_START_THETA] = arc_seg.polar_start_theta; + j[JSON_ARC_POLAY_END_THETA] = arc_seg.polar_end_theta; + start_point_json.push_back(arc_seg.start_point.x()); + start_point_json.push_back(arc_seg.start_point.y()); + j[JSON_ARC_START_POINT] = std::move(start_point_json); + end_point_json.push_back(arc_seg.end_point.x()); + end_point_json.push_back(arc_seg.end_point.y()); + j[JSON_ARC_END_POINT] = std::move(end_point_json); + j[JSON_ARC_DIRECTION] = arc_seg.direction; + j[JSON_ARC_RADIUS] = arc_seg.radius; + center_point_json.push_back(arc_seg.center.x()); + center_point_json.push_back(arc_seg.center.y()); + j[JSON_ARC_CENTER] = std::move(center_point_json); +} + + +static void to_json(json& j, const Polyline& poly_line) { + json points_json = json::array(), fittings_json = json::array(); + points_json = poly_line.points; + + j[JSON_POINTS] = std::move(points_json); + for (const PathFittingData& path_fitting : poly_line.fitting_result) + { + json fitting_json; + fitting_json[JSON_ARC_START_INDEX] = path_fitting.start_point_index; + fitting_json[JSON_ARC_END_INDEX] = path_fitting.end_point_index; + fitting_json[JSON_ARC_PATH_TYPE] = path_fitting.path_type; + if (path_fitting.arc_data.is_arc) + fitting_json[JSON_ARC_DATA] = path_fitting.arc_data; + + fittings_json.push_back(std::move(fitting_json)); + } + j[JSON_ARC_FITTING] = fittings_json; +} + +static void to_json(json& j, const ExtrusionPath& extrusion_path) { + j[JSON_EXTRUSION_POLYLINE] = extrusion_path.polyline; + j[JSON_EXTRUSION_OVERHANG_DEGREE] = extrusion_path.overhang_degree; + j[JSON_EXTRUSION_CURVE_DEGREE] = extrusion_path.curve_degree; + j[JSON_EXTRUSION_MM3_PER_MM] = extrusion_path.mm3_per_mm; + j[JSON_EXTRUSION_WIDTH] = extrusion_path.width; + j[JSON_EXTRUSION_HEIGHT] = extrusion_path.height; + j[JSON_EXTRUSION_ROLE] = extrusion_path.role(); + j[JSON_EXTRUSION_NO_EXTRUSION] = extrusion_path.is_force_no_extrusion(); +} + +static bool convert_extrusion_to_json(json& entity_json, json& entity_paths_json, const ExtrusionEntity* extrusion_entity) { + std::string path_type; + const ExtrusionPath* path = NULL; + const ExtrusionMultiPath* multipath = NULL; + const ExtrusionLoop* loop = NULL; + const ExtrusionEntityCollection* collection = dynamic_cast(extrusion_entity); + + if (!collection) + path = dynamic_cast(extrusion_entity); + + if (!collection && !path) + multipath = dynamic_cast(extrusion_entity); + + if (!collection && !path && !multipath) + loop = dynamic_cast(extrusion_entity); + + path_type = path?JSON_EXTRUSION_TYPE_PATH:(multipath?JSON_EXTRUSION_TYPE_MULTIPATH:(loop?JSON_EXTRUSION_TYPE_LOOP:JSON_EXTRUSION_TYPE_COLLECTION)); + if (path_type.empty()) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(":invalid extrusion path type Found"); + return false; + } + + entity_json[JSON_EXTRUSION_ENTITY_TYPE] = path_type; + + if (path) { + json entity_path_json = *path; + entity_paths_json.push_back(std::move(entity_path_json)); + } + else if (multipath) { + for (const ExtrusionPath& extrusion_path : multipath->paths) + { + json entity_path_json = extrusion_path; + entity_paths_json.push_back(std::move(entity_path_json)); + } + } + else if (loop) { + entity_json[JSON_EXTRUSION_LOOP_ROLE] = loop->loop_role(); + for (const ExtrusionPath& extrusion_path : loop->paths) + { + json entity_path_json = extrusion_path; + entity_paths_json.push_back(std::move(entity_path_json)); + } + } + else { + //recursive collections + entity_json[JSON_EXTRUSION_NO_SORT] = collection->no_sort; + for (const ExtrusionEntity* recursive_extrusion_entity : collection->entities) { + json recursive_entity_json, recursive_entity_paths_json = json::array(); + bool ret = convert_extrusion_to_json(recursive_entity_json, recursive_entity_paths_json, recursive_extrusion_entity); + if (!ret) { + continue; + } + entity_paths_json.push_back(std::move(recursive_entity_json)); + } + } + + if (collection) + entity_json[JSON_EXTRUSION_ENTITIES] = std::move(entity_paths_json); + else + entity_json[JSON_EXTRUSION_PATHS] = std::move(entity_paths_json); + return true; +} + +static void to_json(json& j, const LayerRegion& layer_region) { + json unsupported_bridge_edges_json = json::array(), slices_surfaces_json = json::array(), raw_slices_json = json::array(), thin_fills_json, thin_fill_entities_json = json::array(); + json fill_expolygons_json = json::array(), fill_no_overlap_expolygons_json = json::array(), fill_surfaces_json = json::array(), perimeters_json, perimeter_entities_json = json::array(), fills_json, fill_entities_json = json::array(); + + j[JSON_LAYER_REGION_CONFIG_HASH] = layer_region.region().config_hash(); + //slices + for (const Surface& slice_surface : layer_region.slices.surfaces) { + json surface_json = slice_surface; + slices_surfaces_json.push_back(std::move(surface_json)); + } + j.push_back({JSON_LAYER_REGION_SLICES, std::move(slices_surfaces_json)}); + + //raw_slices + for (const ExPolygon& raw_slice_explogyon : layer_region.raw_slices) { + json raw_polygon_json = raw_slice_explogyon; + + raw_slices_json.push_back(std::move(raw_polygon_json)); + } + j.push_back({JSON_LAYER_REGION_RAW_SLICES, std::move(raw_slices_json)}); + + //thin fills + thin_fills_json[JSON_EXTRUSION_NO_SORT] = layer_region.thin_fills.no_sort; + thin_fills_json[JSON_EXTRUSION_ENTITY_TYPE] = JSON_EXTRUSION_TYPE_COLLECTION; + for (const ExtrusionEntity* extrusion_entity : layer_region.thin_fills.entities) { + json thinfills_entity_json, thinfill_entity_paths_json = json::array(); + bool ret = convert_extrusion_to_json(thinfills_entity_json, thinfill_entity_paths_json, extrusion_entity); + if (!ret) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(":error found at print_z %1%") % layer_region.layer()->print_z; + continue; + } + + thin_fill_entities_json.push_back(std::move(thinfills_entity_json)); + } + thin_fills_json[JSON_EXTRUSION_ENTITIES] = std::move(thin_fill_entities_json); + j.push_back({JSON_LAYER_REGION_THIN_FILLS, std::move(thin_fills_json)}); + + //fill_expolygons + for (const ExPolygon& fill_expolygon : layer_region.fill_expolygons) { + json fill_expolygon_json = fill_expolygon; + + fill_expolygons_json.push_back(std::move(fill_expolygon_json)); + } + j.push_back({JSON_LAYER_REGION_FILL_EXPOLYGONS, std::move(fill_expolygons_json)}); + + //fill_surfaces + for (const Surface& fill_surface : layer_region.fill_surfaces.surfaces) { + json surface_json = fill_surface; + fill_surfaces_json.push_back(std::move(surface_json)); + } + j.push_back({JSON_LAYER_REGION_FILL_SURFACES, std::move(fill_surfaces_json)}); + + //fill_no_overlap_expolygons + for (const ExPolygon& fill_no_overlap_expolygon : layer_region.fill_no_overlap_expolygons) { + json fill_no_overlap_expolygon_json = fill_no_overlap_expolygon; + + fill_no_overlap_expolygons_json.push_back(std::move(fill_no_overlap_expolygon_json)); + } + j.push_back({JSON_LAYER_REGION_FILL_NO_OVERLAP, std::move(fill_no_overlap_expolygons_json)}); + + //unsupported_bridge_edges + for (const Polyline& poly_line : layer_region.unsupported_bridge_edges) + { + json polyline_json = poly_line; + + unsupported_bridge_edges_json.push_back(std::move(polyline_json)); + } + j.push_back({JSON_LAYER_REGION_UNSUPPORTED_BRIDGE_EDGES, std::move(unsupported_bridge_edges_json)}); + + //perimeters + perimeters_json[JSON_EXTRUSION_NO_SORT] = layer_region.perimeters.no_sort; + perimeters_json[JSON_EXTRUSION_ENTITY_TYPE] = JSON_EXTRUSION_TYPE_COLLECTION; + for (const ExtrusionEntity* extrusion_entity : layer_region.perimeters.entities) { + json perimeters_entity_json, perimeters_entity_paths_json = json::array(); + bool ret = convert_extrusion_to_json(perimeters_entity_json, perimeters_entity_paths_json, extrusion_entity); + if (!ret) + continue; + + perimeter_entities_json.push_back(std::move(perimeters_entity_json)); + } + perimeters_json[JSON_EXTRUSION_ENTITIES] = std::move(perimeter_entities_json); + j.push_back({JSON_LAYER_REGION_PERIMETERS, std::move(perimeters_json)}); + + //fills + fills_json[JSON_EXTRUSION_NO_SORT] = layer_region.fills.no_sort; + fills_json[JSON_EXTRUSION_ENTITY_TYPE] = JSON_EXTRUSION_TYPE_COLLECTION; + for (const ExtrusionEntity* extrusion_entity : layer_region.fills.entities) { + json fill_entity_json, fill_entity_paths_json = json::array(); + bool ret = convert_extrusion_to_json(fill_entity_json, fill_entity_paths_json, extrusion_entity); + if (!ret) + continue; + + fill_entities_json.push_back(std::move(fill_entity_json)); + } + fills_json[JSON_EXTRUSION_ENTITIES] = std::move(fill_entities_json); + j.push_back({JSON_LAYER_REGION_FILLS, std::move(fills_json)}); + + return; +} + +//load apis from json +static void from_json(const json& j, Points& p_s) { + int array_size = j.size(); + for (int index = 0; index < array_size/2; index++) + { + coord_t x = j[2*index], y = j[2*index+1]; + Point p(x, y); + p_s.push_back(std::move(p)); + } + return; +} + +static void from_json(const json& j, BoundingBox& bbox) { + bbox.min[0] = j[0]; + bbox.min[1] = j[1]; + bbox.max[0] = j[2]; + bbox.max[1] = j[3]; + bbox.defined = true; + + return; +} + +static void from_json(const json& j, ExPolygon& polygon) { + polygon.contour.points = j[JSON_POLYGON_CONTOUR]; + + int holes_count = j[JSON_POLYGON_HOLES].size(); + for (int holes_index = 0; holes_index < holes_count; holes_index++) + { + Polygon poly; + + poly.points = j[JSON_POLYGON_HOLES][holes_index]; + polygon.holes.push_back(std::move(poly)); + } + return; +} + +static void from_json(const json& j, Surface& surf) { + surf.expolygon = j[JSON_EXPOLYGON]; + surf.surface_type = j[JSON_SURF_TYPE]; + surf.thickness = j[JSON_SURF_THICKNESS]; + surf.thickness_layers = j[JSON_SURF_THICKNESS_LAYER]; + surf.bridge_angle = j[JSON_SURF_BRIDGE_ANGLE]; + surf.extra_perimeters = j[JSON_SURF_EXTRA_PERIMETERS]; + + return; +} + +static void from_json(const json& j, ArcSegment& arc_seg) { + arc_seg.is_arc = j[JSON_IS_ARC]; + arc_seg.length = j[JSON_ARC_LENGTH]; + arc_seg.angle_radians = j[JSON_ARC_ANGLE_RADIUS]; + arc_seg.polar_start_theta = j[JSON_ARC_POLAY_START_THETA]; + arc_seg.polar_end_theta = j[JSON_ARC_POLAY_END_THETA]; + arc_seg.start_point.x() = j[JSON_ARC_START_POINT][0]; + arc_seg.start_point.y() = j[JSON_ARC_START_POINT][1]; + arc_seg.end_point.x() = j[JSON_ARC_END_POINT][0]; + arc_seg.end_point.y() = j[JSON_ARC_END_POINT][1]; + arc_seg.direction = j[JSON_ARC_DIRECTION]; + arc_seg.radius = j[JSON_ARC_RADIUS]; + arc_seg.center.x() = j[JSON_ARC_CENTER][0]; + arc_seg.center.y() = j[JSON_ARC_CENTER][1]; + + return; +} + + +static void from_json(const json& j, Polyline& poly_line) { + poly_line.points = j[JSON_POINTS]; + + int arc_fitting_count = j[JSON_ARC_FITTING].size(); + for (int arc_fitting_index = 0; arc_fitting_index < arc_fitting_count; arc_fitting_index++) + { + const json& fitting_json = j[JSON_ARC_FITTING][arc_fitting_index]; + PathFittingData path_fitting; + path_fitting.start_point_index = fitting_json[JSON_ARC_START_INDEX]; + path_fitting.end_point_index = fitting_json[JSON_ARC_END_INDEX]; + path_fitting.path_type = fitting_json[JSON_ARC_PATH_TYPE]; + + if (fitting_json.contains(JSON_ARC_DATA)) { + path_fitting.arc_data = fitting_json[JSON_ARC_DATA]; + } + + poly_line.fitting_result.push_back(std::move(path_fitting)); + } + return; +} + +static void from_json(const json& j, ExtrusionPath& extrusion_path) { + extrusion_path.polyline = j[JSON_EXTRUSION_POLYLINE]; + extrusion_path.overhang_degree = j[JSON_EXTRUSION_OVERHANG_DEGREE]; + extrusion_path.curve_degree = j[JSON_EXTRUSION_CURVE_DEGREE]; + extrusion_path.mm3_per_mm = j[JSON_EXTRUSION_MM3_PER_MM]; + extrusion_path.width = j[JSON_EXTRUSION_WIDTH]; + extrusion_path.height = j[JSON_EXTRUSION_HEIGHT]; + extrusion_path.set_extrusion_role(j[JSON_EXTRUSION_ROLE]); + extrusion_path.set_force_no_extrusion(j[JSON_EXTRUSION_NO_EXTRUSION]); +} + +static bool convert_extrusion_from_json(const json& entity_json, ExtrusionEntityCollection& entity_collection) { + std::string path_type = entity_json[JSON_EXTRUSION_ENTITY_TYPE]; + bool ret = false; + + if (path_type == JSON_EXTRUSION_TYPE_PATH) { + ExtrusionPath* path = new ExtrusionPath(); + if (!path) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": oom when new ExtrusionPath"); + return false; + } + *path = entity_json[JSON_EXTRUSION_PATHS][0]; + entity_collection.entities.push_back(path); + } + else if (path_type == JSON_EXTRUSION_TYPE_MULTIPATH) { + ExtrusionMultiPath* multipath = new ExtrusionMultiPath(); + if (!multipath) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": oom when new ExtrusionMultiPath"); + return false; + } + int paths_count = entity_json[JSON_EXTRUSION_PATHS].size(); + for (int path_index = 0; path_index < paths_count; path_index++) + { + ExtrusionPath path; + path = entity_json[JSON_EXTRUSION_PATHS][path_index]; + multipath->paths.push_back(std::move(path)); + } + entity_collection.entities.push_back(multipath); + } + else if (path_type == JSON_EXTRUSION_TYPE_LOOP) { + ExtrusionLoop* loop = new ExtrusionLoop(); + if (!loop) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": oom when new ExtrusionLoop"); + return false; + } + loop->set_loop_role(entity_json[JSON_EXTRUSION_LOOP_ROLE]); + int paths_count = entity_json[JSON_EXTRUSION_PATHS].size(); + for (int path_index = 0; path_index < paths_count; path_index++) + { + ExtrusionPath path; + path = entity_json[JSON_EXTRUSION_PATHS][path_index]; + loop->paths.push_back(std::move(path)); + } + entity_collection.entities.push_back(loop); + } + else if (path_type == JSON_EXTRUSION_TYPE_COLLECTION) { + ExtrusionEntityCollection* collection = new ExtrusionEntityCollection(); + if (!collection) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": oom when new ExtrusionEntityCollection"); + return false; + } + collection->no_sort = entity_json[JSON_EXTRUSION_NO_SORT]; + int entities_count = entity_json[JSON_EXTRUSION_ENTITIES].size(); + for (int entity_index = 0; entity_index < entities_count; entity_index++) + { + const json& entity_item_json = entity_json[JSON_EXTRUSION_ENTITIES][entity_index]; + ret = convert_extrusion_from_json(entity_item_json, *collection); + if (!ret) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": convert_extrusion_from_json failed"); + return false; + } + } + entity_collection.entities.push_back(collection); + } + else { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": unknown path type %1%")%path_type; + return false; + } + + return true; +} + +static void convert_layer_region_from_json(const json& j, LayerRegion& layer_region) { + //slices + int slices_count = j[JSON_LAYER_REGION_SLICES].size(); + for (int slices_index = 0; slices_index < slices_count; slices_index++) + { + Surface surface; + + surface = j[JSON_LAYER_REGION_SLICES][slices_index]; + layer_region.slices.surfaces.push_back(std::move(surface)); + } + + //raw_slices + int raw_slices_count = j[JSON_LAYER_REGION_RAW_SLICES].size(); + for (int raw_slices_index = 0; raw_slices_index < raw_slices_count; raw_slices_index++) + { + ExPolygon polygon; + + polygon = j[JSON_LAYER_REGION_RAW_SLICES][raw_slices_index]; + layer_region.raw_slices.push_back(std::move(polygon)); + } + + //thin fills + layer_region.thin_fills.no_sort = j[JSON_LAYER_REGION_THIN_FILLS][JSON_EXTRUSION_NO_SORT]; + int thinfills_entities_count = j[JSON_LAYER_REGION_THIN_FILLS][JSON_EXTRUSION_ENTITIES].size(); + for (int thinfills_entities_index = 0; thinfills_entities_index < thinfills_entities_count; thinfills_entities_index++) + { + const json& extrusion_entity_json = j[JSON_LAYER_REGION_THIN_FILLS][JSON_EXTRUSION_ENTITIES][thinfills_entities_index]; + bool ret = convert_extrusion_from_json(extrusion_entity_json, layer_region.thin_fills); + if (!ret) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(":error parsing thin_fills found at layer %1%, print_z %2%") %layer_region.layer()->id() %layer_region.layer()->print_z; + char error_buf[1024]; + ::sprintf(error_buf, "Error while parsing thin_fills at layer %d, print_z %f", layer_region.layer()->id(), layer_region.layer()->print_z); + throw Slic3r::FileIOError(error_buf); + } + } + + //fill_expolygons + int fill_expolygons_count = j[JSON_LAYER_REGION_FILL_EXPOLYGONS].size(); + for (int fill_expolygons_index = 0; fill_expolygons_index < fill_expolygons_count; fill_expolygons_index++) + { + ExPolygon polygon; + + polygon = j[JSON_LAYER_REGION_FILL_EXPOLYGONS][fill_expolygons_index]; + layer_region.fill_expolygons.push_back(std::move(polygon)); + } + + //fill_surfaces + int fill_surfaces_count = j[JSON_LAYER_REGION_FILL_SURFACES].size(); + for (int fill_surfaces_index = 0; fill_surfaces_index < fill_surfaces_count; fill_surfaces_index++) + { + Surface surface; + + surface = j[JSON_LAYER_REGION_FILL_SURFACES][fill_surfaces_index]; + layer_region.fill_surfaces.surfaces.push_back(std::move(surface)); + } + + //fill_no_overlap_expolygons + int fill_no_overlap_expolygons_count = j[JSON_LAYER_REGION_FILL_NO_OVERLAP].size(); + for (int fill_no_overlap_expolygons_index = 0; fill_no_overlap_expolygons_index < fill_no_overlap_expolygons_count; fill_no_overlap_expolygons_index++) + { + ExPolygon polygon; + + polygon = j[JSON_LAYER_REGION_FILL_NO_OVERLAP][fill_no_overlap_expolygons_index]; + layer_region.fill_no_overlap_expolygons.push_back(std::move(polygon)); + } + + //unsupported_bridge_edges + int unsupported_bridge_edges_count = j[JSON_LAYER_REGION_UNSUPPORTED_BRIDGE_EDGES].size(); + for (int unsupported_bridge_edges_index = 0; unsupported_bridge_edges_index < unsupported_bridge_edges_count; unsupported_bridge_edges_index++) + { + Polyline polyline; + + polyline = j[JSON_LAYER_REGION_UNSUPPORTED_BRIDGE_EDGES][unsupported_bridge_edges_index]; + layer_region.unsupported_bridge_edges.push_back(std::move(polyline)); + } + + //perimeters + layer_region.perimeters.no_sort = j[JSON_LAYER_REGION_PERIMETERS][JSON_EXTRUSION_NO_SORT]; + int perimeters_entities_count = j[JSON_LAYER_REGION_PERIMETERS][JSON_EXTRUSION_ENTITIES].size(); + for (int perimeters_entities_index = 0; perimeters_entities_index < perimeters_entities_count; perimeters_entities_index++) + { + const json& extrusion_entity_json = j[JSON_LAYER_REGION_PERIMETERS][JSON_EXTRUSION_ENTITIES][perimeters_entities_index]; + bool ret = convert_extrusion_from_json(extrusion_entity_json, layer_region.perimeters); + if (!ret) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": error parsing perimeters found at layer %1%, print_z %2%") %layer_region.layer()->id() %layer_region.layer()->print_z; + char error_buf[1024]; + ::sprintf(error_buf, "Error while parsing perimeters at layer %d, print_z %f", layer_region.layer()->id(), layer_region.layer()->print_z); + throw Slic3r::FileIOError(error_buf); + } + } + + //fills + layer_region.fills.no_sort = j[JSON_LAYER_REGION_FILLS][JSON_EXTRUSION_NO_SORT]; + int fills_entities_count = j[JSON_LAYER_REGION_FILLS][JSON_EXTRUSION_ENTITIES].size(); + for (int fills_entities_index = 0; fills_entities_index < fills_entities_count; fills_entities_index++) + { + const json& extrusion_entity_json = j[JSON_LAYER_REGION_FILLS][JSON_EXTRUSION_ENTITIES][fills_entities_index]; + bool ret = convert_extrusion_from_json(extrusion_entity_json, layer_region.fills); + if (!ret) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": error parsing fills found at layer %1%, print_z %2%") %layer_region.layer()->id() %layer_region.layer()->print_z; + char error_buf[1024]; + ::sprintf(error_buf, "Error while parsing fills at layer %d, print_z %f", layer_region.layer()->id(), layer_region.layer()->print_z); + throw Slic3r::FileIOError(error_buf); + } + } + + return; +} + + +void extract_layer(const json& layer_json, Layer& layer) { + //slice_polygons + int slice_polygons_count = layer_json[JSON_LAYER_SLICED_POLYGONS].size(); + for (int polygon_index = 0; polygon_index < slice_polygons_count; polygon_index++) + { + ExPolygon polygon; + + polygon = layer_json[JSON_LAYER_SLICED_POLYGONS][polygon_index]; + layer.lslices.push_back(std::move(polygon)); + } + + //slice_bboxes + int sliced_bboxes_count = layer_json[JSON_LAYER_SLLICED_BBOXES].size(); + for (int bbox_index = 0; bbox_index < sliced_bboxes_count; bbox_index++) + { + BoundingBox bbox; + + bbox = layer_json[JSON_LAYER_SLLICED_BBOXES][bbox_index]; + layer.lslices_bboxes.push_back(std::move(bbox)); + } + + //layer_regions + int layer_region_count = layer.region_count(); + for (int layer_region_index = 0; layer_region_index < layer_region_count; layer_region_index++) + { + LayerRegion* layer_region = layer.get_region(layer_region_index); + const json& layer_region_json = layer_json[JSON_LAYER_REGIONS][layer_region_index]; + convert_layer_region_from_json(layer_region_json, *layer_region); + + //LayerRegion layer_region = layer_json[JSON_LAYER_REGIONS][layer_region_index]; + } + + return; +} + +void extract_support_layer(const json& support_layer_json, SupportLayer& support_layer) { + extract_layer(support_layer_json, support_layer); + + //support_islands + int islands_count = support_layer_json[JSON_SUPPORT_LAYER_ISLANDS].size(); + for (int islands_index = 0; islands_index < islands_count; islands_index++) + { + ExPolygon polygon; + + polygon = support_layer_json[JSON_SUPPORT_LAYER_ISLANDS][islands_index]; + support_layer.support_islands.expolygons.push_back(std::move(polygon)); + } + + //support_fills + support_layer.support_fills.no_sort = support_layer_json[JSON_SUPPORT_LAYER_FILLS][JSON_EXTRUSION_NO_SORT]; + int support_fills_entities_count = support_layer_json[JSON_SUPPORT_LAYER_FILLS][JSON_EXTRUSION_ENTITIES].size(); + for (int support_fills_entities_index = 0; support_fills_entities_index < support_fills_entities_count; support_fills_entities_index++) + { + const json& extrusion_entity_json = support_layer_json[JSON_SUPPORT_LAYER_FILLS][JSON_EXTRUSION_ENTITIES][support_fills_entities_index]; + bool ret = convert_extrusion_from_json(extrusion_entity_json, support_layer.support_fills); + if (!ret) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": error parsing fills found at support_layer %1%, print_z %2%")%support_layer.id() %support_layer.print_z; + char error_buf[1024]; + ::sprintf(error_buf, "Error while parsing fills at support_layer %d, print_z %f", support_layer.id(), support_layer.print_z); + throw Slic3r::FileIOError(error_buf); + } + } + + return; +} + +void extract_tree_support_layer(const json& tree_support_layer_json, TreeSupportLayer& tree_support_layer) { + extract_layer(tree_support_layer_json, tree_support_layer); + + //support_fills + tree_support_layer.support_fills.no_sort = tree_support_layer_json[JSON_SUPPORT_LAYER_FILLS][JSON_EXTRUSION_NO_SORT]; + int treesupport_fills_entities_count = tree_support_layer_json[JSON_SUPPORT_LAYER_FILLS][JSON_EXTRUSION_ENTITIES].size(); + for (int treesupport_fills_entities_index = 0; treesupport_fills_entities_index < treesupport_fills_entities_count; treesupport_fills_entities_index++) + { + const json& extrusion_entity_json = tree_support_layer_json[JSON_SUPPORT_LAYER_FILLS][JSON_EXTRUSION_ENTITIES][treesupport_fills_entities_index]; + bool ret = convert_extrusion_from_json(extrusion_entity_json, tree_support_layer.support_fills); + if (!ret) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": error parsing fills found at tree_support_layer %1%, print_z %2%")%tree_support_layer.id() %tree_support_layer.print_z; + char error_buf[1024]; + ::sprintf(error_buf, "Error while parsing fills at tree_support_layer %d, print_z %f", tree_support_layer.id(), tree_support_layer.print_z); + throw Slic3r::FileIOError(error_buf); + } + } + + return; +} + +int Print::export_cached_data(const std::string& directory, bool with_space) +{ + int ret = 0; + boost::filesystem::path directory_path(directory); + + auto convert_layer_to_json = [](json& layer_json, const Layer* layer) { + json slice_polygons_json = json::array(), slice_bboxs_json = json::array(), layer_regions_json = json::array(); + layer_json[JSON_LAYER_PRINT_Z] = layer->print_z; + layer_json[JSON_LAYER_HEIGHT] = layer->height; + layer_json[JSON_LAYER_SLICE_Z] = layer->slice_z; + layer_json[JSON_LAYER_ID] = layer->id(); + //layer_json["slicing_errors"] = layer->slicing_errors; + + //sliced_polygons + for (const ExPolygon& slice_polygon : layer->lslices) { + json slice_polygon_json = slice_polygon; + slice_polygons_json.push_back(std::move(slice_polygon_json)); + } + layer_json[JSON_LAYER_SLICED_POLYGONS] = std::move(slice_polygons_json); + + //sliced_bbox + for (const BoundingBox& slice_bbox : layer->lslices_bboxes) { + json bbox_json = json::array(); + + bbox_json = slice_bbox; + slice_bboxs_json.push_back(std::move(bbox_json)); + } + layer_json[JSON_LAYER_SLLICED_BBOXES] = std::move(slice_bboxs_json); + + for (const LayerRegion *layer_region : layer->regions()) { + json region_json = *layer_region; + + layer_regions_json.push_back(std::move(region_json)); + } + layer_json[JSON_LAYER_REGIONS] = std::move(layer_regions_json); + + return; + }; + + //firstly clear this directory + if (fs::exists(directory_path)) { + fs::remove_all(directory_path); + } + if (!fs::create_directory(directory_path)) { + BOOST_LOG_TRIVIAL(error) << boost::format("create directory %1% failed")%directory; + return CLI_EXPORT_CACHE_DIRECTORY_CREATE_FAILED; + } + + int count = 0; + for (PrintObject *obj : m_objects) { + const ModelObject* model_obj = obj->model_object(); + if (obj->get_shared_object()) { + BOOST_LOG_TRIVIAL(info) << boost::format("shared object %1%, skip directly")%model_obj->name; + continue; + } + BOOST_LOG_TRIVIAL(info) << boost::format("begin to dump object %1%")%model_obj->name; + + const PrintInstance &print_instance = obj->instances()[0]; + const ModelInstance *model_instance = print_instance.model_instance; + int arrange_order = model_instance->arrange_order; + std::string file_name = directory +"/obj_"+std::to_string(arrange_order)+".json"; + + try { + json root_json, layers_json = json::array(), support_layers_json = json::array(), tree_support_layers_json = json::array(); + + root_json[JSON_OBJECT_NAME] = model_obj->name; + root_json[JSON_ARRANGE_ORDER] = arrange_order; + + //export the layers + for (const Layer *layer : obj->layers()) { + json layer_json; + + convert_layer_to_json(layer_json, layer); + + layers_json.push_back(std::move(layer_json)); + } // for each layer + root_json[JSON_LAYERS] = std::move(layers_json); + + //export the support layers + for (const SupportLayer *support_layer : obj->support_layers()) { + json support_layer_json, support_islands_json = json::array(), support_fills_json, supportfills_entities_json = json::array(); + + convert_layer_to_json(support_layer_json, support_layer); + + support_layer_json[JSON_SUPPORT_LAYER_INTERFACE_ID] = support_layer->interface_id(); + + //support_islands + for (const ExPolygon& support_island : support_layer->support_islands.expolygons) { + json support_island_json = support_island; + support_islands_json.push_back(std::move(support_island_json)); + } + support_layer_json[JSON_SUPPORT_LAYER_ISLANDS] = std::move(support_islands_json); + + //support_fills + support_fills_json[JSON_EXTRUSION_NO_SORT] = support_layer->support_fills.no_sort; + support_fills_json[JSON_EXTRUSION_ENTITY_TYPE] = JSON_EXTRUSION_TYPE_COLLECTION; + for (const ExtrusionEntity* extrusion_entity : support_layer->support_fills.entities) { + json supportfill_entity_json, supportfill_entity_paths_json = json::array(); + bool ret = convert_extrusion_to_json(supportfill_entity_json, supportfill_entity_paths_json, extrusion_entity); + if (!ret) + continue; + + supportfills_entities_json.push_back(std::move(supportfill_entity_json)); + } + support_fills_json[JSON_EXTRUSION_ENTITIES] = std::move(supportfills_entities_json); + support_layer_json[JSON_SUPPORT_LAYER_FILLS] = std::move(support_fills_json); + + support_layers_json.push_back(std::move(support_layer_json)); + } // for each layer + root_json[JSON_SUPPORT_LAYERS] = std::move(support_layers_json); + + //export the tree support layers + for (const TreeSupportLayer *tree_support_layer : obj->tree_support_layers()) { + json treesupport_layer_json, treesupport_fills_json, treesupportfills_entities_json = json::array(); + json overhang_areas_json = json::array(), roof_areas_json = json::array(), roof_1st_layer_json = json::array(), floor_areas_json = json::array(), base_areas_json = json::array(); + + convert_layer_to_json(treesupport_layer_json, tree_support_layer); + + //tree_support_fills + treesupport_fills_json[JSON_EXTRUSION_NO_SORT] = tree_support_layer->support_fills.no_sort; + treesupport_fills_json[JSON_EXTRUSION_ENTITY_TYPE] = JSON_EXTRUSION_TYPE_COLLECTION; + for (const ExtrusionEntity* extrusion_entity : tree_support_layer->support_fills.entities) { + json treesupportfill_entity_json, treesupportfill_entity_paths_json = json::array(); + bool ret = convert_extrusion_to_json(treesupportfill_entity_json, treesupportfill_entity_paths_json, extrusion_entity); + if (!ret) + continue; + + treesupportfills_entities_json.push_back(std::move(treesupportfill_entity_json)); + } + treesupport_fills_json[JSON_EXTRUSION_ENTITIES] = std::move(treesupportfills_entities_json); + treesupport_layer_json[JSON_SUPPORT_LAYER_FILLS] = std::move(treesupport_fills_json); + + //overhang_areas + /*for (const ExPolygon& overhang_area : tree_support_layer->overhang_areas) { + json overhang_area_json = overhang_area; + overhang_areas_json.push_back(std::move(overhang_area_json)); + } + treesupport_layer_json["overhang_areas"] = std::move(overhang_areas_json); + + //roof_areas + for (const ExPolygon& roof_area : tree_support_layer->roof_areas) { + json roof_area_json = roof_area; + roof_areas_json.push_back(std::move(roof_area_json)); + } + treesupport_layer_json["roof_areas"] = std::move(roof_areas_json); + + //roof_1st_layer + for (const ExPolygon& layer_poly : tree_support_layer->roof_1st_layer) { + json layer_poly_json = layer_poly; + roof_1st_layer_json.push_back(std::move(layer_poly_json)); + } + treesupport_layer_json["roof_1st_layer"] = std::move(roof_1st_layer_json); + + //floor_areas + for (const ExPolygon& floor_area : tree_support_layer->floor_areas) { + json floor_area_json = floor_area; + floor_areas_json.push_back(std::move(floor_area_json)); + } + treesupport_layer_json["floor_areas"] = std::move(floor_areas_json); + + //base_areas + for (const ExPolygon& base_area : tree_support_layer->base_areas) { + json base_area_json = base_area; + base_areas_json.push_back(std::move(base_area_json)); + } + treesupport_layer_json["base_areas"] = std::move(base_areas_json);*/ + + tree_support_layers_json.push_back(std::move(treesupport_layer_json)); + } // for each layer + root_json[JSON_TREE_SUPPORT_LAYERS] = std::move(tree_support_layers_json); + + boost::nowide::ofstream c; + c.open(file_name, std::ios::out | std::ios::trunc); + if (with_space) + c << std::setw(4) << root_json << std::endl; + else + c << root_json.dump(0) << std::endl; + c.close(); + count ++; + BOOST_LOG_TRIVIAL(info) << boost::format("dump object %1% to %2% successfully.")%model_obj->name%file_name; + } + catch(std::exception &err) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": save to "< const PrintRegion* { + int regions_count = object->num_printing_regions(); + for (int index = 0; index < regions_count; index++ ) + { + const PrintRegion& print_region = object->printing_region(index); + if (print_region.config_hash() == config_hash ) { + return &print_region; + } + } + return NULL; + }; + + int count = 0; + for (PrintObject *obj : m_objects) { + const ModelObject* model_obj = obj->model_object(); + const PrintInstance &print_instance = obj->instances()[0]; + const ModelInstance *model_instance = print_instance.model_instance; + + obj->clear_layers(); + obj->clear_support_layers(); + obj->clear_tree_support_layers(); + + int arrange_order = model_instance->arrange_order; + if (arrange_order <= 0) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": object %1% has invalid arrange_order %2%, can not load cached_data")%model_obj->name %arrange_order; + continue; + } + std::string file_name = directory +"/obj_"+std::to_string(arrange_order)+".json"; + + if (!fs::exists(file_name)) { + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<> root_json; + + std::string name = root_json.at(JSON_OBJECT_NAME); + int order = root_json.at(JSON_ARRANGE_ORDER); + int layer_count = 0, support_layer_count = 0, treesupport_layer_count = 0; + + layer_count = root_json[JSON_LAYERS].size(); + support_layer_count = root_json[JSON_SUPPORT_LAYERS].size(); + treesupport_layer_count = root_json[JSON_TREE_SUPPORT_LAYERS].size(); + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<add_layer(layer_json[JSON_LAYER_ID], layer_json[JSON_LAYER_HEIGHT], layer_json[JSON_LAYER_PRINT_Z], layer_json[JSON_LAYER_SLICE_Z]); + if (!new_layer) { + BOOST_LOG_TRIVIAL(error) <<__FUNCTION__<< boost::format(":create_layer failed, out of memory"); + return CLI_OUT_OF_MEMORY; + } + if (previous_layer) { + previous_layer->upper_layer = new_layer; + new_layer->lower_layer = previous_layer; + } + previous_layer = new_layer; + + //layer regions + int layer_regions_count = layer_json[JSON_LAYER_REGIONS].size(); + for (int region_index = 0; region_index < layer_regions_count; region_index++) + { + json& region_json = layer_json[JSON_LAYER_REGIONS][region_index]; + size_t config_hash = region_json[JSON_LAYER_REGION_CONFIG_HASH]; + const PrintRegion *print_region = find_region(obj, config_hash); + + if (!print_region){ + BOOST_LOG_TRIVIAL(error) <<__FUNCTION__<< boost::format(":can not find print region of object %1%, layer %2%, print_z %3%, layer_region %4%") + %name % index %new_layer->print_z %region_index; + //delete new_layer; + return CLI_IMPORT_CACHE_DATA_CAN_NOT_USE; + } + + new_layer->add_region(print_region); + } + + } + + //load the layer data parallel + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<(0, obj->layer_count()), + [&root_json, &obj](const tbb::blocked_range& layer_range) { + for (size_t layer_index = layer_range.begin(); layer_index < layer_range.end(); ++ layer_index) { + const json& layer_json = root_json[JSON_LAYERS][layer_index]; + Layer* layer = obj->get_layer(layer_index); + extract_layer(layer_json, *layer); + } + } + ); + + //support layers + Layer* previous_support_layer = NULL; + //create support_layers + for (int index = 0; index < support_layer_count; index++) + { + json& layer_json = root_json[JSON_SUPPORT_LAYERS][index]; + SupportLayer* new_support_layer = obj->add_support_layer(layer_json[JSON_LAYER_ID], layer_json[JSON_SUPPORT_LAYER_INTERFACE_ID], layer_json[JSON_LAYER_HEIGHT], layer_json[JSON_LAYER_PRINT_Z]); + if (!new_support_layer) { + BOOST_LOG_TRIVIAL(error) <<__FUNCTION__<< boost::format(":add_support_layer failed, out of memory"); + return CLI_OUT_OF_MEMORY; + } + if (previous_support_layer) { + previous_support_layer->upper_layer = new_support_layer; + new_support_layer->lower_layer = previous_support_layer; + } + previous_support_layer = new_support_layer; + } + + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": finished load layers, start to load support_layers."); + tbb::parallel_for( + tbb::blocked_range(0, obj->support_layer_count()), + [&root_json, &obj](const tbb::blocked_range& support_layer_range) { + for (size_t layer_index = support_layer_range.begin(); layer_index < support_layer_range.end(); ++ layer_index) { + const json& layer_json = root_json[JSON_SUPPORT_LAYERS][layer_index]; + SupportLayer* support_layer = obj->get_support_layer(layer_index); + extract_support_layer(layer_json, *support_layer); + } + } + ); + + //tree support layers + Layer* previous_tree_support_layer = NULL; + //create tree_support_layers + for (int index = 0; index < treesupport_layer_count; index++) + { + json& layer_json = root_json[JSON_TREE_SUPPORT_LAYERS][index]; + TreeSupportLayer* new_tree_support_layer = obj->add_tree_support_layer(layer_json[JSON_LAYER_ID], layer_json[JSON_LAYER_HEIGHT], layer_json[JSON_LAYER_PRINT_Z], layer_json[JSON_LAYER_SLICE_Z]); + if (!new_tree_support_layer) { + BOOST_LOG_TRIVIAL(error) <<__FUNCTION__<< boost::format(":add_support_layer failed, out of memory"); + return CLI_OUT_OF_MEMORY; + } + if (previous_tree_support_layer) { + previous_tree_support_layer->upper_layer = new_tree_support_layer; + new_tree_support_layer->lower_layer = previous_tree_support_layer; + } + previous_tree_support_layer = new_tree_support_layer; + } + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": finished load support_layers, start to load treesupport_layers."); + tbb::parallel_for( + tbb::blocked_range(0, obj->tree_support_layer_count()), + [&root_json, &obj](const tbb::blocked_range& tree_support_layer_range) { + for (size_t layer_index = tree_support_layer_range.begin(); layer_index < tree_support_layer_range.end(); ++ layer_index) { + const json& layer_json = root_json[JSON_TREE_SUPPORT_LAYERS][layer_index]; + TreeSupportLayer* tree_support_layer = obj->get_tree_support_layer(layer_index); + extract_tree_support_layer(layer_json, *tree_support_layer); + } + } + ); + + count ++; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format("load object %1% from %2% successfully.")%model_obj->name%file_name; + } + catch(nlohmann::detail::parse_error &err) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "<cli_params = "filename.3mf"; def->set_default_value(new ConfigOptionString("output.3mf")); + def = this->add("export_slicedata", coString); + def->label = L("Export slicing data"); + def->tooltip = L("Export slicing data to a folder."); + def->cli_params = "slicing_data_directory"; + def->set_default_value(new ConfigOptionString("cached_data")); + + def = this->add("load_slicedata", coStrings); + def->label = L("Load slicing data"); + def->tooltip = L("Load cached slicing data from directory"); + def->cli_params = "slicing_data_directory"; + def->set_default_value(new ConfigOptionString("cached_data")); + /*def = this->add("export_amf", coBool); def->label = L("Export AMF"); def->tooltip = L("Export the model(s) as AMF."); diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index f921d5977e..f5efaa4454 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -37,7 +37,7 @@ bool is_zero_elevation(const SLAPrintObjectConfig &c) sla::SupportTreeConfig make_support_cfg(const SLAPrintObjectConfig& c) { sla::SupportTreeConfig scfg; - + scfg.enabled = c.supports_enable.getBool(); scfg.head_front_radius_mm = 0.5*c.support_head_front_diameter.getFloat(); double pillar_r = 0.5 * c.support_pillar_diameter.getFloat(); @@ -66,18 +66,18 @@ sla::SupportTreeConfig make_support_cfg(const SLAPrintObjectConfig& c) scfg.pillar_base_safety_distance_mm = c.support_base_safety_distance.getFloat() < EPSILON ? scfg.safety_distance_mm : c.support_base_safety_distance.getFloat(); - + scfg.max_bridges_on_pillar = unsigned(c.support_max_bridges_on_pillar.getInt()); - + return scfg; } sla::PadConfig::EmbedObject builtin_pad_cfg(const SLAPrintObjectConfig& c) { sla::PadConfig::EmbedObject ret; - + ret.enabled = is_zero_elevation(c); - + if(ret.enabled) { ret.everywhere = c.pad_around_object_everywhere.getBool(); ret.object_gap_mm = c.pad_object_gap.getFloat(); @@ -86,24 +86,24 @@ sla::PadConfig::EmbedObject builtin_pad_cfg(const SLAPrintObjectConfig& c) ret.stick_penetration_mm = c.pad_object_connector_penetration .getFloat(); } - + return ret; } sla::PadConfig make_pad_cfg(const SLAPrintObjectConfig& c) { sla::PadConfig pcfg; - + pcfg.wall_thickness_mm = c.pad_wall_thickness.getFloat(); pcfg.wall_slope = c.pad_wall_slope.getFloat() * PI / 180.0; - + pcfg.max_merge_dist_mm = c.pad_max_merge_distance.getFloat(); pcfg.wall_height_mm = c.pad_wall_height.getFloat(); pcfg.brim_size_mm = c.pad_brim_size.getFloat(); - + // set builtin pad implicitly ON pcfg.embed_object = builtin_pad_cfg(c); - + return pcfg; } @@ -174,8 +174,8 @@ static std::vector sla_instances(const ModelObject &mo return instances; } -std::vector SLAPrint::print_object_ids() const -{ +std::vector SLAPrint::print_object_ids() const +{ std::vector out; // Reserve one more for the caller to append the ID of the Print itself. out.reserve(m_objects.size() + 1); @@ -238,7 +238,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con m_material_config.apply_only(config, material_diff, true); // Handle changes to object config defaults m_default_object_config.apply_only(config, object_diff, true); - + if (m_printer) m_printer->apply(m_printer_config); struct ModelObjectStatus { @@ -429,7 +429,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con model_object.sla_support_points = model_object_new.sla_support_points; } model_object.sla_points_status = model_object_new.sla_points_status; - + // Invalidate hollowing if drain holes have changed if (model_object.sla_drain_holes != model_object_new.sla_drain_holes) { @@ -629,15 +629,15 @@ StringObjectException SLAPrint::validate(StringObjectException *exception, Polyg sla::SupportTreeConfig cfg = make_support_cfg(po->config()); double elv = cfg.object_elevation_mm; - + sla::PadConfig padcfg = make_pad_cfg(po->config()); sla::PadConfig::EmbedObject &builtinpad = padcfg.embed_object; - + if(supports_en && !builtinpad.enabled && elv < cfg.head_fullwidth()) return {L( "Elevation is too low for object. Use the \"Pad around " "object\" feature to print the object without elevation."), po}; - + if(supports_en && builtinpad.enabled && cfg.pillar_base_safety_distance_mm < builtinpad.object_gap_mm) { return {L( @@ -646,7 +646,7 @@ StringObjectException SLAPrint::validate(StringObjectException *exception, Polyg "distance' has to be greater than the 'Pad object gap' " "parameter to avoid this."), po}; } - + std::string pval = padcfg.validate(); if (!pval.empty()) return {pval, po}; } @@ -686,7 +686,7 @@ bool SLAPrint::invalidate_step(SLAPrintStep step) return invalidated; } -void SLAPrint::process() +void SLAPrint::process(bool use_cache) { if (m_objects.empty()) return; @@ -695,7 +695,7 @@ void SLAPrint::process() // Assumption: at this point the print objects should be populated only with // the model objects we have to process and the instances are also filtered - + Steps printsteps(this); // We want to first process all objects... @@ -709,7 +709,7 @@ void SLAPrint::process() }; SLAPrintStep print_steps[] = { slapsMergeSlicesAndEval, slapsRasterize }; - + double st = Steps::min_objstatus; BOOST_LOG_TRIVIAL(info) << "Start slicing process."; @@ -749,7 +749,7 @@ void SLAPrint::process() throw_if_canceled(); po->set_done(step); } - + incr = printsteps.progressrange(step); } } @@ -760,7 +760,7 @@ void SLAPrint::process() // this would disable the rasterization step // std::fill(m_stepmask.begin(), m_stepmask.end(), false); - + st = Steps::max_objstatus; for(SLAPrintStep currentstep : print_steps) { throw_if_canceled(); @@ -774,7 +774,7 @@ void SLAPrint::process() throw_if_canceled(); set_done(currentstep); } - + st += printsteps.progressrange(currentstep); } @@ -1132,7 +1132,7 @@ const TriangleMesh& SLAPrintObject::support_mesh() const { if(m_config.supports_enable.getBool() && m_supportdata) return m_supportdata->tree_mesh; - + return EMPTY_MESH; } @@ -1149,7 +1149,7 @@ const indexed_triangle_set &SLAPrintObject::hollowed_interior_mesh() const if (m_hollowing_data && m_hollowing_data->interior && m_config.hollowing_enable.getBool()) return sla::get_mesh(*m_hollowing_data->interior); - + return EMPTY_TRIANGLE_SET; } @@ -1174,7 +1174,7 @@ sla::SupportPoints SLAPrintObject::transformed_support_points() const for (sla::SupportPoint& suppt : spts) { suppt.pos = tr * suppt.pos; } - + return spts; } diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 4652700e0c..0c5ea4a606 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -77,7 +77,7 @@ public: // Get a pad mesh centered around origin in XY, and with zero rotation around Z applied. // Support mesh is only valid if this->is_step_done(slaposPad) is true. const TriangleMesh& pad_mesh() const; - + // Ready after this->is_step_done(slaposDrillHoles) is true const indexed_triangle_set &hollowed_interior_mesh() const; @@ -201,7 +201,7 @@ private: { return level(r1) < level(r2); }); - + if(it == cont.end()) return it; T diff = std::abs(level(*it) - lvl); @@ -307,18 +307,18 @@ private: // Caching the transformed (m_trafo) raw mesh of the object mutable CachedObject m_transformed_rmesh; - + class SupportData : public sla::SupportableMesh { public: sla::SupportTree::UPtr support_tree_ptr; // the supports std::vector support_slices; // sliced supports TriangleMesh tree_mesh, pad_mesh, full_mesh; - + inline SupportData(const TriangleMesh &t) : sla::SupportableMesh{t.its, {}, {}} {} - + sla::SupportTree::UPtr &create_support_tree(const sla::JobController &ctl) { support_tree_ptr = sla::SupportTree::create(*this, ctl); @@ -335,9 +335,9 @@ private: pad_mesh = TriangleMesh{support_tree_ptr->retrieve_mesh(sla::MeshType::Pad)}; } }; - + std::unique_ptr m_supportdata; - + class HollowingData { public: @@ -346,7 +346,7 @@ private: mutable TriangleMesh hollow_mesh_with_holes; // caching the complete hollowed mesh mutable TriangleMesh hollow_mesh_with_holes_trimmed; }; - + std::unique_ptr m_hollowing_data; }; @@ -390,15 +390,15 @@ struct SLAPrintStatistics class SLAArchive { protected: std::vector m_layers; - + virtual std::unique_ptr create_raster() const = 0; virtual sla::RasterEncoder get_encoder() const = 0; - + public: virtual ~SLAArchive() = default; - + virtual void apply(const SLAPrinterConfig &cfg) = 0; - + // Fn have to be thread safe: void(sla::RasterBase& raster, size_t lyrid); template void draw_layers( @@ -434,9 +434,9 @@ class SLAPrint : public PrintBaseWithState { private: // Prevents erroneous use by other classes. typedef PrintBaseWithState Inherited; - + class Steps; // See SLAPrintSteps.cpp - + public: SLAPrint(): m_stepmask(slapsCount, true) {} @@ -451,7 +451,7 @@ public: std::vector print_object_ids() const override; ApplyStatus apply(const Model &model, DynamicPrintConfig config) override; void set_task(const TaskParams ¶ms) override; - void process() override; + void process(bool use_cache = false) override; void finalize() override; // Returns true if an object step is done on all objects and there's at least one object. bool is_step_done(SLAPrintObjectStep step) const; @@ -501,11 +501,11 @@ public: { m_transformed_slices = std::forward(c); } - + friend class SLAPrint::Steps; public: - + explicit PrintLayer(coord_t lvl) : m_level(lvl) {} // for being sorted in their container (see m_printer_input) @@ -527,11 +527,11 @@ public: // The aggregated and leveled print records from various objects. // TODO: use this structure for the preview in the future. const std::vector& print_layers() const { return m_printer_input; } - + void set_printer(SLAArchive *archiver); - + private: - + // Implement same logic as in SLAPrintObject bool invalidate_step(SLAPrintStep st); @@ -548,24 +548,24 @@ private: // Ready-made data for rasterization. std::vector m_printer_input; - + // The archive object which collects the raster images after slicing SLAArchive *m_printer = nullptr; - + // Estimated print time, material consumed. SLAPrintStatistics m_print_statistics; - + class StatusReporter { double m_st = 0; - + public: void operator()(SLAPrint & p, double st, const std::string &msg, unsigned flags = SlicingStatus::DEFAULT, const std::string &logmsg = ""); - + double status() const { return m_st; } } m_report_status; diff --git a/src/libslic3r/Surface.hpp b/src/libslic3r/Surface.hpp index 4591e2bcdf..9494a9dcf1 100644 --- a/src/libslic3r/Surface.hpp +++ b/src/libslic3r/Surface.hpp @@ -6,7 +6,7 @@ namespace Slic3r { -enum SurfaceType { +enum SurfaceType { // Top horizontal surface, visible from the top. stTop, // Bottom horizontal surface, visible from the bottom, printed with a normal extrusion flow. @@ -39,10 +39,14 @@ public: unsigned short thickness_layers; // in layers double bridge_angle; // in radians, ccw, 0 = East, only 0+ (negative means undefined) unsigned short extra_perimeters; - + + Surface(SurfaceType _surface_type = stInternal) + : surface_type(_surface_type), + thickness(-1), thickness_layers(1), bridge_angle(-1), extra_perimeters(0) + {}; Surface(const Slic3r::Surface &rhs) : surface_type(rhs.surface_type), expolygon(rhs.expolygon), - thickness(rhs.thickness), thickness_layers(rhs.thickness_layers), + thickness(rhs.thickness), thickness_layers(rhs.thickness_layers), bridge_angle(rhs.bridge_angle), extra_perimeters(rhs.extra_perimeters) {}; @@ -52,12 +56,12 @@ public: {}; Surface(const Surface &other, const ExPolygon &_expolygon) : surface_type(other.surface_type), expolygon(_expolygon), - thickness(other.thickness), thickness_layers(other.thickness_layers), + thickness(other.thickness), thickness_layers(other.thickness_layers), bridge_angle(other.bridge_angle), extra_perimeters(other.extra_perimeters) {}; Surface(Surface &&rhs) : surface_type(rhs.surface_type), expolygon(std::move(rhs.expolygon)), - thickness(rhs.thickness), thickness_layers(rhs.thickness_layers), + thickness(rhs.thickness), thickness_layers(rhs.thickness_layers), bridge_angle(rhs.bridge_angle), extra_perimeters(rhs.extra_perimeters) {}; Surface(SurfaceType _surface_type, const ExPolygon &&_expolygon) @@ -66,7 +70,7 @@ public: {}; Surface(const Surface &other, const ExPolygon &&_expolygon) : surface_type(other.surface_type), expolygon(std::move(_expolygon)), - thickness(other.thickness), thickness_layers(other.thickness_layers), + thickness(other.thickness), thickness_layers(other.thickness_layers), bridge_angle(other.bridge_angle), extra_perimeters(other.extra_perimeters) {}; @@ -194,8 +198,8 @@ inline size_t number_polygons(const SurfacesPtr &surfaces) } // Append a vector of Surfaces at the end of another vector of polygons. -inline void polygons_append(Polygons &dst, const Surfaces &src) -{ +inline void polygons_append(Polygons &dst, const Surfaces &src) +{ dst.reserve(dst.size() + number_polygons(src)); for (Surfaces::const_iterator it = src.begin(); it != src.end(); ++ it) { dst.emplace_back(it->expolygon.contour); @@ -203,8 +207,8 @@ inline void polygons_append(Polygons &dst, const Surfaces &src) } } -inline void polygons_append(Polygons &dst, Surfaces &&src) -{ +inline void polygons_append(Polygons &dst, Surfaces &&src) +{ dst.reserve(dst.size() + number_polygons(src)); for (Surfaces::iterator it = src.begin(); it != src.end(); ++ it) { dst.emplace_back(std::move(it->expolygon.contour)); @@ -214,8 +218,8 @@ inline void polygons_append(Polygons &dst, Surfaces &&src) } // Append a vector of Surfaces at the end of another vector of polygons. -inline void polygons_append(Polygons &dst, const SurfacesPtr &src) -{ +inline void polygons_append(Polygons &dst, const SurfacesPtr &src) +{ dst.reserve(dst.size() + number_polygons(src)); for (SurfacesPtr::const_iterator it = src.begin(); it != src.end(); ++ it) { dst.emplace_back((*it)->expolygon.contour); @@ -223,8 +227,8 @@ inline void polygons_append(Polygons &dst, const SurfacesPtr &src) } } -inline void polygons_append(Polygons &dst, SurfacesPtr &&src) -{ +inline void polygons_append(Polygons &dst, SurfacesPtr &&src) +{ dst.reserve(dst.size() + number_polygons(src)); for (SurfacesPtr::const_iterator it = src.begin(); it != src.end(); ++ it) { dst.emplace_back(std::move((*it)->expolygon.contour)); @@ -234,41 +238,41 @@ inline void polygons_append(Polygons &dst, SurfacesPtr &&src) } // Append a vector of Surfaces at the end of another vector of polygons. -inline void surfaces_append(Surfaces &dst, const ExPolygons &src, SurfaceType surfaceType) -{ +inline void surfaces_append(Surfaces &dst, const ExPolygons &src, SurfaceType surfaceType) +{ dst.reserve(dst.size() + src.size()); for (const ExPolygon &expoly : src) dst.emplace_back(Surface(surfaceType, expoly)); } -inline void surfaces_append(Surfaces &dst, const ExPolygons &src, const Surface &surfaceTempl) -{ +inline void surfaces_append(Surfaces &dst, const ExPolygons &src, const Surface &surfaceTempl) +{ dst.reserve(dst.size() + number_polygons(src)); for (const ExPolygon &expoly : src) dst.emplace_back(Surface(surfaceTempl, expoly)); } -inline void surfaces_append(Surfaces &dst, const Surfaces &src) -{ +inline void surfaces_append(Surfaces &dst, const Surfaces &src) +{ dst.insert(dst.end(), src.begin(), src.end()); } -inline void surfaces_append(Surfaces &dst, ExPolygons &&src, SurfaceType surfaceType) -{ +inline void surfaces_append(Surfaces &dst, ExPolygons &&src, SurfaceType surfaceType) +{ dst.reserve(dst.size() + src.size()); for (ExPolygon &expoly : src) dst.emplace_back(Surface(surfaceType, std::move(expoly))); src.clear(); } -inline void surfaces_append(Surfaces &dst, ExPolygons &&src, const Surface &surfaceTempl) -{ +inline void surfaces_append(Surfaces &dst, ExPolygons &&src, const Surface &surfaceTempl) +{ dst.reserve(dst.size() + number_polygons(src)); for (ExPolygons::const_iterator it = src.begin(); it != src.end(); ++ it) dst.emplace_back(Surface(surfaceTempl, std::move(*it))); src.clear(); } -inline void surfaces_append(Surfaces &dst, Surfaces &&src) -{ +inline void surfaces_append(Surfaces &dst, Surfaces &&src) +{ if (dst.empty()) { dst = std::move(src); } else { @@ -283,7 +287,7 @@ extern BoundingBox get_extents(const SurfacesPtr &surfaces); inline bool surfaces_could_merge(const Surface &s1, const Surface &s2) { - return + return s1.surface_type == s2.surface_type && s1.thickness == s2.thickness && s1.thickness_layers == s2.thickness_layers && diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index 2c230bfdbd..e5688b38d1 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -13,6 +13,38 @@ #include "libslic3r.h" +//define CLI errors + +#define CLI_SUCCESS 0 +#define CLI_ENVIRONMENT_ERROR -1 +#define CLI_INVALID_PARAMS -2 +#define CLI_FILE_NOTFOUND -3 +#define CLI_FILELIST_INVALID_ORDER -4 +#define CLI_CONFIG_FILE_ERROR -5 +#define CLI_DATA_FILE_ERROR -6 +#define CLI_INVALID_PRINTER_TECH -7 +#define CLI_UNSUPPORTED_OPERATION -8 + +#define CLI_COPY_OBJECTS_ERROR -9 +#define CLI_SCALE_TO_FIT_ERROR -10 +#define CLI_EXPORT_STL_ERROR -11 +#define CLI_EXPORT_OBJ_ERROR -12 +#define CLI_EXPORT_3MF_ERROR -13 +#define CLI_OUT_OF_MEMORY -14 + +#define CLI_NO_SUITABLE_OBJECTS -50 +#define CLI_VALIDATE_ERROR -51 +#define CLI_OBJECTS_PARTLY_INSIDE -52 +#define CLI_EXPORT_CACHE_DIRECTORY_CREATE_FAILED -53 +#define CLI_EXPORT_CACHE_WRITE_FAILED -54 +#define CLI_IMPORT_CACHE_NOT_FOUND -55 +#define CLI_IMPORT_CACHE_DATA_CAN_NOT_USE -56 +#define CLI_IMPORT_CACHE_LOAD_FAILED -57 + + +#define CLI_SLICING_ERROR -100 + + namespace boost { namespace filesystem { class directory_entry; }} namespace Slic3r { @@ -161,11 +193,11 @@ namespace PerlUtils { std::string string_printf(const char *format, ...); -// Standard "generated by Slic3r version xxx timestamp xxx" header string, +// Standard "generated by Slic3r version xxx timestamp xxx" header string, // to be placed at the top of Slic3r generated files. std::string header_slic3r_generated(); -// Standard "generated by PrusaGCodeViewer version xxx timestamp xxx" header string, +// Standard "generated by PrusaGCodeViewer version xxx timestamp xxx" header string, // to be placed at the top of Slic3r generated files. std::string header_gcodeviewer_generated(); @@ -247,38 +279,38 @@ inline INDEX_TYPE next_idx_modulo(INDEX_TYPE idx, const INDEX_TYPE count) } template -inline typename CONTAINER_TYPE::size_type prev_idx_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) -{ +inline typename CONTAINER_TYPE::size_type prev_idx_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) +{ return prev_idx_modulo(idx, container.size()); } template inline typename CONTAINER_TYPE::size_type next_idx_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) -{ +{ return next_idx_modulo(idx, container.size()); } template inline const typename CONTAINER_TYPE::value_type& prev_value_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) -{ +{ return container[prev_idx_modulo(idx, container.size())]; } template -inline typename CONTAINER_TYPE::value_type& prev_value_modulo(typename CONTAINER_TYPE::size_type idx, CONTAINER_TYPE &container) -{ +inline typename CONTAINER_TYPE::value_type& prev_value_modulo(typename CONTAINER_TYPE::size_type idx, CONTAINER_TYPE &container) +{ return container[prev_idx_modulo(idx, container.size())]; } template inline const typename CONTAINER_TYPE::value_type& next_value_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container) -{ +{ return container[next_idx_modulo(idx, container.size())]; } template inline typename CONTAINER_TYPE::value_type& next_value_modulo(typename CONTAINER_TYPE::size_type idx, CONTAINER_TYPE &container) -{ +{ return container[next_idx_modulo(idx, container.size())]; } @@ -300,7 +332,7 @@ template struct IsTriviallyCopyable : public std::is_trivially_copya struct FilePtr { FilePtr(FILE *f) : f(f) {} ~FilePtr() { this->close(); } - void close() { + void close() { if (this->f) { ::fclose(this->f); this->f = nullptr;