Merge branch 'master' into lm_tm_hollowing

This commit is contained in:
Lukas Matena 2020-01-06 12:41:29 +01:00
commit 0551411c48
82 changed files with 2066 additions and 462 deletions

View file

@ -630,39 +630,38 @@ size_t ConfigBase::load_from_gcode_string(const char* str)
return 0;
// Walk line by line in reverse until a non-configuration key appears.
char *data_start = const_cast<char*>(str);
const char *data_start = str;
// boost::nowide::ifstream seems to cook the text data somehow, so less then the 64k of characters may be retrieved.
char *end = data_start + strlen(str);
const char *end = data_start + strlen(str);
size_t num_key_value_pairs = 0;
for (;;) {
// Extract next line.
for (--end; end > data_start && (*end == '\r' || *end == '\n'); --end);
if (end == data_start)
break;
char *start = end;
*(++end) = 0;
const char *start = end ++;
for (; start > data_start && *start != '\r' && *start != '\n'; --start);
if (start == data_start)
break;
// Extracted a line from start to end. Extract the key = value pair.
if (end - (++start) < 10 || start[0] != ';' || start[1] != ' ')
if (end - (++ start) < 10 || start[0] != ';' || start[1] != ' ')
break;
char *key = start + 2;
const char *key = start + 2;
if (!(*key >= 'a' && *key <= 'z') || (*key >= 'A' && *key <= 'Z'))
// A key must start with a letter.
break;
char *sep = strchr(key, '=');
if (sep == nullptr || sep[-1] != ' ' || sep[1] != ' ')
const char *sep = key;
for (; sep != end && *sep != '='; ++ sep) ;
if (sep == end || sep[-1] != ' ' || sep[1] != ' ')
break;
char *value = sep + 2;
const char *value = sep + 2;
if (value > end)
break;
char *key_end = sep - 1;
const char *key_end = sep - 1;
if (key_end - key < 3)
break;
*key_end = 0;
// The key may contain letters, digits and underscores.
for (char *c = key; c != key_end; ++c)
for (const char *c = key; c != key_end; ++ c)
if (!((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') || (*c >= '0' && *c <= '9') || *c == '_')) {
key = nullptr;
break;
@ -670,7 +669,7 @@ size_t ConfigBase::load_from_gcode_string(const char* str)
if (key == nullptr)
break;
try {
this->set_deserialize(key, value);
this->set_deserialize(std::string(key, key_end), std::string(value, end));
++num_key_value_pairs;
}
catch (UnknownOptionException & /* e */) {
@ -760,15 +759,15 @@ ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool cre
void DynamicConfig::read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra, t_config_option_keys* keys)
{
std::vector<char*> args;
std::vector<const char*> args;
// push a bogus executable name (argv[0])
args.emplace_back(const_cast<char*>(""));
args.emplace_back("");
for (size_t i = 0; i < tokens.size(); ++ i)
args.emplace_back(const_cast<char *>(tokens[i].c_str()));
this->read_cli(int(args.size()), &args[0], extra, keys);
args.emplace_back(tokens[i].c_str());
this->read_cli(int(args.size()), args.data(), extra, keys);
}
bool DynamicConfig::read_cli(int argc, char** argv, t_config_option_keys* extra, t_config_option_keys* keys)
bool DynamicConfig::read_cli(int argc, const char* const argv[], t_config_option_keys* extra, t_config_option_keys* keys)
{
// cache the CLI option => opt_key mapping
std::map<std::string,std::string> opts;

View file

@ -1779,7 +1779,7 @@ public:
// Command line processing
void read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra, t_config_option_keys* keys = nullptr);
bool read_cli(int argc, char** argv, t_config_option_keys* extra, t_config_option_keys* keys = nullptr);
bool read_cli(int argc, const char* const argv[], t_config_option_keys* extra, t_config_option_keys* keys = nullptr);
std::map<t_config_option_key, std::unique_ptr<ConfigOption>>::const_iterator cbegin() const { return options.cbegin(); }
std::map<t_config_option_key, std::unique_ptr<ConfigOption>>::const_iterator cend() const { return options.cend(); }

View file

@ -88,6 +88,7 @@ const char* V3_ATTR = "v3";
const char* OBJECTID_ATTR = "objectid";
const char* TRANSFORM_ATTR = "transform";
const char* PRINTABLE_ATTR = "printable";
const char* INSTANCESCOUNT_ATTR = "instances_count";
const char* KEY_ATTR = "key";
const char* VALUE_ATTR = "value";
@ -729,8 +730,8 @@ namespace Slic3r {
return false;
}
// fixes the min z of the model if negative
model.adjust_min_z();
// // fixes the min z of the model if negative
// model.adjust_min_z();
return true;
}
@ -1712,6 +1713,9 @@ namespace Slic3r {
return false;
}
// Added because of github #3435, currently not used by PrusaSlicer
int instances_count_id = get_attribute_value_int(attributes, num_attributes, INSTANCESCOUNT_ATTR);
m_objects_metadata.insert(IdToMetadataMap::value_type(object_id, ObjectMetadata()));
m_curr_config.object_id = object_id;
return true;
@ -1812,7 +1816,9 @@ namespace Slic3r {
break;
}
}
#if !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
Transform3d inv_matrix = volume_matrix_to_object.inverse();
#endif // !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
// splits volume out of imported geometry
TriangleMesh triangle_mesh;
@ -1832,11 +1838,15 @@ namespace Slic3r {
for (unsigned int v = 0; v < 3; ++v)
{
unsigned int tri_id = geometry.triangles[src_start_id + ii + v] * 3;
#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
facet.vertex[v] = Vec3f(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]);
#else
Vec3f vertex(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]);
facet.vertex[v] = has_transform ?
// revert the vertices to the original mesh reference system
(inv_matrix * vertex.cast<double>()).cast<float>() :
vertex;
#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
}
}
@ -1844,9 +1854,15 @@ namespace Slic3r {
triangle_mesh.repair();
ModelVolume* volume = object.add_volume(std::move(triangle_mesh));
#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
// stores the volume matrix taken from the metadata, if present
if (has_transform)
volume->source.transform = Slic3r::Geometry::Transformation(volume_matrix_to_object);
#else
// apply the volume matrix taken from the metadata, if present
if (has_transform)
volume->set_transformation(Slic3r::Geometry::Transformation(volume_matrix_to_object));
#endif //ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
volume->calculate_convex_hull();
// apply the remaining volume's metadata
@ -2635,7 +2651,8 @@ namespace Slic3r {
const ModelObject* obj = obj_metadata.second.object;
if (obj != nullptr)
{
stream << " <" << OBJECT_TAG << " id=\"" << obj_metadata.first << "\">\n";
// Output of instances count added because of github #3435, currently not used by PrusaSlicer
stream << " <" << OBJECT_TAG << " " << ID_ATTR << "=\"" << obj_metadata.first << "\" " << INSTANCESCOUNT_ATTR << "=\"" << obj->instances.size() << "\">\n";
// stores object's name
if (!obj->name.empty())
@ -2673,7 +2690,11 @@ namespace Slic3r {
// stores volume's local matrix
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MATRIX_KEY << "\" " << VALUE_ATTR << "=\"";
#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
Transform3d matrix = volume->get_matrix() * volume->source.transform.get_matrix();
#else
const Transform3d& matrix = volume->get_matrix();
#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
for (int r = 0; r < 4; ++r)
{
for (int c = 0; c < 4; ++c)

View file

@ -585,24 +585,36 @@ void AMFParserContext::endElement(const char * /* name */)
stl_allocate(&stl);
bool has_transform = ! m_volume_transform.isApprox(Transform3d::Identity(), 1e-10);
#if !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
Transform3d inv_matrix = m_volume_transform.inverse();
#endif // !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
for (size_t i = 0; i < m_volume_facets.size();) {
stl_facet &facet = stl.facet_start[i/3];
for (unsigned int v = 0; v < 3; ++v)
{
unsigned int tri_id = m_volume_facets[i++] * 3;
#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
facet.vertex[v] = Vec3f(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]);
#else
Vec3f vertex(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]);
facet.vertex[v] = has_transform ?
// revert the vertices to the original mesh reference system
(inv_matrix * vertex.cast<double>()).cast<float>() :
vertex;
#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
}
}
stl_get_size(&stl);
mesh.repair();
m_volume->set_mesh(std::move(mesh));
if (has_transform)
m_volume->set_transformation(m_volume_transform);
#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
// stores the volume matrix taken from the metadata, if present
if (has_transform)
m_volume->source.transform = Slic3r::Geometry::Transformation(m_volume_transform);
#else
if (has_transform)
m_volume->set_transformation(m_volume_transform);
#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
if (m_volume->source.input_file.empty() && (m_volume->type() == ModelVolumeType::MODEL_PART))
{
m_volume->source.object_idx = (int)m_model.objects.size() - 1;
@ -671,7 +683,7 @@ void AMFParserContext::endElement(const char * /* name */)
config->set_deserialize(opt_key, m_value[1]);
} else if (m_path.size() == 3 && m_path[1] == NODE_TYPE_OBJECT && m_object && strcmp(opt_key, "layer_height_profile") == 0) {
// Parse object's layer height profile, a semicolon separated list of floats.
char *p = const_cast<char*>(m_value[1].c_str());
char *p = m_value[1].data();
for (;;) {
char *end = strchr(p, ';');
if (end != nullptr)
@ -686,7 +698,7 @@ void AMFParserContext::endElement(const char * /* name */)
// Parse object's layer height profile, a semicolon separated list of floats.
unsigned char coord_idx = 0;
Eigen::Matrix<float, 5, 1, Eigen::DontAlign> point(Eigen::Matrix<float, 5, 1, Eigen::DontAlign>::Zero());
char *p = const_cast<char*>(m_value[1].c_str());
char *p = m_value[1].data();
for (;;) {
char *end = strchr(p, ';');
if (end != nullptr)
@ -706,7 +718,7 @@ void AMFParserContext::endElement(const char * /* name */)
else if (m_path.size() == 5 && m_path[1] == NODE_TYPE_OBJECT && m_path[3] == NODE_TYPE_RANGE &&
m_object && strcmp(opt_key, "layer_height_range") == 0) {
// Parse object's layer_height_range, a semicolon separated doubles.
char* p = const_cast<char*>(m_value[1].c_str());
char* p = m_value[1].data();
char* end = strchr(p, ';');
*end = 0;
@ -998,7 +1010,7 @@ bool load_amf(const char* path, DynamicPrintConfig* config, Model* model, bool c
return false;
std::string zip_mask(2, '\0');
file.read(const_cast<char*>(zip_mask.data()), 2);
file.read(zip_mask.data(), 2);
file.close();
return (zip_mask == "PK") ? load_amf_archive(path, config, model, check_version) : load_amf_file(path, config, model);
@ -1147,8 +1159,12 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
stream << " <metadata type=\"slic3r.modifier\">1</metadata>\n";
stream << " <metadata type=\"slic3r.volume_type\">" << ModelVolume::type_to_string(volume->type()) << "</metadata>\n";
stream << " <metadata type=\"slic3r.matrix\">";
#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
const Transform3d& matrix = volume->get_matrix() * volume->source.transform.get_matrix();
#else
const Transform3d& matrix = volume->get_matrix();
stream << std::setprecision(std::numeric_limits<double>::max_digits10);
#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
stream << std::setprecision(std::numeric_limits<double>::max_digits10);
for (int r = 0; r < 4; ++r)
{
for (int c = 0; c < 4; ++c)
@ -1248,7 +1264,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
pt::write_xml(oss, tree);
out = oss.str();
int del_header_pos = out.find("<custom_gcodes_per_height");
size_t del_header_pos = out.find("<custom_gcodes_per_height");
if (del_header_pos != std::string::npos)
out.erase(out.begin(), out.begin() + del_header_pos);

View file

@ -449,7 +449,7 @@ bool loadvector(FILE *pFile, std::vector<std::string> &v)
if (::fread(&len, sizeof(len), 1, pFile) != 1)
return false;
std::string s(" ", len);
if (::fread(const_cast<char*>(s.c_str()), 1, len, pFile) != len)
if (::fread(s.data(), 1, len, pFile) != len)
return false;
v.push_back(std::move(s));
}
@ -471,7 +471,7 @@ bool loadvectornameidx(FILE *pFile, std::vector<T> &v)
if (::fread(&len, sizeof(len), 1, pFile) != 1)
return false;
v[i].name.assign(" ", len);
if (::fread(const_cast<char*>(v[i].name.c_str()), 1, len, pFile) != len)
if (::fread(v[i].name.data(), 1, len, pFile) != len)
return false;
}
return true;

View file

@ -122,21 +122,21 @@ Polygons AvoidCrossingPerimeters::collect_contours_all_layers(const PrintObjectP
const Layer* layer1 = object->layers()[i * 2];
const Layer* layer2 = object->layers()[i * 2 + 1];
Polygons polys;
polys.reserve(layer1->slices.size() + layer2->slices.size());
for (const ExPolygon &expoly : layer1->slices)
polys.reserve(layer1->lslices.size() + layer2->lslices.size());
for (const ExPolygon &expoly : layer1->lslices)
//FIXME no holes?
polys.emplace_back(expoly.contour);
for (const ExPolygon &expoly : layer2->slices)
for (const ExPolygon &expoly : layer2->lslices)
//FIXME no holes?
polys.emplace_back(expoly.contour);
polygons_per_layer[i] = union_(polys);
}
});
}
});
if (object->layers().size() & 1) {
const Layer *layer = object->layers().back();
Polygons polys;
polys.reserve(layer->slices.size());
for (const ExPolygon &expoly : layer->slices)
polys.reserve(layer->lslices.size());
for (const ExPolygon &expoly : layer->lslices)
//FIXME no holes?
polys.emplace_back(expoly.contour);
polygons_per_layer.back() = union_(polys);
@ -2006,8 +2006,8 @@ void GCode::process_layer(
// - for each island, we extrude perimeters first, unless user set the infill_first
// option
// (Still, we have to keep track of regions because we need to apply their config)
size_t n_slices = layer.slices.size();
const std::vector<BoundingBox> &layer_surface_bboxes = layer.slices_bboxes;
size_t n_slices = layer.lslices.size();
const std::vector<BoundingBox> &layer_surface_bboxes = layer.lslices_bboxes;
// Traverse the slices in an increasing order of bounding box size, so that the islands inside another islands are tested first,
// so we can just test a point inside ExPolygon::contour and we may skip testing the holes.
std::vector<size_t> slices_test_order;
@ -2023,7 +2023,7 @@ void GCode::process_layer(
const BoundingBox &bbox = layer_surface_bboxes[i];
return point(0) >= bbox.min(0) && point(0) < bbox.max(0) &&
point(1) >= bbox.min(1) && point(1) < bbox.max(1) &&
layer.slices[i].contour.contains(point);
layer.lslices[i].contour.contains(point);
};
for (size_t region_id = 0; region_id < print.regions().size(); ++ region_id) {
@ -2155,7 +2155,7 @@ void GCode::process_layer(
m_config.apply(instance_to_print.print_object.config(), true);
m_layer = layers[instance_to_print.layer_id].layer();
if (m_config.avoid_crossing_perimeters)
m_avoid_crossing_perimeters.init_layer_mp(union_ex(m_layer->slices, true));
m_avoid_crossing_perimeters.init_layer_mp(union_ex(m_layer->lslices, true));
if (this->config().gcode_label_objects)
gcode += std::string("; printing object ") + instance_to_print.print_object.model_object()->name + " id:" + std::to_string(instance_to_print.layer_id) + " copy " + std::to_string(instance_to_print.instance_id) + "\n";
@ -2476,7 +2476,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou
// Create the distance field for a layer below.
const coord_t distance_field_resolution = coord_t(scale_(1.) + 0.5);
*lower_layer_edge_grid = make_unique<EdgeGrid::Grid>();
(*lower_layer_edge_grid)->create(m_layer->lower_layer->slices, distance_field_resolution);
(*lower_layer_edge_grid)->create(m_layer->lower_layer->lslices, distance_field_resolution);
(*lower_layer_edge_grid)->calculate_sdf();
#if 0
{

View file

@ -362,12 +362,11 @@ protected:
bool m_second_layer_things_done;
// Index of a last object copy extruded.
std::pair<const PrintObject*, Point> m_last_obj_copy;
/* Extensions for colorprint - now it's not a just color_print_heights,
* there can be some custom gcode.
* Updated before the export and erased during the process,
* so no toolchange occurs twice.
* */
std::vector<Model::CustomGCode> m_custom_gcode_per_print_z;
// Extensions for colorprint - now it's not a just color_print_heights,
// there can be some custom gcode.
// Updated before the export and erased during the process,
// so no toolchange occurs twice.
std::vector<Model::CustomGCode> m_custom_gcode_per_print_z;
// Time estimators
GCodeTimeEstimator m_normal_time_estimator;

View file

@ -47,8 +47,8 @@ void Layer::make_slices()
slices = union_ex(slices_p);
}
this->slices.clear();
this->slices.reserve(slices.size());
this->lslices.clear();
this->lslices.reserve(slices.size());
// prepare ordering points
Points ordering_points;
@ -61,19 +61,21 @@ void Layer::make_slices()
// populate slices vector
for (size_t i : order)
this->slices.push_back(std::move(slices[i]));
this->lslices.emplace_back(std::move(slices[i]));
}
// Merge typed slices into untyped slices. This method is used to revert the effects of detect_surfaces_type() called for posPrepareInfill.
void Layer::merge_slices()
{
if (m_regions.size() == 1) {
if (m_regions.size() == 1 && (this->id() > 0 || this->object()->config().elefant_foot_compensation.value == 0)) {
// Optimization, also more robust. Don't merge classified pieces of layerm->slices,
// but use the non-split islands of a layer. For a single region print, these shall be equal.
m_regions.front()->slices.set(this->slices, stInternal);
// Don't use this optimization on 1st layer with Elephant foot compensation applied, as this->lslices are uncompensated,
// while regions are compensated.
m_regions.front()->slices.set(this->lslices, stInternal);
} else {
for (LayerRegion *layerm : m_regions)
// without safety offset, artifacts are generated (GH #2494)
// without safety offset, artifacts are generated (upstream Slic3r GH #2494)
layerm->slices.set(union_ex(to_polygons(std::move(layerm->slices.surfaces)), true), stInternal);
}
}

View file

@ -106,12 +106,16 @@ public:
coordf_t print_z; // Z used for printing in unscaled coordinates
coordf_t height; // layer height in unscaled coordinates
// collection of expolygons generated by slicing the original geometry;
// also known as 'islands' (all regions and surface types are merged here)
// The slices are chained by the shortest traverse distance and this traversal
// order will be recovered by the G-code generator.
ExPolygons slices;
std::vector<BoundingBox> slices_bboxes;
// Collection of expolygons generated by slicing the possibly multiple meshes of the source geometry
// (with possibly differing extruder ID and slicing parameters) and merged.
// For the first layer, if the ELephant foot compensation is applied, this lslice is uncompensated, therefore
// it includes the Elephant foot effect, thus it corresponds to the shape of the printed 1st layer.
// These lslices aka islands are chained by the shortest traverse distance and this traversal
// order will be applied by the G-code generator to the extrusions fitting into these lslices.
// These lslices are also used to detect overhangs and overlaps between successive layers, therefore it is important
// that the 1st lslice is not compensated by the Elephant foot compensation algorithm.
ExPolygons lslices;
std::vector<BoundingBox> lslices_bboxes;
size_t region_count() const { return m_regions.size(); }
const LayerRegion* get_region(int idx) const { return m_regions.at(idx); }

View file

@ -72,7 +72,7 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
if (this->layer()->lower_layer != nullptr)
// Cummulative sum of polygons over all the regions.
g.lower_slices = &this->layer()->lower_layer->slices;
g.lower_slices = &this->layer()->lower_layer->lslices;
g.layer_id = (int)this->layer()->id();
g.ext_perimeter_flow = this->flow(frExternalPerimeter);
@ -139,7 +139,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
// Remove voids from fill_boundaries, that are not supported by the layer below.
if (lower_layer_covered == nullptr) {
lower_layer_covered = &lower_layer_covered_tmp;
lower_layer_covered_tmp = to_polygons(lower_layer->slices);
lower_layer_covered_tmp = to_polygons(lower_layer->lslices);
}
if (! lower_layer_covered->empty())
voids = diff(voids, *lower_layer_covered);
@ -260,7 +260,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
// of very thin (but still working) anchors, the grown expolygon would go beyond them
BridgeDetector bd(
initial,
lower_layer->slices,
lower_layer->lslices,
this->flow(frInfill, true).scaled_width()
);
#ifdef SLIC3R_DEBUG

View file

@ -66,7 +66,7 @@ Model& Model::assign_copy(Model &&rhs)
rhs.objects.clear();
// copy custom code per height
this->custom_gcode_per_print_z = rhs.custom_gcode_per_print_z;
this->custom_gcode_per_print_z = std::move(rhs.custom_gcode_per_print_z);
return *this;
}
@ -1953,25 +1953,23 @@ extern bool model_has_advanced_features(const Model &model)
extern void update_custom_gcode_per_print_z_from_config(std::vector<Model::CustomGCode>& custom_gcode_per_print_z, DynamicPrintConfig* config)
{
if (!config->has("colorprint_heights"))
auto *colorprint_heights = config->option<ConfigOptionFloats>("colorprint_heights");
if (colorprint_heights == nullptr)
return;
const std::vector<std::string>& colors = GCodePreviewData::ColorPrintColors();
const auto& colorprint_values = config->option<ConfigOptionFloats>("colorprint_heights")->values;
if (!colorprint_values.empty())
{
if (custom_gcode_per_print_z.empty() && ! colorprint_heights->values.empty()) {
// Convert the old colorprint_heighs only if there is no equivalent data in a new format.
const std::vector<std::string>& colors = GCodePreviewData::ColorPrintColors();
const auto& colorprint_values = colorprint_heights->values;
custom_gcode_per_print_z.clear();
custom_gcode_per_print_z.reserve(colorprint_values.size());
int i = 0;
for (auto val : colorprint_values)
custom_gcode_per_print_z.emplace_back(Model::CustomGCode{ val, ColorChangeCode, 1, colors[(++i)%7] });
}
}
/* There is one and only place this configuration option is used now.
* It wouldn't be used in the future, so erase it.
* */
// The "colorprint_heights" config value has been deprecated. At this point of time it has been converted
// to a new format and therefore it shall be erased.
config->erase("colorprint_heights");
}

View file

@ -403,8 +403,13 @@ public:
int object_idx{ -1 };
int volume_idx{ -1 };
Vec3d mesh_offset{ Vec3d::Zero() };
#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
Geometry::Transformation transform;
template<class Archive> void serialize(Archive& ar) { ar(input_file, object_idx, volume_idx, mesh_offset, transform); }
#else
template<class Archive> void serialize(Archive& ar) { ar(input_file, object_idx, volume_idx, mesh_offset); }
#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
};
Source source;
@ -754,21 +759,15 @@ public:
// Extensions for color print
struct CustomGCode
{
bool operator<(const CustomGCode& other) const { return other.print_z > this->print_z; }
bool operator==(const CustomGCode& other) const
bool operator<(const CustomGCode& rhs) const { return this->print_z < rhs.print_z; }
bool operator==(const CustomGCode& rhs) const
{
return (other.print_z == this->print_z ) &&
(other.gcode == this->gcode ) &&
(other.extruder == this->extruder ) &&
(other.color == this->color );
}
bool operator!=(const CustomGCode& other) const
{
return (other.print_z != this->print_z ) ||
(other.gcode != this->gcode ) ||
(other.extruder != this->extruder ) ||
(other.color != this->color );
return (rhs.print_z == this->print_z ) &&
(rhs.gcode == this->gcode ) &&
(rhs.extruder == this->extruder ) &&
(rhs.color == this->color );
}
bool operator!=(const CustomGCode& rhs) const { return ! (*this == rhs); }
double print_z;
std::string gcode;
@ -879,9 +878,9 @@ extern bool model_volume_list_changed(const ModelObject &model_object_old, const
extern bool model_has_multi_part_objects(const Model &model);
// If the model has advanced features, then it cannot be processed in simple mode.
extern bool model_has_advanced_features(const Model &model);
/* If loaded configuration has a "colorprint_heights" option (if it was imported from older Slicer),
* then model.custom_gcode_per_print_z should be updated considering this option
* */
// If loaded configuration has a "colorprint_heights" option (if it was imported from older Slicer),
// and if model.custom_gcode_per_print_z is empty (there is no color print data available in a new format
// then model.custom_gcode_per_print_z should be updated considering this option.
extern void update_custom_gcode_per_print_z_from_config(std::vector<Model::CustomGCode>& custom_gcode_per_print_z, DynamicPrintConfig* config);
#ifndef NDEBUG

View file

@ -1658,7 +1658,7 @@ void Print::_make_skirt()
for (const Layer *layer : object->m_layers) {
if (layer->print_z > skirt_height_z)
break;
for (const ExPolygon &expoly : layer->slices)
for (const ExPolygon &expoly : layer->lslices)
// Collect the outer contour points only, ignore holes for the calculation of the convex hull.
append(object_points, expoly.contour.points);
}
@ -1787,7 +1787,7 @@ void Print::_make_brim()
Polygons islands;
for (PrintObject *object : m_objects) {
Polygons object_islands;
for (ExPolygon &expoly : object->m_layers.front()->slices)
for (ExPolygon &expoly : object->m_layers.front()->lslices)
object_islands.push_back(expoly.contour);
if (! object->support_layers().empty())
object->support_layers().front()->support_fills.polygons_covered_by_spacing(object_islands, float(SCALED_EPSILON));

View file

@ -182,7 +182,7 @@ private:
void _slice(const std::vector<coordf_t> &layer_height_profile);
std::string _fix_slicing_errors();
void _simplify_slices(double distance);
void simplify_slices(double distance);
bool has_support_material() const;
void detect_surfaces_type();
void process_external_surfaces();

View file

@ -1333,9 +1333,11 @@ void PrintConfigDef::init_fff_params()
def->enum_values.push_back("octoprint");
def->enum_values.push_back("duet");
def->enum_values.push_back("flashair");
def->enum_values.push_back("astrobox");
def->enum_labels.push_back("OctoPrint");
def->enum_labels.push_back("Duet");
def->enum_labels.push_back("FlashAir");
def->enum_values.push_back("AstroBox");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<PrintHostType>(htOctoPrint));
@ -3466,7 +3468,8 @@ CLIMiscConfigDef::CLIMiscConfigDef()
def = this->add("loglevel", coInt);
def->label = L("Logging level");
def->tooltip = L("Messages with severity lower or eqal to the loglevel will be printed out. 0:trace, 1:debug, 2:info, 3:warning, 4:error, 5:fatal");
def->tooltip = L("Sets logging sensitivity. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:trace\n"
"For example. loglevel=2 logs fatal, error and warning level messages.");
def->min = 0;
#if (defined(_MSC_VER) || defined(__MINGW32__)) && defined(SLIC3R_GUI)

View file

@ -30,7 +30,7 @@ enum GCodeFlavor : unsigned char {
};
enum PrintHostType {
htOctoPrint, htDuet, htFlashAir
htOctoPrint, htDuet, htFlashAir, htAstroBox
};
enum InfillPattern {
@ -103,6 +103,7 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<PrintHostType>::g
keys_map["octoprint"] = htOctoPrint;
keys_map["duet"] = htDuet;
keys_map["flashair"] = htFlashAir;
keys_map["astrobox"] = htAstroBox;
}
return keys_map;
}

View file

@ -117,7 +117,7 @@ void PrintObject::slice()
BOOST_LOG_TRIVIAL(info) << warning;
// Simplify slices if required.
if (m_print->config().resolution)
this->_simplify_slices(scale_(this->print()->config().resolution));
this->simplify_slices(scale_(this->print()->config().resolution));
// Update bounding boxes
tbb::parallel_for(
tbb::blocked_range<size_t>(0, m_layers.size()),
@ -125,10 +125,10 @@ void PrintObject::slice()
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
m_print->throw_if_canceled();
Layer &layer = *m_layers[layer_idx];
layer.slices_bboxes.clear();
layer.slices_bboxes.reserve(layer.slices.size());
for (const ExPolygon &expoly : layer.slices)
layer.slices_bboxes.emplace_back(get_extents(expoly));
layer.lslices_bboxes.clear();
layer.lslices_bboxes.reserve(layer.lslices.size());
for (const ExPolygon &expoly : layer.lslices)
layer.lslices_bboxes.emplace_back(get_extents(expoly));
}
});
if (m_layers.empty())
@ -242,13 +242,6 @@ void PrintObject::make_perimeters()
m_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Generating perimeters in parallel - end";
/*
simplify slices (both layer and region slices),
we only need the max resolution for perimeters
### This makes this method not-idempotent, so we keep it disabled for now.
###$self->_simplify_slices(&Slic3r::SCALED_RESOLUTION);
*/
this->set_done(posPerimeters);
}
@ -692,7 +685,7 @@ void PrintObject::detect_surfaces_type()
if (upper_layer) {
Polygons upper_slices = interface_shells ?
to_polygons(upper_layer->get_region(idx_region)->slices.surfaces) :
to_polygons(upper_layer->slices);
to_polygons(upper_layer->lslices);
surfaces_append(top,
//FIXME implement offset2_ex working over ExPolygons, that should be a bit more efficient than calling offset_ex twice.
offset_ex(offset_ex(diff_ex(layerm_slices_surfaces, upper_slices, true), -offset), offset),
@ -721,7 +714,7 @@ void PrintObject::detect_surfaces_type()
surfaces_append(
bottom,
offset2_ex(
diff(layerm_slices_surfaces, to_polygons(lower_layer->slices), true),
diff(layerm_slices_surfaces, to_polygons(lower_layer->lslices), true),
-offset, offset),
surface_type_bottom_other);
// if user requested internal shells, we need to identify surfaces
@ -733,7 +726,7 @@ void PrintObject::detect_surfaces_type()
bottom,
offset2_ex(
diff(
intersection(layerm_slices_surfaces, to_polygons(lower_layer->slices)), // supported
intersection(layerm_slices_surfaces, to_polygons(lower_layer->lslices)), // supported
to_polygons(lower_layer->get_region(idx_region)->slices.surfaces),
true),
-offset, offset),
@ -879,7 +872,7 @@ void PrintObject::process_external_surfaces()
// Shrink the holes, let the layer above expand slightly inside the unsupported areas.
polygons_append(voids, offset(surface.expolygon, unsupported_width));
}
surfaces_covered[layer_idx] = diff(to_polygons(this->m_layers[layer_idx]->slices), voids);
surfaces_covered[layer_idx] = diff(to_polygons(this->m_layers[layer_idx]->lslices), voids);
}
}
);
@ -985,8 +978,8 @@ void PrintObject::discover_vertical_shells()
cache.bottom_surfaces = union_(cache.bottom_surfaces, false);
// For a multi-material print, simulate perimeter / infill split as if only a single extruder has been used for the whole print.
if (perimeter_offset > 0.) {
// The layer.slices are forced to merge by expanding them first.
polygons_append(cache.holes, offset(offset_ex(layer.slices, 0.3f * perimeter_min_spacing), - perimeter_offset - 0.3f * perimeter_min_spacing));
// The layer.lslices are forced to merge by expanding them first.
polygons_append(cache.holes, offset(offset_ex(layer.lslices, 0.3f * perimeter_min_spacing), - perimeter_offset - 0.3f * perimeter_min_spacing));
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
{
Slic3r::SVG svg(debug_out_path("discover_vertical_shells-extra-holes-%d.svg", debug_idx), get_extents(layer.slices));
@ -1762,78 +1755,101 @@ end:
;
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - begin";
tbb::parallel_for(
tbb::blocked_range<size_t>(0, m_layers.size()),
[this, upscaled, clipped](const tbb::blocked_range<size_t>& range) {
for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
m_print->throw_if_canceled();
Layer *layer = m_layers[layer_id];
// Apply size compensation and perform clipping of multi-part objects.
float delta = float(scale_(m_config.xy_size_compensation.value));
//FIXME only apply the compensation if no raft is enabled.
float elephant_foot_compensation = 0.f;
if (layer_id == 0 && m_config.raft_layers == 0)
// Only enable Elephant foot compensation if printing directly on the print bed.
elephant_foot_compensation = float(scale_(m_config.elefant_foot_compensation.value));
if (layer->m_regions.size() == 1) {
// Optimized version for a single region layer.
if (layer_id == 0) {
if (delta > elephant_foot_compensation) {
delta -= elephant_foot_compensation;
elephant_foot_compensation = 0.f;
} else if (delta > 0)
elephant_foot_compensation -= delta;
}
if (delta != 0.f || elephant_foot_compensation > 0.f) {
// Single region, growing or shrinking.
LayerRegion *layerm = layer->m_regions.front();
// Apply the XY compensation.
ExPolygons expolygons = (delta == 0.f) ?
to_expolygons(std::move(layerm->slices.surfaces)) :
offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), delta);
// Apply the elephant foot compensation.
if (elephant_foot_compensation > 0)
expolygons = union_ex(Slic3r::elephant_foot_compensation(expolygons, layerm->flow(frExternalPerimeter), unscale<double>(elephant_foot_compensation)));
layerm->slices.set(std::move(expolygons), stInternal);
}
} else {
bool upscale = ! upscaled && delta > 0.f;
bool clip = ! clipped && m_config.clip_multipart_objects.value;
if (upscale || clip) {
// Multiple regions, growing or just clipping one region by the other.
// When clipping the regions, priority is given to the first regions.
Polygons processed;
for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) {
LayerRegion *layerm = layer->m_regions[region_id];
ExPolygons slices = to_expolygons(std::move(layerm->slices.surfaces));
if (upscale)
slices = offset_ex(std::move(slices), delta);
if (region_id > 0 && clip)
// Trim by the slices of already processed regions.
slices = diff_ex(to_polygons(std::move(slices)), processed);
if (clip && (region_id + 1 < layer->m_regions.size()))
// Collect the already processed regions to trim the to be processed regions.
polygons_append(processed, slices);
layerm->slices.set(std::move(slices), stInternal);
}
}
if (delta < 0.f || elephant_foot_compensation > 0.f) {
// Apply the negative XY compensation.
Polygons trimming;
static const float eps = float(scale_(m_config.slice_closing_radius.value) * 1.5);
if (elephant_foot_compensation > 0.f) {
trimming = to_polygons(Slic3r::elephant_foot_compensation(offset_ex(layer->merged(eps), std::min(delta, 0.f) - eps),
layer->m_regions.front()->flow(frExternalPerimeter), unscale<double>(elephant_foot_compensation)));
} else
trimming = offset(layer->merged(float(SCALED_EPSILON)), delta - float(SCALED_EPSILON));
for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id)
layer->m_regions[region_id]->trim_surfaces(trimming);
}
}
// Merge all regions' slices to get islands, chain them by a shortest path.
layer->make_slices();
}
});
{
// Compensation value, scaled.
const float xy_compensation_scaled = float(scale_(m_config.xy_size_compensation.value));
const float elephant_foot_compensation_scaled = (m_config.raft_layers == 0) ?
// Only enable Elephant foot compensation if printing directly on the print bed.
float(scale_(m_config.elefant_foot_compensation.value)) :
0.f;
// Uncompensated slices for the first layer in case the Elephant foot compensation is applied.
ExPolygons lslices_1st_layer;
tbb::parallel_for(
tbb::blocked_range<size_t>(0, m_layers.size()),
[this, upscaled, clipped, xy_compensation_scaled, elephant_foot_compensation_scaled, &lslices_1st_layer]
(const tbb::blocked_range<size_t>& range) {
for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
m_print->throw_if_canceled();
Layer *layer = m_layers[layer_id];
// Apply size compensation and perform clipping of multi-part objects.
float elfoot = (layer_id == 0) ? elephant_foot_compensation_scaled : 0.f;
if (layer->m_regions.size() == 1) {
assert(! upscaled);
assert(! clipped);
// Optimized version for a single region layer.
// Single region, growing or shrinking.
LayerRegion *layerm = layer->m_regions.front();
if (elfoot > 0) {
// Apply the elephant foot compensation and store the 1st layer slices without the Elephant foot compensation applied.
lslices_1st_layer = to_expolygons(std::move(layerm->slices.surfaces));
float delta = xy_compensation_scaled;
if (delta > elfoot) {
delta -= elfoot;
elfoot = 0.f;
} else if (delta > 0)
elfoot -= delta;
layerm->slices.set(
union_ex(
Slic3r::elephant_foot_compensation(
(delta == 0.f) ? lslices_1st_layer : offset_ex(lslices_1st_layer, delta),
layerm->flow(frExternalPerimeter), unscale<double>(elfoot))),
stInternal);
if (xy_compensation_scaled != 0.f)
lslices_1st_layer = offset_ex(std::move(lslices_1st_layer), xy_compensation_scaled);
} else if (xy_compensation_scaled != 0.f) {
// Apply the XY compensation.
layerm->slices.set(
offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), xy_compensation_scaled),
stInternal);
}
} else {
bool upscale = ! upscaled && xy_compensation_scaled > 0.f;
bool clip = ! clipped && m_config.clip_multipart_objects.value;
if (upscale || clip) {
// Multiple regions, growing or just clipping one region by the other.
// When clipping the regions, priority is given to the first regions.
Polygons processed;
for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) {
LayerRegion *layerm = layer->m_regions[region_id];
ExPolygons slices = to_expolygons(std::move(layerm->slices.surfaces));
if (upscale)
slices = offset_ex(std::move(slices), xy_compensation_scaled);
if (region_id > 0 && clip)
// Trim by the slices of already processed regions.
slices = diff_ex(to_polygons(std::move(slices)), processed);
if (clip && (region_id + 1 < layer->m_regions.size()))
// Collect the already processed regions to trim the to be processed regions.
polygons_append(processed, slices);
layerm->slices.set(std::move(slices), stInternal);
}
}
if (xy_compensation_scaled < 0.f || elfoot > 0.f) {
// Apply the negative XY compensation.
Polygons trimming;
static const float eps = float(scale_(m_config.slice_closing_radius.value) * 1.5);
if (elfoot > 0.f) {
lslices_1st_layer = offset_ex(layer->merged(eps), std::min(xy_compensation_scaled, 0.f) - eps);
trimming = to_polygons(Slic3r::elephant_foot_compensation(lslices_1st_layer,
layer->m_regions.front()->flow(frExternalPerimeter), unscale<double>(elfoot)));
} else
trimming = offset(layer->merged(float(SCALED_EPSILON)), xy_compensation_scaled - float(SCALED_EPSILON));
for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id)
layer->m_regions[region_id]->trim_surfaces(trimming);
}
}
// Merge all regions' slices to get islands, chain them by a shortest path.
layer->make_slices();
}
});
if (elephant_foot_compensation_scaled > 0.f) {
// The Elephant foot has been compensated, therefore the 1st layer's lslices are shrank with the Elephant foot compensation value.
// Store the uncompensated value there.
assert(! m_layers.empty());
assert(m_layers.front()->id() == 0);
m_layers.front()->lslices = std::move(lslices_1st_layer);
}
}
m_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - end";
}
@ -2131,7 +2147,7 @@ std::string PrintObject::_fix_slicing_errors()
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - fixing slicing errors in parallel - end";
// remove empty layers from bottom
while (! m_layers.empty() && m_layers.front()->slices.empty()) {
while (! m_layers.empty() && (m_layers.front()->lslices.empty() || m_layers.front()->empty())) {
delete m_layers.front();
m_layers.erase(m_layers.begin());
m_layers.front()->lower_layer = nullptr;
@ -2147,7 +2163,7 @@ std::string PrintObject::_fix_slicing_errors()
// Simplify the sliced model, if "resolution" configuration parameter > 0.
// The simplification is problematic, because it simplifies the slices independent from each other,
// which makes the simplified discretization visible on the object surface.
void PrintObject::_simplify_slices(double distance)
void PrintObject::simplify_slices(double distance)
{
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - siplifying slices in parallel - begin";
tbb::parallel_for(
@ -2160,9 +2176,9 @@ void PrintObject::_simplify_slices(double distance)
layer->m_regions[region_idx]->slices.simplify(distance);
{
ExPolygons simplified;
for (const ExPolygon& expoly : layer->slices)
for (const ExPolygon &expoly : layer->lslices)
expoly.simplify(distance, &simplified);
layer->slices = std::move(simplified);
layer->lslices = std::move(simplified);
}
}
});
@ -2194,7 +2210,7 @@ void PrintObject::clip_fill_surfaces()
// Detect things that we need to support.
// Cummulative slices.
Polygons slices;
polygons_append(slices, layer->slices);
polygons_append(slices, layer->lslices);
// Cummulative fill surfaces.
Polygons fill_surfaces;
// Solid surfaces to be supported.

View file

@ -149,7 +149,7 @@ private:
Semver(semver_t ver) : ver(ver) {}
static semver_t semver_zero() { return { 0, 0, 0, nullptr, nullptr }; }
static char * strdup(const std::string &str) { return ::semver_strdup(const_cast<char*>(str.c_str())); }
static char * strdup(const std::string &str) { return ::semver_strdup(str.data()); }
};

