mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-25 15:44:12 -06:00
Merge branch 'master' into tm_colldetection_upgr
This commit is contained in:
commit
a7c07960ee
116 changed files with 5089 additions and 16124 deletions
|
@ -42,14 +42,20 @@ public:
|
|||
bool bridge;
|
||||
|
||||
Flow(float _w, float _h, float _nd, bool _bridge = false) :
|
||||
width(_w), height(_h), nozzle_diameter(_nd), bridge(_bridge) {};
|
||||
width(_w), height(_h), nozzle_diameter(_nd), bridge(_bridge) {}
|
||||
|
||||
float spacing() const;
|
||||
float spacing(const Flow &other) const;
|
||||
double mm3_per_mm() const;
|
||||
coord_t scaled_width() const { return coord_t(scale_(this->width)); };
|
||||
coord_t scaled_spacing() const { return coord_t(scale_(this->spacing())); };
|
||||
coord_t scaled_spacing(const Flow &other) const { return coord_t(scale_(this->spacing(other))); };
|
||||
coord_t scaled_width() const { return coord_t(scale_(this->width)); }
|
||||
coord_t scaled_spacing() const { return coord_t(scale_(this->spacing())); }
|
||||
coord_t scaled_spacing(const Flow &other) const { return coord_t(scale_(this->spacing(other))); }
|
||||
|
||||
// Elephant foot compensation spacing to be used to detect narrow parts, where the elephant foot compensation cannot be applied.
|
||||
// To be used on frExternalPerimeter only.
|
||||
// Enable some perimeter squish (see INSET_OVERLAP_TOLERANCE).
|
||||
// Here an overlap of 0.2x external perimeter spacing is allowed for by the elephant foot compensation.
|
||||
coord_t scaled_elephant_foot_spacing() const { return coord_t(0.5f * float(this->scaled_width() + 0.6f * this->scaled_spacing())); }
|
||||
|
||||
static Flow new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height, float bridge_flow_ratio);
|
||||
// Create a flow from the spacing of extrusion lines.
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include "3mf.hpp"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
@ -1749,6 +1751,11 @@ namespace Slic3r {
|
|||
bool _3MF_Exporter::_add_model_file_to_archive(mz_zip_archive& archive, Model& model)
|
||||
{
|
||||
std::stringstream stream;
|
||||
// https://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10
|
||||
// Conversion of a floating-point value to text and back is exact as long as at least max_digits10 were used (9 for float, 17 for double).
|
||||
// It is guaranteed to produce the same floating-point value, even though the intermediate text representation is not exact.
|
||||
// The default value of std::stream precision is 6 digits only!
|
||||
stream << std::setprecision(std::numeric_limits<float>::max_digits10);
|
||||
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
stream << "<" << MODEL_TAG << " unit=\"millimeter\" xml:lang=\"en-US\" xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\" xmlns:slic3rpe=\"http://schemas.slic3r.org/3mf/2017/06\">\n";
|
||||
stream << " <" << METADATA_TAG << " name=\"" << SLIC3RPE_3MF_VERSION << "\">" << VERSION_3MF << "</" << METADATA_TAG << ">\n";
|
||||
|
@ -1864,7 +1871,7 @@ namespace Slic3r {
|
|||
for (int i = 0; i < stl.stats.shared_vertices; ++i)
|
||||
{
|
||||
stream << " <" << VERTEX_TAG << " ";
|
||||
Vec3d v = matrix * stl.v_shared[i].cast<double>();
|
||||
Vec3f v = (matrix * stl.v_shared[i].cast<double>()).cast<float>();
|
||||
stream << "x=\"" << v(0) << "\" ";
|
||||
stream << "y=\"" << v(1) << "\" ";
|
||||
stream << "z=\"" << v(2) << "\" />\n";
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <limits>
|
||||
#include <string.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
@ -856,6 +857,11 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
|||
return false;
|
||||
|
||||
std::stringstream stream;
|
||||
// https://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10
|
||||
// Conversion of a floating-point value to text and back is exact as long as at least max_digits10 were used (9 for float, 17 for double).
|
||||
// It is guaranteed to produce the same floating-point value, even though the intermediate text representation is not exact.
|
||||
// The default value of std::stream precision is 6 digits only!
|
||||
stream << std::setprecision(std::numeric_limits<float>::max_digits10);
|
||||
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
stream << "<amf unit=\"millimeter\">\n";
|
||||
stream << "<metadata type=\"cad\">Slic3r " << SLIC3R_VERSION << "</metadata>\n";
|
||||
|
@ -927,7 +933,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
|||
for (size_t i = 0; i < stl.stats.shared_vertices; ++i) {
|
||||
stream << " <vertex>\n";
|
||||
stream << " <coordinates>\n";
|
||||
Vec3d v = matrix * stl.v_shared[i].cast<double>();
|
||||
Vec3f v = (matrix * stl.v_shared[i].cast<double>()).cast<float>();
|
||||
stream << " <x>" << v(0) << "</x>\n";
|
||||
stream << " <y>" << v(1) << "</y>\n";
|
||||
stream << " <z>" << v(2) << "</z>\n";
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "libslic3r.h"
|
||||
#include "GCode.hpp"
|
||||
#include "ExtrusionEntity.hpp"
|
||||
#include "EdgeGrid.hpp"
|
||||
|
@ -574,6 +575,16 @@ void GCode::_do_export(Print &print, FILE *file)
|
|||
// resets analyzer
|
||||
m_analyzer.reset();
|
||||
|
||||
// send extruder offset data to analyzer
|
||||
GCodeAnalyzer::ExtruderOffsetsMap extruder_offsets;
|
||||
for (unsigned int extruder_id : print.extruders())
|
||||
{
|
||||
Vec2d offset = print.config().extruder_offset.get_at(extruder_id);
|
||||
if (!offset.isApprox(Vec2d::Zero()))
|
||||
extruder_offsets[extruder_id] = offset;
|
||||
}
|
||||
m_analyzer.set_extruder_offsets(extruder_offsets);
|
||||
|
||||
// resets analyzer's tracking data
|
||||
m_last_mm3_per_mm = GCodeAnalyzer::Default_mm3_per_mm;
|
||||
m_last_width = GCodeAnalyzer::Default_Width;
|
||||
|
@ -843,7 +854,7 @@ void GCode::_do_export(Print &print, FILE *file)
|
|||
for (unsigned int extruder_id : print.extruders()) {
|
||||
const Vec2d &extruder_offset = print.config().extruder_offset.get_at(extruder_id);
|
||||
Polygon s(outer_skirt);
|
||||
s.translate(Point::new_scale(- extruder_offset(0), - extruder_offset(1)));
|
||||
s.translate(Point::new_scale(-extruder_offset(0), -extruder_offset(1)));
|
||||
skirts.emplace_back(std::move(s));
|
||||
}
|
||||
m_ooze_prevention.enable = true;
|
||||
|
@ -2488,6 +2499,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||
// adds analyzer tags and updates analyzer's tracking data
|
||||
if (m_enable_analyzer)
|
||||
{
|
||||
// PrusaMultiMaterial::Writer may generate GCodeAnalyzer::Height_Tag and GCodeAnalyzer::Width_Tag lines without updating m_last_height and m_last_width
|
||||
// so, if the last role was erWipeTower we force export of GCodeAnalyzer::Height_Tag and GCodeAnalyzer::Width_Tag lines
|
||||
bool last_was_wipe_tower = (m_last_analyzer_extrusion_role == erWipeTower);
|
||||
|
||||
if (path.role() != m_last_analyzer_extrusion_role)
|
||||
{
|
||||
m_last_analyzer_extrusion_role = path.role();
|
||||
|
@ -2505,7 +2520,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||
gcode += buf;
|
||||
}
|
||||
|
||||
if (m_last_width != path.width)
|
||||
if (last_was_wipe_tower || (m_last_width != path.width))
|
||||
{
|
||||
m_last_width = path.width;
|
||||
|
||||
|
@ -2514,7 +2529,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||
gcode += buf;
|
||||
}
|
||||
|
||||
if (m_last_height != path.height)
|
||||
if (last_was_wipe_tower || (m_last_height != path.height))
|
||||
{
|
||||
m_last_height = path.height;
|
||||
|
||||
|
|
|
@ -101,6 +101,11 @@ GCodeAnalyzer::GCodeAnalyzer()
|
|||
reset();
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::set_extruder_offsets(const GCodeAnalyzer::ExtruderOffsetsMap& extruder_offsets)
|
||||
{
|
||||
m_extruder_offsets = extruder_offsets;
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::reset()
|
||||
{
|
||||
_set_units(Millimeters);
|
||||
|
@ -118,6 +123,7 @@ void GCodeAnalyzer::reset()
|
|||
_reset_axes_position();
|
||||
|
||||
m_moves_map.clear();
|
||||
m_extruder_offsets.clear();
|
||||
}
|
||||
|
||||
const std::string& GCodeAnalyzer::process_gcode(const std::string& gcode)
|
||||
|
@ -654,7 +660,15 @@ void GCodeAnalyzer::_store_move(GCodeAnalyzer::GCodeMove::EType type)
|
|||
it = m_moves_map.insert(TypeToMovesMap::value_type(type, GCodeMovesList())).first;
|
||||
|
||||
// store move
|
||||
it->second.emplace_back(type, _get_extrusion_role(), _get_extruder_id(), _get_mm3_per_mm(), _get_width(), _get_height(), _get_feedrate(), _get_start_position(), _get_end_position(), _get_delta_extrusion(), _get_cp_color_id());
|
||||
Vec3d extruder_offset = Vec3d::Zero();
|
||||
unsigned int extruder_id = _get_extruder_id();
|
||||
ExtruderOffsetsMap::iterator extr_it = m_extruder_offsets.find(extruder_id);
|
||||
if (extr_it != m_extruder_offsets.end())
|
||||
extruder_offset = Vec3d(extr_it->second(0), extr_it->second(1), 0.0);
|
||||
|
||||
Vec3d start_position = _get_start_position() + extruder_offset;
|
||||
Vec3d end_position = _get_end_position() + extruder_offset;
|
||||
it->second.emplace_back(type, _get_extrusion_role(), extruder_id, _get_mm3_per_mm(), _get_width(), _get_height(), _get_feedrate(), start_position, end_position, _get_delta_extrusion(), _get_cp_color_id());
|
||||
}
|
||||
|
||||
bool GCodeAnalyzer::_is_valid_extrusion_role(int value) const
|
||||
|
|
|
@ -86,6 +86,7 @@ public:
|
|||
|
||||
typedef std::vector<GCodeMove> GCodeMovesList;
|
||||
typedef std::map<GCodeMove::EType, GCodeMovesList> TypeToMovesMap;
|
||||
typedef std::map<unsigned int, Vec2d> ExtruderOffsetsMap;
|
||||
|
||||
private:
|
||||
struct State
|
||||
|
@ -104,6 +105,7 @@ private:
|
|||
State m_state;
|
||||
GCodeReader m_parser;
|
||||
TypeToMovesMap m_moves_map;
|
||||
ExtruderOffsetsMap m_extruder_offsets;
|
||||
|
||||
// The output of process_layer()
|
||||
std::string m_process_output;
|
||||
|
@ -111,6 +113,8 @@ private:
|
|||
public:
|
||||
GCodeAnalyzer();
|
||||
|
||||
void set_extruder_offsets(const ExtruderOffsetsMap& extruder_offsets);
|
||||
|
||||
// Reinitialize the analyzer
|
||||
void reset();
|
||||
|
||||
|
|
|
@ -242,6 +242,7 @@ public:
|
|||
|
||||
void set_scaling_factor(const Vec3d& scaling_factor);
|
||||
void set_scaling_factor(Axis axis, double scaling_factor);
|
||||
bool is_scaling_uniform() const { return std::abs(m_scaling_factor.x() - m_scaling_factor.y()) < 1e-8 && std::abs(m_scaling_factor.x() - m_scaling_factor.z()) < 1e-8; }
|
||||
|
||||
const Vec3d& get_mirror() const { return m_mirror; }
|
||||
double get_mirror(Axis axis) const { return m_mirror(axis); }
|
||||
|
|
|
@ -65,6 +65,7 @@ void Layer::make_slices()
|
|||
this->slices.expolygons.push_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) {
|
||||
|
@ -78,6 +79,24 @@ void Layer::merge_slices()
|
|||
}
|
||||
}
|
||||
|
||||
ExPolygons Layer::merged(float offset_scaled) const
|
||||
{
|
||||
assert(offset_scaled >= 0.f);
|
||||
// If no offset is set, apply EPSILON offset before union, and revert it afterwards.
|
||||
float offset_scaled2 = 0;
|
||||
if (offset_scaled == 0.f) {
|
||||
offset_scaled = float( EPSILON);
|
||||
offset_scaled2 = float(- EPSILON);
|
||||
}
|
||||
Polygons polygons;
|
||||
for (LayerRegion *layerm : m_regions)
|
||||
append(polygons, offset(to_expolygons(layerm->slices.surfaces), offset_scaled));
|
||||
ExPolygons out = union_ex(polygons);
|
||||
if (offset_scaled2 != 0.f)
|
||||
out = offset_ex(out, offset_scaled2);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Here the perimeters are created cummulatively for all layer regions sharing the same parameters influencing the perimeters.
|
||||
// The perimeter paths and the thin fills (ExtrusionEntityCollection) are assigned to the first compatible layer region.
|
||||
// The resulting fill surface is split back among the originating regions.
|
||||
|
@ -86,13 +105,14 @@ void Layer::make_perimeters()
|
|||
BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id();
|
||||
|
||||
// keep track of regions whose perimeters we have already generated
|
||||
std::set<size_t> done;
|
||||
std::vector<unsigned char> done(m_regions.size(), false);
|
||||
|
||||
for (LayerRegionPtrs::iterator layerm = m_regions.begin(); layerm != m_regions.end(); ++ layerm) {
|
||||
size_t region_id = layerm - m_regions.begin();
|
||||
if (done.find(region_id) != done.end()) continue;
|
||||
if (done[region_id])
|
||||
continue;
|
||||
BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << ", region " << region_id;
|
||||
done.insert(region_id);
|
||||
done[region_id] = true;
|
||||
const PrintRegionConfig &config = (*layerm)->region()->config();
|
||||
|
||||
// find compatible regions
|
||||
|
@ -112,7 +132,7 @@ void Layer::make_perimeters()
|
|||
&& config.thin_walls == other_config.thin_walls
|
||||
&& config.external_perimeters_first == other_config.external_perimeters_first) {
|
||||
layerms.push_back(other_layerm);
|
||||
done.insert(it - m_regions.begin());
|
||||
done[it - m_regions.begin()] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,15 +144,13 @@ void Layer::make_perimeters()
|
|||
SurfaceCollection new_slices;
|
||||
{
|
||||
// group slices (surfaces) according to number of extra perimeters
|
||||
std::map<unsigned short,Surfaces> slices; // extra_perimeters => [ surface, surface... ]
|
||||
for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) {
|
||||
for (Surfaces::iterator s = (*l)->slices.surfaces.begin(); s != (*l)->slices.surfaces.end(); ++s) {
|
||||
slices[s->extra_perimeters].push_back(*s);
|
||||
}
|
||||
}
|
||||
std::map<unsigned short, Surfaces> slices; // extra_perimeters => [ surface, surface... ]
|
||||
for (LayerRegion *layerm : layerms)
|
||||
for (Surface &surface : layerm->slices.surfaces)
|
||||
slices[surface.extra_perimeters].emplace_back(surface);
|
||||
// merge the surfaces assigned to each group
|
||||
for (std::map<unsigned short,Surfaces>::const_iterator it = slices.begin(); it != slices.end(); ++it)
|
||||
new_slices.append(union_ex(it->second, true), it->second.front());
|
||||
for (std::pair<const unsigned short,Surfaces> &surfaces_with_extra_perimeters : slices)
|
||||
new_slices.append(union_ex(surfaces_with_extra_perimeters.second, true), surfaces_with_extra_perimeters.second.front());
|
||||
}
|
||||
|
||||
// make perimeters
|
||||
|
|
|
@ -63,7 +63,12 @@ public:
|
|||
void prepare_fill_surfaces();
|
||||
void make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces);
|
||||
void process_external_surfaces(const Layer* lower_layer);
|
||||
double infill_area_threshold() const;
|
||||
double infill_area_threshold() const;
|
||||
// Trim surfaces by trimming polygons. Used by the elephant foot compensation at the 1st layer.
|
||||
void trim_surfaces(const Polygons &trimming_polygons);
|
||||
// Single elephant foot compensation step, used by the elephant foor compensation at the 1st layer.
|
||||
// Trim surfaces by trimming polygons (shrunk by an elephant foot compensation step), but don't shrink narrow parts so much that no perimeter would fit.
|
||||
void elephant_foot_compensation_step(const float elephant_foot_compensation_perimeter_step, const Polygons &trimming_polygons);
|
||||
|
||||
void export_region_slices_to_svg(const char *path) const;
|
||||
void export_region_fill_surfaces_to_svg(const char *path) const;
|
||||
|
@ -117,7 +122,10 @@ public:
|
|||
// Test whether whether there are any slices assigned to this layer.
|
||||
bool empty() const;
|
||||
void make_slices();
|
||||
// Merge typed slices into untyped slices. This method is used to revert the effects of detect_surfaces_type() called for posPrepareInfill.
|
||||
void merge_slices();
|
||||
// Slices merged into islands, to be used by the elephant foot compensation to trim the individual surfaces with the shrunk merged slices.
|
||||
ExPolygons merged(float offset) const;
|
||||
template <class T> bool any_internal_region_slice_contains(const T &item) const {
|
||||
for (const LayerRegion *layerm : m_regions) if (layerm->slices.any_internal_contains(item)) return true;
|
||||
return false;
|
||||
|
|
|
@ -74,7 +74,7 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
|
|||
// Cummulative sum of polygons over all the regions.
|
||||
g.lower_slices = &this->layer()->lower_layer->slices;
|
||||
|
||||
g.layer_id = this->layer()->id();
|
||||
g.layer_id = (int)this->layer()->id();
|
||||
g.ext_perimeter_flow = this->flow(frExternalPerimeter);
|
||||
g.overhang_flow = this->region()->flow(frPerimeter, -1, true, false, -1, *this->layer()->object());
|
||||
g.solid_infill_flow = this->flow(frSolidInfill);
|
||||
|
@ -385,6 +385,28 @@ double LayerRegion::infill_area_threshold() const
|
|||
return ss*ss;
|
||||
}
|
||||
|
||||
void LayerRegion::trim_surfaces(const Polygons &trimming_polygons)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
for (const Surface &surface : this->slices.surfaces)
|
||||
assert(surface.surface_type == stInternal);
|
||||
#endif /* NDEBUG */
|
||||
this->slices.set(intersection_ex(to_polygons(std::move(this->slices.surfaces)), trimming_polygons, false), stInternal);
|
||||
}
|
||||
|
||||
void LayerRegion::elephant_foot_compensation_step(const float elephant_foot_compensation_perimeter_step, const Polygons &trimming_polygons)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
for (const Surface &surface : this->slices.surfaces)
|
||||
assert(surface.surface_type == stInternal);
|
||||
#endif /* NDEBUG */
|
||||
ExPolygons slices_expolygons = to_expolygons(std::move(this->slices.surfaces));
|
||||
Polygons slices_polygons = to_polygons(slices_expolygons);
|
||||
Polygons tmp = intersection(slices_polygons, trimming_polygons, false);
|
||||
append(tmp, diff(slices_polygons, offset(offset_ex(slices_expolygons, -elephant_foot_compensation_perimeter_step), elephant_foot_compensation_perimeter_step)));
|
||||
this->slices.set(std::move(union_ex(tmp)), stInternal);
|
||||
}
|
||||
|
||||
void LayerRegion::export_region_slices_to_svg(const char *path) const
|
||||
{
|
||||
BoundingBox bbox;
|
||||
|
|
|
@ -592,6 +592,7 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
|
|||
this->input_file = rhs.input_file;
|
||||
this->config = rhs.config;
|
||||
this->sla_support_points = rhs.sla_support_points;
|
||||
this->sla_points_status = rhs.sla_points_status;
|
||||
this->layer_height_ranges = rhs.layer_height_ranges;
|
||||
this->layer_height_profile = rhs.layer_height_profile;
|
||||
this->origin_translation = rhs.origin_translation;
|
||||
|
@ -625,6 +626,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
|
|||
this->input_file = std::move(rhs.input_file);
|
||||
this->config = std::move(rhs.config);
|
||||
this->sla_support_points = std::move(rhs.sla_support_points);
|
||||
this->sla_points_status = std::move(rhs.sla_points_status);
|
||||
this->layer_height_ranges = std::move(rhs.layer_height_ranges);
|
||||
this->layer_height_profile = std::move(rhs.layer_height_profile);
|
||||
this->origin_translation = std::move(rhs.origin_translation);
|
||||
|
@ -1130,6 +1132,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
|||
if (keep_upper) {
|
||||
upper->set_model(nullptr);
|
||||
upper->sla_support_points.clear();
|
||||
upper->sla_points_status = sla::PointsStatus::None;
|
||||
upper->clear_volumes();
|
||||
upper->input_file = "";
|
||||
}
|
||||
|
@ -1137,6 +1140,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
|||
if (keep_lower) {
|
||||
lower->set_model(nullptr);
|
||||
lower->sla_support_points.clear();
|
||||
lower->sla_points_status = sla::PointsStatus::None;
|
||||
lower->clear_volumes();
|
||||
lower->input_file = "";
|
||||
}
|
||||
|
|
|
@ -180,6 +180,9 @@ public:
|
|||
// saved in mesh coordinates to allow using them for several instances.
|
||||
// The format is (x, y, z, point_size, supports_island)
|
||||
std::vector<sla::SupportPoint> sla_support_points;
|
||||
// To keep track of where the points came from (used for synchronization between
|
||||
// the SLA gizmo and the backend).
|
||||
sla::PointsStatus sla_points_status = sla::PointsStatus::None;
|
||||
|
||||
/* This vector accumulates the total translation applied to the object by the
|
||||
center_around_origin() method. Callers might want to apply the same translation
|
||||
|
|
|
@ -523,6 +523,9 @@ exit_for_rearrange_regions:
|
|||
invalidated = true;
|
||||
}
|
||||
|
||||
for (PrintObject *object : m_objects)
|
||||
object->update_slicing_parameters();
|
||||
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
|
@ -1098,6 +1101,12 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
|||
}
|
||||
}
|
||||
|
||||
// Update SlicingParameters for each object where the SlicingParameters is not valid.
|
||||
// If it is not valid, then it is ensured that PrintObject.m_slicing_params is not in use
|
||||
// (posSlicing and posSupportMaterial was invalidated).
|
||||
for (PrintObject *object : m_objects)
|
||||
object->update_slicing_parameters();
|
||||
|
||||
#ifdef _DEBUG
|
||||
check_model_ids_equal(m_model, model);
|
||||
#endif /* _DEBUG */
|
||||
|
@ -1202,13 +1211,13 @@ std::string Print::validate() const
|
|||
break;
|
||||
}
|
||||
}
|
||||
SlicingParameters slicing_params0 = m_objects.front()->slicing_parameters();
|
||||
const SlicingParameters &slicing_params0 = m_objects.front()->slicing_parameters();
|
||||
size_t tallest_object_idx = 0;
|
||||
if (has_custom_layering)
|
||||
PrintObject::update_layer_height_profile(*m_objects.front()->model_object(), slicing_params0, layer_height_profiles.front());
|
||||
for (size_t i = 1; i < m_objects.size(); ++ i) {
|
||||
const PrintObject *object = m_objects[i];
|
||||
const SlicingParameters slicing_params = object->slicing_parameters();
|
||||
const PrintObject *object = m_objects[i];
|
||||
const SlicingParameters &slicing_params = object->slicing_parameters();
|
||||
if (std::abs(slicing_params.first_print_layer_height - slicing_params0.first_print_layer_height) > EPSILON ||
|
||||
std::abs(slicing_params.layer_height - slicing_params0.layer_height ) > EPSILON)
|
||||
return L("The Wipe Tower is only supported for multiple objects if they have equal layer heigths");
|
||||
|
|
|
@ -93,7 +93,7 @@ public:
|
|||
const LayerPtrs& layers() const { return m_layers; }
|
||||
const SupportLayerPtrs& support_layers() const { return m_support_layers; }
|
||||
const Transform3d& trafo() const { return m_trafo; }
|
||||
const Points& copies() const { return m_copies; }
|
||||
const Points& copies() const { return m_copies; }
|
||||
|
||||
// since the object is aligned to origin, bounding box coincides with size
|
||||
BoundingBox bounding_box() const { return BoundingBox(Point(0,0), to_2d(this->size)); }
|
||||
|
@ -131,7 +131,7 @@ public:
|
|||
// by the interactive layer height editor and by the printing process itself.
|
||||
// The slicing parameters are dependent on various configuration values
|
||||
// (layer height, first layer height, raft settings, print nozzle diameter etc).
|
||||
SlicingParameters slicing_parameters() const;
|
||||
const SlicingParameters& slicing_parameters() const { return m_slicing_params; }
|
||||
static SlicingParameters slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object);
|
||||
|
||||
// returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)
|
||||
|
@ -161,6 +161,8 @@ protected:
|
|||
bool invalidate_all_steps();
|
||||
// Invalidate steps based on a set of parameters changed.
|
||||
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
||||
// If ! m_slicing_params.valid, recalculate.
|
||||
void update_slicing_parameters();
|
||||
|
||||
static PrintObjectConfig object_config_from_model_object(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders);
|
||||
static PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_region_config, const ModelVolume &volume, size_t num_extruders);
|
||||
|
@ -195,11 +197,13 @@ private:
|
|||
// for external callers)
|
||||
Point m_copies_shift;
|
||||
|
||||
SlicingParameters m_slicing_params;
|
||||
LayerPtrs m_layers;
|
||||
SupportLayerPtrs m_support_layers;
|
||||
|
||||
std::vector<ExPolygons> _slice_region(size_t region_id, const std::vector<float> &z, bool modifier);
|
||||
std::vector<ExPolygons> _slice_volumes(const std::vector<float> &z, const std::vector<const ModelVolume*> &volumes) const;
|
||||
std::vector<ExPolygons> _slice_volume(const std::vector<float> &z, const ModelVolume &volume) const;
|
||||
};
|
||||
|
||||
struct WipeTowerData
|
||||
|
|
|
@ -59,6 +59,41 @@ void PrintConfigDef::init_common_params()
|
|||
def->cli = "max-print-height=f";
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloat(200.0);
|
||||
|
||||
def = this->add("slice_closing_radius", coFloat);
|
||||
def->label = L("Slice gap closing radius");
|
||||
def->category = L("Advanced");
|
||||
def->tooltip = L("Cracks smaller than 2x gap closing radius are being filled during the triangle mesh slicing. "
|
||||
"The gap closing operation may reduce the final print resolution, therefore it is advisable to keep the value reasonably low.");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "slice-closing-radius=f";
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloat(0.049);
|
||||
|
||||
def = this->add("print_host", coString);
|
||||
def->label = L("Hostname, IP or URL");
|
||||
def->tooltip = L("Slic3r can upload G-code files to a printer host. This field should contain "
|
||||
"the hostname, IP address or URL of the printer host instance.");
|
||||
def->cli = "print-host=s";
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionString("");
|
||||
|
||||
def = this->add("printhost_apikey", coString);
|
||||
def->label = L("API Key / Password");
|
||||
def->tooltip = L("Slic3r can upload G-code files to a printer host. This field should contain "
|
||||
"the API Key or the password required for authentication.");
|
||||
def->cli = "printhost-apikey=s";
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionString("");
|
||||
|
||||
def = this->add("printhost_cafile", coString);
|
||||
def->label = "HTTPS CA File";
|
||||
def->tooltip = "Custom CA certificate file can be specified for HTTPS OctoPrint connections, in crt/pem format. "
|
||||
"If left blank, the default OS CA certificate repository is used.";
|
||||
def->cli = "printhost-cafile=s";
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionString("");
|
||||
}
|
||||
|
||||
void PrintConfigDef::init_fff_params()
|
||||
|
@ -1320,30 +1355,6 @@ void PrintConfigDef::init_fff_params()
|
|||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionEnum<PrintHostType>(htOctoPrint);
|
||||
|
||||
def = this->add("printhost_apikey", coString);
|
||||
def->label = L("API Key / Password");
|
||||
def->tooltip = L("Slic3r can upload G-code files to a printer host. This field should contain "
|
||||
"the API Key or the password required for authentication.");
|
||||
def->cli = "printhost-apikey=s";
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionString("");
|
||||
|
||||
def = this->add("printhost_cafile", coString);
|
||||
def->label = "HTTPS CA File";
|
||||
def->tooltip = "Custom CA certificate file can be specified for HTTPS OctoPrint connections, in crt/pem format. "
|
||||
"If left blank, the default OS CA certificate repository is used.";
|
||||
def->cli = "printhost-cafile=s";
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionString("");
|
||||
|
||||
def = this->add("print_host", coString);
|
||||
def->label = L("Hostname, IP or URL");
|
||||
def->tooltip = L("Slic3r can upload G-code files to a printer host. This field should contain "
|
||||
"the hostname, IP address or URL of the printer host instance.");
|
||||
def->cli = "print-host=s";
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionString("");
|
||||
|
||||
def = this->add("only_retract_when_crossing_perimeters", coBool);
|
||||
def->label = L("Only retract when crossing perimeters");
|
||||
def->tooltip = L("Disables retraction when the travel path does not exceed the upper layer's perimeters "
|
||||
|
|
|
@ -38,7 +38,7 @@ enum GCodeFlavor {
|
|||
};
|
||||
|
||||
enum PrintHostType {
|
||||
htOctoPrint, htDuet, htSL1,
|
||||
htOctoPrint, htDuet
|
||||
};
|
||||
|
||||
enum InfillPattern {
|
||||
|
@ -384,6 +384,7 @@ public:
|
|||
ConfigOptionEnum<SeamPosition> seam_position;
|
||||
// ConfigOptionFloat seam_preferred_direction;
|
||||
// ConfigOptionFloat seam_preferred_direction_jitter;
|
||||
ConfigOptionFloat slice_closing_radius;
|
||||
ConfigOptionBool support_material;
|
||||
// Automatic supports (generated based on support_material_threshold).
|
||||
ConfigOptionBool support_material_auto;
|
||||
|
@ -425,6 +426,7 @@ protected:
|
|||
OPT_PTR(layer_height);
|
||||
OPT_PTR(raft_layers);
|
||||
OPT_PTR(seam_position);
|
||||
OPT_PTR(slice_closing_radius);
|
||||
// OPT_PTR(seam_preferred_direction);
|
||||
// OPT_PTR(seam_preferred_direction_jitter);
|
||||
OPT_PTR(support_material);
|
||||
|
@ -963,6 +965,8 @@ public:
|
|||
//Number of the layers needed for the exposure time fade [3;20]
|
||||
ConfigOptionInt faded_layers /*= 10*/;
|
||||
|
||||
ConfigOptionFloat slice_closing_radius;
|
||||
|
||||
// Enabling or disabling support creation
|
||||
ConfigOptionBool supports_enable;
|
||||
|
||||
|
@ -1036,6 +1040,7 @@ protected:
|
|||
{
|
||||
OPT_PTR(layer_height);
|
||||
OPT_PTR(faded_layers);
|
||||
OPT_PTR(slice_closing_radius);
|
||||
OPT_PTR(supports_enable);
|
||||
OPT_PTR(support_head_front_diameter);
|
||||
OPT_PTR(support_head_penetration);
|
||||
|
|
|
@ -157,8 +157,6 @@ template<> class FilePrinter<FilePrinterFormat::SLA_PNGZIP>
|
|||
"expTimeFirst = " + expt_first_str + "\n"
|
||||
"numFade = " + cnt_fade_layers + "\n"
|
||||
"layerHeight = " + layerh_str + "\n"
|
||||
"expTime = "+expt_str+" + resinType = generic+layerHeight = "
|
||||
+layerh_str+" + printer = DWARF3\n"
|
||||
"usedMaterial = " + used_material + "\n"
|
||||
"numSlow = " + cnt_slow_layers + "\n"
|
||||
"numFast = " + cnt_fast_layers + "\n";
|
||||
|
|
|
@ -104,7 +104,7 @@ void PrintObject::slice()
|
|||
return;
|
||||
m_print->set_status(10, "Processing triangulated mesh");
|
||||
std::vector<coordf_t> layer_height_profile;
|
||||
this->update_layer_height_profile(*this->model_object(), this->slicing_parameters(), layer_height_profile);
|
||||
this->update_layer_height_profile(*this->model_object(), m_slicing_params, layer_height_profile);
|
||||
m_print->throw_if_canceled();
|
||||
this->_slice(layer_height_profile);
|
||||
m_print->throw_if_canceled();
|
||||
|
@ -453,7 +453,8 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|
|||
} else if (
|
||||
opt_key == "layer_height"
|
||||
|| opt_key == "first_layer_height"
|
||||
|| opt_key == "raft_layers") {
|
||||
|| opt_key == "raft_layers"
|
||||
|| opt_key == "slice_closing_radius") {
|
||||
steps.emplace_back(posSlice);
|
||||
}
|
||||
else if (
|
||||
|
@ -567,8 +568,11 @@ bool PrintObject::invalidate_step(PrintObjectStep step)
|
|||
} else if (step == posSlice) {
|
||||
invalidated |= this->invalidate_steps({ posPerimeters, posPrepareInfill, posInfill, posSupportMaterial });
|
||||
invalidated |= m_print->invalidate_steps({ psSkirt, psBrim });
|
||||
} else if (step == posSupportMaterial)
|
||||
this->m_slicing_params.valid = false;
|
||||
} else if (step == posSupportMaterial) {
|
||||
invalidated |= m_print->invalidate_steps({ psSkirt, psBrim });
|
||||
this->m_slicing_params.valid = false;
|
||||
}
|
||||
|
||||
// Wipe tower depends on the ordering of extruders, which in turn depends on everything.
|
||||
// It also decides about what the wipe_into_infill / wipe_into_object features will do,
|
||||
|
@ -806,7 +810,7 @@ void PrintObject::process_external_surfaces()
|
|||
for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
|
||||
m_print->throw_if_canceled();
|
||||
// BOOST_LOG_TRIVIAL(trace) << "Processing external surface, layer" << m_layers[layer_idx]->print_z;
|
||||
m_layers[layer_idx]->get_region(region_id)->process_external_surfaces((layer_idx == 0) ? NULL : m_layers[layer_idx - 1]);
|
||||
m_layers[layer_idx]->get_region((int)region_id)->process_external_surfaces((layer_idx == 0) ? NULL : m_layers[layer_idx - 1]);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -1359,11 +1363,11 @@ PrintRegionConfig PrintObject::region_config_from_model_volume(const PrintRegion
|
|||
return config;
|
||||
}
|
||||
|
||||
SlicingParameters PrintObject::slicing_parameters() const
|
||||
void PrintObject::update_slicing_parameters()
|
||||
{
|
||||
return SlicingParameters::create_from_config(
|
||||
this->print()->config(), m_config,
|
||||
unscale<double>(this->size(2)), this->object_extruders());
|
||||
if (! m_slicing_params.valid)
|
||||
m_slicing_params = SlicingParameters::create_from_config(
|
||||
this->print()->config(), m_config, unscale<double>(this->size(2)), this->object_extruders());
|
||||
}
|
||||
|
||||
SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object)
|
||||
|
@ -1450,23 +1454,21 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
|
|||
tbb_init = new tbb::task_scheduler_init(1);
|
||||
#endif
|
||||
|
||||
SlicingParameters slicing_params = this->slicing_parameters();
|
||||
|
||||
// 1) Initialize layers and their slice heights.
|
||||
std::vector<float> slice_zs;
|
||||
{
|
||||
this->clear_layers();
|
||||
// Object layers (pairs of bottom/top Z coordinate), without the raft.
|
||||
std::vector<coordf_t> object_layers = generate_object_layers(slicing_params, layer_height_profile);
|
||||
std::vector<coordf_t> object_layers = generate_object_layers(m_slicing_params, layer_height_profile);
|
||||
// Reserve object layers for the raft. Last layer of the raft is the contact layer.
|
||||
int id = int(slicing_params.raft_layers());
|
||||
int id = int(m_slicing_params.raft_layers());
|
||||
slice_zs.reserve(object_layers.size());
|
||||
Layer *prev = nullptr;
|
||||
for (size_t i_layer = 0; i_layer < object_layers.size(); i_layer += 2) {
|
||||
coordf_t lo = object_layers[i_layer];
|
||||
coordf_t hi = object_layers[i_layer + 1];
|
||||
coordf_t slice_z = 0.5 * (lo + hi);
|
||||
Layer *layer = this->add_layer(id ++, hi - lo, hi + slicing_params.object_print_z_min, slice_z);
|
||||
Layer *layer = this->add_layer(id ++, hi - lo, hi + m_slicing_params.object_print_z_min, slice_z);
|
||||
slice_zs.push_back(float(slice_z));
|
||||
if (prev != nullptr) {
|
||||
prev->upper_layer = layer;
|
||||
|
@ -1478,46 +1480,151 @@ void PrintObject::_slice(const std::vector<coordf_t> &layer_height_profile)
|
|||
prev = layer;
|
||||
}
|
||||
}
|
||||
|
||||
// Count model parts and modifier meshes, check whether the model parts are of the same region.
|
||||
int single_volume_region = -2; // not set yet
|
||||
size_t num_volumes = 0;
|
||||
size_t num_modifiers = 0;
|
||||
std::vector<int> map_volume_to_region(this->model_object()->volumes.size());
|
||||
for (int region_id = 0; region_id < (int)this->region_volumes.size(); ++ region_id) {
|
||||
for (int volume_id : this->region_volumes[region_id]) {
|
||||
const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
|
||||
if (model_volume->is_model_part()) {
|
||||
map_volume_to_region[volume_id] = region_id;
|
||||
if (single_volume_region == -2)
|
||||
// first model volume met
|
||||
single_volume_region = region_id;
|
||||
else if (single_volume_region != region_id)
|
||||
// multiple volumes met and they are not equal
|
||||
single_volume_region = -1;
|
||||
++ num_volumes;
|
||||
} else if (model_volume->is_modifier())
|
||||
++ num_modifiers;
|
||||
}
|
||||
}
|
||||
assert(num_volumes > 0);
|
||||
|
||||
// Slice all non-modifier volumes.
|
||||
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - region " << region_id;
|
||||
std::vector<ExPolygons> expolygons_by_layer = this->_slice_region(region_id, slice_zs, false);
|
||||
m_print->throw_if_canceled();
|
||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " start";
|
||||
for (size_t layer_id = 0; layer_id < expolygons_by_layer.size(); ++ layer_id)
|
||||
m_layers[layer_id]->regions()[region_id]->slices.append(std::move(expolygons_by_layer[layer_id]), stInternal);
|
||||
m_print->throw_if_canceled();
|
||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " end";
|
||||
bool clipped = false;
|
||||
bool upscaled = false;
|
||||
if (! m_config.clip_multipart_objects.value || single_volume_region >= 0) {
|
||||
// Cheap path: Slice regions without mutual clipping.
|
||||
// The cheap path is possible if no clipping is allowed or if slicing volumes of just a single region.
|
||||
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - region " << region_id;
|
||||
// slicing in parallel
|
||||
std::vector<ExPolygons> expolygons_by_layer = this->_slice_region(region_id, slice_zs, false);
|
||||
m_print->throw_if_canceled();
|
||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " start";
|
||||
for (size_t layer_id = 0; layer_id < expolygons_by_layer.size(); ++ layer_id)
|
||||
m_layers[layer_id]->regions()[region_id]->slices.append(std::move(expolygons_by_layer[layer_id]), stInternal);
|
||||
m_print->throw_if_canceled();
|
||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " end";
|
||||
}
|
||||
} else {
|
||||
// Expensive path: Slice one volume after the other in the order they are presented at the user interface,
|
||||
// clip the last volumes with the first.
|
||||
// First slice the volumes.
|
||||
struct SlicedVolume {
|
||||
SlicedVolume(int volume_id, int region_id, std::vector<ExPolygons> &&expolygons_by_layer) :
|
||||
volume_id(volume_id), region_id(region_id), expolygons_by_layer(std::move(expolygons_by_layer)) {}
|
||||
int volume_id;
|
||||
int region_id;
|
||||
std::vector<ExPolygons> expolygons_by_layer;
|
||||
};
|
||||
std::vector<SlicedVolume> sliced_volumes;
|
||||
sliced_volumes.reserve(num_volumes);
|
||||
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id)
|
||||
for (int volume_id : this->region_volumes[region_id]) {
|
||||
const ModelVolume *model_volume = this->model_object()->volumes[volume_id];
|
||||
if (model_volume->is_model_part()) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - volume " << volume_id;
|
||||
// slicing in parallel
|
||||
sliced_volumes.emplace_back(volume_id, map_volume_to_region[volume_id], this->_slice_volume(slice_zs, *model_volume));
|
||||
}
|
||||
}
|
||||
// Second clip the volumes in the order they are presented at the user interface.
|
||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - parallel clipping - start";
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<size_t>(0, slice_zs.size()),
|
||||
[this, &sliced_volumes, num_modifiers](const tbb::blocked_range<size_t>& range) {
|
||||
float delta = float(scale_(m_config.xy_size_compensation.value));
|
||||
// Only upscale together with clipping if there are no modifiers, as the modifiers shall be applied before upscaling
|
||||
// (upscaling may grow the object outside of the modifier mesh).
|
||||
bool upscale = delta > 0 && num_modifiers == 0;
|
||||
for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
|
||||
m_print->throw_if_canceled();
|
||||
// Trim volumes in a single layer, one by the other, possibly apply upscaling.
|
||||
{
|
||||
Polygons processed;
|
||||
for (SlicedVolume &sliced_volume : sliced_volumes) {
|
||||
ExPolygons slices = std::move(sliced_volume.expolygons_by_layer[layer_id]);
|
||||
if (upscale)
|
||||
slices = offset_ex(std::move(slices), delta);
|
||||
if (! processed.empty())
|
||||
// Trim by the slices of already processed regions.
|
||||
slices = diff_ex(to_polygons(std::move(slices)), processed);
|
||||
if (size_t(&sliced_volume - &sliced_volumes.front()) + 1 < sliced_volumes.size())
|
||||
// Collect the already processed regions to trim the to be processed regions.
|
||||
polygons_append(processed, slices);
|
||||
sliced_volume.expolygons_by_layer[layer_id] = std::move(slices);
|
||||
}
|
||||
}
|
||||
// Collect and union volumes of a single region.
|
||||
for (int region_id = 0; region_id < (int)this->region_volumes.size(); ++ region_id) {
|
||||
ExPolygons expolygons;
|
||||
size_t num_volumes = 0;
|
||||
for (SlicedVolume &sliced_volume : sliced_volumes)
|
||||
if (sliced_volume.region_id == region_id && ! sliced_volume.expolygons_by_layer[layer_id].empty()) {
|
||||
++ num_volumes;
|
||||
append(expolygons, std::move(sliced_volume.expolygons_by_layer[layer_id]));
|
||||
}
|
||||
if (num_volumes > 1)
|
||||
// Merge the islands using a positive / negative offset.
|
||||
expolygons = offset_ex(offset_ex(expolygons, float(scale_(EPSILON))), -float(scale_(EPSILON)));
|
||||
m_layers[layer_id]->regions()[region_id]->slices.append(std::move(expolygons), stInternal);
|
||||
}
|
||||
}
|
||||
});
|
||||
BOOST_LOG_TRIVIAL(debug) << "Slicing objects - parallel clipping - end";
|
||||
clipped = true;
|
||||
upscaled = m_config.xy_size_compensation.value > 0 && num_modifiers == 0;
|
||||
}
|
||||
|
||||
// Slice all modifier volumes.
|
||||
if (this->region_volumes.size() > 1) {
|
||||
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++ region_id) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - region " << region_id;
|
||||
// slicing in parallel
|
||||
std::vector<ExPolygons> expolygons_by_layer = this->_slice_region(region_id, slice_zs, true);
|
||||
m_print->throw_if_canceled();
|
||||
if (expolygons_by_layer.empty())
|
||||
continue;
|
||||
// loop through the other regions and 'steal' the slices belonging to this one
|
||||
BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - stealing " << region_id << " start";
|
||||
for (size_t other_region_id = 0; other_region_id < this->region_volumes.size(); ++ other_region_id) {
|
||||
if (region_id == other_region_id)
|
||||
continue;
|
||||
for (size_t layer_id = 0; layer_id < expolygons_by_layer.size(); ++ layer_id) {
|
||||
Layer *layer = m_layers[layer_id];
|
||||
LayerRegion *layerm = layer->m_regions[region_id];
|
||||
LayerRegion *other_layerm = layer->m_regions[other_region_id];
|
||||
if (layerm == nullptr || other_layerm == nullptr)
|
||||
continue;
|
||||
Polygons other_slices = to_polygons(other_layerm->slices);
|
||||
ExPolygons my_parts = intersection_ex(other_slices, to_polygons(expolygons_by_layer[layer_id]));
|
||||
if (my_parts.empty())
|
||||
continue;
|
||||
// Remove such parts from original region.
|
||||
other_layerm->slices.set(diff_ex(other_slices, to_polygons(my_parts)), stInternal);
|
||||
// Append new parts to our region.
|
||||
layerm->slices.append(std::move(my_parts), stInternal);
|
||||
}
|
||||
}
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<size_t>(0, m_layers.size()),
|
||||
[this, &expolygons_by_layer, region_id](const tbb::blocked_range<size_t>& range) {
|
||||
for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
|
||||
for (size_t other_region_id = 0; other_region_id < this->region_volumes.size(); ++ other_region_id) {
|
||||
if (region_id == other_region_id)
|
||||
continue;
|
||||
Layer *layer = m_layers[layer_id];
|
||||
LayerRegion *layerm = layer->m_regions[region_id];
|
||||
LayerRegion *other_layerm = layer->m_regions[other_region_id];
|
||||
if (layerm == nullptr || other_layerm == nullptr)
|
||||
continue;
|
||||
Polygons other_slices = to_polygons(other_layerm->slices);
|
||||
ExPolygons my_parts = intersection_ex(other_slices, to_polygons(expolygons_by_layer[layer_id]));
|
||||
if (my_parts.empty())
|
||||
continue;
|
||||
// Remove such parts from original region.
|
||||
other_layerm->slices.set(diff_ex(other_slices, to_polygons(my_parts)), stInternal);
|
||||
// Append new parts to our region.
|
||||
layerm->slices.append(std::move(my_parts), stInternal);
|
||||
}
|
||||
}
|
||||
});
|
||||
m_print->throw_if_canceled();
|
||||
BOOST_LOG_TRIVIAL(debug) << "Slicing modifier volumes - stealing " << region_id << " end";
|
||||
}
|
||||
|
@ -1540,38 +1647,94 @@ 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](const tbb::blocked_range<size_t>& range) {
|
||||
[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));
|
||||
float elephant_foot_compensation = 0.f;
|
||||
if (layer_id == 0)
|
||||
delta -= float(scale_(m_config.elefant_foot_compensation.value));
|
||||
bool scale = delta != 0.f;
|
||||
bool clip = m_config.clip_multipart_objects.value || delta > 0.f;
|
||||
elephant_foot_compensation = float(scale_(m_config.elefant_foot_compensation.value));
|
||||
if (layer->m_regions.size() == 1) {
|
||||
if (scale) {
|
||||
// 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();
|
||||
layerm->slices.set(offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), delta), stInternal);
|
||||
// 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) {
|
||||
float elephant_foot_spacing = float(layerm->flow(frExternalPerimeter).scaled_elephant_foot_spacing());
|
||||
float external_perimeter_nozzle = float(scale_(this->print()->config().nozzle_diameter.get_at(layerm->region()->config().perimeter_extruder.value - 1)));
|
||||
// Apply the elephant foot compensation by steps of 1/10 nozzle diameter.
|
||||
float steps = std::ceil(elephant_foot_compensation / (0.1f * external_perimeter_nozzle));
|
||||
size_t nsteps = size_t(steps);
|
||||
float step = elephant_foot_compensation / steps;
|
||||
for (size_t i = 0; i < nsteps; ++ i) {
|
||||
Polygons tmp = offset(expolygons, - step);
|
||||
append(tmp, diff(to_polygons(expolygons), offset(offset_ex(expolygons, -elephant_foot_spacing - step), elephant_foot_spacing + step)));
|
||||
expolygons = union_ex(tmp);
|
||||
}
|
||||
}
|
||||
layerm->slices.set(std::move(expolygons), stInternal);
|
||||
}
|
||||
} else if (scale || clip) {
|
||||
// Multiple regions, growing, shrinking 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 (scale)
|
||||
slices = offset_ex(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);
|
||||
} 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) {
|
||||
// Apply the negative XY compensation.
|
||||
Polygons trimming = offset(layer->merged(float(EPSILON)), delta - float(EPSILON));
|
||||
for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id)
|
||||
layer->m_regions[region_id]->trim_surfaces(trimming);
|
||||
}
|
||||
if (elephant_foot_compensation > 0.f) {
|
||||
// Apply the elephant foot compensation.
|
||||
std::vector<float> elephant_foot_spacing;
|
||||
elephant_foot_spacing.reserve(layer->m_regions.size());
|
||||
float external_perimeter_nozzle = 0.f;
|
||||
for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) {
|
||||
LayerRegion *layerm = layer->m_regions[region_id];
|
||||
elephant_foot_spacing.emplace_back(float(layerm->flow(frExternalPerimeter).scaled_elephant_foot_spacing()));
|
||||
external_perimeter_nozzle += float(scale_(this->print()->config().nozzle_diameter.get_at(layerm->region()->config().perimeter_extruder.value - 1)));
|
||||
}
|
||||
external_perimeter_nozzle /= (float)layer->m_regions.size();
|
||||
// Apply the elephant foot compensation by steps of 1/10 nozzle diameter.
|
||||
float steps = std::ceil(elephant_foot_compensation / (0.1f * external_perimeter_nozzle));
|
||||
size_t nsteps = size_t(steps);
|
||||
float step = elephant_foot_compensation / steps;
|
||||
for (size_t i = 0; i < nsteps; ++ i) {
|
||||
Polygons trimming_polygons = offset(layer->merged(float(EPSILON)), - step - float(EPSILON));
|
||||
for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id)
|
||||
layer->m_regions[region_id]->elephant_foot_compensation_step(elephant_foot_spacing[region_id] + step, trimming_polygons);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Merge all regions' slices to get islands, chain them by a shortest path.
|
||||
|
@ -1643,13 +1806,35 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z,
|
|||
const Print *print = this->print();
|
||||
auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
|
||||
mslicer.init(&mesh, callback);
|
||||
mslicer.slice(z, &layers, callback);
|
||||
mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback);
|
||||
m_print->throw_if_canceled();
|
||||
}
|
||||
}
|
||||
return layers;
|
||||
}
|
||||
|
||||
std::vector<ExPolygons> PrintObject::_slice_volume(const std::vector<float> &z, const ModelVolume &volume) const
|
||||
{
|
||||
std::vector<ExPolygons> layers;
|
||||
// Compose mesh.
|
||||
//FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
|
||||
TriangleMesh mesh(volume.mesh);
|
||||
mesh.transform(volume.get_matrix());
|
||||
if (mesh.stl.stats.number_of_facets > 0) {
|
||||
mesh.transform(m_trafo);
|
||||
// apply XY shift
|
||||
mesh.translate(- unscale<float>(m_copies_shift(0)), - unscale<float>(m_copies_shift(1)), 0);
|
||||
// perform actual slicing
|
||||
TriangleMeshSlicer mslicer;
|
||||
const Print *print = this->print();
|
||||
auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
|
||||
mslicer.init(&mesh, callback);
|
||||
mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback);
|
||||
m_print->throw_if_canceled();
|
||||
}
|
||||
return layers;
|
||||
}
|
||||
|
||||
std::string PrintObject::_fix_slicing_errors()
|
||||
{
|
||||
// Collect layers with slicing errors.
|
||||
|
@ -2245,7 +2430,7 @@ void PrintObject::combine_infill()
|
|||
|
||||
void PrintObject::_generate_support_material()
|
||||
{
|
||||
PrintObjectSupportMaterial support_material(this, PrintObject::slicing_parameters());
|
||||
PrintObjectSupportMaterial support_material(this, m_slicing_params);
|
||||
support_material.generate(*this);
|
||||
}
|
||||
|
||||
|
|
|
@ -144,6 +144,8 @@ static std::vector<SLAAutoSupports::MyLayer> make_layers(
|
|||
const float layer_height = (layer_id!=0 ? heights[layer_id]-heights[layer_id-1] : heights[0]);
|
||||
const float safe_angle = 5.f * (float(M_PI)/180.f); // smaller number - less supports
|
||||
const float between_layers_offset = float(scale_(layer_height / std::tan(safe_angle)));
|
||||
const float slope_angle = 75.f * (float(M_PI)/180.f); // smaller number - less supports
|
||||
const float slope_offset = float(scale_(layer_height / std::tan(slope_angle)));
|
||||
//FIXME This has a quadratic time complexity, it will be excessively slow for many tiny islands.
|
||||
for (SLAAutoSupports::Structure &top : layer_above.islands) {
|
||||
for (SLAAutoSupports::Structure &bottom : layer_below.islands) {
|
||||
|
@ -173,6 +175,7 @@ static std::vector<SLAAutoSupports::MyLayer> make_layers(
|
|||
overhangs_sorted.emplace_back(std::move(*p.first));
|
||||
top.overhangs = std::move(overhangs_sorted);
|
||||
top.overhangs_area *= float(SCALING_FACTOR * SCALING_FACTOR);
|
||||
top.overhangs_slopes = diff_ex(top_polygons, offset(bottom_polygons, slope_offset));
|
||||
top.dangling_areas = diff_ex(top_polygons, offset(bottom_polygons, between_layers_offset));
|
||||
}
|
||||
}
|
||||
|
@ -241,9 +244,9 @@ void SLAAutoSupports::process(const std::vector<ExPolygons>& slices, const std::
|
|||
// What we now have in polygons needs support, regardless of what the forces are, so we can add them.
|
||||
//FIXME is it an island point or not? Vojtech thinks it is.
|
||||
uniformly_cover(s.dangling_areas, s, point_grid);
|
||||
} else if (! s.overhangs.empty()) {
|
||||
} else if (! s.overhangs_slopes.empty()) {
|
||||
//FIXME add the support force deficit as a parameter, only cover until the defficiency is covered.
|
||||
uniformly_cover(s.overhangs, s, point_grid);
|
||||
uniformly_cover(s.overhangs_slopes, s, point_grid);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,8 +65,12 @@ public:
|
|||
std::vector<Link> islands_above;
|
||||
std::vector<Link> islands_below;
|
||||
#endif
|
||||
// Overhangs, that are dangling considerably.
|
||||
ExPolygons dangling_areas;
|
||||
// Complete overhands.
|
||||
ExPolygons overhangs;
|
||||
// Overhangs, where the surface must slope.
|
||||
ExPolygons overhangs_slopes;
|
||||
float overhangs_area;
|
||||
|
||||
bool overlaps(const Structure &rhs) const {
|
||||
|
|
|
@ -561,7 +561,7 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
|
|||
heights.emplace_back(hi);
|
||||
|
||||
std::vector<ExPolygons> out; out.reserve(size_t(std::ceil(h/layerh)));
|
||||
slicer.slice(heights, &out, thrfn);
|
||||
slicer.slice(heights, 0.f, &out, thrfn);
|
||||
|
||||
size_t count = 0; for(auto& o : out) count += o.size();
|
||||
|
||||
|
|
|
@ -16,6 +16,14 @@ class TriangleMesh;
|
|||
|
||||
namespace sla {
|
||||
|
||||
// An enum to keep track of where the current points on the ModelObject came from.
|
||||
enum class PointsStatus {
|
||||
None, // No points were generated so far.
|
||||
Generating, // The autogeneration algorithm triggered, but not yet finished.
|
||||
AutoGenerated, // Points were autogenerated (i.e. copied from the backend).
|
||||
UserModified // User has done some edits.
|
||||
};
|
||||
|
||||
struct SupportPoint {
|
||||
Vec3f pos;
|
||||
float head_front_radius;
|
||||
|
|
|
@ -2129,7 +2129,7 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const
|
|||
fullmesh.merge(get_pad());
|
||||
TriangleMeshSlicer slicer(&fullmesh);
|
||||
SlicedSupports ret;
|
||||
slicer.slice(heights, &ret, get().ctl().cancelfn);
|
||||
slicer.slice(heights, 0.f, &ret, get().ctl().cancelfn);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -337,11 +337,34 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
|
|||
}
|
||||
}
|
||||
}
|
||||
if (model_object.sla_support_points != model_object_new.sla_support_points) {
|
||||
/*if (model_object.sla_support_points != model_object_new.sla_support_points) {
|
||||
model_object.sla_support_points = model_object_new.sla_support_points;
|
||||
if (it_print_object_status != print_object_status.end())
|
||||
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints));
|
||||
}
|
||||
if (model_object.sla_points_status != model_object_new.sla_points_status) {
|
||||
// Change of this status should invalidate support points. The points themselves are not enough, there are none
|
||||
// in case that nothing was generated OR that points were autogenerated already and not copied to the front-end.
|
||||
// These cases can only be differentiated by checking the status change. However, changing from 'Generating' should NOT
|
||||
// invalidate - that would keep stopping the background processing without a reason.
|
||||
if (model_object.sla_points_status != sla::PointsStatus::Generating)
|
||||
if (it_print_object_status != print_object_status.end())
|
||||
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints));
|
||||
model_object.sla_points_status = model_object_new.sla_points_status;
|
||||
}*/
|
||||
|
||||
bool old_user_modified = model_object.sla_points_status == sla::PointsStatus::UserModified;
|
||||
bool new_user_modified = model_object_new.sla_points_status == sla::PointsStatus::UserModified;
|
||||
if ((old_user_modified && ! new_user_modified) || // switching to automatic supports from manual supports
|
||||
(! old_user_modified && new_user_modified) || // switching to manual supports from automatic supports
|
||||
(new_user_modified && model_object.sla_support_points != model_object_new.sla_support_points)) {
|
||||
if (it_print_object_status != print_object_status.end())
|
||||
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints));
|
||||
|
||||
model_object.sla_points_status = model_object_new.sla_points_status;
|
||||
model_object.sla_support_points = model_object_new.sla_support_points;
|
||||
}
|
||||
|
||||
// Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step.
|
||||
model_object.name = model_object_new.name;
|
||||
model_object.input_file = model_object_new.input_file;
|
||||
|
@ -613,7 +636,7 @@ void SLAPrint::process()
|
|||
ilh, float(lh));
|
||||
|
||||
auto& layers = po.m_model_slices; layers.clear();
|
||||
slicer.slice(heights, &layers, [this](){ throw_if_canceled(); });
|
||||
slicer.slice(heights, float(po.config().slice_closing_radius.value), &layers, [this](){ throw_if_canceled(); });
|
||||
};
|
||||
|
||||
// In this step we check the slices, identify island and cover them with
|
||||
|
@ -629,10 +652,11 @@ void SLAPrint::process()
|
|||
BOOST_LOG_TRIVIAL(debug) << "Support point count "
|
||||
<< mo.sla_support_points.size();
|
||||
|
||||
// If there are no points on the front-end, we will do the
|
||||
// autoplacement. Otherwise we will just blindly copy the frontend data
|
||||
// Unless the user modified the points or we already did the calculation, we will do
|
||||
// the autoplacement. Otherwise we will just blindly copy the frontend data
|
||||
// into the backend cache.
|
||||
if(mo.sla_support_points.empty()) {
|
||||
if (mo.sla_points_status != sla::PointsStatus::UserModified) {
|
||||
|
||||
// calculate heights of slices (slices are calculated already)
|
||||
double lh = po.m_config.layer_height.getFloat();
|
||||
|
||||
|
@ -644,7 +668,9 @@ void SLAPrint::process()
|
|||
this->throw_if_canceled();
|
||||
SLAAutoSupports::Config config;
|
||||
const SLAPrintObjectConfig& cfg = po.config();
|
||||
config.density_relative = float(cfg.support_points_density_relative / 100.f); // the config value is in percents
|
||||
|
||||
// the density config value is in percents:
|
||||
config.density_relative = float(cfg.support_points_density_relative / 100.f);
|
||||
config.minimal_distance = float(cfg.support_points_minimal_distance);
|
||||
|
||||
// Construction of this object does the calculation.
|
||||
|
@ -668,7 +694,7 @@ void SLAPrint::process()
|
|||
report_status(*this, -1, L("Generating support points"), SlicingStatus::RELOAD_SLA_SUPPORT_POINTS);
|
||||
}
|
||||
else {
|
||||
// There are some points on the front-end, no calculation will be done.
|
||||
// There are either some points on the front-end, or the user removed them on purpose. No calculation will be done.
|
||||
po.m_supportdata->support_points = po.transformed_support_points();
|
||||
}
|
||||
};
|
||||
|
@ -1341,7 +1367,8 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
|
|||
bool invalidated = false;
|
||||
for (const t_config_option_key &opt_key : opt_keys) {
|
||||
if ( opt_key == "layer_height"
|
||||
|| opt_key == "faded_layers") {
|
||||
|| opt_key == "faded_layers"
|
||||
|| opt_key == "slice_closing_radius") {
|
||||
steps.emplace_back(slaposObjectSlice);
|
||||
} else if (
|
||||
opt_key == "supports_enable"
|
||||
|
|
|
@ -149,6 +149,7 @@ SlicingParameters SlicingParameters::create_from_config(
|
|||
params.object_print_z_max += print_z;
|
||||
}
|
||||
|
||||
params.valid = true;
|
||||
return params;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@ struct SlicingParameters
|
|||
// Height of the object to be printed. This value does not contain the raft height.
|
||||
coordf_t object_print_z_height() const { return object_print_z_max - object_print_z_min; }
|
||||
|
||||
bool valid;
|
||||
|
||||
// Number of raft layers.
|
||||
size_t base_raft_layers;
|
||||
// Number of interface layers including the contact layer.
|
||||
|
@ -100,6 +102,8 @@ static_assert(IsTriviallyCopyable<SlicingParameters>::value, "SlicingParameters
|
|||
// The two slicing parameters lead to the same layering as long as the variable layer thickness is not in action.
|
||||
inline bool equal_layering(const SlicingParameters &sp1, const SlicingParameters &sp2)
|
||||
{
|
||||
assert(sp1.valid);
|
||||
assert(sp2.valid);
|
||||
return sp1.base_raft_layers == sp2.base_raft_layers &&
|
||||
sp1.interface_raft_layers == sp2.interface_raft_layers &&
|
||||
sp1.base_raft_layer_height == sp2.base_raft_layer_height &&
|
||||
|
|
|
@ -42,15 +42,6 @@
|
|||
#define ENABLE_VOLUMES_CENTERING_FIXES (1 && ENABLE_1_42_0_ALPHA4)
|
||||
|
||||
|
||||
//====================
|
||||
// 1.42.0.alpha5 techs
|
||||
//====================
|
||||
#define ENABLE_1_42_0_ALPHA5 1
|
||||
|
||||
// Toolbar items hidden/shown in dependence of the user mode
|
||||
#define ENABLE_MODE_AWARE_TOOLBAR_ITEMS (1 && ENABLE_1_42_0_ALPHA5)
|
||||
|
||||
|
||||
//====================
|
||||
// 1.42.0.alpha7 techs
|
||||
//====================
|
||||
|
@ -59,4 +50,13 @@
|
|||
// Printbed textures generated from svg files
|
||||
#define ENABLE_TEXTURES_FROM_SVG (1 && ENABLE_1_42_0_ALPHA7)
|
||||
|
||||
|
||||
//====================
|
||||
// 1.42.0.alpha8 techs
|
||||
//====================
|
||||
#define ENABLE_1_42_0_ALPHA8 1
|
||||
|
||||
// Toolbars and Gizmos use icons imported from svg files
|
||||
#define ENABLE_SVG_ICONS (1 && ENABLE_1_42_0_ALPHA8 && ENABLE_TEXTURES_FROM_SVG)
|
||||
|
||||
#endif // _technologies_h_
|
||||
|
|
|
@ -852,7 +852,7 @@ void TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLin
|
|||
}
|
||||
}
|
||||
|
||||
void TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const
|
||||
void TriangleMeshSlicer::slice(const std::vector<float> &z, const float closing_radius, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const
|
||||
{
|
||||
std::vector<Polygons> layers_p;
|
||||
this->slice(z, &layers_p, throw_on_cancel);
|
||||
|
@ -861,13 +861,13 @@ void TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<ExPolygo
|
|||
layers->resize(z.size());
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<size_t>(0, z.size()),
|
||||
[&layers_p, layers, throw_on_cancel, this](const tbb::blocked_range<size_t>& range) {
|
||||
[&layers_p, closing_radius, layers, throw_on_cancel, this](const tbb::blocked_range<size_t>& range) {
|
||||
for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
|
||||
#ifdef SLIC3R_TRIANGLEMESH_DEBUG
|
||||
printf("Layer " PRINTF_ZU " (slice_z = %.2f):\n", layer_id, z[layer_id]);
|
||||
#endif
|
||||
throw_on_cancel();
|
||||
this->make_expolygons(layers_p[layer_id], &(*layers)[layer_id]);
|
||||
this->make_expolygons(layers_p[layer_id], closing_radius, &(*layers)[layer_id]);
|
||||
}
|
||||
});
|
||||
BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::make_expolygons in parallel - end";
|
||||
|
@ -1600,7 +1600,7 @@ void TriangleMeshSlicer::make_expolygons_simple(std::vector<IntersectionLine> &l
|
|||
#endif
|
||||
}
|
||||
|
||||
void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slices) const
|
||||
void TriangleMeshSlicer::make_expolygons(const Polygons &loops, const float closing_radius, ExPolygons* slices) const
|
||||
{
|
||||
/*
|
||||
Input loops are not suitable for evenodd nor nonzero fill types, as we might get
|
||||
|
@ -1655,7 +1655,7 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slic
|
|||
// 0.0499 comes from https://github.com/slic3r/Slic3r/issues/959
|
||||
// double safety_offset = scale_(0.0499);
|
||||
// 0.0001 is set to satisfy GH #520, #1029, #1364
|
||||
double safety_offset = scale_(0.0001);
|
||||
double safety_offset = scale_(closing_radius);
|
||||
|
||||
/* The following line is commented out because it can generate wrong polygons,
|
||||
see for example issue #661 */
|
||||
|
@ -1670,17 +1670,17 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slic
|
|||
#endif
|
||||
|
||||
// append to the supplied collection
|
||||
/* Fix for issue #661 { */
|
||||
expolygons_append(*slices, offset2_ex(union_(loops, false), +safety_offset, -safety_offset));
|
||||
//expolygons_append(*slices, ex_slices);
|
||||
/* } */
|
||||
if (safety_offset > 0)
|
||||
expolygons_append(*slices, offset2_ex(union_(loops, false), +safety_offset, -safety_offset));
|
||||
else
|
||||
expolygons_append(*slices, union_ex(loops, false));
|
||||
}
|
||||
|
||||
void TriangleMeshSlicer::make_expolygons(std::vector<IntersectionLine> &lines, ExPolygons* slices) const
|
||||
void TriangleMeshSlicer::make_expolygons(std::vector<IntersectionLine> &lines, const float closing_radius, ExPolygons* slices) const
|
||||
{
|
||||
Polygons pp;
|
||||
this->make_loops(lines, &pp);
|
||||
this->make_expolygons(pp, slices);
|
||||
this->make_expolygons(pp, closing_radius, slices);
|
||||
}
|
||||
|
||||
void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) const
|
||||
|
|
|
@ -165,7 +165,7 @@ public:
|
|||
TriangleMeshSlicer(TriangleMesh* mesh) { this->init(mesh, [](){}); }
|
||||
void init(TriangleMesh *mesh, throw_on_cancel_callback_type throw_on_cancel);
|
||||
void slice(const std::vector<float> &z, std::vector<Polygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const;
|
||||
void slice(const std::vector<float> &z, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const;
|
||||
void slice(const std::vector<float> &z, const float closing_radius, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const;
|
||||
enum FacetSliceType {
|
||||
NoSlice = 0,
|
||||
Slicing = 1,
|
||||
|
@ -184,9 +184,9 @@ private:
|
|||
|
||||
void _slice_do(size_t facet_idx, std::vector<IntersectionLines>* lines, boost::mutex* lines_mutex, const std::vector<float> &z) const;
|
||||
void make_loops(std::vector<IntersectionLine> &lines, Polygons* loops) const;
|
||||
void make_expolygons(const Polygons &loops, ExPolygons* slices) const;
|
||||
void make_expolygons(const Polygons &loops, const float closing_radius, ExPolygons* slices) const;
|
||||
void make_expolygons_simple(std::vector<IntersectionLine> &lines, ExPolygons* slices) const;
|
||||
void make_expolygons(std::vector<IntersectionLine> &lines, ExPolygons* slices) const;
|
||||
void make_expolygons(std::vector<IntersectionLine> &lines, const float closing_radius, ExPolygons* slices) const;
|
||||
};
|
||||
|
||||
TriangleMesh make_cube(double x, double y, double z);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue