Merge branch 'merge-upstream'

Signed-off-by: SoftFever <softfeverever@gmail.com>

# Conflicts:
#	src/libslic3r/Preset.cpp
#	src/libslic3r/PrintConfig.cpp
#	src/libslic3r/PrintConfig.hpp
This commit is contained in:
SoftFever 2023-09-30 08:44:32 +08:00
commit 59bab91da9
579 changed files with 23269 additions and 11097 deletions

View file

@ -80,20 +80,196 @@ using ItemGroup = std::vector<std::reference_wrapper<Item>>;
const double BIG_ITEM_TRESHOLD = 0.02;
#define VITRIFY_TEMP_DIFF_THRSH 15 // bed temp can be higher than vitrify temp, but not higher than this thresh
void update_arrange_params(ArrangeParams& params, const DynamicPrintConfig& print_cfg, const ArrangePolygons& selected)
{
double skirt_distance = get_real_skirt_dist(print_cfg);
// Note: skirt_distance is now defined between outermost brim and skirt, not the object and skirt.
// So we can't do max but do adding instead.
params.brim_skirt_distance = skirt_distance;
params.bed_shrink_x = params.brim_skirt_distance;
params.bed_shrink_y = params.brim_skirt_distance;
// for sequential print, we need to inflate the bed because cleareance_radius is so large
if (params.is_seq_print) {
float shift_dist = params.cleareance_radius / 2 - 5;
params.bed_shrink_x -= shift_dist;
params.bed_shrink_y -= shift_dist;
}
}
void update_selected_items_inflation(ArrangePolygons& selected, const DynamicPrintConfig* print_cfg, ArrangeParams& params) {
// do not inflate brim_width. Objects are allowed to have overlapped brim.
Points bedpts = get_shrink_bedpts(print_cfg, params);
BoundingBox bedbb = Polygon(bedpts).bounding_box();
// set obj distance for auto seq_print
if (params.min_obj_distance == 0 && params.is_seq_print)
params.min_obj_distance = scaled(params.cleareance_radius + 0.001);
double brim_max = 0;
bool plate_has_tree_support = false;
std::for_each(selected.begin(), selected.end(), [&](ArrangePolygon& ap) {
brim_max = std::max(brim_max, ap.brim_width);
if (ap.has_tree_support) plate_has_tree_support = true; });
std::for_each(selected.begin(), selected.end(), [&](ArrangePolygon& ap) {
// 1. if user input a distance, use it
// 2. if there is an object with tree support, all objects use the max tree branch radius (brim_max=branch diameter)
// 3. otherwise, use each object's own brim width
ap.inflation = params.min_obj_distance != 0 ? params.min_obj_distance / 2 :
plate_has_tree_support ? scaled(brim_max / 2) : scaled(ap.brim_width);
BoundingBox apbb = ap.poly.contour.bounding_box();
auto diffx = bedbb.size().x() - apbb.size().x() - 5;
auto diffy = bedbb.size().y() - apbb.size().y() - 5;
if (diffx > 0 && diffy > 0) {
auto min_diff = std::min(diffx, diffy);
ap.inflation = std::min(min_diff / 2, ap.inflation);
}
});
}
void update_unselected_items_inflation(ArrangePolygons& unselected, const DynamicPrintConfig* print_cfg, const ArrangeParams& params)
{
if (params.is_seq_print) {
float shift_dist = params.cleareance_radius / 2 - 5;
// dont forget to move the excluded region
for (auto& region : unselected) {
if (region.is_virt_object) region.poly.translate(-scaled(shift_dist), -scaled(shift_dist));
}
}
// For occulusion regions, inflation should be larger to prevent genrating brim on them.
// However, extrusion cali regions are exceptional, since we can allow brim overlaps them.
// 屏蔽区域只需要膨胀brim宽度防止brim长过去挤出标定区域不需要膨胀brim可以长过去。
// 以前我们认为还需要膨胀clearance_radius/2这其实是不需要的因为这些区域并不会真的摆放物体
// 其他物体的膨胀轮廓是可以跟它们重叠的。
double scaled_exclusion_gap = scale_(1);
std::for_each(unselected.begin(), unselected.end(),
[&](auto& ap) { ap.inflation = !ap.is_virt_object ? (params.min_obj_distance == 0 ? scaled(ap.brim_width) : params.min_obj_distance / 2)
: (ap.is_extrusion_cali_object ? 0 : scaled_exclusion_gap); });
}
void update_selected_items_axis_align(ArrangePolygons& selected, const DynamicPrintConfig* print_cfg, const ArrangeParams& params)
{
// now only need to consider "Align to x axis"
if (!params.align_to_y_axis)
return;
for (ArrangePolygon& ap : selected) {
bool validResult = false;
double angle = 0.0;
{
const auto& pts = ap.transformed_poly().contour;
int lpt = pts.size();
double a00 = 0, a10 = 0, a01 = 0, a20 = 0, a11 = 0, a02 = 0, a30 = 0, a21 = 0, a12 = 0, a03 = 0;
double xi, yi, xi2, yi2, xi_1, yi_1, xi_12, yi_12, dxy, xii_1, yii_1;
xi_1 = pts.back().x();
yi_1 = pts.back().y();
xi_12 = xi_1 * xi_1;
yi_12 = yi_1 * yi_1;
for (int i = 0; i < lpt; i++) {
xi = pts[i].x();
yi = pts[i].y();
xi2 = xi * xi;
yi2 = yi * yi;
dxy = xi_1 * yi - xi * yi_1;
xii_1 = xi_1 + xi;
yii_1 = yi_1 + yi;
a00 += dxy;
a10 += dxy * xii_1;
a01 += dxy * yii_1;
a20 += dxy * (xi_1 * xii_1 + xi2);
a11 += dxy * (xi_1 * (yii_1 + yi_1) + xi * (yii_1 + yi));
a02 += dxy * (yi_1 * yii_1 + yi2);
a30 += dxy * xii_1 * (xi_12 + xi2);
a03 += dxy * yii_1 * (yi_12 + yi2);
a21 += dxy * (xi_12 * (3 * yi_1 + yi) + 2 * xi * xi_1 * yii_1 + xi2 * (yi_1 + 3 * yi));
a12 += dxy * (yi_12 * (3 * xi_1 + xi) + 2 * yi * yi_1 * xii_1 + yi2 * (xi_1 + 3 * xi));
xi_1 = xi;
yi_1 = yi;
xi_12 = xi2;
yi_12 = yi2;
}
if (std::abs(a00) > EPSILON) {
double db1_2, db1_6, db1_12, db1_24, db1_20, db1_60;
double m00, m10, m01, m20, m11, m02, m30, m21, m12, m03;
if (a00 > 0) {
db1_2 = 0.5;
db1_6 = 0.16666666666666666666666666666667;
db1_12 = 0.083333333333333333333333333333333;
db1_24 = 0.041666666666666666666666666666667;
db1_20 = 0.05;
db1_60 = 0.016666666666666666666666666666667;
}
else {
db1_2 = -0.5;
db1_6 = -0.16666666666666666666666666666667;
db1_12 = -0.083333333333333333333333333333333;
db1_24 = -0.041666666666666666666666666666667;
db1_20 = -0.05;
db1_60 = -0.016666666666666666666666666666667;
}
m00 = a00 * db1_2;
m10 = a10 * db1_6;
m01 = a01 * db1_6;
m20 = a20 * db1_12;
m11 = a11 * db1_24;
m02 = a02 * db1_12;
m30 = a30 * db1_20;
m21 = a21 * db1_60;
m12 = a12 * db1_60;
m03 = a03 * db1_20;
double cx = m10 / m00;
double cy = m01 / m00;
double a = m20 / m00 - cx * cx;
double b = m11 / m00 - cx * cy;
double c = m02 / m00 - cy * cy;
//if a and c are close, there is no dominant axis, then do not rotate
if (std::abs(a) < 1.5*std::abs(c) && std::abs(c) < 1.5*std::abs(a)) {
validResult = false;
}
else {
angle = std::atan2(2 * b, (a - c)) / 2;
validResult = true;
}
}
}
if (validResult) { ap.rotation += (PI / 2 - angle); }
}
}
//it will bed accurate after call update_params
Points get_shrink_bedpts(const DynamicPrintConfig* print_cfg, const ArrangeParams& params)
{
Points bedpts = get_bed_shape(*print_cfg);
// shrink bed by moving to center by dist
auto shrinkFun = [](Points& bedpts, double dist, int direction) {
#define SGN(x) ((x) >= 0 ? 1 : -1)
Point center = Polygon(bedpts).bounding_box().center();
for (auto& pt : bedpts) pt[direction] += dist * SGN(center[direction] - pt[direction]);
};
shrinkFun(bedpts, scaled(params.bed_shrink_x), 0);
shrinkFun(bedpts, scaled(params.bed_shrink_y), 1);
return bedpts;
}
// Fill in the placer algorithm configuration with values carefully chosen for
// Slic3r.
template<class PConf>
void fill_config(PConf& pcfg, const ArrangeParams &params) {
if (params.is_seq_print) {
// Start placing the items from the center of the print bed
pcfg.starting_point = PConf::Alignment::BOTTOM_LEFT;
}
else {
// Start placing the items from the center of the print bed
pcfg.starting_point = PConf::Alignment::TOP_RIGHT;
}
if (params.is_seq_print) {
// Start placing the items from the center of the print bed
pcfg.starting_point = PConf::Alignment::BOTTOM_LEFT;
}
else {
// Start placing the items from the center of the print bed
pcfg.starting_point = PConf::Alignment::TOP_RIGHT;
}
if (params.do_final_align) {
// Align the arranged pile into the center of the bin
pcfg.alignment = PConf::Alignment::CENTER;
@ -495,6 +671,14 @@ public:
m_norm = std::sqrt(m_bin_area);
fill_config(m_pconf, params);
this->params = params;
// if best object center is not bed center, specify starting point here
if (std::abs(this->params.align_center.x() - 0.5) > 0.001 || std::abs(this->params.align_center.y() - 0.5) > 0.001) {
auto binbb = sl::boundingBox(m_bin);
m_pconf.best_object_pos = binbb.minCorner() + Point{ binbb.width() * this->params.align_center.x(), binbb.height() * this->params.align_center.y() };
m_pconf.alignment = PConfig::Alignment::USER_DEFINED;
}
for (auto& region : m_pconf.m_excluded_regions) {
Box bb = region.boundingBox();
m_excluded_and_extruCali_regions.emplace_back(bb);
@ -551,6 +735,7 @@ public:
for (Item itm : items) {
if (itm.is_wipe_tower) {
starting_point = itm.boundingBox().center();
BOOST_LOG_TRIVIAL(debug) << "arrange we have wipe tower, change starting point to: " << starting_point;
break;
}
}
@ -575,15 +760,13 @@ public:
if (on_packed)
on_packed(ap);
BOOST_LOG_TRIVIAL(debug) << "arrange " + last_packed.name + " succeed!"
<< ", plate id=" << ap.bed_idx;
<< ", plate id=" << ap.bed_idx << ", pos=" << last_packed.translation();
}
});
if (progressind) {
m_pck.unfitIndicator([this, progressind](std::string name) {
BOOST_LOG_TRIVIAL(debug) << "arrange not fit: " + name;
m_pck.unfitIndicator([this](std::string name) {
BOOST_LOG_TRIVIAL(debug) << "arrange progress: " + name;
});
}
if (stopcond) m_pck.stopCondition(stopcond);

View file

@ -2,7 +2,7 @@
#define ARRANGE_HPP
#include "ExPolygon.hpp"
#include "PrintConfig.hpp"
namespace Slic3r {
class BoundingBox;
@ -53,7 +53,8 @@ struct ArrangePolygon {
int locked_plate{ -1 };
bool is_virt_object{ false };
bool is_extrusion_cali_object{ false };
bool is_wipe_tower{false};
bool is_wipe_tower{ false };
bool has_tree_support{false};
//BBS: add row/col for sudoku-style layout
int row{0};
int col{0};
@ -120,6 +121,7 @@ struct ArrangeParams {
bool allow_multi_materials_on_same_plate = true;
bool avoid_extrusion_cali_region = true;
bool is_seq_print = false;
bool align_to_y_axis = false;
float bed_shrink_x = 0;
float bed_shrink_y = 0;
float brim_skirt_distance = 0;
@ -127,6 +129,7 @@ struct ArrangeParams {
float clearance_height_to_lid = 0;
float cleareance_radius = 0;
float printable_height = 256.0;
Vec2d align_center{ 0.5,0.5 };
ArrangePolygons excluded_regions; // regions cant't be used
ArrangePolygons nonprefered_regions; // regions can be used but not prefered
@ -144,8 +147,39 @@ struct ArrangeParams {
ArrangeParams() = default;
explicit ArrangeParams(coord_t md) : min_obj_distance(md) {}
// to json format
std::string to_json() const{
std::string ret = "{";
ret += "\"min_obj_distance\":" + std::to_string(min_obj_distance) + ",";
ret += "\"accuracy\":" + std::to_string(accuracy) + ",";
ret += "\"parallel\":" + std::to_string(parallel) + ",";
ret += "\"allow_rotations\":" + std::to_string(allow_rotations) + ",";
ret += "\"do_final_align\":" + std::to_string(do_final_align) + ",";
ret += "\"allow_multi_materials_on_same_plate\":" + std::to_string(allow_multi_materials_on_same_plate) + ",";
ret += "\"avoid_extrusion_cali_region\":" + std::to_string(avoid_extrusion_cali_region) + ",";
ret += "\"is_seq_print\":" + std::to_string(is_seq_print) + ",";
ret += "\"bed_shrink_x\":" + std::to_string(bed_shrink_x) + ",";
ret += "\"bed_shrink_y\":" + std::to_string(bed_shrink_y) + ",";
ret += "\"brim_skirt_distance\":" + std::to_string(brim_skirt_distance) + ",";
ret += "\"clearance_height_to_rod\":" + std::to_string(clearance_height_to_rod) + ",";
ret += "\"clearance_height_to_lid\":" + std::to_string(clearance_height_to_lid) + ",";
ret += "\"cleareance_radius\":" + std::to_string(cleareance_radius) + ",";
ret += "\"printable_height\":" + std::to_string(printable_height) + ",";
return ret;
}
};
void update_arrange_params(ArrangeParams& params, const DynamicPrintConfig& print_cfg, const ArrangePolygons& selected);
void update_selected_items_inflation(ArrangePolygons& selected, const DynamicPrintConfig* print_cfg, ArrangeParams& params);
void update_unselected_items_inflation(ArrangePolygons& unselected, const DynamicPrintConfig* print_cfg, const ArrangeParams& params);
void update_selected_items_axis_align(ArrangePolygons& selected, const DynamicPrintConfig* print_cfg, const ArrangeParams& params);
Points get_shrink_bedpts(const DynamicPrintConfig* print_cfg, const ArrangeParams& params);
/**
* \brief Arranges the input polygons.
*

View file

@ -416,6 +416,8 @@ set(lisbslic3r_sources
if (APPLE)
list(APPEND lisbslic3r_sources
MacUtils.mm
Format/ModelIO.hpp
Format/ModelIO.mm
)
endif ()
@ -532,6 +534,12 @@ if(NOT WIN32)
endif()
endif()
if (APPLE)
find_library(FOUNDATION Foundation REQUIRED)
find_library(MODELIO ModelIO REQUIRED)
target_link_libraries(libslic3r ${FOUNDATION} ${MODELIO})
endif ()
if (TARGET OpenVDB::openvdb)
target_link_libraries(libslic3r OpenVDB::openvdb)
endif()

View file

@ -786,6 +786,7 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex
try {
boost::nowide::ifstream ifs(file);
ifs >> j;
ifs.close();
const ConfigDef* config_def = this->def();
if (config_def == nullptr) {

View file

@ -534,23 +534,26 @@ public:
}
return false;
}
size_t i = 0;
size_t cnt = std::min(this->size(), rhs_vec->size());
bool modified = false;
for (; i < cnt; ++ i)
if (! rhs_vec->is_nil(i) && this->values[i] != rhs_vec->values[i]) {
this->values[i] = rhs_vec->values[i];
modified = true;
}
for (; i < rhs_vec->size(); ++ i)
if (! rhs_vec->is_nil(i)) {
if (this->values.empty())
this->values.resize(i + 1);
else
this->values.resize(i + 1, this->values.front());
this->values[i] = rhs_vec->values[i];
modified = true;
}
if (cnt < 1)
return false;
if (this->values.empty())
this->values.resize(rhs_vec->size());
else
this->values.resize(rhs_vec->size(), this->values.front());
bool modified = false;
auto default_value = this->values[0];
for (size_t i = 0; i < rhs_vec->size(); ++i) {
if (!rhs_vec->is_nil(i)) {
this->values[i] = rhs_vec->values[i];
modified = true;
} else {
this->values[i] = default_value;
}
}
return modified;
}

View file

@ -3,6 +3,7 @@
#include <string>
#include <vector>
#include <nlohmann/json.hpp>
namespace Slic3r {
@ -43,6 +44,24 @@ struct Item
std::string extra; // this field is used for the extra data like :
// - G-code text for the Type::Custom
// - message text for the Type::PausePrint
void from_json(const nlohmann::json& j) {
std::string type_str;
j.at("type").get_to(type_str);
std::map<std::string,Type> str2type = { {"ColorChange", ColorChange },
{"PausePrint",PausePrint},
{"ToolChange",ToolChange},
{"Template",Template},
{"Custom",Custom},
{"Unknown",Unknown} };
type = Unknown;
if (str2type.find(type_str) != str2type.end())
type = str2type[type_str];
j.at("print_z").get_to(print_z);
j.at("color").get_to(color);
j.at("extruder").get_to(extruder);
if(j.contains("extra"))
j.at("extra").get_to(extra);
}
};
enum Mode
@ -71,6 +90,24 @@ struct Info
(rhs.gcodes == this->gcodes );
}
bool operator!=(const Info& rhs) const { return !(*this == rhs); }
void from_json(const nlohmann::json& j) {
std::string mode_str;
if (j.contains("mode"))
j.at("mode").get_to(mode_str);
if (mode_str == "SingleExtruder") mode = SingleExtruder;
else if (mode_str == "MultiAsSingle") mode = MultiAsSingle;
else if (mode_str == "MultiExtruder") mode = MultiExtruder;
else mode = Undef;
auto j_gcodes = j.at("gcodes");
gcodes.reserve(j_gcodes.size());
for (auto& jj : j_gcodes) {
Item item;
item.from_json(jj);
gcodes.push_back(item);
}
}
};
// If loaded configuration has a "colorprint_heights" option (if it was imported from older Slicer),

View file

@ -786,7 +786,7 @@ void Layer::make_ironing()
// Check whether there is any non-solid hole in the regions.
bool internal_infill_solid = region_config.sparse_infill_density.value > 95.;
for (const Surface &surface : ironing_params.layerm->fill_surfaces.surfaces)
if ((! internal_infill_solid && surface.surface_type == stInternal) || surface.surface_type == stInternalBridge || surface.surface_type == stInternalVoid) {
if ((!internal_infill_solid && surface.surface_type == stInternal) || surface.surface_type == stInternalBridge || surface.surface_type == stInternalVoid || surface.surface_type==stInternalWithLoop) {
// Some fill region is not quite solid. Don't iron over the whole surface.
iron_completely = false;
break;
@ -798,7 +798,7 @@ void Layer::make_ironing()
polygons_append(polys, surface.expolygon);
} else {
for (const Surface &surface : ironing_params.layerm->slices.surfaces)
if (surface.surface_type == stTop || (iron_everything && surface.surface_type == stBottom))
if ((surface.surface_type == stTop && region_config.top_shell_layers > 0) || (iron_everything && surface.surface_type == stBottom && region_config.bottom_shell_layers > 0))
// stBottomBridge is not being ironed on purpose, as it would likely destroy the bridges.
polygons_append(polys, surface.expolygon);
}

View file

@ -0,0 +1,19 @@
#include <string>
namespace Slic3r {
/**
* Uses ModelIO to convert supported model types to a temporary STL
* that can then be consumed by the existing STL loader
* @param input_file The File to load
* @return Path to the temporary file, or an empty string if conversion failed
*/
std::string make_temp_stl_with_modelio(const std::string &input_file);
/**
* Convenience function to delete the file.
* No return value since success isn't required
* @param temp_file File path to delete
*/
void delete_temp_file(const std::string &temp_file);
}

View file

@ -0,0 +1,27 @@
#include "ModelIO.hpp"
#import <ModelIO/ModelIO.h>
namespace Slic3r {
std::string make_temp_stl_with_modelio(const std::string &input_file)
{
NSURL *input_url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:input_file.c_str()]];
MDLAsset *asset = [[MDLAsset alloc] initWithURL:input_url];
NSString *tmp_file_name = [[[NSUUID UUID] UUIDString] stringByAppendingPathExtension:@"stl"];
NSURL *tmp_file_url = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:tmp_file_name]];
if ([asset exportAssetToURL:tmp_file_url]) {
std::string output_file = std::string([[tmp_file_url path] UTF8String]);
return output_file;
}
return std::string();
}
void delete_temp_file(const std::string &temp_file)
{
NSString *file_path = [NSString stringWithUTF8String:temp_file.c_str()];
[[NSFileManager defaultManager] removeItemAtPath:file_path error:NULL];
}
} // namespace Slic3r

View file

@ -116,6 +116,7 @@ const std::string BBL_DESIGNER_USER_ID_TAG = "DesignerUserId";
const std::string BBL_DESIGNER_COVER_FILE_TAG = "DesignerCover";
const std::string BBL_DESCRIPTION_TAG = "Description";
const std::string BBL_COPYRIGHT_TAG = "CopyRight";
const std::string BBL_COPYRIGHT_NORMATIVE_TAG = "Copyright";
const std::string BBL_LICENSE_TAG = "License";
const std::string BBL_REGION_TAG = "Region";
const std::string BBL_MODIFICATION_TAG = "ModificationDate";
@ -226,11 +227,14 @@ static constexpr const char* HIT_NORMAL_ATTR = "hit_normal";
// BBS: encrypt
static constexpr const char* RELATIONSHIP_TAG = "Relationship";
static constexpr const char* PID_ATTR = "pid";
static constexpr const char* PUUID_ATTR = "p:uuid";
static constexpr const char* PUUID_ATTR = "p:UUID";
static constexpr const char* PUUID_LOWER_ATTR = "p:uuid";
static constexpr const char* PPATH_ATTR = "p:path";
static constexpr const char *OBJECT_UUID_SUFFIX = "-61cb-4c03-9d28-80fed5dfa1dc";
static constexpr const char *OBJECT_UUID_SUFFIX2 = "-71cb-4c03-9d28-80fed5dfa1dc";
static constexpr const char* BUILD_UUID = "d8eb061-b1ec-4553-aec9-835e5b724bb4";
static constexpr const char *SUB_OBJECT_UUID_SUFFIX = "-81cb-4c03-9d28-80fed5dfa1dc";
static constexpr const char *COMPONENT_UUID_SUFFIX = "-b206-40ff-9872-83e8017abed1";
static constexpr const char* BUILD_UUID = "2c7c17d8-22b5-4d84-8835-1976022ea369";
static constexpr const char* BUILD_UUID_SUFFIX = "-b1ec-4553-aec9-835e5b724bb4";
static constexpr const char* TARGET_ATTR = "Target";
static constexpr const char* RELS_TYPE_ATTR = "Type";
@ -281,6 +285,8 @@ static constexpr const char* PLATER_NAME_ATTR = "plater_name";
static constexpr const char* PLATE_IDX_ATTR = "index";
static constexpr const char* SLICE_PREDICTION_ATTR = "prediction";
static constexpr const char* SLICE_WEIGHT_ATTR = "weight";
static constexpr const char* TIMELAPSE_TYPE_ATTR = "timelapse_type";
static constexpr const char* TIMELAPSE_ERROR_CODE_ATTR = "timelapse_error_code";
static constexpr const char* OUTSIDE_ATTR = "outside";
static constexpr const char* SUPPORT_USED_ATTR = "support_used";
static constexpr const char* LABEL_OBJECT_ENABLED_ATTR = "label_object_enabled";
@ -1679,7 +1685,12 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
std::string name(stat.m_filename);
std::replace(name.begin(), name.end(), '\\', '/');
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("extract %1%th file %2%, total=%3%\n")%(i+1)%name%num_entries;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format("extract %1%th file %2%, total=%3%")%(i+1)%name%num_entries;
if (name.find("/../") != std::string::npos) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", find file path including /../, not valid, skip it\n");
continue;
}
if (boost::algorithm::iequals(name, BBS_LAYER_HEIGHTS_PROFILE_FILE)) {
// extract slic3r layer heights profile file
@ -1763,6 +1774,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
//BBS parsing pattern config files
_extract_file_from_archive(archive, stat);
}
else {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", %1% skipped, already parsed or a directory or not supported\n")%name;
}
}
}
@ -2175,7 +2189,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
}
}
char error_buf[1024];
::sprintf(error_buf, "File %s not found from archive", path.c_str());
::snprintf(error_buf, 1024, "File %s not found from archive", path.c_str());
add_error(error_buf);
return false;
}
@ -2234,7 +2248,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
if (!XML_ParseBuffer(m_xml_parser, (int)stat.m_uncomp_size, 1)) {
char error_buf[1024];
::sprintf(error_buf, "Error (%s) while parsing xml file at line %d", XML_ErrorString(XML_GetErrorCode(m_xml_parser)), (int)XML_GetCurrentLineNumber(m_xml_parser));
::snprintf(error_buf, 1024, "Error (%s) while parsing xml file at line %d", XML_ErrorString(XML_GetErrorCode(m_xml_parser)), (int)XML_GetCurrentLineNumber(m_xml_parser));
add_error(error_buf);
return false;
}
@ -2280,7 +2294,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
CallbackData* data = (CallbackData*)pOpaque;
if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->importer.parse_error()) {
char error_buf[1024];
::sprintf(error_buf, "Error (%s) while parsing '%s' at line %d", data->importer.parse_error_message(), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser));
::snprintf(error_buf, 1024, "Error (%s) while parsing '%s' at line %d", data->importer.parse_error_message(), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser));
throw Slic3r::FileIOError(error_buf);
}
return n;
@ -2501,6 +2515,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
void _BBS_3MF_Importer::_extract_auxiliary_file_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model)
{
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", stat.m_uncomp_size is %1%")%stat.m_uncomp_size;
if (stat.m_uncomp_size > 0) {
std::string dest_file;
if (stat.m_is_utf8) {
@ -2518,6 +2533,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
dest_file = dest_file.substr(found + AUXILIARY_STR_LEN);
else
return;
if (dest_file.find('/') != std::string::npos) {
boost::filesystem::path src_path = boost::filesystem::path(dest_file);
boost::filesystem::path parent_path = src_path.parent_path();
@ -3175,6 +3191,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
m_curr_object->name = bbs_get_attribute_value_string(attributes, num_attributes, NAME_ATTR);
m_curr_object->uuid = bbs_get_attribute_value_string(attributes, num_attributes, PUUID_ATTR);
if (m_curr_object->uuid.empty()) {
m_curr_object->uuid = bbs_get_attribute_value_string(attributes, num_attributes, PUUID_LOWER_ATTR);
}
m_curr_object->pid = bbs_get_attribute_value_int(attributes, num_attributes, PID_ATTR);
}
@ -3563,7 +3582,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found license = " << m_curr_characters;
model_info.license = xml_unescape(m_curr_characters);
} else if (m_curr_metadata_name == BBL_COPYRIGHT_TAG) {
BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found copyright = " << m_curr_characters;
BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found CopyRight = " << m_curr_characters;
model_info.copyright = xml_unescape(m_curr_characters);
} else if (m_curr_metadata_name == BBL_COPYRIGHT_NORMATIVE_TAG) {
BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found Copyright = " << m_curr_characters;
model_info.copyright = xml_unescape(m_curr_characters);
} else if (m_curr_metadata_name == BBL_REGION_TAG) {
BOOST_LOG_TRIVIAL(trace) << "design_info, load_3mf found region = " << m_curr_characters;
@ -4027,7 +4049,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
{
if (!m_curr_plater)
{
add_error("don't find plater created before");
add_error("_handle_end_config_plater: don't find plate created before");
return false;
}
m_plater_data.emplace(m_curr_plater->plate_index, m_curr_plater);
@ -4039,7 +4061,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
{
if (!m_curr_plater)
{
add_error("don't find plater created before");
add_error("_handle_start_config_plater_instance: don't find plate created before");
return false;
}
@ -4051,7 +4073,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
{
if (!m_curr_plater)
{
add_error("don't find plater created before");
add_error("_handle_end_config_plater_instance: don't find plate created before");
return false;
}
if ((m_curr_instance.object_id == -1) || (m_curr_instance.instance_id == -1))
@ -4430,6 +4452,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
volume->supported_facets.shrink_to_fit();
volume->seam_facets.shrink_to_fit();
volume->mmu_segmentation_facets.shrink_to_fit();
volume->mmu_segmentation_facets.touch();
}
volume->set_type(volume_data->part_type);
@ -4709,6 +4732,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
current_object->name = bbs_get_attribute_value_string(attributes, num_attributes, NAME_ATTR);
current_object->uuid = bbs_get_attribute_value_string(attributes, num_attributes, PUUID_ATTR);
if (current_object->uuid.empty()) {
current_object->uuid = bbs_get_attribute_value_string(attributes, num_attributes, PUUID_LOWER_ATTR);
}
current_object->pid = bbs_get_attribute_value_int(attributes, num_attributes, PID_ATTR);
}
@ -5096,7 +5122,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
CallbackData* data = (CallbackData*)pOpaque;
if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->importer.object_parse_error()) {
char error_buf[1024];
::sprintf(error_buf, "Error (%s) while parsing '%s' at line %d", data->importer.object_parse_error_message(), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser));
::snprintf(error_buf, 1024, "Error (%s) while parsing '%s' at line %d", data->importer.object_parse_error_message(), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser));
throw Slic3r::FileIOError(error_buf);
}
return n;
@ -5219,7 +5245,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
bool _add_content_types_file_to_archive(mz_zip_archive& archive);
bool _add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data, const char* local_path, int index);
bool _add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data, const char* local_path, int index, bool generate_small_thumbnail = false);
bool _add_calibration_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data, int index);
bool _add_bbox_file_to_archive(mz_zip_archive& archive, const PlateBBoxData& id_bboxes, int index);
bool _add_relationships_file_to_archive(mz_zip_archive & archive,
@ -5245,7 +5271,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
bool _add_project_embedded_presets_to_archive(mz_zip_archive& archive, Model& model, std::vector<Preset*> project_presets);
bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const ObjectToObjectDataMap &objects_data, int export_plate_idx = -1, bool save_gcode = true, bool use_loaded_id = false);
bool _add_cut_information_file_to_archive(mz_zip_archive &archive, Model &model);
bool _add_slice_info_config_file_to_archive(mz_zip_archive &archive, const Model &model, PlateDataPtrs &plate_data_list, const ObjectToObjectDataMap &objects_data);
bool _add_slice_info_config_file_to_archive(mz_zip_archive &archive, const Model &model, PlateDataPtrs &plate_data_list, const ObjectToObjectDataMap &objects_data, const DynamicPrintConfig& config);
bool _add_gcode_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, Export3mfProgressFn proFn = nullptr);
bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model, const DynamicPrintConfig* config);
bool _add_auxiliary_dir_to_archive(mz_zip_archive &archive, const std::string &aux_dir, PackingTemporaryData &data);
@ -5464,9 +5490,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
{
if (thumbnail_data[index]->is_valid())
{
if (!_add_thumbnail_file_to_archive(archive, *thumbnail_data[index], "Metadata/plate", index)) {
if (!_add_thumbnail_file_to_archive(archive, *thumbnail_data[index], "Metadata/plate", index, true)) {
return false;
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(",add thumbnail %1%'s data into 3mf")%(index+1);
thumbnail_status[index] = true;
}
@ -5746,7 +5773,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
// Adds sliced info of plate file ("Metadata/slice_info.config")
// This file contains all sliced info of all plates
if (!_add_slice_info_config_file_to_archive(archive, model, plate_data_list, objects_data)) {
if (!_add_slice_info_config_file_to_archive(archive, model, plate_data_list, objects_data, *config)) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", _add_slice_info_config_file_to_archive failed\n");
return false;
}
@ -5843,7 +5870,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return true;
}
bool _BBS_3MF_Exporter::_add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data, const char* local_path, int index)
bool _BBS_3MF_Exporter::_add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data, const char* local_path, int index, bool generate_small_thumbnail)
{
bool res = false;
@ -5860,6 +5887,49 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to add thumbnail file to archive\n");
}
if (generate_small_thumbnail && thumbnail_data.is_valid()) {
//generate small size of thumbnail
std::vector<unsigned char> small_pixels;
small_pixels.resize(PLATE_THUMBNAIL_SMALL_WIDTH * PLATE_THUMBNAIL_SMALL_HEIGHT * 4);
/* step width and step height */
int sw = thumbnail_data.width / PLATE_THUMBNAIL_SMALL_WIDTH;
int sh = thumbnail_data.height / PLATE_THUMBNAIL_SMALL_HEIGHT;
for (int i = 0; i < thumbnail_data.height; i += sh) {
for (int j = 0; j < thumbnail_data.width; j += sw) {
int r = 0, g = 0, b = 0, a = 0;
for (int m = 0; m < sh; m++) {
for (int n = 0; n < sw; n++) {
r += (int)thumbnail_data.pixels[4 * ((i + m) * thumbnail_data.width + j + n) + 0];
g += (int)thumbnail_data.pixels[4 * ((i + m) * thumbnail_data.width + j + n) + 1];
b += (int)thumbnail_data.pixels[4 * ((i + m) * thumbnail_data.width + j + n) + 2];
a += (int)thumbnail_data.pixels[4 * ((i + m) * thumbnail_data.width + j + n) + 3];
}
}
r = std::clamp(0, r / sw / sh, 255);
g = std::clamp(0, g / sw / sh, 255);
b = std::clamp(0, b / sw / sh, 255);
a = std::clamp(0, a / sw / sh, 255);
small_pixels[4 * (i / sw * PLATE_THUMBNAIL_SMALL_WIDTH + j / sh) + 0] = (unsigned char)r;
small_pixels[4 * (i / sw * PLATE_THUMBNAIL_SMALL_WIDTH + j / sh) + 1] = (unsigned char)g;
small_pixels[4 * (i / sw * PLATE_THUMBNAIL_SMALL_WIDTH + j / sh) + 2] = (unsigned char)b;
small_pixels[4 * (i / sw * PLATE_THUMBNAIL_SMALL_WIDTH + j / sh) + 3] = (unsigned char)a;
//memcpy((void*)&small_pixels[4*(i / sw * PLATE_THUMBNAIL_SMALL_WIDTH + j / sh)], thumbnail_data.pixels.data() + 4*(i * thumbnail_data.width + j), 4);
}
}
size_t small_png_size = 0;
void* small_png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)small_pixels.data(), PLATE_THUMBNAIL_SMALL_WIDTH, PLATE_THUMBNAIL_SMALL_HEIGHT, 4, &small_png_size, MZ_DEFAULT_COMPRESSION, 1);
if (png_data != nullptr) {
std::string thumbnail_name = (boost::format("%1%_%2%_small.png") % local_path % (index + 1)).str();
res = mz_zip_writer_add_mem(&archive, thumbnail_name.c_str(), (const void*)small_png_data, small_png_size, MZ_NO_COMPRESSION);
mz_free(small_png_data);
}
if (!res) {
add_error("Unable to add small thumbnail file to archive");
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", Unable to add small thumbnail file to archive\n");
}
}
return res;
}
@ -5909,27 +5979,46 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
if (from.empty()) {
stream << " <Relationship Target=\"/" << MODEL_FILE << "\" Id=\"rel-1\" Type=\"http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel\"/>\n";
if (data._3mf_thumbnail.empty()) {
if (export_plate_idx < 0) {
stream << " <Relationship Target=\"/" << THUMBNAIL_FILE
<< "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
if (export_plate_idx < 0) {
//use cover image if have
if (data._3mf_thumbnail.empty()) {
stream << " <Relationship Target=\"/Metadata/plate_1.png"
<< "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
} else {
std::string thumbnail_file_str = (boost::format("Metadata/plate_%1%.png") % (export_plate_idx + 1)).str();
stream << " <Relationship Target=\"/" << xml_escape(thumbnail_file_str)
<< "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_thumbnail)
<< "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
}
} else {
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_thumbnail)
<< "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
}
if (!data._3mf_printer_thumbnail_middle.empty()) {
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_printer_thumbnail_middle)
<< "\" Id=\"rel-4\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-middle\"/>\n";
if (data._3mf_printer_thumbnail_middle.empty()) {
stream << " <Relationship Target=\"/Metadata/plate_1.png"
<< "\" Id=\"rel-4\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-middle\"/>\n";
} else {
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_printer_thumbnail_middle)
<< "\" Id=\"rel-4\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-middle\"/>\n";
}
if (data._3mf_printer_thumbnail_small.empty()) {
stream << "<Relationship Target=\"/Metadata/plate_1_small.png"
<< "\" Id=\"rel-5\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-small\"/>\n";
} else {
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_printer_thumbnail_small)
<< "\" Id=\"rel-5\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-small\"/>\n";
}
}
else {
//always use plate thumbnails
std::string thumbnail_file_str = (boost::format("Metadata/plate_%1%.png") % (export_plate_idx + 1)).str();
stream << " <Relationship Target=\"/" << xml_escape(thumbnail_file_str)
<< "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
thumbnail_file_str = (boost::format("Metadata/plate_%1%.png") % (export_plate_idx + 1)).str();
stream << " <Relationship Target=\"/" << xml_escape(thumbnail_file_str)
<< "\" Id=\"rel-4\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-middle\"/>\n";
thumbnail_file_str = (boost::format("Metadata/plate_%1%_small.png") % (export_plate_idx + 1)).str();
stream << " <Relationship Target=\"/" << xml_escape(thumbnail_file_str)
<< "\" Id=\"rel-5\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-small\"/>\n";
}
if (!data._3mf_printer_thumbnail_small.empty())
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_printer_thumbnail_small)
<< "\" Id=\"rel-5\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-small\"/>\n";
}
else if (targets.empty()) {
return false;
@ -6059,7 +6148,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
metadata_item_map[BBL_DESIGNER_USER_ID_TAG] = user_id;
metadata_item_map[BBL_DESIGNER_COVER_FILE_TAG] = xml_escape(design_cover);
metadata_item_map[BBL_DESCRIPTION_TAG] = xml_escape(description);
metadata_item_map[BBL_COPYRIGHT_TAG] = xml_escape(copyright);
metadata_item_map[BBL_COPYRIGHT_NORMATIVE_TAG] = xml_escape(copyright);
metadata_item_map[BBL_LICENSE_TAG] = xml_escape(license);
/* save model info */
@ -6313,9 +6402,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
}
//add the transform of the volume
if (ppath->empty())
stream << " <" << COMPONENT_TAG << " objectid=\"" << volume_id; // << "\"/>\n";
stream << " <" << COMPONENT_TAG << " objectid=\"" << volume_id;
else
stream << " <" << COMPONENT_TAG << " p:path=\"" << xml_escape(*ppath) << "\" objectid=\"" << volume_id; // << "\"/>\n";
stream << "\" " << PUUID_ATTR << "=\"" << hex_wrap<boost::uint32_t>{(boost::uint32_t) object_data.backup_id} << COMPONENT_UUID_SUFFIX;
const Transform3d &transf = volume->get_matrix();
stream << "\" " << TRANSFORM_ATTR << "=\"";
for (unsigned c = 0; c < 4; ++c) {
@ -6437,17 +6527,17 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
output_buffer += OBJECT_TAG;
output_buffer += " id=\"";
output_buffer += std::to_string(volume_id);
/*if (m_production_ext) {
if (m_production_ext) {
std::stringstream stream;
reset_stream(stream);
stream << "\" " << PUUID_ATTR << "=\"" << hex_wrap<boost::uint32_t>{(boost::uint32_t)backup_id} << OBJECT_UUID_SUFFIX;
stream << "\" " << PUUID_ATTR << "=\"" << hex_wrap<boost::uint32_t>{(boost::uint32_t) object_data.backup_id} << SUB_OBJECT_UUID_SUFFIX;
//output_buffer += "\" ";
//output_buffer += PUUID_ATTR;
//output_buffer += "=\"";
//output_buffer += std::to_string(hex_wrap<boost::uint32_t>{(boost::uint32_t)backup_id});
//output_buffer += OBJECT_UUID_SUFFIX;
output_buffer += stream.str();
}*/
}
output_buffer += "\" type=\"";
output_buffer += type;
output_buffer += "\">\n";
@ -6580,6 +6670,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
{
// This happens for empty projects
if (build_items.size() == 0) {
stream << " <" << BUILD_TAG << "/>\n";
return true;
}
@ -6621,12 +6712,12 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
++count;
const std::vector<double>& layer_height_profile = object->layer_height_profile.get();
if (layer_height_profile.size() >= 4 && layer_height_profile.size() % 2 == 0) {
sprintf(buffer, "object_id=%d|", count);
snprintf(buffer, 1024, "object_id=%d|", count);
out += buffer;
// Store the layer height profile as a single semicolon separated list.
for (size_t i = 0; i < layer_height_profile.size(); ++i) {
sprintf(buffer, (i == 0) ? "%f" : ";%f", layer_height_profile[i]);
snprintf(buffer, 1024, (i == 0) ? "%f" : ";%f", layer_height_profile[i]);
out += buffer;
}
@ -6797,7 +6888,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
{
assert(is_decimal_separator_point());
char buffer[1024];
sprintf(buffer, "; %s\n\n", header_slic3r_generated().c_str());
snprintf(buffer, 1024, "; %s\n\n", header_slic3r_generated().c_str());
std::string out = buffer;
for (const std::string &key : config.keys())
@ -6828,7 +6919,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
bool _BBS_3MF_Exporter::_add_project_embedded_presets_to_archive(mz_zip_archive& archive, Model& model, std::vector<Preset*> project_presets)
{
char buffer[1024];
sprintf(buffer, "; %s\n\n", header_slic3r_generated().c_str());
snprintf(buffer, 1024, "; %s\n\n", header_slic3r_generated().c_str());
std::string out = buffer;
int print_count = 0, filament_count = 0, printer_count = 0;
const std::string& temp_path = model.get_backup_path();
@ -7235,7 +7326,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return true;
}
bool _BBS_3MF_Exporter::_add_slice_info_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const ObjectToObjectDataMap &objects_data)
bool _BBS_3MF_Exporter::_add_slice_info_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const ObjectToObjectDataMap &objects_data, const DynamicPrintConfig& config)
{
std::stringstream stream;
// Store mesh transformation in full precision, as the volumes are stored transformed and they need to be transformed back
@ -7260,6 +7351,16 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
stream << " <" << PLATE_TAG << ">\n";
//plate index
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << PLATE_IDX_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->plate_index + 1 << "\"/>\n";
int timelapse_type = int(config.opt_enum<TimelapseType>("timelapse_type"));
for (auto it = plate_data->warnings.begin(); it != plate_data->warnings.end(); it++) {
if (it->msg == NOT_GENERATE_TIMELAPSE) {
timelapse_type = -1;
break;
}
}
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << TIMELAPSE_TYPE_ATTR << "\" " << VALUE_ATTR << "=\"" << timelapse_type << "\"/>\n";
//stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << TIMELAPSE_ERROR_CODE_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->timelapse_warning_code << "\"/>\n";
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SLICE_PREDICTION_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->get_gcode_prediction_str() << "\"/>\n";
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << SLICE_WEIGHT_ATTR << "\" " << VALUE_ATTR << "=\"" << plate_data->get_gcode_weight_str() << "\"/>\n";
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << OUTSIDE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha<< plate_data->toolpath_outside << "\"/>\n";

View file

@ -14,6 +14,10 @@ class Preset;
struct FilamentInfo;
struct ThumbnailData;
#define PLATE_THUMBNAIL_SMALL_WIDTH 128
#define PLATE_THUMBNAIL_SMALL_HEIGHT 128
#define GCODE_FILE_FORMAT "Metadata/plate_%1%.gcode"
#define THUMBNAIL_FILE_FORMAT "Metadata/plate_%1%.png"
#define TOP_FILE_FORMAT "Metadata/top_%1%.png"
@ -84,6 +88,7 @@ struct PlateData
bool is_sliced_valid = false;
bool toolpath_outside {false};
bool is_label_object_enabled {false};
int timelapse_warning_code = 0; // 1<<0 sprial vase, 1<<1 by object
std::vector<GCodeProcessorResult::SliceWarning> warnings;

View file

@ -190,6 +190,10 @@ bool get_svg_profile(const char *path, std::vector<Element_Info> &element_infos,
profile_line_points.push_back({pt1, pt2});
}
}
if (profile_line_points.empty())
continue;
// keep the start and end points of profile connected
if (shape->fill.gradient != nullptr)
profile_line_points.back().second = profile_line_points[0].first;
@ -269,6 +273,9 @@ bool get_svg_profile(const char *path, std::vector<Element_Info> &element_infos,
wires.emplace_back(wire);
}
if (wires.empty())
continue;
gp_Vec dir(0, 0, 10);
BRepBuilderAPI_MakeFace face_make(wires[index]);
for (int i = 0; i < wires.size(); ++i) {

View file

@ -980,6 +980,33 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
return gcode;
}
bool WipeTowerIntegration::is_empty_wipe_tower_gcode(GCode &gcodegen, int extruder_id, bool finish_layer)
{
assert(m_layer_idx >= 0);
if (m_layer_idx >= (int) m_tool_changes.size())
return true;
bool ignore_sparse = false;
if (gcodegen.config().wipe_tower_no_sparse_layers.value) {
ignore_sparse = (m_tool_changes[m_layer_idx].size() == 1 && m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool);
}
if (m_enable_timelapse_print && m_is_first_print) {
return false;
}
if (gcodegen.writer().need_toolchange(extruder_id) || finish_layer) {
if (!(size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size()))
throw Slic3r::RuntimeError("Wipe tower generation failed, possibly due to empty first layer.");
if (!ignore_sparse) {
return false;
}
}
return true;
}
// Print is finished. Now it remains to unload the filament safely with ramming over the wipe tower.
std::string WipeTowerIntegration::finalize(GCode &gcodegen)
{
@ -1367,6 +1394,7 @@ namespace DoExport {
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Machine end G-code")), config.machine_end_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Before layer change G-code")), config.before_layer_change_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Layer change G-code")), config.layer_change_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Time lapse G-code")), config.time_lapse_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Change filament G-code")), config.change_filament_gcode.value);
//BBS
//if (ret.size() < MAX_TAGS_COUNT) check(_(L("Printing by object G-code")), config.printing_by_object_gcode.value);
@ -1489,6 +1517,16 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
BOOST_LOG_TRIVIAL(debug) << "Start processing gcode, " << log_memory_info();
// Post-process the G-code to update time stamps.
m_timelapse_warning_code = 0;
if (m_config.printer_structure.value == PrinterStructure::psI3 && m_spiral_vase) {
m_timelapse_warning_code += 1;
}
if (m_config.printer_structure.value == PrinterStructure::psI3 && print->config().print_sequence == PrintSequence::ByObject) {
m_timelapse_warning_code += (1 << 1);
}
m_processor.result().timelapse_warning_code = m_timelapse_warning_code;
m_processor.result().support_traditional_timelapse = m_support_traditional_timelapse;
m_processor.finalize(true);
// DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics);
DoExport::update_print_estimated_stats(m_processor, m_writer.extruders(), print->m_print_statistics, print->config());
@ -1651,16 +1689,13 @@ namespace DoExport {
output((boost::format("; thumbnail begin %dx%d %d\n") % data.width % data.height % encoded.size()).str().c_str());
unsigned int row_count = 0;
while (encoded.size() > max_row_length)
{
output((boost::format("; %s\n") % encoded.substr(0, max_row_length)).str().c_str());
encoded = encoded.substr(max_row_length);
//BBS: optimize performance ,reduce too much memeory operation
size_t current_index = 0;
while(current_index<encoded.size()){
output((boost::format("; %s\n") % encoded.substr(current_index, max_row_length)).str().c_str());
current_index+=std::min(max_row_length,encoded.size()-current_index);
++row_count;
}
if (encoded.size() > 0)
output((boost::format("; %s\n") % encoded).str().c_str());
output("; thumbnail end\n");
output("; THUMBNAIL_BLOCK_END\n\n");
@ -1948,7 +1983,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
[&print]() { print.throw_if_canceled(); });
}
}
// Write some terse information on the slicing parameters.
const PrintObject *first_object = print.objects().front();
@ -2248,8 +2283,12 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
file.writeln(this->placeholder_parser_process("filament_start_gcode", print.config().filament_start_gcode.values[initial_extruder_id], initial_extruder_id, &config));
}
*/
if (is_bbl_printers)
if (is_bbl_printers) {
this->_print_first_layer_extruder_temperatures(file, print, machine_start_gcode, initial_extruder_id, true);
if (m_config.support_air_filtration.getBool() && m_config.activate_air_filtration.get_at(initial_extruder_id)) {
file.write(m_writer.set_exhaust_fan(m_config.during_print_exhaust_fan_speed.get_at(initial_extruder_id), true));
}
}
print.throw_if_canceled();
// Set other general things.
@ -2512,6 +2551,9 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
file.write(m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100%
file.write(m_writer.postamble());
file.write(m_writer.set_chamber_temperature(0, false)); //close chamber_temperature
// adds tags for time estimators
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Last_Line_M73_Placeholder).c_str());
file.write_format("; EXECUTABLE_BLOCK_END\n\n");
@ -2561,6 +2603,19 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
}
file.write("\n");
bool activate_air_filtration = false;
for (const auto& extruder : m_writer.extruders())
activate_air_filtration |= m_config.activate_air_filtration.get_at(extruder.id());
activate_air_filtration &= m_config.support_air_filtration.getBool();
if (activate_air_filtration) {
int complete_print_exhaust_fan_speed = 0;
for (const auto& extruder : m_writer.extruders())
if (m_config.activate_air_filtration.get_at(extruder.id()))
complete_print_exhaust_fan_speed = std::max(complete_print_exhaust_fan_speed, m_config.complete_print_exhaust_fan_speed.get_at(extruder.id()));
file.write(m_writer.set_exhaust_fan(complete_print_exhaust_fan_speed, true));
}
print.throw_if_canceled();
}
@ -2901,6 +2956,7 @@ int GCode::get_bed_temperature(const int extruder_id, const bool is_first_layer,
return bed_temp_opt->get_at(extruder_id);
}
// Write 1st layer bed temperatures into the G-code.
// Only do that if the start G-code does not already contain any M-code controlling an extruder temperature.
// M140 - Set Extruder Temperature
@ -3336,10 +3392,45 @@ LayerResult GCode::process_layer(
+ "\n";
}
PrinterStructure printer_structure = m_config.printer_structure.value;
bool need_insert_timelapse_gcode_for_traditional = false;
if (printer_structure == PrinterStructure::psI3 &&
!m_spiral_vase &&
(!m_wipe_tower || !m_wipe_tower->enable_timelapse_print()) &&
print.config().print_sequence == PrintSequence::ByLayer) {
need_insert_timelapse_gcode_for_traditional = true;
}
bool has_insert_timelapse_gcode = false;
bool has_wipe_tower = (layer_tools.has_wipe_tower && m_wipe_tower);
auto insert_timelapse_gcode = [this, print_z, &print]() -> std::string {
std::string gcode_res;
if (!print.config().time_lapse_gcode.value.empty()) {
DynamicConfig config;
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
gcode_res = this->placeholder_parser_process("timelapse_gcode", print.config().time_lapse_gcode.value, m_writer.extruder()->id(), &config) + "\n";
}
return gcode_res;
};
// BBS: don't use lazy_raise when enable spiral vase
gcode += this->change_layer(print_z); // this will increase m_layer_index
m_layer = &layer;
m_object_layer_over_raft = false;
if (printer_structure == PrinterStructure::psI3 && !need_insert_timelapse_gcode_for_traditional && !m_spiral_vase && print.config().print_sequence == PrintSequence::ByLayer) {
std::string timepals_gcode = insert_timelapse_gcode();
gcode += timepals_gcode;
m_writer.set_current_position_clear(false);
//BBS: check whether custom gcode changes the z position. Update if changed
double temp_z_after_timepals_gcode;
if (GCodeProcessor::get_last_z_from_gcode(timepals_gcode, temp_z_after_timepals_gcode)) {
Vec3d pos = m_writer.get_position();
pos(2) = temp_z_after_timepals_gcode;
m_writer.set_position(pos);
}
}
if (! print.config().layer_change_gcode.value.empty()) {
DynamicConfig config;
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
@ -3649,9 +3740,29 @@ LayerResult GCode::process_layer(
// Extrude the skirt, brim, support, perimeters, infill ordered by the extruders.
for (unsigned int extruder_id : layer_tools.extruders)
{
gcode += (layer_tools.has_wipe_tower && m_wipe_tower) ?
m_wipe_tower->tool_change(*this, extruder_id, extruder_id == layer_tools.extruders.back()) :
this->set_extruder(extruder_id, print_z);
if (has_wipe_tower) {
if (!m_wipe_tower->is_empty_wipe_tower_gcode(*this, extruder_id, extruder_id == layer_tools.extruders.back())) {
if (need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode) {
gcode += this->retract(false, false, LiftType::NormalLift);
m_writer.add_object_change_labels(gcode);
std::string timepals_gcode = insert_timelapse_gcode();
gcode += timepals_gcode;
m_writer.set_current_position_clear(false);
//BBS: check whether custom gcode changes the z position. Update if changed
double temp_z_after_timepals_gcode;
if (GCodeProcessor::get_last_z_from_gcode(timepals_gcode, temp_z_after_timepals_gcode)) {
Vec3d pos = m_writer.get_position();
pos(2) = temp_z_after_timepals_gcode;
m_writer.set_position(pos);
}
has_insert_timelapse_gcode = true;
}
gcode += m_wipe_tower->tool_change(*this, extruder_id, extruder_id == layer_tools.extruders.back());
}
} else {
gcode += this->set_extruder(extruder_id, print_z);
}
// let analyzer tag generator aware of a role type change
if (layer_tools.has_wipe_tower && m_wipe_tower)
@ -3845,11 +3956,11 @@ LayerResult GCode::process_layer(
//BBS: for first layer, we always print wall firstly to get better bed adhesive force
//This behaviour is same with cura
if (is_infill_first && !first_layer) {
gcode += this->extrude_infill(print, by_region_specific, false);
gcode += this->extrude_infill(print, by_region_specific, false);
gcode += this->extrude_perimeters(print, by_region_specific);
} else {
gcode += this->extrude_perimeters(print, by_region_specific);
gcode += this->extrude_infill(print,by_region_specific, false);
gcode += this->extrude_infill(print,by_region_specific, false);
}
// ironing
gcode += this->extrude_infill(print,by_region_specific, true);
@ -3900,6 +4011,25 @@ LayerResult GCode::process_layer(
BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
log_memory_info();
if (!has_wipe_tower && need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode) {
if (m_support_traditional_timelapse)
m_support_traditional_timelapse = false;
gcode += this->retract(false, false, LiftType::NormalLift);
m_writer.add_object_change_labels(gcode);
std::string timepals_gcode = insert_timelapse_gcode();
gcode += timepals_gcode;
m_writer.set_current_position_clear(false);
//BBS: check whether custom gcode changes the z position. Update if changed
double temp_z_after_timepals_gcode;
if (GCodeProcessor::get_last_z_from_gcode(timepals_gcode, temp_z_after_timepals_gcode)) {
Vec3d pos = m_writer.get_position();
pos(2) = temp_z_after_timepals_gcode;
m_writer.set_position(pos);
}
}
result.gcode = std::move(gcode);
result.cooling_buffer_flush = object_layer || raft_layer || last_layer;
return result;

View file

@ -91,6 +91,7 @@ public:
std::string prime(GCode &gcodegen);
void next_layer() { ++ m_layer_idx; m_tool_change_idx = 0; }
std::string tool_change(GCode &gcodegen, int extruder_id, bool finish_layer);
bool is_empty_wipe_tower_gcode(GCode &gcodegen, int extruder_id, bool finish_layer);
std::string finalize(GCode &gcodegen);
std::vector<float> used_filament_length() const;
@ -529,6 +530,9 @@ private:
// Index of a last object copy extruded.
std::pair<const PrintObject*, Point> m_last_obj_copy;
int m_timelapse_warning_code = 0;
bool m_support_traditional_timelapse = true;
bool m_silent_time_estimator_enabled;
// Processor

View file

@ -59,7 +59,8 @@ const std::vector<std::string> GCodeProcessor::Reserved_Tags = {
"_GP_FIRST_LINE_M73_PLACEHOLDER",
"_GP_LAST_LINE_M73_PLACEHOLDER",
"_GP_ESTIMATED_PRINTING_TIME_PLACEHOLDER",
"_GP_TOTAL_LAYER_NUMBER_PLACEHOLDER"
"_GP_TOTAL_LAYER_NUMBER_PLACEHOLDER",
"_DURING_PRINT_EXHAUST_FAN"
};
const std::vector<std::string> GCodeProcessor::Reserved_Tags_compatible = {
@ -383,6 +384,8 @@ void GCodeProcessor::TimeProcessor::reset()
machine_limits = MachineEnvelopeConfig();
filament_load_times = 0.0f;
filament_unload_times = 0.0f;
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
machines[i].reset();
}
@ -427,6 +430,14 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename, st
return std::string(line_M73);
};
auto format_line_exhaust_fan_control = [](const std::string& mask,int fan_index,int percent) {
char line_fan[64] = { 0 };
sprintf(line_fan,mask.c_str(),
std::to_string(fan_index).c_str(),
std::to_string(int((percent/100.0)*255)).c_str());
return std::string(line_fan);
};
auto format_time_float = [](float time) {
return Slic3r::float_to_string_decimal_point(time, 2);
};
@ -542,7 +553,7 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename, st
// add lines M73 to exported gcode
auto process_line_move = [
// Lambdas, mostly for string formatting, all with an empty capture block.
time_in_minutes, format_time_float, format_line_M73_main, format_line_M73_stop_int, format_line_M73_stop_float, time_in_last_minute,
time_in_minutes, format_time_float, format_line_M73_main, format_line_M73_stop_int, format_line_M73_stop_float, time_in_last_minute,format_line_exhaust_fan_control,
&self = std::as_const(*this),
// Caches, to be modified
&g1_times_cache_it, &last_exported_main, &last_exported_stop,
@ -561,6 +572,7 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename, st
if (it != machine.g1_times_cache.end() && it->id == g1_lines_counter) {
std::pair<int, int> to_export_main = { int(100.0f * it->elapsed_time / machine.time),
time_in_minutes(machine.time - it->elapsed_time) };
if (last_exported_main[i] != to_export_main) {
export_line += format_line_M73_main(machine.line_m73_main_mask.c_str(),
to_export_main.first, to_export_main.second);
@ -802,6 +814,7 @@ void GCodeProcessorResult::reset() {
toolpath_outside = false;
//BBS: add label_object_enabled
label_object_enabled = false;
timelapse_warning_code = 0;
printable_height = 0.0f;
settings_ids.reset();
extruders_count = 0;
@ -829,6 +842,7 @@ void GCodeProcessorResult::reset() {
toolpath_outside = false;
//BBS: add label_object_enabled
label_object_enabled = false;
timelapse_warning_code = 0;
printable_height = 0.0f;
settings_ids.reset();
extruders_count = 0;
@ -998,6 +1012,8 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
const ConfigOptionBool* spiral_vase = config.option<ConfigOptionBool>("spiral_mode");
if (spiral_vase != nullptr)
m_spiral_vase_active = spiral_vase->value;
}
void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
@ -1498,9 +1514,9 @@ void GCodeProcessor::finalize(bool post_process)
m_height_compare.output();
m_width_compare.output();
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
if (post_process)
if (post_process){
m_time_processor.post_process(m_result.filename, m_result.moves, m_result.lines_ends, m_layer_id);
}
#if ENABLE_GCODE_VIEWER_STATISTICS
m_result.time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - m_start_time).count();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
@ -1817,6 +1833,7 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line, bool
case '9':
switch (cmd[3]) {
case '0': { process_M190(line); break; } // Wait bed temperature
case '1': { process_M191(line); break; } // Wait chamber temperature
default: break;
}
default:
@ -1935,7 +1952,7 @@ template<typename T>
// Legacy conversion, which is costly due to having to make a copy of the string before conversion.
try {
assert(sv.size() < 1024);
assert(sv.data() != nullptr);
assert(sv.data() != nullptr);
std::string str { sv };
size_t read = 0;
if constexpr (std::is_same_v<T, int>)
@ -3751,6 +3768,15 @@ void GCodeProcessor::process_M190(const GCodeReader::GCodeLine& line)
m_highest_bed_temp = m_highest_bed_temp < (int)new_temp ? (int)new_temp : m_highest_bed_temp;
}
void GCodeProcessor::process_M191(const GCodeReader::GCodeLine& line)
{
float chamber_temp = 0;
const float wait_chamber_temp_time = 720.0;
// BBS: when chamber_temp>40,caculate time required for heating
if (line.has_value('S', chamber_temp) && chamber_temp > 40)
simulate_st_synchronize(wait_chamber_temp_time);
}
void GCodeProcessor::process_M201(const GCodeReader::GCodeLine& line)
{
@ -4355,6 +4381,29 @@ void GCodeProcessor::update_slice_warnings()
m_result.warnings.push_back(warning);
}
// bbs:HRC checker
warning.params.clear();
warning.level = 1;
if (!m_result.support_traditional_timelapse) {
warning.msg = NOT_SUPPORT_TRADITIONAL_TIMELAPSE;
warning.error_code = "1000C003";
m_result.warnings.push_back(warning);
}
if (m_result.timelapse_warning_code != 0) {
if (m_result.timelapse_warning_code & 1) {
warning.msg = NOT_GENERATE_TIMELAPSE;
warning.error_code = "1001C001";
m_result.warnings.push_back(warning);
}
if ((m_result.timelapse_warning_code >> 1) & 1) {
warning.msg = NOT_GENERATE_TIMELAPSE;
warning.error_code = "1001C002";
m_result.warnings.push_back(warning);
}
}
m_result.warnings.shrink_to_fit();
}

View file

@ -20,6 +20,8 @@ namespace Slic3r {
// slice warnings enum strings
#define NOZZLE_HRC_CHECKER "the_actual_nozzle_hrc_smaller_than_the_required_nozzle_hrc"
#define BED_TEMP_TOO_HIGH_THAN_FILAMENT "bed_temperature_too_high_than_filament"
#define NOT_SUPPORT_TRADITIONAL_TIMELAPSE "not_support_traditional_timelapse"
#define NOT_GENERATE_TIMELAPSE "not_generate_timelapse"
enum class EMoveType : unsigned char
{
@ -179,6 +181,8 @@ namespace Slic3r {
bool toolpath_outside;
//BBS: add object_label_enabled
bool label_object_enabled;
int timelapse_warning_code {0};
bool support_traditional_timelapse{true};
float printable_height;
SettingsIds settings_ids;
size_t extruders_count;
@ -212,6 +216,7 @@ namespace Slic3r {
bed_exclude_area = other.bed_exclude_area;
toolpath_outside = other.toolpath_outside;
label_object_enabled = other.label_object_enabled;
timelapse_warning_code = other.timelapse_warning_code;
printable_height = other.printable_height;
settings_ids = other.settings_ids;
extruders_count = other.extruders_count;
@ -255,7 +260,8 @@ namespace Slic3r {
First_Line_M73_Placeholder,
Last_Line_M73_Placeholder,
Estimated_Printing_Time_Placeholder,
Total_Layer_Number_Placeholder
Total_Layer_Number_Placeholder,
During_Print_Exhaust_Fan
};
static const std::string& reserved_tag(ETags tag) { return s_IsBBLPrinter ? Reserved_Tags[static_cast<unsigned char>(tag)] : Reserved_Tags_compatible[static_cast<unsigned char>(tag)]; }
@ -357,6 +363,7 @@ namespace Slic3r {
float time() const;
};
private:
struct TimeMachine
{
@ -452,6 +459,7 @@ namespace Slic3r {
// Additional load / unload times for a filament exchange sequence.
float filament_load_times;
float filament_unload_times;
std::array<TimeMachine, static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count)> machines;
void reset();
@ -617,7 +625,6 @@ namespace Slic3r {
private:
GCodeReader m_parser;
EUnits m_units;
EPositioningType m_global_positioning_type;
EPositioningType m_e_local_positioning_type;
@ -711,6 +718,7 @@ namespace Slic3r {
void reset();
const GCodeProcessorResult& get_result() const { return m_result; }
GCodeProcessorResult& result() { return m_result; }
GCodeProcessorResult&& extract_result() { return std::move(m_result); }
// Load a G-code into a stand-alone G-code viewer.
@ -829,6 +837,9 @@ namespace Slic3r {
//BBS: wait bed temperature
void process_M190(const GCodeReader::GCodeLine& line);
//BBS: wait chamber temperature
void process_M191(const GCodeReader::GCodeLine& line);
// Set max printing acceleration
void process_M201(const GCodeReader::GCodeLine& line);

View file

@ -157,6 +157,25 @@ std::string GCodeWriter::set_bed_temperature(int temperature, bool wait)
return gcode.str();
}
std::string GCodeWriter::set_chamber_temperature(int temperature, bool wait)
{
std::string code, comment;
std::ostringstream gcode;
if (wait)
{
gcode<<"M106 P2 S255 \n";
gcode<<"M191 S"<<std::to_string(temperature)<<" ;"<<"set chamber_temperature and wait for it to be reached\n";
gcode<<"M106 P2 S0 \n";
}
else {
code = "M141";
comment = "set chamber_temperature";
gcode << code << " S" << temperature << ";" << comment << "\n";
}
return gcode.str();
}
// copied from PrusaSlicer
std::string GCodeWriter::set_acceleration_internal(Acceleration type, unsigned int acceleration)
{
@ -784,6 +803,16 @@ std::string GCodeWriter::set_additional_fan(unsigned int speed)
return gcode.str();
}
std::string GCodeWriter::set_exhaust_fan( int speed,bool add_eol)
{
std::ostringstream gcode;
gcode << "M106" << " P3" << " S" << (int)(speed / 100.0 * 255);
if(add_eol)
gcode << "\n";
return gcode.str();
}
void GCodeWriter::add_object_start_labels(std::string& gcode)
{
if (!m_gcode_label_objects_start.empty()) {

View file

@ -45,6 +45,7 @@ public:
std::string postamble() const;
std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1) const;
std::string set_bed_temperature(int temperature, bool wait = false);
std::string set_chamber_temperature(int temperature, bool wait = false);
std::string set_print_acceleration(unsigned int acceleration) { return set_acceleration_internal(Acceleration::Print, acceleration); }
std::string set_travel_acceleration(unsigned int acceleration) { return set_acceleration_internal(Acceleration::Travel, acceleration); }
std::string set_jerk_xy(double jerk);
@ -90,6 +91,7 @@ public:
std::string set_fan(unsigned int speed) const;
//BBS: set additional fan speed for BBS machine only
static std::string set_additional_fan(unsigned int speed);
static std::string set_exhaust_fan(int speed,bool add_eol);
//BBS
void set_object_start_str(std::string start_string) { m_gcode_label_objects_start = start_string; }
bool is_object_start_str_empty() { return m_gcode_label_objects_start.empty(); }

View file

@ -40,6 +40,11 @@
// Transtltion
#include "I18N.hpp"
// ModelIO support
#ifdef __APPLE__
#include "Format/ModelIO.hpp"
#endif
#define _L(s) Slic3r::I18N::translate(s)
namespace Slic3r {
@ -204,6 +209,18 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c
//FIXME options & LoadStrategy::CheckVersion ?
//BBS: is_xxx is used for is_bbs_3mf when load 3mf
result = load_bbs_3mf(input_file.c_str(), config, config_substitutions, &model, plate_data, project_presets, is_xxx, file_version, proFn, options, project, plate_id);
#ifdef __APPLE__
else if (boost::algorithm::iends_with(input_file, ".usd") || boost::algorithm::iends_with(input_file, ".usda") ||
boost::algorithm::iends_with(input_file, ".usdc") || boost::algorithm::iends_with(input_file, ".usdz") ||
boost::algorithm::iends_with(input_file, ".abc") || boost::algorithm::iends_with(input_file, ".ply")) {
std::string temp_stl = make_temp_stl_with_modelio(input_file);
if (temp_stl.empty()) {
throw Slic3r::RuntimeError("Failed to convert asset to STL via ModelIO.");
}
result = load_stl(temp_stl.c_str(), &model);
delete_temp_file(temp_stl);
}
#endif
else
throw Slic3r::RuntimeError(_L("Unknown file format. Input file must have .stl, .obj, .amf(.xml) extension."));
@ -2048,6 +2065,9 @@ static void reset_instance_transformation(ModelObject* object, size_t src_instan
const Transform3d &assemble_matrix = obj_instance->get_assemble_transformation().get_matrix();
const Transform3d &instance_inverse_matrix = instance_transformation_copy.get_matrix().inverse();
Transform3d new_instance_inverse_matrix = instance_inverse_matrix * obj_instance->get_transformation().get_matrix(true).inverse();
if (place_on_cut) { // reset the rotation of cut plane
new_instance_inverse_matrix = new_instance_inverse_matrix * Transformation(cut_matrix).get_matrix(true, false, true, true).inverse();
}
Transform3d new_assemble_transform = assemble_matrix * new_instance_inverse_matrix;
obj_instance->set_assemble_from_transform(new_assemble_transform);
}
@ -2097,7 +2117,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, std::array<Vec3d, 4> plane_poi
// Displacement (in instance coordinates) to be applied to place the upper parts
Vec3d local_displace = Vec3d::Zero();
Vec3d local_dowels_displace = Vec3d::Zero();
for (ModelVolume *volume : volumes) {
const auto volume_matrix = volume->get_matrix();
@ -2122,7 +2142,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, std::array<Vec3d, 4> plane_poi
}
ModelObjectPtrs res;
if (attributes.has(ModelObjectCutAttribute::CutToParts) && !upper->volumes.empty()) {
reset_instance_transformation(upper, instance, cut_matrix);
res.push_back(upper);
@ -2356,7 +2376,7 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
{
Vec3d shift = model_instance->get_transformation().get_matrix(true) * new_vol->get_offset();
model_instance->set_offset(model_instance->get_offset() + shift);
//BBS: add assemble_view related logic
Geometry::Transformation instance_transformation_copy = model_instance->get_transformation();
instance_transformation_copy.set_offset(-new_vol->get_offset());
@ -2365,6 +2385,7 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
Transform3d new_instance_inverse_matrix = instance_inverse_matrix * model_instance->get_transformation().get_matrix(true).inverse();
Transform3d new_assemble_transform = assemble_matrix * new_instance_inverse_matrix;
model_instance->set_assemble_from_transform(new_assemble_transform);
model_instance->set_offset_to_assembly(new_vol->get_offset());
}
new_vol->set_offset(Vec3d::Zero());
@ -3234,6 +3255,91 @@ void ModelInstance::transform_polygon(Polygon* polygon) const
}
//BBS
// BBS set print speed table and find maximum speed
void Model::setPrintSpeedTable(const DynamicPrintConfig& config, const PrintConfig& print_config) {
//Slic3r::DynamicPrintConfig config = wxGetApp().preset_bundle->full_config();
printSpeedMap.maxSpeed = 0;
if (config.has("inner_wall_speed")) {
printSpeedMap.perimeterSpeed = config.opt_float("inner_wall_speed");
if (printSpeedMap.perimeterSpeed > printSpeedMap.maxSpeed)
printSpeedMap.maxSpeed = printSpeedMap.perimeterSpeed;
}
if (config.has("outer_wall_speed")) {
printSpeedMap.externalPerimeterSpeed = config.opt_float("outer_wall_speed");
printSpeedMap.maxSpeed = std::max(printSpeedMap.maxSpeed, printSpeedMap.externalPerimeterSpeed);
}
if (config.has("sparse_infill_speed")) {
printSpeedMap.infillSpeed = config.opt_float("sparse_infill_speed");
if (printSpeedMap.infillSpeed > printSpeedMap.maxSpeed)
printSpeedMap.maxSpeed = printSpeedMap.infillSpeed;
}
if (config.has("internal_solid_infill_speed")) {
printSpeedMap.solidInfillSpeed = config.opt_float("internal_solid_infill_speed");
if (printSpeedMap.solidInfillSpeed > printSpeedMap.maxSpeed)
printSpeedMap.maxSpeed = printSpeedMap.solidInfillSpeed;
}
if (config.has("top_surface_speed")) {
printSpeedMap.topSolidInfillSpeed = config.opt_float("top_surface_speed");
if (printSpeedMap.topSolidInfillSpeed > printSpeedMap.maxSpeed)
printSpeedMap.maxSpeed = printSpeedMap.topSolidInfillSpeed;
}
if (config.has("support_speed")) {
printSpeedMap.supportSpeed = config.opt_float("support_speed");
if (printSpeedMap.supportSpeed > printSpeedMap.maxSpeed)
printSpeedMap.maxSpeed = printSpeedMap.supportSpeed;
}
//auto& print = wxGetApp().plater()->get_partplate_list().get_current_fff_print();
//auto print_config = print.config();
//printSpeedMap.bed_poly.points = get_bed_shape(*(wxGetApp().plater()->config()));
printSpeedMap.bed_poly.points = get_bed_shape(config);
Pointfs excluse_area_points = print_config.bed_exclude_area.values;
Polygons exclude_polys;
Polygon exclude_poly;
for (int i = 0; i < excluse_area_points.size(); i++) {
auto pt = excluse_area_points[i];
exclude_poly.points.emplace_back(scale_(pt.x()), scale_(pt.y()));
if (i % 4 == 3) { // exclude areas are always rectangle
exclude_polys.push_back(exclude_poly);
exclude_poly.points.clear();
}
}
printSpeedMap.bed_poly = diff({ printSpeedMap.bed_poly }, exclude_polys)[0];
}
// find temperature of heatend and bed and matierial of an given extruder
void Model::setExtruderParams(const DynamicPrintConfig& config, int extruders_count) {
extruderParamsMap.clear();
//Slic3r::DynamicPrintConfig config = wxGetApp().preset_bundle->full_config();
// BBS
//int numExtruders = wxGetApp().preset_bundle->filament_presets.size();
for (unsigned int i = 0; i != extruders_count; ++i) {
std::string matName = "";
// BBS
int bedTemp = 35;
double endTemp = 0.f;
if (config.has("filament_type")) {
matName = config.opt_string("filament_type", i);
}
if (config.has("nozzle_temperature")) {
endTemp = config.opt_int("nozzle_temperature", i);
}
// FIXME: curr_bed_type is now a plate config rather than a global config.
// Currently bed temp is not used for brim generation, so just comment it for now.
#if 0
if (config.has("curr_bed_type")) {
BedType curr_bed_type = config.opt_enum<BedType>("curr_bed_type");
bedTemp = config.opt_int(get_bed_temp_key(curr_bed_type), i);
}
#endif
if (i == 0) extruderParamsMap.insert({ i,{matName, bedTemp, endTemp} });
extruderParamsMap.insert({ i + 1,{matName, bedTemp, endTemp} });
}
}
// update the maxSpeed of an object if it is different from the global configuration
double Model::findMaxSpeed(const ModelObject* object) {
auto objectKeys = object->config.keys();

View file

@ -1561,6 +1561,9 @@ public:
static double getThermalLength(const ModelVolume* modelVolumePtr);
static double getThermalLength(const std::vector<ModelVolume*> modelVolumePtrs);
static Polygon getBedPolygon() { return Model::printSpeedMap.bed_poly; }
//BBS static functions that update extruder params and speed table
static void setPrintSpeedTable(const DynamicPrintConfig& config, const PrintConfig& print_config);
static void setExtruderParams(const DynamicPrintConfig& config, int extruders_count);
// BBS: backup
static Model read_from_archive(

View file

@ -145,24 +145,23 @@ ArrangePolygon get_instance_arrange_poly(ModelInstance* instance, const Slic3r::
// get brim width
auto obj = instance->get_object();
#if 0
ap.brim_width = instance->get_auto_brim_width();
auto brim_type_ptr = obj->get_config_value<ConfigOptionEnum<BrimType>>(config, "brim_type");
if (brim_type_ptr) {
auto brim_type = brim_type_ptr->getInt();
if (brim_type == btOuterOnly)
ap.brim_width = obj->get_config_value<ConfigOptionFloat>(config, "brim_width")->getFloat();
else if (brim_type == btNoBrim)
ap.brim_width = 0;
}
#else
ap.brim_width = 0;
ap.brim_width = 1.0;
// For by-layer printing, need to shrink bed a little, so the support won't go outside bed.
// We set it to 5mm because that's how much a normal support will grow by default.
// normal support 5mm, other support 22mm, no support 0mm
auto supp_type_ptr = obj->get_config_value<ConfigOptionBool>(config, "enable_support");
if (supp_type_ptr && supp_type_ptr->getBool())
ap.brim_width = 5.0;
#endif
auto support_type_ptr = obj->get_config_value<ConfigOptionEnum<SupportType>>(config, "support_type");
auto support_type = support_type_ptr->value;
auto enable_support = supp_type_ptr->getBool();
int support_int = support_type_ptr->getInt();
if (enable_support && (support_type == stNormalAuto || support_type == stNormal))
ap.brim_width = 6.0;
else if (enable_support) {
ap.brim_width = 24.0; // 2*MAX_BRANCH_RADIUS_FIRST_LAYER
ap.has_tree_support = true;
}
ap.height = obj->bounding_box().size().z();
ap.name = obj->name;

View file

@ -115,7 +115,7 @@ public:
area_cumulation_accurate(face_normals, normals_quantize, areas, 10);
area_cumulation_accurate(face_normals_hull, normals_hull_quantize, areas_hull, 10);
area_cumulation_accurate(face_normals_hull, normals_hull_quantize, areas_hull, 14);
add_supplements();

View file

@ -100,6 +100,87 @@ bool decode_png(IStream &in_buf, ImageGreyscale &out_img)
return true;
}
bool decode_colored_png(IStream &in_buf, ImageColorscale &out_img)
{
static const constexpr int PNG_SIG_BYTES = 8;
std::vector<png_byte> sig(PNG_SIG_BYTES, 0);
in_buf.read(sig.data(), PNG_SIG_BYTES);
if (!png_check_sig(sig.data(), PNG_SIG_BYTES)) {
BOOST_LOG_TRIVIAL(error) << boost::format("decode_colored_png: png_check_sig failed");
return false;
}
PNGDescr dsc;
dsc.png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr,
nullptr);
if(!dsc.png) {
BOOST_LOG_TRIVIAL(error) << boost::format("decode_colored_png: png_create_read_struct failed");
return false;
}
dsc.info = png_create_info_struct(dsc.png);
if(!dsc.info) {
BOOST_LOG_TRIVIAL(error) << boost::format("decode_colored_png: png_create_info_struct failed");
png_destroy_read_struct(&dsc.png, &dsc.info, NULL);
return false;
}
png_set_read_fn(dsc.png, static_cast<void *>(&in_buf), png_read_callback);
// Tell that we have already read the first bytes to check the signature
png_set_sig_bytes(dsc.png, PNG_SIG_BYTES);
png_read_info(dsc.png, dsc.info);
out_img.cols = png_get_image_width(dsc.png, dsc.info);
out_img.rows = png_get_image_height(dsc.png, dsc.info);
size_t color_type = png_get_color_type(dsc.png, dsc.info);
size_t bit_depth = png_get_bit_depth(dsc.png, dsc.info);
unsigned long rowbytes = png_get_rowbytes(dsc.png, dsc.info);
switch(color_type)
{
case PNG_COLOR_TYPE_RGB:
out_img.bytes_per_pixel = 3;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
out_img.bytes_per_pixel = 4;
break;
default: //not supported currently
png_destroy_read_struct(&dsc.png, &dsc.info, NULL);
return false;
}
BOOST_LOG_TRIVIAL(info) << boost::format("png's cols %1%, rows %2%, color_type %3%, bit_depth %4%, bytes_per_pixel %5%, rowbytes %6%")%out_img.cols %out_img.rows %color_type %bit_depth %out_img.bytes_per_pixel %rowbytes;
out_img.buf.resize(out_img.rows * rowbytes);
int filter_type = png_get_filter_type(dsc.png, dsc.info);
int compression_type = png_get_compression_type(dsc.png, dsc.info);
int interlace_type = png_get_interlace_type(dsc.png, dsc.info);
BOOST_LOG_TRIVIAL(info) << boost::format("filter_type %1%, compression_type %2%, interlace_type %3%, rowbytes %4%")%filter_type %compression_type %interlace_type %rowbytes;
auto readbuf = static_cast<png_bytep>(out_img.buf.data());
for (size_t r = out_img.rows; r > 0; r--)
{
png_read_row(dsc.png, readbuf + (r - 1) * rowbytes, nullptr);
}
png_read_end(dsc.png, dsc.info);
png_destroy_read_struct(&dsc.png, &dsc.info, NULL);
return true;
}
bool decode_colored_png(const ReadBuf &in_buf, ImageColorscale &out_img)
{
struct ReadBufStream stream{in_buf};
return decode_colored_png(stream, out_img);
}
// Down to earth function to store a packed RGB image to file. Mostly useful for debugging purposes.
// Based on https://www.lemoda.net/c/write-png/
// png_color_type is PNG_COLOR_TYPE_RGB or PNG_COLOR_TYPE_GRAY
@ -112,7 +193,7 @@ static bool write_rgb_or_gray_to_file(const char *file_name_utf8, size_t width,
png_structp png_ptr = nullptr;
png_infop info_ptr = nullptr;
png_byte **row_pointers = nullptr;
FILE *fp = boost::nowide::fopen(file_name_utf8, "wb");
if (! fp) {
BOOST_LOG_TRIVIAL(error) << "write_png_file: File could not be opened for writing: " << file_name_utf8;

View file

@ -23,11 +23,19 @@ template<class PxT> struct Image {
};
using ImageGreyscale = Image<uint8_t>;
struct ImageColorscale:Image<unsigned char>
{
int bytes_per_pixel;
};
// Only decodes true 8 bit grayscale png images. Returns false for other formats
// TODO (if needed): implement transformation of rgb images into grayscale...
bool decode_png(IStream &stream, ImageGreyscale &out_img);
//BBS: decode png for other format
bool decode_colored_png(IStream &in_buf, ImageColorscale &out_img);
// TODO (if needed)
// struct RGB { uint8_t r, g, b; };
// using ImageRGB = Image<RGB>;
@ -39,30 +47,36 @@ struct ReadBuf { const void *buf = nullptr; const size_t sz = 0; };
bool is_png(const ReadBuf &pngbuf);
struct ReadBufStream: public IStream {
const ReadBuf &rbuf_ref;
size_t pos = 0;
explicit ReadBufStream(const ReadBuf &buf): rbuf_ref{buf} {}
size_t read(std::uint8_t *outp, size_t amount) override
{
if (amount > rbuf_ref.sz - pos) return 0;
auto buf = static_cast<const std::uint8_t *>(rbuf_ref.buf);
std::copy(buf + pos, buf + (pos + amount), outp);
pos += amount;
return amount;
}
bool is_ok() const override { return pos < rbuf_ref.sz; }
};
template<class Img> bool decode_png(const ReadBuf &in_buf, Img &out_img)
{
struct ReadBufStream: public IStream {
const ReadBuf &rbuf_ref; size_t pos = 0;
explicit ReadBufStream(const ReadBuf &buf): rbuf_ref{buf} {}
size_t read(std::uint8_t *outp, size_t amount) override
{
if (amount > rbuf_ref.sz - pos) return 0;
auto buf = static_cast<const std::uint8_t *>(rbuf_ref.buf);
std::copy(buf + pos, buf + (pos + amount), outp);
pos += amount;
return amount;
}
bool is_ok() const override { return pos < rbuf_ref.sz; }
} stream{in_buf};
struct ReadBufStream stream{in_buf};
return decode_png(stream, out_img);
}
bool decode_colored_png(const ReadBuf &in_buf, ImageColorscale &out_img);
// TODO: std::istream of FILE* could be similarly adapted in case its needed...

View file

@ -781,6 +781,8 @@ static std::vector<std::string> s_Preset_filament_options {
"temperature_vitrification", "reduce_fan_stop_start_freq", "slow_down_for_layer_cooling", "fan_min_speed",
"fan_max_speed", "enable_overhang_bridge_fan", "overhang_fan_speed", "overhang_fan_threshold", "close_fan_the_first_x_layers", "full_fan_speed_layer", "fan_cooling_layer_time", "slow_down_layer_time", "slow_down_min_speed",
"filament_start_gcode", "filament_end_gcode",
//exhaust fan control
"activate_air_filtration","during_print_exhaust_fan_speed","complete_print_exhaust_fan_speed",
// Retract overrides
"filament_retraction_length", "filament_z_hop", "filament_z_hop_types", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_lift_enforce", "filament_retraction_speed", "filament_deretraction_speed", "filament_retract_restart_extra", "filament_retraction_minimum_travel",
"filament_retract_when_changing_layer", "filament_wipe", "filament_retract_before_wipe",
@ -788,7 +790,7 @@ static std::vector<std::string> s_Preset_filament_options {
"filament_vendor", "compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits",
//BBS
"filament_wipe_distance", "additional_cooling_fan_speed",
"bed_temperature_difference", "nozzle_temperature_range_low", "nozzle_temperature_range_high",
"nozzle_temperature_range_low", "nozzle_temperature_range_high",
//SoftFever
"enable_pressure_advance", "pressure_advance","chamber_temperature", "filament_shrink", "support_material_interface_fan_speed", "filament_notes" /*,"filament_seam_gap"*/,
"filament_loading_speed", "filament_loading_speed_start", "filament_load_time",
@ -809,13 +811,13 @@ static std::vector<std::string> s_Preset_printer_options {
"printer_technology",
"printable_area", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "gcode_flavor",
"fan_kickstart", "fan_speedup_time", "fan_speedup_overhangs",
"single_extruder_multi_material", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "layer_change_gcode", "change_filament_gcode",
"single_extruder_multi_material", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "layer_change_gcode", "time_lapse_gcode", "change_filament_gcode",
"printer_model", "printer_variant", "printable_height", "extruder_clearance_radius", "extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod",
"default_print_profile", "inherits",
"silent_mode",
// BBS
"scan_first_layer", "machine_load_filament_time", "machine_unload_filament_time","time_cost", "machine_pause_gcode", "template_custom_gcode",
"nozzle_type", "nozzle_hrc","auxiliary_fan", "nozzle_volume","upward_compatible_machine", "z_hop_types", "retract_lift_enforce",
"nozzle_type", "nozzle_hrc","auxiliary_fan", "nozzle_volume","upward_compatible_machine", "z_hop_types", "retract_lift_enforce","support_chamber_temp_control","support_air_filtration","printer_structure",
//SoftFever
"host_type", "print_host", "printhost_apikey",
"print_host_webui",

View file

@ -2828,6 +2828,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_vendor_configs_from_json(
const std::string &path, const std::string &vendor_name, LoadConfigBundleAttributes flags, ForwardCompatibilitySubstitutionRule compatibility_rule)
{
CNumericLocalesSetter locales_setter;
// Enable substitutions for user config bundle, throw an exception when loading a system profile.
ConfigSubstitutionContext substitution_context { compatibility_rule };
PresetsConfigSubstitutions substitutions;

View file

@ -100,6 +100,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
"printable_area",
//BBS: add bed_exclude_area
"bed_exclude_area",
"thumbnail_size",
"before_layer_change_gcode",
"enable_pressure_advance",
"pressure_advance",
@ -146,6 +147,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
"textured_plate_temp_initial_layer",
"gcode_add_line_number",
"layer_change_gcode",
"time_lapse_gcode",
"fan_min_speed",
"fan_max_speed",
"printable_height",
@ -194,7 +196,10 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
"gcode_label_objects",
"exclude_object",
"support_material_interface_fan_speed",
"single_extruder_multi_material_priming"
"single_extruder_multi_material_priming",
"activate_air_filtration",
"during_print_exhaust_fan_speed",
"complete_print_exhaust_fan_speed"
};
static std::unordered_set<std::string> steps_ignore;

View file

@ -110,11 +110,11 @@ void PrintBase::set_status(int percent, const std::string &message, unsigned in
BOOST_LOG_TRIVIAL(debug) <<boost::format("Percent %1%: %2%\n")%percent %message.c_str();
}
void PrintBase::status_update_warnings(int step, PrintStateBase::WarningLevel /* warning_level */,
void PrintBase::status_update_warnings(int step, PrintStateBase::WarningLevel warning_level,
const std::string &message, const PrintObjectBase* print_object, PrintStateBase::SlicingNotificationType message_id)
{
if (this->m_status_callback) {
auto status = print_object ? SlicingStatus(*print_object, step, message, message_id) : SlicingStatus(*this, step, message, message_id);
auto status = print_object ? SlicingStatus(*print_object, step, message, message_id, warning_level) : SlicingStatus(*this, step, message, message_id, warning_level);
m_status_callback(status);
}
else if (! message.empty())
@ -122,12 +122,12 @@ void PrintBase::status_update_warnings(int step, PrintStateBase::WarningLevel /*
}
//BBS: add PrintObject id into slicing status
void PrintBase::status_update_warnings(int step, PrintStateBase::WarningLevel /* warning_level */,
void PrintBase::status_update_warnings(int step, PrintStateBase::WarningLevel warning_level,
const std::string& message, PrintObjectBase &object, PrintStateBase::SlicingNotificationType message_id)
{
//BBS: add object it into slicing status
if (this->m_status_callback) {
m_status_callback(SlicingStatus(object, step, message, message_id));
m_status_callback(SlicingStatus(object, step, message, message_id, warning_level));
}
else if (!message.empty())
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", PrintObject warning: %1%\n")% message.c_str();

View file

@ -431,18 +431,18 @@ public:
struct SlicingStatus {
SlicingStatus(int percent, const std::string &text, unsigned int flags = 0, int warning_step = -1,
PrintStateBase::SlicingNotificationType msg_type = PrintStateBase::SlicingDefaultNotification) :
percent(percent), text(text), flags(flags), warning_step(warning_step), message_type(msg_type)
PrintStateBase::SlicingNotificationType msg_type = PrintStateBase::SlicingDefaultNotification, PrintStateBase::WarningLevel warning_level = PrintStateBase::WarningLevel::NON_CRITICAL) :
percent(percent), text(text), flags(flags), warning_step(warning_step), message_type(msg_type), warning_level(warning_level)
{
}
SlicingStatus(const PrintBase &print, int warning_step, const std::string& text,
PrintStateBase::SlicingNotificationType msg_type = PrintStateBase::SlicingDefaultNotification) :
flags(UPDATE_PRINT_STEP_WARNINGS), warning_object_id(print.id()), text(text), warning_step(warning_step), message_type(msg_type)
PrintStateBase::SlicingNotificationType msg_type = PrintStateBase::SlicingDefaultNotification, PrintStateBase::WarningLevel warning_level = PrintStateBase::WarningLevel::NON_CRITICAL) :
flags(UPDATE_PRINT_STEP_WARNINGS), warning_object_id(print.id()), text(text), warning_step(warning_step), message_type(msg_type), warning_level(warning_level)
{
}
SlicingStatus(const PrintObjectBase &print_object, int warning_step, const std::string& text,
PrintStateBase::SlicingNotificationType msg_type = PrintStateBase::SlicingDefaultNotification) :
flags(UPDATE_PRINT_OBJECT_STEP_WARNINGS), warning_object_id(print_object.id()), text(text), warning_step(warning_step), message_type(msg_type)
PrintStateBase::SlicingNotificationType msg_type = PrintStateBase::SlicingDefaultNotification, PrintStateBase::WarningLevel warning_level = PrintStateBase::WarningLevel::NON_CRITICAL) :
flags(UPDATE_PRINT_OBJECT_STEP_WARNINGS), warning_object_id(print_object.id()), text(text), warning_step(warning_step), message_type(msg_type), warning_level(warning_level)
{
}
int percent { -1 };
@ -466,6 +466,7 @@ public:
int warning_step { -1 };
PrintStateBase::SlicingNotificationType message_type {PrintStateBase::SlicingDefaultNotification};
PrintStateBase::WarningLevel warning_level {PrintStateBase::WarningLevel::NON_CRITICAL};
};
typedef std::function<void(const SlicingStatus&)> status_callback_type;
// Default status console print out in the form of percent => message.
@ -532,7 +533,7 @@ protected:
void status_update_warnings(int step, PrintStateBase::WarningLevel warning_level,
const std::string &message, const PrintObjectBase* print_object = nullptr, PrintStateBase::SlicingNotificationType message_id = PrintStateBase::SlicingDefaultNotification);
//BBS: add api to update printobject's warnings
void status_update_warnings(int step, PrintStateBase::WarningLevel /* warning_level */,
void status_update_warnings(int step, PrintStateBase::WarningLevel warning_level,
const std::string& message, PrintObjectBase &object, PrintStateBase::SlicingNotificationType message_id = PrintStateBase::SlicingDefaultNotification);
// If the background processing stop was requested, throw CanceledException.

View file

@ -296,6 +296,15 @@ static t_config_enum_values s_keys_map_NozzleType {
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(NozzleType)
static t_config_enum_values s_keys_map_PrinterStructure {
{"undefine", int(PrinterStructure::psUndefine)},
{"corexy", int(PrinterStructure::psCoreXY)},
{"i3", int(PrinterStructure::psI3)},
{"hbot", int(PrinterStructure::psHbot)},
{"delta", int(PrinterStructure::psDelta)}
};
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PrinterStructure)
static t_config_enum_values s_keys_map_PerimeterGeneratorType{
{ "classic", int(PerimeterGeneratorType::Classic) },
{ "arachne", int(PerimeterGeneratorType::Arachne) }
@ -492,7 +501,7 @@ void PrintConfigDef::init_common_params()
def->mode = comAdvanced;
def->cli = ConfigOptionDef::nocli;
def->set_default_value(new ConfigOptionEnum<AuthorizationType>(atKeyPassword));
// temporary workaround for compatibility with older Slicer
{
def = this->add("preset_name", coString);
@ -617,7 +626,7 @@ void PrintConfigDef::init_fff_params()
def->enum_values.emplace_back("Textured PEI Plate");
def->enum_labels.emplace_back(L("Cool Plate"));
def->enum_labels.emplace_back(L("Engineering Plate"));
def->enum_labels.emplace_back(L("High Temp Plate"));
def->enum_labels.emplace_back(L("Smooth PEI Plate / High Temp Plate"));
def->enum_labels.emplace_back(L("Textured PEI Plate"));
def->set_default_value(new ConfigOptionEnum<BedType>(btPC));
@ -1036,6 +1045,30 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionString());
def->cli = ConfigOptionDef::nocli;
def = this->add("activate_air_filtration",coBools);
def->label = L("Activate air filtration");
def->tooltip = L("Activate for better air filtration");
def->mode = comSimple;
def->set_default_value(new ConfigOptionBools{false});
def = this->add("during_print_exhaust_fan_speed", coInts);
def->label = L("Fan speed");
def->tooltip=L("Speed of exhuast fan during printing.This speed will overwrite the speed in filament custom gcode");
def->sidetext = L("%");
def->min=0;
def->max=100;
def->mode = comSimple;
def->set_default_value(new ConfigOptionInts{60});
def = this->add("complete_print_exhaust_fan_speed", coInts);
def->label = L("Fan speed");
def->sidetext = L("%");
def->tooltip=L("Speed of exhuast fan after printing completes");
def->min=0;
def->max=100;
def->mode = comSimple;
def->set_default_value(new ConfigOptionInts{80});
def = this->add("close_fan_the_first_x_layers", coInts);
def->label = L("No cooling for the first");
def->tooltip = L("Close all cooling fan for the first certain layers. Cooling fan of the first layer used to be closed "
@ -1546,12 +1579,17 @@ def = this->add("filament_loading_speed", coFloats);
def->enum_values.push_back("PC");
def->enum_values.push_back("PA");
def->enum_values.push_back("PA-CF");
def->enum_values.push_back("PA6-CF");
def->enum_values.push_back("PLA-CF");
def->enum_values.push_back("PET-CF");
def->enum_values.push_back("PETG-CF");
def->enum_values.push_back("PVA");
def->enum_values.push_back("HIPS");
def->enum_values.push_back("PLA-AERO");
def->enum_values.push_back("PPS");
def->enum_values.push_back("PPS-CF");
def->enum_values.push_back("PPA-CF");
def->enum_values.push_back("PPA-GF");
def->mode = comSimple;
def->set_default_value(new ConfigOptionStrings { "PLA" });
@ -1790,8 +1828,8 @@ def = this->add("filament_loading_speed", coFloats);
def = this->add("accel_to_decel_factor", coPercent);
def->label = L("accel_to_decel");
def->tooltip = L("Klipper's max_accel_to_decel will be adjusted to this % of acceleration");
def->sidetext = L("%");
def->tooltip = L("Klipper's max_accel_to_decel will be adjusted to this %% of acceleration");
def->sidetext = L("%%");
def->min = 1;
def->max = 100;
def->mode = comAdvanced;
@ -2022,6 +2060,15 @@ def = this->add("filament_loading_speed", coFloats);
def->tooltip = L("Enable this to enable the camera on printer to check the quality of first layer");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
// BBS
def = this->add("thumbnail_size", coPoints);
def->label = L("Thumbnail size");
def->tooltip = L("Decides the size of thumbnail stored in gcode files");
def->mode = comDevelop;
def->gui_type = ConfigOptionDef::GUIType::one_string;
def->set_default_value(new ConfigOptionPoints{ Vec2d(50,50) });
//BBS
// def = this->add("spaghetti_detector", coBool);
// def->label = L("Enable spaghetti detector");
@ -2045,6 +2092,7 @@ def = this->add("filament_loading_speed", coFloats);
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<NozzleType>(ntUndefine));
def = this->add("nozzle_hrc", coInt);
def->label = L("Nozzle HRC");
def->tooltip = L("The nozzle's hardness. Zero means no checking for nozzle's hardness during slicing.");
@ -2054,12 +2102,36 @@ def = this->add("filament_loading_speed", coFloats);
def->mode = comDevelop;
def->set_default_value(new ConfigOptionInt{0});
def = this->add("printer_structure", coEnum);
def->label = L("Printer structure");
def->tooltip = L("The physical arrangement and components of a printing device");
def->enum_keys_map = &ConfigOptionEnum<PrinterStructure>::get_enum_values();
def->enum_values.push_back("undefine");
def->enum_values.push_back("corexy");
def->enum_values.push_back("i3");
def->enum_values.push_back("hbot");
def->enum_values.push_back("delta");
def->enum_labels.push_back(L("Undefine"));
def->enum_labels.push_back(L("CoreXY"));
def->enum_labels.push_back(L("I3"));
def->enum_labels.push_back(L("Hbot"));
def->enum_labels.push_back(L("Delta"));
def->mode = comDevelop;
def->set_default_value(new ConfigOptionEnum<PrinterStructure>(psUndefine));
def = this->add("best_object_pos", coPoint);
def->label = L("Best object position");
def->tooltip = L("Best auto arranging position in range [0,1] w.r.t. bed shape.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionPoint(Vec2d(0.5, 0.5)));
def = this->add("auxiliary_fan", coBool);
def->label = L("Auxiliary part cooling fan");
def->tooltip = L("Enable this option if machine has auxiliary part cooling fan");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("fan_speedup_time", coFloat);
// Label is set in Tab.cpp in the Line object.
//def->label = L("Fan speed-up time");
@ -2090,6 +2162,7 @@ def = this->add("filament_loading_speed", coFloats);
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("time_cost", coFloat);
def->label = L("Time cost");
def->tooltip = L("The printer cost per hour");
@ -2098,6 +2171,19 @@ def = this->add("filament_loading_speed", coFloats);
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0));
def =this->add("support_chamber_temp_control",coBool);
def->label=L("Support control chamber temperature");
def->tooltip=L("This option is enabled if machine support controlling chamber temperature");
def->mode=comDevelop;
def->set_default_value(new ConfigOptionBool(false));
def->readonly=false;
def =this->add("support_air_filtration",coBool);
def->label=L("Support air filtration");
def->tooltip=L("Enable this if printer support air filtration");
def->mode=comDevelop;
def->set_default_value(new ConfigOptionBool(false));
def = this->add("gcode_flavor", coEnum);
def->label = L("G-code flavor");
def->tooltip = L("What kind of gcode the printer is compatible with");
@ -2294,6 +2380,14 @@ def = this->add("filament_loading_speed", coFloats);
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString(""));
def = this->add("time_lapse_gcode",coString);
def->label = L("Time lapse G-code");
def->multiline = true;
def->full_width = true;
def->height =5;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString(""));
def = this->add("silent_mode", coBool);
def->label = L("Supports silent mode");
def->tooltip = L("Whether the machine supports silent mode in which machine use lower acceleration to print");
@ -2891,6 +2985,21 @@ def = this->add("filament_loading_speed", coFloats);
def->mode = comSimple;
def->set_default_value(new ConfigOptionFloats { 0.4 });
def = this->add("retract_lift_above", coFloats);
def->label = L("Z hop lower boundary");
def->tooltip = L("Z hop will only come into effect when Z is above this value and is below the parameter: \"Z hop upper boundary\"");
def->sidetext = L("mm");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloats{0.});
def = this->add("retract_lift_below", coFloats);
def->label = L("Z hop upper boundary");
def->tooltip = L("If this value is positive, Z hop will only come into effect when Z is above the parameter: \"Z hop lower boundary\" and is below this value");
def->sidetext = L("mm");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloats{0.});
def = this->add("z_hop_types", coEnums);
def->label = L("Z hop type");
def->tooltip = L("Z hop type");
@ -3733,7 +3842,10 @@ def = this->add("filament_loading_speed", coFloats);
def = this->add("chamber_temperature", coInts);
def->label = L("Chamber temperature");
def->tooltip = L("Target chamber temperature");
def->tooltip = L("Higher chamber temperature can help suppress or reduce warping and potentially lead to higher interlayer bonding strength for high temperature materials like ABS, ASA, PC, PA and so on."
"At the same time, the air filtration of ABS and ASA will get worse.While for PLA, PETG, TPU, PVA and other low temperature materials,"
"the actual chamber temperature should not be high to avoid cloggings, so 0 which stands for turning off is highly recommended"
);
def->sidetext = L("°C");
def->full_label = L("Chamber temperature");
def->min = 0;
@ -3765,15 +3877,6 @@ def = this->add("filament_loading_speed", coFloats);
def->max = max_temp;
def->set_default_value(new ConfigOptionInts { 240 });
def = this->add("bed_temperature_difference", coInts);
def->label = L("Bed temperature difference");
def->tooltip = L("Do not recommend bed temperature of other layer to be lower than initial layer for more than this threshold. "
"Too low bed temperature of other layer may cause the model broken free from build plate");
def->sidetext = L("°C");
def->min = 0;
def->max = 30;
def->mode = comDevelop;
def->set_default_value(new ConfigOptionInts { 10 });
def = this->add("detect_thin_wall", coBool);
def->label = L("Detect thin wall");
@ -4974,7 +5077,7 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
"remove_freq_sweep", "remove_bed_leveling", "remove_extrusion_calibration",
"support_transition_line_width", "support_transition_speed", "bed_temperature", "bed_temperature_initial_layer",
"can_switch_nozzle_type", "can_add_auxiliary_fan", "extra_flush_volume", "spaghetti_detector", "adaptive_layer_height",
"z_hop_type", "z_lift_type"
"z_hop_type", "z_lift_type", "bed_temperature_difference"
};
if (ignore.find(opt_key) != ignore.end()) {
@ -5683,6 +5786,12 @@ CLIActionsConfigDef::CLIActionsConfigDef()
def->cli_params = "option";
def->set_default_value(new ConfigOptionBool(false));
def = this->add("min_save", coBool);
def->label = L("Minimum save");
def->tooltip = L("export 3mf with minimum size.");
def->cli_params = "option";
def->set_default_value(new ConfigOptionBool(false));
def = this->add("mtcpp", coInt);
def->label = L("mtcpp");
def->tooltip = L("max triangle count per plate for slicing.");
@ -5789,12 +5898,12 @@ CLITransformConfigDef::CLITransformConfigDef()
def->cli_params = "count";
def->set_default_value(new ConfigOptionInt(1));
/*def = this->add("ensure_on_bed", coBool);
def = this->add("ensure_on_bed", coBool);
def->label = L("Ensure on bed");
def->tooltip = L("Lift the object above the bed when it is partially below. Enabled by default, use --no-ensure-on-bed to disable.");
def->set_default_value(new ConfigOptionBool(true));
def->tooltip = L("Lift the object above the bed when it is partially below. Disabled by default");
def->set_default_value(new ConfigOptionBool(false));
def = this->add("copy", coInt);
/*def = this->add("copy", coInt);
def->label = L("Copy");
def->tooltip =L("Duplicate copies of model");
def->min = 1;
@ -5814,18 +5923,18 @@ CLITransformConfigDef::CLITransformConfigDef()
def->tooltip = L("Convert the units of model");
def->set_default_value(new ConfigOptionBool(false));
def = this->add("orient", coBool);
def->label = L("Orient");
def->tooltip = L("Orient the model");
def = this->add("orient", coInt);
def->label = L("Orient Options");
def->tooltip = L("Orient options: 0-disable, 1-enable, others-auto");
//def->cli = "orient|o";
def->set_default_value(new ConfigOptionBool(false));
def->set_default_value(new ConfigOptionInt(0));
/*def = this->add("repair", coBool);
def->label = L("Repair");
def->tooltip = L("Repair the model's meshes if it is non-manifold mesh");
def->set_default_value(new ConfigOptionBool(false));*/
/*def = this->add("rotate", coFloat);
def = this->add("rotate", coFloat);
def->label = L("Rotate");
def->tooltip = L("Rotation angle around the Z axis in degrees.");
def->set_default_value(new ConfigOptionFloat(0));
@ -5838,7 +5947,7 @@ CLITransformConfigDef::CLITransformConfigDef()
def = this->add("rotate_y", coFloat);
def->label = L("Rotate around Y");
def->tooltip = L("Rotation angle around the Y axis in degrees.");
def->set_default_value(new ConfigOptionFloat(0));*/
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("scale", coFloat);
def->label = L("Scale");
@ -5947,6 +6056,12 @@ CLIMiscConfigDef::CLIMiscConfigDef()
def->tooltip = L("Render with a software renderer. The bundled MESA software renderer is loaded instead of the default OpenGL driver.");
def->min = 0;*/
#endif /* _MSC_VER */
def = this->add("load_custom_gcodes", coString);
def->label = L("Load custom gcode");
def->tooltip = L("Load custom gcode from json");
def->cli_params = "custom_gcode_toolchange.json";
def->set_default_value(new ConfigOptionString());
}
const CLIActionsConfigDef cli_actions_config_def;
@ -6017,6 +6132,17 @@ Polygon get_bed_shape_with_excluded_area(const PrintConfig& cfg)
if (!tmp.empty()) bed_poly = tmp[0];
return bed_poly;
}
bool has_skirt(const DynamicPrintConfig& cfg)
{
auto opt_skirt_height = cfg.option("skirt_height");
auto opt_skirt_loops = cfg.option("skirt_loops");
auto opt_draft_shield = cfg.option("draft_shield");
return (opt_skirt_height && opt_skirt_height->getInt() > 0 && opt_skirt_loops && opt_skirt_loops->getInt() > 0)
|| (opt_draft_shield && opt_draft_shield->getInt() != dsDisabled);
}
float get_real_skirt_dist(const DynamicPrintConfig& cfg) {
return has_skirt(cfg) ? cfg.opt_float("skirt_distance") : 0;
}
} // namespace Slic3r
#include <cereal/types/polymorphic.hpp>

View file

@ -208,6 +208,15 @@ enum NozzleType {
ntCount
};
// BBS
enum PrinterStructure {
psUndefine=0,
psCoreXY,
psI3,
psHbot,
psDelta
};
// BBS
enum ZHopType {
zhtAuto = 0,
@ -878,8 +887,10 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionBool, gcode_add_line_number))
((ConfigOptionBool, bbl_bed_temperature_gcode))
((ConfigOptionEnum<GCodeFlavor>, gcode_flavor))
((ConfigOptionFloat, time_cost))
((ConfigOptionString, layer_change_gcode))
((ConfigOptionString, time_lapse_gcode))
((ConfigOptionFloat, max_volumetric_extrusion_rate_slope))
((ConfigOptionInt, max_volumetric_extrusion_rate_slope_segment_length))
@ -911,6 +922,11 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionEnum<NozzleType>, nozzle_type))
((ConfigOptionInt, nozzle_hrc))
((ConfigOptionBool, auxiliary_fan))
((ConfigOptionBool, support_air_filtration))
((ConfigOptionEnum<PrinterStructure>,printer_structure))
((ConfigOptionBool, support_chamber_temp_control))
// SoftFever
((ConfigOptionBool, use_firmware_retraction))
((ConfigOptionBool, use_relative_e_distances))
@ -994,6 +1010,9 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
((ConfigOptionFloatOrPercent, bridge_acceleration))
((ConfigOptionFloat, travel_acceleration))
((ConfigOptionFloatOrPercent, sparse_infill_acceleration))
((ConfigOptionBools, activate_air_filtration))
((ConfigOptionInts, during_print_exhaust_fan_speed))
((ConfigOptionInts, complete_print_exhaust_fan_speed))
((ConfigOptionFloatOrPercent, internal_solid_infill_acceleration))
((ConfigOptionFloatOrPercent, initial_layer_line_width))
((ConfigOptionFloat, initial_layer_print_height))
@ -1015,6 +1034,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
((ConfigOptionInts, fan_min_speed))
((ConfigOptionFloats, min_layer_height))
((ConfigOptionFloat, printable_height))
((ConfigOptionPoint, best_object_pos))
((ConfigOptionFloats, slow_down_min_speed))
((ConfigOptionFloats, nozzle_diameter))
((ConfigOptionBool, reduce_infill_retraction))
@ -1036,7 +1056,6 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
((ConfigOptionInts , chamber_temperature))
((ConfigOptionBools, wipe))
// BBS
((ConfigOptionInts, bed_temperature_difference))
((ConfigOptionInts, nozzle_temperature_range_low))
((ConfigOptionInts, nozzle_temperature_range_high))
((ConfigOptionFloats, wipe_distance))
@ -1384,6 +1403,8 @@ Points get_bed_shape(const DynamicPrintConfig &cfg);
Points get_bed_shape(const PrintConfig &cfg);
Points get_bed_shape(const SLAPrinterConfig &cfg);
Slic3r::Polygon get_bed_shape_with_excluded_area(const PrintConfig& cfg);
bool has_skirt(const DynamicPrintConfig& cfg);
float get_real_skirt_dist(const DynamicPrintConfig& cfg);
// ModelConfig is a wrapper around DynamicPrintConfig with an addition of a timestamp.
// Each change of ModelConfig is tracked by assigning a new timestamp from a global counter.

View file

@ -507,7 +507,7 @@ void PrintObject::generate_support_material()
{LargeOverhang,L("large overhangs")} };
std::string warning_message = format(L("It seems object %s has %s. Please re-orient the object or enable support generation."),
this->model_object()->name, reasons[sntype]);
this->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, warning_message, PrintStateBase::SlicingNeedSupportOn);
this->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL, warning_message, PrintStateBase::SlicingNeedSupportOn);
}
#if 0
@ -874,7 +874,7 @@ bool PrintObject::invalidate_state_by_config_options(
} else if (
opt_key == "bottom_shell_layers"
|| opt_key == "top_shell_layers") {
steps.emplace_back(posPrepareInfill);
const auto *old_shell_layers = old_config.option<ConfigOptionInt>(opt_key);
@ -886,7 +886,7 @@ bool PrintObject::invalidate_state_by_config_options(
if (value_changed && this->object_extruders().size() > 1) {
steps.emplace_back(posSlice);
}
}
else if (m_print->config().spiral_mode && opt_key == "bottom_shell_layers") {
// Changing the number of bottom layers when a spiral vase is enabled requires re-slicing the object again.
// Otherwise, holes in the bottom layers could be filled, as is reported in GH #5528.

View file

@ -23,8 +23,9 @@ class BBLModelTask;
enum MachineBedType {
//BED_TYPE_AUTO = 0,
BED_TYPE_PC = 0,
BED_TYPE_PEI,
BED_TYPE_PE,
BED_TYPE_PEI,
BED_TYPE_PTE,
BED_TYPE_COUNT,
};
@ -191,6 +192,8 @@ public:
static BBLSubTask::SubTaskStatus parse_user_service_task_status(int status);
};
typedef std::function<void(BBLModelTask* subtask)> OnGetSubTaskFn;
class BBLTask {
public:
enum TaskStatus {

View file

@ -97,7 +97,8 @@ void its_short_edge_collpase(indexed_triangle_set &mesh, size_t target_triangle_
//shuffle the faces and traverse in random order, this MASSIVELY improves the quality of the result
std::shuffle(face_indices.begin(), face_indices.end(), generator);
int allowed_face_removals = int(face_indices.size()) - int(target_triangle_count);
for (const size_t &face_idx : face_indices) {
if (face_removal_flags[face_idx]) {
// if face already removed from previous collapses, skip (each collapse removes two triangles [at least] )
@ -130,10 +131,13 @@ void its_short_edge_collpase(indexed_triangle_set &mesh, size_t target_triangle_
// remove faces
remove_face(face_idx, neighbor_to_remove_face_idx);
remove_face(neighbor_to_remove_face_idx, face_idx);
allowed_face_removals-=2;
// break. this triangle is done
break;
}
if (allowed_face_removals <= 0) { break; }
}
// filter face_indices, remove those that have been collapsed

View file

@ -419,6 +419,7 @@ private:
std::vector<std::vector<MinimumSpanningTree>> m_spanning_trees;
std::vector< std::unordered_map<Line, bool, LineHash>> m_mst_line_x_layer_contour_caches;
coordf_t MAX_BRANCH_RADIUS = 10.0;
coordf_t MAX_BRANCH_RADIUS_FIRST_LAYER = 12.0;
coordf_t MIN_BRANCH_RADIUS = 0.5;
float tree_support_branch_diameter_angle = 5.0;
bool is_strong = false;

View file

@ -254,8 +254,7 @@ void TriangleSelector::select_patch(int facet_start, std::unique_ptr<Cursor> &&c
}
}
const float highlight_angle_limit = cos(Geometry::deg2rad(highlight_by_angle_deg));
Vec3f vec_down = (trafo_no_translate.inverse() * -Vec3d::UnitZ()).normalized().cast<float>();
const float highlight_angle_limit = -cos(Geometry::deg2rad(highlight_by_angle_deg));
// BBS
std::vector<int> start_facets;
@ -291,7 +290,9 @@ void TriangleSelector::select_patch(int facet_start, std::unique_ptr<Cursor> &&c
while (facet_idx < int(facets_to_check.size())) {
int facet = facets_to_check[facet_idx];
const Vec3f& facet_normal = m_face_normals[m_triangles[facet].source_triangle];
if (!visited[facet] && (highlight_by_angle_deg == 0.f || vec_down.dot(facet_normal) >= highlight_angle_limit)) {
Matrix3f normal_matrix = static_cast<Matrix3f>(trafo_no_translate.matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>());
float world_normal_z = (normal_matrix* facet_normal).normalized().z();
if (!visited[facet] && (highlight_by_angle_deg == 0.f || world_normal_z < highlight_angle_limit)) {
if (select_triangle(facet, new_state, triangle_splitting)) {
// add neighboring facets to list to be processed later
for (int neighbor_idx : m_neighbors[facet])
@ -331,8 +332,7 @@ void TriangleSelector::seed_fill_select_triangles(const Vec3f &hit, int facet_st
facet_queue.push(facet_start);
const double facet_angle_limit = cos(Geometry::deg2rad(seed_fill_angle)) - EPSILON;
const float highlight_angle_limit = cos(Geometry::deg2rad(highlight_by_angle_deg));
Vec3f vec_down = (trafo_no_translate.inverse() * -Vec3d::UnitZ()).normalized().cast<float>();
const float highlight_angle_limit = -cos(Geometry::deg2rad(highlight_by_angle_deg));
// Depth-first traversal of neighbors of the face hit by the ray thrown from the mouse cursor.
while (!facet_queue.empty()) {
@ -340,7 +340,9 @@ void TriangleSelector::seed_fill_select_triangles(const Vec3f &hit, int facet_st
facet_queue.pop();
const Vec3f &facet_normal = m_face_normals[m_triangles[current_facet].source_triangle];
if (!visited[current_facet] && (highlight_by_angle_deg == 0.f || vec_down.dot(facet_normal) >= highlight_angle_limit)) {
Matrix3f normal_matrix = static_cast<Matrix3f>(trafo_no_translate.matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>());
float world_normal_z = (normal_matrix * facet_normal).normalized().z();
if (!visited[current_facet] && (highlight_by_angle_deg == 0.f || world_normal_z < highlight_angle_limit)) {
if (m_triangles[current_facet].is_split()) {
for (int split_triangle_idx = 0; split_triangle_idx <= m_triangles[current_facet].number_of_split_sides(); ++split_triangle_idx) {
assert(split_triangle_idx < int(m_triangles[current_facet].children.size()));

View file

@ -60,6 +60,7 @@
#define CLI_FILAMENTS_DIFFERENT_TEMP -62
#define CLI_OBJECT_COLLISION_IN_SEQ_PRINT -63
#define CLI_OBJECT_COLLISION_IN_LAYER_PRINT -64
#define CLI_SPIRAL_MODE_CANNOT_DUPLICATE -65
#define CLI_SLICING_ERROR -100
#define CLI_GCODE_PATH_CONFLICTS -101

View file

@ -666,6 +666,17 @@ void CalibPressureAdvancePattern::generate_custom_gcodes(const DynamicPrintConfi
model.plates_custom_gcodes[model.curr_plate_index] = info;
}
void CalibPressureAdvancePattern::set_start_offset(const Vec3d &offset)
{
m_starting_point = offset;
m_is_start_point_fixed = true;
}
Vec3d CalibPressureAdvancePattern::get_start_offset()
{
return m_starting_point;
}
void CalibPressureAdvancePattern::refresh_setup(const DynamicPrintConfig &config,
bool is_bbl_machine,
const Model &model,
@ -683,6 +694,9 @@ void CalibPressureAdvancePattern::refresh_setup(const DynamicPrintConfig &config
void CalibPressureAdvancePattern::_refresh_starting_point(const Model &model)
{
if (m_is_start_point_fixed)
return;
ModelObject *obj = model.objects.front();
BoundingBoxf3 bbox = obj->instance_bounding_box(*obj->instances.front(), false);

View file

@ -251,6 +251,9 @@ public:
void generate_custom_gcodes(const DynamicPrintConfig &config, bool is_bbl_machine, Model &model, const Vec3d &origin);
void set_start_offset(const Vec3d &offset);
Vec3d get_start_offset();
protected:
double speed_first_layer() const { return m_config.option<ConfigOptionFloat>("initial_layer_speed")->value; };
double speed_perimeter() const { return m_config.option<ConfigOptionFloat>("outer_wall_speed")->value; };
@ -293,6 +296,7 @@ private:
GCodeWriter m_writer;
bool m_is_delta;
Vec3d m_starting_point;
bool m_is_start_point_fixed = false;
const double m_handle_xy_size{5};
const double m_handle_spacing{2};