View file

@ -1,6 +1,5 @@
#include "ClipperUtils.hpp"
#include "ExtrusionEntityCollection.hpp"
#include "PerimeterGenerator.hpp"
#include "Layer.hpp"
#include "Print.hpp"
#include "SupportMaterial.hpp"
@ -445,8 +444,8 @@ Polygons collect_region_slices_by_type(const Layer &layer, SurfaceType surface_t
Polygons collect_slices_outer(const Layer &layer)
{
Polygons out;
out.reserve(out.size() + layer.slices.size());
for (const ExPolygon &expoly : layer.slices)
out.reserve(out.size() + layer.lslices.size());
for (const ExPolygon &expoly : layer.lslices)
out.emplace_back(expoly.contour);
return out;
}
@ -907,9 +906,9 @@ namespace SupportMaterialInternal {
polyline.extend_start(fw);
polyline.extend_end(fw);
// Is the straight perimeter segment supported at both sides?
for (size_t i = 0; i < lower_layer.slices.size(); ++ i)
if (lower_layer.slices_bboxes[i].contains(polyline.first_point()) && lower_layer.slices_bboxes[i].contains(polyline.last_point()) &&
lower_layer.slices[i].contains(polyline.first_point()) && lower_layer.slices[i].contains(polyline.last_point())) {
for (size_t i = 0; i < lower_layer.lslices.size(); ++ i)
if (lower_layer.lslices_bboxes[i].contains(polyline.first_point()) && lower_layer.lslices_bboxes[i].contains(polyline.last_point()) &&
lower_layer.lslices[i].contains(polyline.first_point()) && lower_layer.lslices[i].contains(polyline.last_point())) {
// Offset a polyline into a thick line.
polygons_append(bridges, offset(polyline, 0.5f * w + 10.f));
break;
@ -998,7 +997,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
// inflate the polygons over and over.
Polygons &covered = buildplate_covered[layer_id];
covered = buildplate_covered[layer_id - 1];
polygons_append(covered, offset(lower_layer.slices, scale_(0.01)));
polygons_append(covered, offset(lower_layer.lslices, scale_(0.01)));
covered = union_(covered, false); // don't apply the safety offset.
}
}
@ -1027,7 +1026,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
Polygons contact_polygons;
Polygons slices_margin_cached;
float slices_margin_cached_offset = -1.;
Polygons lower_layer_polygons = (layer_id == 0) ? Polygons() : to_polygons(object.layers()[layer_id-1]->slices);
Polygons lower_layer_polygons = (layer_id == 0) ? Polygons() : to_polygons(object.layers()[layer_id-1]->lslices);
// Offset of the lower layer, to trim the support polygons with to calculate dense supports.
float no_interface_offset = 0.f;
if (layer_id == 0) {
@ -1166,7 +1165,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
slices_margin_cached_offset = slices_margin_offset;
slices_margin_cached = (slices_margin_offset == 0.f) ?
lower_layer_polygons :
offset2(to_polygons(lower_layer.slices), - no_interface_offset * 0.5f, slices_margin_offset + no_interface_offset * 0.5f, SUPPORT_SURFACES_OFFSET_PARAMETERS);
offset2(to_polygons(lower_layer.lslices), - no_interface_offset * 0.5f, slices_margin_offset + no_interface_offset * 0.5f, SUPPORT_SURFACES_OFFSET_PARAMETERS);
if (! buildplate_covered.empty()) {
// Trim the inflated contact surfaces by the top surfaces as well.
polygons_append(slices_margin_cached, buildplate_covered[layer_id]);
@ -1573,7 +1572,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
task_group.run([this, &projection, &projection_raw, &layer, &layer_support_area, layer_id] {
// Remove the areas that touched from the projection that will continue on next, lower, top surfaces.
// Polygons trimming = union_(to_polygons(layer.slices), touching, true);
Polygons trimming = offset(layer.slices, float(SCALED_EPSILON));
Polygons trimming = offset(layer.lslices, float(SCALED_EPSILON));
projection = diff(projection_raw, trimming, false);
#ifdef SLIC3R_DEBUG
{
@ -2105,7 +2104,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object(
const Layer &object_layer = *object.layers()[i];
if (object_layer.print_z - object_layer.height > support_layer.print_z + gap_extra_above - EPSILON)
break;
polygons_append(polygons_trimming, offset(object_layer.slices, gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS));
polygons_append(polygons_trimming, offset(object_layer.lslices, gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS));
}
if (! m_slicing_params.soluble_interface) {
// Collect all bottom surfaces, which will be extruded with a bridging flow.
@ -2218,7 +2217,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_raf
// Expand the bases of the support columns in the 1st layer.
columns_base->polygons = diff(
offset(columns_base->polygons, inflate_factor_1st_layer),
offset(m_object->layers().front()->slices, (float)scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS));
offset(m_object->layers().front()->lslices, (float)scale_(m_gap_xy), SUPPORT_SURFACES_OFFSET_PARAMETERS));
if (contacts != nullptr)
columns_base->polygons = diff(columns_base->polygons, interface_polygons);
}

View file

@ -56,4 +56,16 @@
// Enable closing 3Dconnextion imgui settings dialog by clicking on [X] and [Close] buttons
#define ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG (1 && ENABLE_2_2_0_ALPHA1)
// Enable not applying volume transformation during 3mf and amf loading, but keeping it as a ModelVolume member
#define ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE (1 && ENABLE_2_2_0_ALPHA1)
//==================
// 2.2.0.beta1 techs
//==================
#define ENABLE_2_2_0_BETA1 1
// Enable using Y axis of 3Dconnexion devices as zoom
#define ENABLE_3DCONNEXION_Y_AS_ZOOM (1 && ENABLE_2_2_0_BETA1)
#endif // _technologies_h_

View file

@ -65,7 +65,14 @@ extern std::string normalize_utf8_nfc(const char *src);
extern std::error_code rename_file(const std::string &from, const std::string &to);
// Copy a file, adjust the access attributes, so that the target is writable.
extern int copy_file(const std::string &from, const std::string &to);
int copy_file_inner(const std::string &from, const std::string &to);
// Copy file to a temp file first, then rename it to the final file name.
// If with_check is true, then the content of the copied file is compared to the content
// of the source file before renaming.
extern int copy_file(const std::string &from, const std::string &to, const bool with_check = false);
// Compares two files, returns 0 if identical, -1 if different.
extern int check_copy(const std::string& origin, const std::string& copy);
// Ignore system and hidden files, which may be created by the DropBox synchronisation process.
// https://github.com/prusa3d/PrusaSlicer/issues/1298

View file

@ -417,27 +417,76 @@ std::error_code rename_file(const std::string &from, const std::string &to)
#endif
}
int copy_file(const std::string &from, const std::string &to)
int copy_file_inner(const std::string& from, const std::string& to)
{
const boost::filesystem::path source(from);
const boost::filesystem::path target(to);
static const auto perms = boost::filesystem::owner_read | boost::filesystem::owner_write | boost::filesystem::group_read | boost::filesystem::others_read; // aka 644
const boost::filesystem::path source(from);
const boost::filesystem::path target(to);
static const auto perms = boost::filesystem::owner_read | boost::filesystem::owner_write | boost::filesystem::group_read | boost::filesystem::others_read; // aka 644
// Make sure the file has correct permission both before and after we copy over it.
// NOTE: error_code variants are used here to supress expception throwing.
// Error code of permission() calls is ignored on purpose - if they fail,
// the copy_file() function will fail appropriately and we don't want the permission()
// calls to cause needless failures on permissionless filesystems (ie. FATs on SD cards etc.)
// or when the target file doesn't exist.
boost::system::error_code ec;
boost::filesystem::permissions(target, perms, ec);
boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec);
if (ec) {
return -1;
}
boost::filesystem::permissions(target, perms, ec);
// Make sure the file has correct permission both before and after we copy over it.
// NOTE: error_code variants are used here to supress expception throwing.
// Error code of permission() calls is ignored on purpose - if they fail,
// the copy_file() function will fail appropriately and we don't want the permission()
// calls to cause needless failures on permissionless filesystems (ie. FATs on SD cards etc.)
// or when the target file doesn't exist.
boost::system::error_code ec;
boost::filesystem::permissions(target, perms, ec);
boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec);
if (ec) {
return -1;
}
boost::filesystem::permissions(target, perms, ec);
return 0;
}
return 0;
int copy_file(const std::string &from, const std::string &to, const bool with_check)
{
std::string to_temp = to + ".tmp";
int ret_val = copy_file_inner(from,to_temp);
if(ret_val == 0)
{
if (with_check)
ret_val = check_copy(from, to_temp);
if (ret_val == 0 && rename_file(to_temp, to))
ret_val = -1;
}
return ret_val;
}
int check_copy(const std::string &origin, const std::string &copy)
{
std::ifstream f1(origin, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
std::ifstream f2(copy, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
if (f1.fail() || f2.fail())
return -1;
std::streampos fsize = f1.tellg();
if (fsize != f2.tellg())
return -1;
f1.seekg(0, std::ifstream::beg);
f2.seekg(0, std::ifstream::beg);
// Compare by reading 8 MiB buffers one at a time.
size_t buffer_size = 8 * 1024 * 1024;
std::vector<char> buffer_origin(buffer_size, 0);
std::vector<char> buffer_copy(buffer_size, 0);
do {
f1.read(buffer_origin.data(), buffer_size);
f2.read(buffer_copy.data(), buffer_size);
std::streampos origin_cnt = f1.gcount();
std::streampos copy_cnt = f2.gcount();
if (origin_cnt != copy_cnt ||
(origin_cnt > 0 && std::memcmp(buffer_origin.data(), buffer_copy.data(), origin_cnt) != 0))
// Files are different.
return -1;
fsize -= origin_cnt;
} while (f1.good() && f2.good());
// All data has been read and compared equal.
return (f1.eof() && f2.eof() && fsize == 0) ? 0 : -1;
}
// Ignore system and hidden files, which may be created by the DropBox synchronisation process.
@ -486,7 +535,7 @@ std::string encode_path(const char *src)
// Convert a wide string to a local code page.
int size_needed = ::WideCharToMultiByte(0, 0, wstr_src.data(), (int)wstr_src.size(), nullptr, 0, nullptr, nullptr);
std::string str_dst(size_needed, 0);
::WideCharToMultiByte(0, 0, wstr_src.data(), (int)wstr_src.size(), const_cast<char*>(str_dst.data()), size_needed, nullptr, nullptr);
::WideCharToMultiByte(0, 0, wstr_src.data(), (int)wstr_src.size(), str_dst.data(), size_needed, nullptr, nullptr);
return str_dst;
#else /* WIN32 */
return src;
@ -503,7 +552,7 @@ std::string decode_path(const char *src)
// Convert the string encoded using the local code page to a wide string.
int size_needed = ::MultiByteToWideChar(0, 0, src, len, nullptr, 0);
std::wstring wstr_dst(size_needed, 0);
::MultiByteToWideChar(0, 0, src, len, const_cast<wchar_t*>(wstr_dst.data()), size_needed);
::MultiByteToWideChar(0, 0, src, len, wstr_dst.data(), size_needed);
// Convert a wide string to utf8.
return boost::nowide::narrow(wstr_dst.c_str());
#else /* WIN32 */