mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-13 19:35:55 +08:00
merge complete
This commit is contained in:
parent
a4f9c28a9a
commit
a36142d258
@ -244,26 +244,26 @@ Polygons BridgeDetector::coverage(double angle, bool precise) const {
|
||||
if (n_supported >= 2) {
|
||||
// trim it to not allow to go outside of the intersections
|
||||
BoundingBox center_bound = intersects[0].bounding_box();
|
||||
coord_t min_y = center_bound.center().y, max_y = center_bound.center().y;
|
||||
coord_t min_y = center_bound.center()(1), max_y = center_bound.center()(1);
|
||||
for (Polygon &poly_bound : intersects) {
|
||||
center_bound = poly_bound.bounding_box();
|
||||
if (min_y > center_bound.center().y) min_y = center_bound.center().y;
|
||||
if (max_y < center_bound.center().y) max_y = center_bound.center().y;
|
||||
if (min_y > center_bound.center()(1)) min_y = center_bound.center()(1);
|
||||
if (max_y < center_bound.center()(1)) max_y = center_bound.center()(1);
|
||||
}
|
||||
coord_t min_x = trapezoid[0].x, max_x = trapezoid[0].x;
|
||||
coord_t min_x = trapezoid[0](0), max_x = trapezoid[0](0);
|
||||
for (Point &p : trapezoid.points) {
|
||||
if (min_x > p.x) min_x = p.x;
|
||||
if (max_x < p.x) max_x = p.x;
|
||||
if (min_x > p(0)) min_x = p(0);
|
||||
if (max_x < p(0)) max_x = p(0);
|
||||
}
|
||||
//add what get_trapezoids3 has removed (+EPSILON)
|
||||
min_x -= (this->spacing / 4 + 1);
|
||||
max_x += (this->spacing / 4 + 1);
|
||||
coord_t mid_x = (min_x + max_x) / 2;
|
||||
for (Point &p : trapezoid.points) {
|
||||
if (p.y < min_y) p.y = min_y;
|
||||
if (p.y > max_y) p.y = max_y;
|
||||
if (p.x > min_x && p.x < mid_x) p.x = min_x;
|
||||
if (p.x < max_x && p.x > mid_x) p.x = max_x;
|
||||
if (p(1) < min_y) p(1) = min_y;
|
||||
if (p(1) > max_y) p(1) = max_y;
|
||||
if (p(0) > min_x && p(0) < mid_x) p(0) = min_x;
|
||||
if (p(0) < max_x && p(0) > mid_x) p(0) = max_x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -314,11 +314,11 @@ ExPolygon::get_trapezoids3_half(Polygons* polygons, float spacing) const {
|
||||
BoundingBox bb(pp);
|
||||
|
||||
// get all x coordinates
|
||||
int min_x = pp[0].x, max_x = pp[0].x;
|
||||
int min_x = pp[0].x(), max_x = pp[0].x();
|
||||
std::vector<coord_t> xx;
|
||||
for (Points::const_iterator p = pp.begin(); p != pp.end(); ++p) {
|
||||
if (min_x > p->x) min_x = p->x;
|
||||
if (max_x < p->x) max_x = p->x;
|
||||
if (min_x > p->x()) min_x = p->x();
|
||||
if (max_x < p->x()) max_x = p->x();
|
||||
}
|
||||
for (int x = min_x; x < max_x-spacing/2; x += spacing) {
|
||||
xx.push_back(x);
|
||||
@ -334,14 +334,14 @@ ExPolygon::get_trapezoids3_half(Polygons* polygons, float spacing) const {
|
||||
// build rectangle
|
||||
Polygon poly;
|
||||
poly.points.resize(4);
|
||||
poly[0].x = *x +spacing / 4;
|
||||
poly[0].y = bb.min.y;
|
||||
poly[1].x = next_x -spacing / 4;
|
||||
poly[1].y = bb.min.y;
|
||||
poly[2].x = next_x -spacing / 4;
|
||||
poly[2].y = bb.max.y;
|
||||
poly[3].x = *x +spacing / 4;
|
||||
poly[3].y = bb.max.y;
|
||||
poly[0].x() = *x + spacing / 4;
|
||||
poly[0].y() = bb.min(1);
|
||||
poly[1].x() = next_x - spacing / 4;
|
||||
poly[1].y() = bb.min(1);
|
||||
poly[2].x() = next_x - spacing / 4;
|
||||
poly[2].y() = bb.max(1);
|
||||
poly[3].x() = *x + spacing / 4;
|
||||
poly[3].y() = bb.max(1);
|
||||
|
||||
// intersect with this expolygon
|
||||
// append results to return value
|
||||
|
@ -59,7 +59,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
|
||||
layerm.fill_surfaces.group(&groups);
|
||||
|
||||
//if internal infill can be dense, place it on his own group
|
||||
if (layerm.region()->config.infill_dense.getBool() && layerm.region()->config.fill_density<40) {
|
||||
if (layerm.region()->config().infill_dense.getBool() && layerm.region()->config().fill_density<40) {
|
||||
SurfacesPtr *denseGroup = NULL;
|
||||
const uint32_t nbGroups = groups.size();
|
||||
for (uint32_t num_group = 0; num_group < nbGroups; ++num_group) {
|
||||
@ -193,8 +193,8 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
|
||||
(surface.is_top() ? layerm.region()->config().top_fill_pattern.value : layerm.region()->config().bottom_fill_pattern.value) :
|
||||
ipRectilinear;
|
||||
} else {
|
||||
if (layerm.region()->config.infill_dense.getBool()
|
||||
&& layerm.region()->config.fill_density<40
|
||||
if (layerm.region()->config().infill_dense.getBool()
|
||||
&& layerm.region()->config().fill_density<40
|
||||
&& surface.maxNbSolidLayersOnTop <= 1
|
||||
&& surface.maxNbSolidLayersOnTop > 0) {
|
||||
density = 42;
|
||||
@ -262,8 +262,8 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
|
||||
f->loop_clipping = scale_(flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER;
|
||||
//give the overlap size to let the infill do his overlap
|
||||
//add overlap if at least one perimeter
|
||||
if (layerm.region()->config.perimeters.getInt() > 0) {
|
||||
f->overlap = layerm.region()->config.get_abs_value("infill_overlap", (perimeter_spacing + (f->spacing)) / 2);
|
||||
if (layerm.region()->config().perimeters > 0) {
|
||||
f->overlap = layerm.region()->config().get_abs_value("infill_overlap", (perimeter_spacing + (f->spacing)) / 2);
|
||||
if (f->overlap!=0) {
|
||||
f->no_overlap_expolygons = intersection_ex(layerm.fill_no_overlap_expolygons, ExPolygons() = { surface.expolygon });
|
||||
} else {
|
||||
@ -278,8 +278,8 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
|
||||
FillParams params;
|
||||
params.density = 0.01 * density;
|
||||
params.dont_adjust = false;
|
||||
params.fill_exactly = layerm.region()->config.enforce_full_fill_volume.getBool();
|
||||
params.dont_connect = layerm.region()->config.infill_not_connected.getBool();
|
||||
params.fill_exactly = layerm.region()->config().enforce_full_fill_volume.getBool();
|
||||
params.dont_connect = layerm.region()->config().infill_not_connected.getBool();
|
||||
|
||||
// calculate actual flow from spacing (which might have been adjusted by the infill
|
||||
// pattern generator)
|
||||
@ -293,8 +293,8 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
|
||||
|
||||
float flow_percent = 1;
|
||||
if(surface.is_overBridge()){
|
||||
params.density = layerm.region()->config.over_bridge_flow_ratio;
|
||||
//params.flow_mult = layerm.region()->config.over_bridge_flow_ratio;
|
||||
params.density = layerm.region()->config().over_bridge_flow_ratio;
|
||||
//params.flow_mult = layerm.region()->config().over_bridge_flow_ratio;
|
||||
}
|
||||
|
||||
f->fill_surface_extrusion(&surface, params, flow, erNone, out.entities);
|
||||
|
@ -151,7 +151,7 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams ¶
|
||||
for (auto pline = polylines.begin(); pline != polylines.end(); ++pline){
|
||||
Lines lines = pline->lines();
|
||||
for (auto line = lines.begin(); line != lines.end(); ++line){
|
||||
lengthTot += unscale(line->length());
|
||||
lengthTot += unscaled(line->length());
|
||||
nbLines++;
|
||||
}
|
||||
}
|
||||
@ -159,13 +159,13 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams ¶
|
||||
// compute real volume
|
||||
double poylineVolume = 0;
|
||||
for (auto poly = this->no_overlap_expolygons.begin(); poly != this->no_overlap_expolygons.end(); ++poly) {
|
||||
poylineVolume += flow.height*unscale(unscale(poly->area()));
|
||||
poylineVolume += flow.height*unscaled(unscaled(poly->area()));
|
||||
// add external "perimeter gap"
|
||||
double perimeterRoundGap = unscale(poly->contour.length()) * flow.height * (1 - 0.25*PI) * 0.5;
|
||||
double perimeterRoundGap = unscaled(poly->contour.length()) * flow.height * (1 - 0.25*PI) * 0.5;
|
||||
// add holes "perimeter gaps"
|
||||
double holesGaps = 0;
|
||||
for (auto hole = poly->holes.begin(); hole != poly->holes.end(); ++hole) {
|
||||
holesGaps += unscale(hole->length()) * flow.height * (1 - 0.25*PI) * 0.5;
|
||||
holesGaps += unscaled(hole->length()) * flow.height * (1 - 0.25*PI) * 0.5;
|
||||
}
|
||||
poylineVolume += perimeterRoundGap + holesGaps;
|
||||
}
|
||||
@ -196,7 +196,7 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams ¶
|
||||
}
|
||||
/// push the path
|
||||
extrusion_entities_append_paths(
|
||||
eec->entities, STDMOVE(polylines),
|
||||
eec->entities, std::move(polylines),
|
||||
good_role,
|
||||
flow.mm3_per_mm() * params.flow_mult * multFlow,
|
||||
flow.width * params.flow_mult * multFlow,
|
||||
|
@ -89,8 +89,8 @@ void FillConcentricWGapFill::fill_surface_extrusion(const Surface *surface, cons
|
||||
coord_t distance = coord_t(min_spacing / params.density);
|
||||
|
||||
if (params.density > 0.9999f && !params.dont_adjust) {
|
||||
distance = this->_adjust_solid_spacing(bounding_box.size().x, distance);
|
||||
this->spacing = unscale(distance);
|
||||
distance = this->_adjust_solid_spacing(bounding_box.size().x(), distance);
|
||||
this->spacing = unscaled(distance);
|
||||
}
|
||||
|
||||
ExPolygons gaps;
|
||||
|
@ -37,12 +37,12 @@ namespace Slic3r {
|
||||
double volumeToOccupy = 0;
|
||||
for (auto poly = this->no_overlap_expolygons.begin(); poly != this->no_overlap_expolygons.end(); ++poly) {
|
||||
// add external "perimeter gap"
|
||||
double poylineVolume = flow.height*unscale(unscale(poly->area()));
|
||||
double perimeterRoundGap = unscale(poly->contour.length()) * flow.height * (1 - 0.25*PI) * 0.5;
|
||||
double poylineVolume = flow.height*unscaled(unscaled(poly->area()));
|
||||
double perimeterRoundGap = unscaled(poly->contour.length()) * flow.height * (1 - 0.25*PI) * 0.5;
|
||||
// add holes "perimeter gaps"
|
||||
double holesGaps = 0;
|
||||
for (auto hole = poly->holes.begin(); hole != poly->holes.end(); ++hole) {
|
||||
holesGaps += unscale(hole->length()) * flow.height * (1 - 0.25*PI) * 0.5;
|
||||
holesGaps += unscaled(hole->length()) * flow.height * (1 - 0.25*PI) * 0.5;
|
||||
}
|
||||
poylineVolume += perimeterRoundGap + holesGaps;
|
||||
|
||||
@ -88,7 +88,7 @@ namespace Slic3r {
|
||||
for (auto pline = polylines_layer1.begin(); pline != polylines_layer1.end(); ++pline) {
|
||||
Lines lines = pline->lines();
|
||||
for (auto line = lines.begin(); line != lines.end(); ++line) {
|
||||
lengthTot += unscale(line->length());
|
||||
lengthTot += unscaled(line->length());
|
||||
nbLines++;
|
||||
}
|
||||
}
|
||||
@ -102,7 +102,7 @@ namespace Slic3r {
|
||||
eecroot->entities.push_back(eec);
|
||||
eec->no_sort = false; //can be sorted inside the pass
|
||||
extrusion_entities_append_paths(
|
||||
eec->entities, STDMOVE(polylines_layer1),
|
||||
eec->entities, std::move(polylines_layer1),
|
||||
flow.bridge ? erBridgeInfill : rolePass[0],
|
||||
//reduced flow height for a better view (it's only a gui thing)
|
||||
params.flow_mult * flow.mm3_per_mm() * percentFlow[0] * (params.fill_exactly ? volumeToOccupy / extrudedVolume : 1),
|
||||
@ -122,18 +122,18 @@ namespace Slic3r {
|
||||
for (auto pline = polylines_layer1.begin(); pline != polylines_layer1.end(); ++pline) {
|
||||
Lines lines = pline->lines();
|
||||
for (auto line = lines.begin(); line != lines.end(); ++line) {
|
||||
lengthTot += unscale(line->length());
|
||||
lengthTot += unscaled(line->length());
|
||||
nbLines++;
|
||||
}
|
||||
}
|
||||
|
||||
// add external "perimeter gap"
|
||||
double poylineVolume = flow.height*unscale(unscale(poly->area()));
|
||||
double perimeterRoundGap = unscale(poly->contour.length()) * flow.height * (1 - 0.25*PI) * 0.5;
|
||||
double poylineVolume = flow.height*unscaled(unscaled(poly->area()));
|
||||
double perimeterRoundGap = unscaled(poly->contour.length()) * flow.height * (1 - 0.25*PI) * 0.5;
|
||||
// add holes "perimeter gaps"
|
||||
double holesGaps = 0;
|
||||
for (auto hole = poly->holes.begin(); hole != poly->holes.end(); ++hole) {
|
||||
holesGaps += unscale(hole->length()) * flow.height * (1 - 0.25*PI) * 0.5;
|
||||
holesGaps += unscaled(hole->length()) * flow.height * (1 - 0.25*PI) * 0.5;
|
||||
}
|
||||
poylineVolume += perimeterRoundGap + holesGaps;
|
||||
|
||||
@ -149,7 +149,7 @@ namespace Slic3r {
|
||||
good_role = flow.bridge ? erBridgeInfill : rolePass[0];
|
||||
}
|
||||
extrusion_entities_append_paths(
|
||||
eec->entities, STDMOVE(polylines_layer1),
|
||||
eec->entities, std::move(polylines_layer1),
|
||||
good_role,
|
||||
//reduced flow height for a better view (it's only a gui thing)
|
||||
params.flow_mult * flow.mm3_per_mm() * percentFlow[0] * (params.fill_exactly ? poylineVolume / extrudedVolume : 1),
|
||||
@ -187,7 +187,7 @@ namespace Slic3r {
|
||||
for (auto pline = polylines_layer2.begin(); pline != polylines_layer2.end(); ++pline){
|
||||
Lines lines = pline->lines();
|
||||
for (auto line = lines.begin(); line != lines.end(); ++line){
|
||||
lengthTot += unscale(line->length());
|
||||
lengthTot += unscaled(line->length());
|
||||
nbLines++;
|
||||
}
|
||||
}
|
||||
@ -205,7 +205,7 @@ namespace Slic3r {
|
||||
}
|
||||
// print thin
|
||||
extrusion_entities_append_paths(
|
||||
eec->entities, STDMOVE(polylines_layer2),
|
||||
eec->entities, std::move(polylines_layer2),
|
||||
good_role,
|
||||
params.flow_mult * flow.mm3_per_mm() * percentFlow[1] * (params.fill_exactly ? volumeToOccupy / extrudedVolume : 1),
|
||||
//min-reduced flow width for a better view (it's only a gui thing)
|
||||
@ -244,7 +244,7 @@ namespace Slic3r {
|
||||
for (auto pline = polylines_layer3.begin(); pline != polylines_layer3.end(); ++pline){
|
||||
Lines lines = pline->lines();
|
||||
for (auto line = lines.begin(); line != lines.end(); ++line){
|
||||
lengthTot += unscale(line->length());
|
||||
lengthTot += unscaled(line->length());
|
||||
nbLines++;
|
||||
}
|
||||
}
|
||||
@ -261,7 +261,7 @@ namespace Slic3r {
|
||||
}
|
||||
// print thin
|
||||
extrusion_entities_append_paths(
|
||||
eec->entities, STDMOVE(polylines_layer3),
|
||||
eec->entities, std::move(polylines_layer3),
|
||||
good_role, //slow (if last)
|
||||
//reduced flow width for a better view (it's only a gui thing)
|
||||
params.flow_mult * flow.mm3_per_mm() * percentFlow[2] * (params.fill_exactly ? volumeToOccupy / extrudedVolume : 1),
|
||||
|
@ -1502,7 +1502,7 @@ void GCode::process_layer(
|
||||
// fill->first_point fits inside ith slice
|
||||
point_inside_surface(i, fill->first_point())) {
|
||||
if (islands[i].by_region.empty()) {
|
||||
islands[i].by_region.assign(print.regions.size(), ObjectByExtruder::Island::Region());
|
||||
islands[i].by_region.assign(print.regions().size(), ObjectByExtruder::Island::Region());
|
||||
}
|
||||
//don't do fill->entities because it will discard no_sort
|
||||
islands[i].by_region[region_id].append(entity_type, fill, entity_overrides, layer_to_print.object()->copies().size());
|
||||
@ -2293,8 +2293,8 @@ std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectBy
|
||||
{
|
||||
std::string gcode;
|
||||
for (const ObjectByExtruder::Island::Region ®ion : by_region) {
|
||||
if (print.regions[®ion - &by_region.front()]->config().infill_first == is_infill_first) {
|
||||
m_config.apply(print.regions[®ion - &by_region.front()]->config);
|
||||
if (print.regions()[®ion - &by_region.front()]->config().infill_first == is_infill_first) {
|
||||
m_config.apply(print.regions()[®ion - &by_region.front()]->config());
|
||||
ExtrusionEntityCollection chained = region.infills.chained_path_from(m_last_pos, false);
|
||||
gcode += extrude_entity(chained, "infill");
|
||||
}
|
||||
|
@ -375,6 +375,8 @@ std::string GCodePreviewData::get_legend_title() const
|
||||
return L("Volumetric flow rate (mm3/s)");
|
||||
case Extrusion::Tool:
|
||||
return L("Tool");
|
||||
case Extrusion::Filament:
|
||||
return L("Filament");
|
||||
case Extrusion::ColorPrint:
|
||||
return L("Color Print");
|
||||
}
|
||||
@ -438,6 +440,7 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
|
||||
break;
|
||||
}
|
||||
case Extrusion::Tool:
|
||||
case Extrusion::Filament:
|
||||
{
|
||||
unsigned int tools_colors_count = tool_colors.size() / 4;
|
||||
items.reserve(tools_colors_count);
|
||||
|
@ -71,6 +71,7 @@ public:
|
||||
Feedrate,
|
||||
VolumetricRate,
|
||||
Tool,
|
||||
Filament,
|
||||
ColorPrint,
|
||||
Num_View_Types
|
||||
};
|
||||
|
@ -485,7 +485,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
|
||||
continue;
|
||||
|
||||
|
||||
if ((!print.config().infill_first ? perimeters_done : !perimeters_done) || (!object->config().wipe_into_objects && region.config().wipe_into_infill)) {
|
||||
if ((!region.config().infill_first ? perimeters_done : !perimeters_done) || (!object->config().wipe_into_objects && region.config().wipe_into_infill)) {
|
||||
for (const ExtrusionEntity* ee : this_layer->regions()[region_id]->fills.entities) { // iterate through all infill Collections
|
||||
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
|
||||
|
||||
@ -498,7 +498,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
|
||||
if (volume_to_wipe<=0)
|
||||
continue;
|
||||
|
||||
if (!object->config().wipe_into_objects && !print.config().infill_first && region.config().wipe_into_infill)
|
||||
if (!object->config().wipe_into_objects && !region.config().infill_first && region.config().wipe_into_infill)
|
||||
// In this case we must check that the original extruder is used on this layer before the one we are overridding
|
||||
// (and the perimeters will be finished before the infill is printed):
|
||||
if (!lt.is_extruder_order(region.config().perimeter_extruder - 1, new_extruder))
|
||||
@ -512,7 +512,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
|
||||
}
|
||||
|
||||
// Now the same for perimeters - see comments above for explanation:
|
||||
if (object->config().wipe_into_objects && (print.config().infill_first ? perimeters_done : !perimeters_done))
|
||||
if (object->config().wipe_into_objects && (region.config().infill_first ? perimeters_done : !perimeters_done))
|
||||
{
|
||||
for (const ExtrusionEntity* ee : this_layer->regions()[region_id]->perimeters.entities) {
|
||||
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
|
||||
@ -572,12 +572,12 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
|
||||
// printed before its perimeter, or not be printed at all (in case its original extruder has
|
||||
// not been added to LayerTools
|
||||
// Either way, we will now force-override it with something suitable:
|
||||
if (print.config().infill_first
|
||||
if (region.config().infill_first
|
||||
|| object->config().wipe_into_objects // in this case the perimeter is overridden, so we can override by the last one safely
|
||||
|| lt.is_extruder_order(region.config().perimeter_extruder - 1, last_nonsoluble_extruder // !infill_first, but perimeter is already printed when last extruder prints
|
||||
|| std::find(lt.extruders.begin(), lt.extruders.end(), region.config().infill_extruder - 1) == lt.extruders.end()) // we have to force override - this could violate infill_first (FIXME)
|
||||
)
|
||||
set_extruder_override(fill, copy, (print.config().infill_first ? first_nonsoluble_extruder : last_nonsoluble_extruder), num_of_copies);
|
||||
set_extruder_override(fill, copy, (region.config().infill_first ? first_nonsoluble_extruder : last_nonsoluble_extruder), num_of_copies);
|
||||
else {
|
||||
// In this case we can (and should) leave it to be printed normally.
|
||||
// Force overriding would mean it gets printed before its perimeter.
|
||||
@ -591,7 +591,7 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
|
||||
|| is_entity_overridden(fill, copy) )
|
||||
continue;
|
||||
|
||||
set_extruder_override(fill, copy, (print.config().infill_first ? last_nonsoluble_extruder : first_nonsoluble_extruder), num_of_copies);
|
||||
set_extruder_override(fill, copy, (region.config().infill_first ? last_nonsoluble_extruder : first_nonsoluble_extruder), num_of_copies);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,8 @@ public:
|
||||
// Unspecified fill polygons, used for overhang detection ("ensure vertical wall thickness feature")
|
||||
// and for re-starting of infills.
|
||||
ExPolygons fill_expolygons;
|
||||
// Unspecified fill polygons, used for interecting when we don't want the infill/perimeter overlap
|
||||
ExPolygons fill_no_overlap_expolygons;
|
||||
// collection of surfaces for infill generation
|
||||
SurfaceCollection fill_surfaces;
|
||||
|
||||
@ -110,8 +112,8 @@ public:
|
||||
ExPolygonCollection slices;
|
||||
|
||||
size_t region_count() const { return m_regions.size(); }
|
||||
const LayerRegion* get_region(int idx) const { return m_regions.at(idx); }
|
||||
LayerRegion* get_region(int idx) { return m_regions[idx]; }
|
||||
const LayerRegion* get_region(size_t idx) const { return m_regions.at(idx); }
|
||||
LayerRegion* get_region(size_t idx) { return m_regions[idx]; }
|
||||
LayerRegion* add_region(PrintRegion* print_region);
|
||||
const LayerRegionPtrs& regions() const { return m_regions; }
|
||||
// Test whether whether there are any slices assigned to this layer.
|
||||
|
@ -93,15 +93,15 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
|
||||
void LayerRegion::process_external_surfaces(const Layer* lower_layer)
|
||||
{
|
||||
const Surfaces &surfaces = this->fill_surfaces.surfaces;
|
||||
const bool has_infill = this->region()->config.fill_density.value > 0.;
|
||||
coord_t margin = scale_(this->region()->config.external_infill_margin.getFloat());
|
||||
coord_t margin_bridged = scale_(this->region()->config.bridged_infill_margin.getFloat());
|
||||
const bool has_infill = this->region()->config().fill_density.value > 0.;
|
||||
coord_t margin = scale_(this->region()->config().external_infill_margin.getFloat());
|
||||
coord_t margin_bridged = scale_(this->region()->config().bridged_infill_margin.getFloat());
|
||||
//if no infill, reduce the margin for averythign to only the perimeter
|
||||
if (!has_infill) {
|
||||
if ((this->region()->config.perimeters.value > 0)) {
|
||||
const coord_t perimeter_width = scale_(this->region()->config.perimeter_extrusion_width.get_abs_value(this->layer()->object()->config.layer_height.value));
|
||||
const coord_t first_perimeter_width = scale_(this->region()->config.external_perimeter_extrusion_width.get_abs_value(this->layer()->object()->config.layer_height.value));
|
||||
margin = first_perimeter_width + perimeter_width * (this->region()->config.perimeters.value - 1);
|
||||
if ((this->region()->config().perimeters > 0)) {
|
||||
const coord_t perimeter_width = scale_(this->region()->config().perimeter_extrusion_width.get_abs_value(this->layer()->object()->config().layer_height.value));
|
||||
const coord_t first_perimeter_width = scale_(this->region()->config().external_perimeter_extrusion_width.get_abs_value(this->layer()->object()->config().layer_height.value));
|
||||
margin = first_perimeter_width + perimeter_width * (this->region()->config().perimeters.value - 1);
|
||||
} else margin = 0;
|
||||
margin_bridged = margin;
|
||||
}
|
||||
|
@ -115,4 +115,15 @@ Vec3d Linef3::intersect_plane(double z) const
|
||||
return Vec3d(this->a(0) + v(0) * t, this->a(1) + v(1) * t, z);
|
||||
}
|
||||
|
||||
Point Line::point_at(double distance) const {
|
||||
Point point;
|
||||
double len = this->length();
|
||||
point = this->a;
|
||||
if (this->a.x() != this->b.x())
|
||||
point.x() = this->a.x() + (this->b.x() - this->a.x()) * distance / len;
|
||||
if (this->a.y() != this->b.y())
|
||||
point.y() = this->a.y() + (this->b.y() - this->a.y()) * distance / len;
|
||||
return point;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -46,6 +46,10 @@ public:
|
||||
|
||||
static double distance_to_squared(const Point &point, const Point &a, const Point &b);
|
||||
static double distance_to(const Point &point, const Point &a, const Point &b) { return sqrt(distance_to_squared(point, a, b)); }
|
||||
Point point_at(double distance) const;
|
||||
coord_t Line::dot(Line &l2) const { return vector().dot(l2.vector()); }
|
||||
void extend_end(double distance) { Line line = *this; line.reverse(); this->b = line.point_at(-distance); }
|
||||
void extend_start(double distance) { this->a = this->point_at(-distance); }
|
||||
|
||||
Point a;
|
||||
Point b;
|
||||
|
@ -344,10 +344,10 @@ add_point_same_percent(ThickPolyline* pattern, ThickPolyline* to_modify)
|
||||
coordf_t new_width = to_modify->width[idx_other - 1] * (1 - percent_dist);
|
||||
new_width += to_modify->width[idx_other] * (percent_dist);
|
||||
Point new_point;
|
||||
new_point.x = (coord_t)((double)(to_modify->points[idx_other - 1].x) * (1 - percent_dist));
|
||||
new_point.x += (coord_t)((double)(to_modify->points[idx_other].x) * (percent_dist));
|
||||
new_point.y = (coord_t)((double)(to_modify->points[idx_other - 1].y) * (1 - percent_dist));
|
||||
new_point.y += (coord_t)((double)(to_modify->points[idx_other].y) * (percent_dist));
|
||||
new_point.x() = (coord_t)((double)(to_modify->points[idx_other - 1].x()) * (1 - percent_dist));
|
||||
new_point.x() += (coord_t)((double)(to_modify->points[idx_other].x()) * (percent_dist));
|
||||
new_point.y() = (coord_t)((double)(to_modify->points[idx_other - 1].y()) * (1 - percent_dist));
|
||||
new_point.y() += (coord_t)((double)(to_modify->points[idx_other].y()) * (percent_dist));
|
||||
to_modify->width.insert(to_modify->width.begin() + idx_other, new_width);
|
||||
to_modify->points.insert(to_modify->points.begin() + idx_other, new_point);
|
||||
}
|
||||
@ -425,9 +425,11 @@ get_coeff_from_angle_countour(Point &point, const ExPolygon &contour, coord_t mi
|
||||
double
|
||||
dot(Line l1, Line l2)
|
||||
{
|
||||
Vectorf v_1 = normalize(Vectorf(l1.b.x - l1.a.x, l1.b.y - l1.a.y));
|
||||
Vectorf v_2 = normalize(Vectorf(l2.b.x - l2.a.x, l2.b.y - l2.a.y));
|
||||
return v_1.x*v_2.x + v_1.y*v_2.y;
|
||||
Vec2d v_1(l1.b.x() - l1.a.x(), l1.b.y() - l1.a.y());
|
||||
v_1.normalize();
|
||||
Vec2d v_2(l2.b.x() - l2.a.x(), l2.b.y() - l2.a.y());
|
||||
v_2.normalize();
|
||||
return v_1.x()*v_2.x() + v_1.y()*v_2.y();
|
||||
}
|
||||
|
||||
void
|
||||
@ -503,19 +505,19 @@ MedialAxis::fusion_curve(ThickPolylines &pp)
|
||||
//length_pull *= 0.144 * get_coeff_from_angle_countour(polyline.points.back(), this->expolygon, min(min_width, polyline.length() / 2));
|
||||
|
||||
////compute dir
|
||||
//Vectorf pull_direction(polyline.points[1].x - polyline.points[0].x, polyline.points[1].y - polyline.points[0].y);
|
||||
//Vectorf pull_direction(polyline.points[1].x() - polyline.points[0].x(), polyline.points[1].y() - polyline.points[0].y());
|
||||
//pull_direction = normalize(pull_direction);
|
||||
//pull_direction.x *= length_pull;
|
||||
//pull_direction.y *= length_pull;
|
||||
//pull_direction.x() *= length_pull;
|
||||
//pull_direction.y() *= length_pull;
|
||||
|
||||
////pull the points
|
||||
//Point &p1 = pp[crosspoint[0]].points[0];
|
||||
//p1.x = p1.x + (coord_t)pull_direction.x;
|
||||
//p1.y = p1.y + (coord_t)pull_direction.y;
|
||||
//p1.x() = p1.x() + (coord_t)pull_direction.x();
|
||||
//p1.y() = p1.y() + (coord_t)pull_direction.y();
|
||||
|
||||
//Point &p2 = pp[crosspoint[1]].points[0];
|
||||
//p2.x = p2.x + (coord_t)pull_direction.x;
|
||||
//p2.y = p2.y + (coord_t)pull_direction.y;
|
||||
//p2.x() = p2.x() + (coord_t)pull_direction.x();
|
||||
//p2.y() = p2.y() + (coord_t)pull_direction.y();
|
||||
|
||||
//delete the now unused polyline
|
||||
pp.erase(pp.begin() + i);
|
||||
@ -579,19 +581,19 @@ MedialAxis::fusion_corners(ThickPolylines &pp)
|
||||
length_pull *= 0.144 * get_coeff_from_angle_countour(polyline.points.back(), this->expolygon, min(min_width, polyline.length() / 2));
|
||||
|
||||
//compute dir
|
||||
Vectorf pull_direction(polyline.points[1].x - polyline.points[0].x, polyline.points[1].y - polyline.points[0].y);
|
||||
pull_direction = normalize(pull_direction);
|
||||
pull_direction.x *= length_pull;
|
||||
pull_direction.y *= length_pull;
|
||||
Vec2d pull_direction(polyline.points[1].x() - polyline.points[0].x(), polyline.points[1].y() - polyline.points[0].y());
|
||||
pull_direction.normalize();
|
||||
pull_direction.x() *= length_pull;
|
||||
pull_direction.y() *= length_pull;
|
||||
|
||||
//pull the points
|
||||
Point &p1 = pp[crosspoint[0]].points[0];
|
||||
p1.x = p1.x + pull_direction.x;
|
||||
p1.y = p1.y + pull_direction.y;
|
||||
p1.x() = p1.x() + pull_direction.x();
|
||||
p1.y() = p1.y() + pull_direction.y();
|
||||
|
||||
Point &p2 = pp[crosspoint[1]].points[0];
|
||||
p2.x = p2.x + pull_direction.x;
|
||||
p2.y = p2.y + pull_direction.y;
|
||||
p2.x() = p2.x() + pull_direction.x();
|
||||
p2.y() = p2.y() + pull_direction.y();
|
||||
|
||||
//delete the now unused polyline
|
||||
pp.erase(pp.begin() + i);
|
||||
@ -711,10 +713,10 @@ MedialAxis::extends_line(ThickPolyline& polyline, const ExPolygons& anchors, con
|
||||
best_anchor = p_maybe_inside;
|
||||
}
|
||||
}
|
||||
if (best_anchor.x != 0 && best_anchor.y != 0) {
|
||||
if (best_anchor.x() != 0 && best_anchor.y() != 0) {
|
||||
Point p_obj = best_anchor + new_bound;
|
||||
p_obj.x /= 2;
|
||||
p_obj.y /= 2;
|
||||
p_obj.x() /= 2;
|
||||
p_obj.y() /= 2;
|
||||
Line l2 = Line(new_back, p_obj);
|
||||
l2.extend_end(max_width);
|
||||
(void)bounds.contour.first_intersection(l2, &new_bound);
|
||||
@ -937,8 +939,8 @@ MedialAxis::main_fusion(ThickPolylines& pp)
|
||||
size_t idx_point = 1;
|
||||
while (idx_point < min(polyline.points.size(), best_candidate->points.size())) {
|
||||
//fusion
|
||||
polyline.points[idx_point].x = polyline.points[idx_point].x * coeff_poly + best_candidate->points[idx_point].x * coeff_candi;
|
||||
polyline.points[idx_point].y = polyline.points[idx_point].y * coeff_poly + best_candidate->points[idx_point].y * coeff_candi;
|
||||
polyline.points[idx_point].x() = polyline.points[idx_point].x() * coeff_poly + best_candidate->points[idx_point].x() * coeff_candi;
|
||||
polyline.points[idx_point].y() = polyline.points[idx_point].y() * coeff_poly + best_candidate->points[idx_point].y() * coeff_candi;
|
||||
|
||||
// The width decrease with distance from the centerline.
|
||||
// This formula is what works the best, even if it's not perfect (created empirically). 0->3% error on a gap fill on some tests.
|
||||
@ -1048,10 +1050,10 @@ MedialAxis::remove_too_thin_extrusion(ThickPolylines& pp)
|
||||
if (polyline.points.front().distance_to(polyline.points[1]) * percent_can_keep > SCALED_RESOLUTION) {
|
||||
//Can split => move the first point and assign a new weight.
|
||||
//the update of endpoints wil be performed in concatThickPolylines
|
||||
polyline.points.front().x = polyline.points.front().x +
|
||||
(coord_t)((polyline.points[1].x - polyline.points.front().x) * (1 - percent_can_keep));
|
||||
polyline.points.front().y = polyline.points.front().y +
|
||||
(coord_t)((polyline.points[1].y - polyline.points.front().y) * (1 - percent_can_keep));
|
||||
polyline.points.front().x() = polyline.points.front().x() +
|
||||
(coord_t)((polyline.points[1].x() - polyline.points.front().x()) * (1 - percent_can_keep));
|
||||
polyline.points.front().y() = polyline.points.front().y() +
|
||||
(coord_t)((polyline.points[1].y() - polyline.points.front().y()) * (1 - percent_can_keep));
|
||||
polyline.width.front() = min_width;
|
||||
} else {
|
||||
/// almost 0-length, Remove
|
||||
@ -1072,10 +1074,10 @@ MedialAxis::remove_too_thin_extrusion(ThickPolylines& pp)
|
||||
if (polyline.points.back().distance_to(polyline.points[polyline.points.size() - 2]) * percent_can_keep > SCALED_RESOLUTION) {
|
||||
//Can split => move the first point and assign a new weight.
|
||||
//the update of endpoints wil be performed in concatThickPolylines
|
||||
polyline.points.back().x = polyline.points.back().x +
|
||||
(coord_t)((polyline.points[polyline.points.size() - 2].x - polyline.points.back().x) * (1 - percent_can_keep));
|
||||
polyline.points.back().y = polyline.points.back().y +
|
||||
(coord_t)((polyline.points[polyline.points.size() - 2].y - polyline.points.back().y) * (1 - percent_can_keep));
|
||||
polyline.points.back().x() = polyline.points.back().x() +
|
||||
(coord_t)((polyline.points[polyline.points.size() - 2].x() - polyline.points.back().x()) * (1 - percent_can_keep));
|
||||
polyline.points.back().y() = polyline.points.back().y() +
|
||||
(coord_t)((polyline.points[polyline.points.size() - 2].y() - polyline.points.back().y()) * (1 - percent_can_keep));
|
||||
polyline.width.back() = min_width;
|
||||
} else {
|
||||
/// almost 0-length, Remove
|
||||
@ -1139,11 +1141,11 @@ MedialAxis::concatenate_polylines_with_crossing(ThickPolylines& pp)
|
||||
continue;
|
||||
}
|
||||
|
||||
Pointf v_poly(polyline.lines().back().vector().x, polyline.lines().back().vector().y);
|
||||
v_poly.scale(1 / std::sqrt(v_poly.x*v_poly.x + v_poly.y*v_poly.y));
|
||||
Pointf v_other(other.lines().front().vector().x, other.lines().front().vector().y);
|
||||
v_other.scale(1 / std::sqrt(v_other.x*v_other.x + v_other.y*v_other.y));
|
||||
float other_dot = v_poly.x*v_other.x + v_poly.y*v_other.y;
|
||||
Vec2d v_poly(polyline.lines().back().vector().x(), polyline.lines().back().vector().y());
|
||||
v_poly *= (1 / std::sqrt(v_poly.x()*v_poly.x() + v_poly.y()*v_poly.y()));
|
||||
Vec2d v_other(other.lines().front().vector().x(), other.lines().front().vector().y());
|
||||
v_other *= (1 / std::sqrt(v_other.x()*v_other.x() + v_other.y()*v_other.y()));
|
||||
float other_dot = v_poly.x()*v_other.x() + v_poly.y()*v_other.y();
|
||||
if (other_dot > best_dot) {
|
||||
best_candidate = &other;
|
||||
best_idx = j;
|
||||
@ -1306,8 +1308,8 @@ MedialAxis::simplify_polygon_frontier()
|
||||
const Point* closest = bounds.contour.closest_point(p_check);
|
||||
if (closest != nullptr && closest->distance_to(p_check) + SCALED_EPSILON
|
||||
< min(p_check.distance_to(simplified_poly.contour.points[prev_i]), p_check.distance_to(simplified_poly.contour.points[next_i])) / 2) {
|
||||
p_check.x = closest->x;
|
||||
p_check.y = closest->y;
|
||||
p_check.x() = closest->x();
|
||||
p_check.y() = closest->y();
|
||||
need_intersect = true;
|
||||
} else {
|
||||
simplified_poly.contour.points.erase(simplified_poly.contour.points.begin() + i);
|
||||
@ -1553,7 +1555,7 @@ ExtrusionEntityCollection thin_variable_width(const ThickPolylines &polylines, E
|
||||
path.polyline.append(line.b);
|
||||
// Convert from spacing to extrusion width based on the extrusion model
|
||||
// of a square extrusion ended with semi circles.
|
||||
flow.width = unscale(w) + flow.height * (1. - 0.25 * PI);
|
||||
flow.width = unscaled(w) + flow.height * (1. - 0.25 * PI);
|
||||
#ifdef SLIC3R_DEBUG
|
||||
printf(" filling %f gap\n", flow.width);
|
||||
#endif
|
||||
|
@ -180,13 +180,13 @@ Point MultiPoint::point_projection(const Point &point) const {
|
||||
dmin = d;
|
||||
proj = pt1;
|
||||
}
|
||||
Pointf v1(coordf_t(pt1.x - pt0.x), coordf_t(pt1.y - pt0.y));
|
||||
Vec2d v1(coordf_t(pt1(0) - pt0(0)), coordf_t(pt1(1) - pt0(1)));
|
||||
coordf_t div = dot(v1);
|
||||
if (div > 0.) {
|
||||
Pointf v2(coordf_t(point.x - pt0.x), coordf_t(point.y - pt0.y));
|
||||
Vec2d v2(coordf_t(point(0) - pt0(0)), coordf_t(point(1) - pt0(1)));
|
||||
coordf_t t = dot(v1, v2) / div;
|
||||
if (t > 0. && t < 1.) {
|
||||
Point foot(coord_t(floor(coordf_t(pt0.x) + t * v1.x + 0.5)), coord_t(floor(coordf_t(pt0.y) + t * v1.y + 0.5)));
|
||||
Point foot(coord_t(floor(coordf_t(pt0(0)) + t * v1(0) + 0.5)), coord_t(floor(coordf_t(pt0(1)) + t * v1(1) + 0.5)));
|
||||
d = foot.distance_to(point);
|
||||
if (d < dmin) {
|
||||
dmin = d;
|
||||
@ -199,8 +199,7 @@ Point MultiPoint::point_projection(const Point &point) const {
|
||||
return proj;
|
||||
}
|
||||
|
||||
Points
|
||||
MultiPoint::_douglas_peucker(const Points &points, const double tolerance)
|
||||
std::vector<Point> MultiPoint::_douglas_peucker(const std::vector<Point>& pts, const double tolerance)
|
||||
{
|
||||
std::vector<Point> result_pts;
|
||||
if (! pts.empty()) {
|
||||
|
@ -131,7 +131,7 @@ void PerimeterGenerator::process()
|
||||
//it's not dangerous as it will be intersected by 'unsupported' later
|
||||
//FIXME: add overlap in this->fill_surfaces->append
|
||||
// add overlap (perimeter_spacing/4 was good in test, ie 25%)
|
||||
coord_t overlap = scale_(this->config->get_abs_value("infill_overlap", unscale(perimeter_spacing)));
|
||||
coord_t overlap = scale_(this->config->get_abs_value("infill_overlap", unscale<double>(perimeter_spacing)));
|
||||
unsupported_filtered = intersection_ex(unsupported_filtered, offset_ex(bridgeable_simplified, overlap));
|
||||
} else {
|
||||
unsupported_filtered.clear();
|
||||
@ -675,7 +675,7 @@ PerimeterGenerator::_get_nearest_point(const PerimeterGeneratorLoops &children,
|
||||
const double dist = nearest_p.distance_to(p);
|
||||
//Try to find a point in the far side, aligning them
|
||||
if (dist + dist_cut / 20 < intersect.distance ||
|
||||
(config->perimeter_loop_seam.value == spRear && (intersect.idx_polyline_outter <0 || p.y > intersect.outter_best.y)
|
||||
(config->perimeter_loop_seam.value == spRear && (intersect.idx_polyline_outter <0 || p.y() > intersect.outter_best.y())
|
||||
&& dist <= max_dist && intersect.distance + dist_cut / 20)) {
|
||||
//ok, copy the idx
|
||||
intersect.distance = (coord_t)nearest_p.distance_to(p);
|
||||
@ -692,7 +692,7 @@ PerimeterGenerator::_get_nearest_point(const PerimeterGeneratorLoops &children,
|
||||
const Point &nearest_p = *child.polygon.closest_point(p);
|
||||
const double dist = nearest_p.distance_to(p);
|
||||
if (dist + SCALED_EPSILON < intersect.distance ||
|
||||
(config->perimeter_loop_seam.value == spRear && (intersect.idx_polyline_outter<0 || p.y < intersect.outter_best.y)
|
||||
(config->perimeter_loop_seam.value == spRear && (intersect.idx_polyline_outter<0 || p.y() < intersect.outter_best.y())
|
||||
&& dist <= max_dist && intersect.distance + dist_cut / 20)) {
|
||||
//ok, copy the idx
|
||||
intersect.distance = (coord_t)nearest_p.distance_to(p);
|
||||
@ -1131,8 +1131,8 @@ PerimeterGenerator::_traverse_and_join_loops(const PerimeterGeneratorLoop &loop,
|
||||
travel_path_begin[2].extruder_id = -1;
|
||||
Line line(outer_start->polyline.points.back(), inner_start->polyline.points.front());
|
||||
Point p_dist_cut_extrude = (line.b - line.a);
|
||||
p_dist_cut_extrude.x = (coord_t)(p_dist_cut_extrude.x * ((double)max_width_extrusion) / (line.length() * 2));
|
||||
p_dist_cut_extrude.y = (coord_t)(p_dist_cut_extrude.y * ((double)max_width_extrusion) / (line.length() * 2));
|
||||
p_dist_cut_extrude.x() = (coord_t)(p_dist_cut_extrude.x() * ((double)max_width_extrusion) / (line.length() * 2));
|
||||
p_dist_cut_extrude.y() = (coord_t)(p_dist_cut_extrude.y() * ((double)max_width_extrusion) / (line.length() * 2));
|
||||
//extrude a bit after the turn, to close the loop
|
||||
Point p_start_travel = line.a;
|
||||
p_start_travel += p_dist_cut_extrude;
|
||||
@ -1168,8 +1168,8 @@ PerimeterGenerator::_traverse_and_join_loops(const PerimeterGeneratorLoop &loop,
|
||||
travel_path_end[2].extruder_id = -1;
|
||||
Line line(inner_end->polyline.points.back(), outer_end->polyline.points.front());
|
||||
Point p_dist_cut_extrude = (line.b - line.a);
|
||||
p_dist_cut_extrude.x = (coord_t)(p_dist_cut_extrude.x * ((double)max_width_extrusion) / (line.length() * 2));
|
||||
p_dist_cut_extrude.y = (coord_t)(p_dist_cut_extrude.y * ((double)max_width_extrusion) / (line.length() * 2));
|
||||
p_dist_cut_extrude.x() = (coord_t)(p_dist_cut_extrude.x() * ((double)max_width_extrusion) / (line.length() * 2));
|
||||
p_dist_cut_extrude.y() = (coord_t)(p_dist_cut_extrude.y() * ((double)max_width_extrusion) / (line.length() * 2));
|
||||
//extrude a bit after the turn, to close the loop
|
||||
Point p_start_travel_2 = line.a;
|
||||
p_start_travel_2 += p_dist_cut_extrude;
|
||||
|
@ -100,6 +100,29 @@ int Point::nearest_point_index(const PointConstPtrs &points) const
|
||||
return idx;
|
||||
}
|
||||
|
||||
/* distance to the closest point of line */
|
||||
double
|
||||
Point::distance_to(const Line &line) const {
|
||||
const double dx = line.b.x() - line.a.x();
|
||||
const double dy = line.b.y() - line.a.y();
|
||||
|
||||
const double l2 = dx*dx + dy*dy; // avoid a sqrt
|
||||
if (l2 == 0.0) return this->distance_to(line.a); // line.a == line.b case
|
||||
|
||||
// Consider the line extending the segment, parameterized as line.a + t (line.b - line.a).
|
||||
// We find projection of this point onto the line.
|
||||
// It falls where t = [(this-line.a) . (line.b-line.a)] / |line.b-line.a|^2
|
||||
const double t = ((this->x() - line.a.x()) * dx + (this->y() - line.a.y()) * dy) / l2;
|
||||
if (t < 0.0) return this->distance_to(line.a); // beyond the 'a' end of the segment
|
||||
else if (t > 1.0) return this->distance_to(line.b); // beyond the 'b' end of the segment
|
||||
Point projection(
|
||||
line.a.x() + t * dx,
|
||||
line.a.y() + t * dy
|
||||
);
|
||||
return this->distance_to(projection);
|
||||
}
|
||||
|
||||
|
||||
int Point::nearest_point_index(const PointPtrs &points) const
|
||||
{
|
||||
PointConstPtrs p;
|
||||
|
@ -51,6 +51,9 @@ inline coord_t cross2(const Vec2crd &v1, const Vec2crd &v2) { return v1(0) * v2(
|
||||
inline float cross2(const Vec2f &v1, const Vec2f &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
||||
inline double cross2(const Vec2d &v1, const Vec2d &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
||||
|
||||
inline coordf_t dot(const Vec2d &v1, const Vec2d &v2) { return v1.x() * v2.x() + v1.y() * v2.y(); }
|
||||
inline coordf_t dot(const Vec2d &v) { return v.x() * v.x() + v.y() * v.y(); }
|
||||
|
||||
inline Vec2crd to_2d(const Vec3crd &pt3) { return Vec2crd(pt3(0), pt3(1)); }
|
||||
inline Vec2i64 to_2d(const Vec3i64 &pt3) { return Vec2i64(pt3(0), pt3(1)); }
|
||||
inline Vec2f to_2d(const Vec3f &pt3) { return Vec2f (pt3(0), pt3(1)); }
|
||||
@ -118,6 +121,13 @@ public:
|
||||
double ccw_angle(const Point &p1, const Point &p2) const;
|
||||
Point projection_onto(const MultiPoint &poly) const;
|
||||
Point projection_onto(const Line &line) const;
|
||||
|
||||
double distance_to(const Point &point) const { return (point - *this).cast<double>().norm(); }
|
||||
double distance_to(const Line &line) const;
|
||||
bool coincides_with(const Point &point) const { return this->x() == point.x() && this->y() == point.y(); }
|
||||
bool coincides_with_epsilon(const Point &point) const {
|
||||
return std::abs(this->x() - point.x()) < SCALED_EPSILON && std::abs(this->y() - point.y()) < SCALED_EPSILON;
|
||||
}
|
||||
};
|
||||
|
||||
namespace int128 {
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
Polyline& operator=(const Polyline &other) { points = other.points; return *this; }
|
||||
Polyline& operator=(Polyline &&other) { points = std::move(other.points); return *this; }
|
||||
static Polyline new_scale(const std::vector<Vec2d> &points) {
|
||||
Polyline pl;
|
||||
Polyline pl;
|
||||
pl.points.reserve(points.size());
|
||||
for (const Vec2d &pt : points)
|
||||
pl.points.emplace_back(Point::new_scale(pt(0), pt(1)));
|
||||
@ -138,6 +138,11 @@ bool remove_degenerate(Polylines &polylines);
|
||||
/// join something or is a dead-end.
|
||||
class ThickPolyline : public Polyline {
|
||||
public:
|
||||
/// width size must be == point size
|
||||
std::vector<coordf_t> width;
|
||||
/// if true => it's an endpoint, if false it join an other ThickPolyline. first is at front(), second is at back()
|
||||
std::pair<bool, bool> endpoints;
|
||||
|
||||
ThickPolyline() : endpoints(std::make_pair(false, false)) {}
|
||||
ThickLines thicklines() const;
|
||||
void reverse() {
|
||||
@ -145,14 +150,6 @@ public:
|
||||
std::reverse(this->width.begin(), this->width.end());
|
||||
std::swap(this->endpoints.first, this->endpoints.second);
|
||||
}
|
||||
|
||||
/// width size must be == point size
|
||||
std::vector<coordf_t> width;
|
||||
/// if true => it's an endpoint, if false it join an other ThickPolyline. first is at front(), second is at back()
|
||||
std::pair<bool,bool> endpoints;
|
||||
ThickPolyline() : endpoints(std::make_pair(false, false)) {};
|
||||
ThickLines thicklines() const;
|
||||
void reverse();
|
||||
};
|
||||
|
||||
/// concatenate poylines if possible and refresh the endpoints
|
||||
|
@ -179,6 +179,7 @@ private:
|
||||
void generate_support_material();
|
||||
|
||||
void _slice();
|
||||
void _offsetHoles(float hole_delta, LayerRegion *layerm);
|
||||
std::string _fix_slicing_errors();
|
||||
void _simplify_slices(double distance);
|
||||
void _make_perimeters();
|
||||
@ -187,7 +188,9 @@ private:
|
||||
void process_external_surfaces();
|
||||
void discover_vertical_shells();
|
||||
void bridge_over_infill();
|
||||
void replaceSurfaceType(SurfaceType st_to_replace, SurfaceType st_replacement, SurfaceType st_under_it);
|
||||
void clip_fill_surfaces();
|
||||
void count_distance_solid();
|
||||
void discover_horizontal_shells();
|
||||
void combine_infill();
|
||||
void _generate_support_material();
|
||||
|
@ -84,12 +84,9 @@ void PrintConfigDef::init_fff_params()
|
||||
"are very confident on your model, or you want to print an item with a geometry "
|
||||
"designed for vase mode.");
|
||||
def->cli = "remove-small-gaps!";
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionBool(true);
|
||||
|
||||
def = this->add("bed_shape", coPoints);
|
||||
def->label = L("Bed shape");
|
||||
def->default_value = new ConfigOptionPoints { Pointf(0,0), Pointf(200,0), Pointf(200,200), Pointf(0,200) };
|
||||
|
||||
def = this->add("bed_temperature", coInts);
|
||||
def->label = L("Other layers");
|
||||
def->tooltip = L("Bed temperature for layers after the first one. "
|
||||
@ -170,6 +167,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->cli = "top-fan-speed=i@";
|
||||
def->min = 0;
|
||||
def->max = 100;
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionInts{ 100 };
|
||||
|
||||
def = this->add("bridge_flow_ratio", coFloat);
|
||||
@ -191,9 +189,10 @@ void PrintConfigDef::init_fff_params()
|
||||
def->tooltip = L("This factor affects the amount of plastic to overextrude "
|
||||
"when we are filling on top of a bridge surface."
|
||||
"With a number >1, we can retreive the correct z-height "
|
||||
"even if the bridged layer has fallen a bit.");
|
||||
"even if the bridged layer has fallen a bit.");
|
||||
def->cli = "over-bridge-flow-ratio=f";
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloat(1);
|
||||
|
||||
def = this->add("bridge_speed", coFloat);
|
||||
@ -439,6 +438,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_labels.push_back(L("Hilbert Curve"));
|
||||
def->enum_labels.push_back(L("Archimedean Chords"));
|
||||
def->enum_labels.push_back(L("Octagram Spiral"));
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionEnum<InfillPattern>(ipRectilinear);
|
||||
|
||||
def = this->add("enforce_full_fill_volume", coBool);
|
||||
@ -446,6 +446,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Infill");
|
||||
def->tooltip = L("Experimental option which modifies (top/bottom) fill flow to have the exact amount of plastic inside the volume to fill.");
|
||||
def->cli = "enforce-full-fill-volume!";
|
||||
def->mode = comExpert;
|
||||
def->default_value = new ConfigOptionBool(true);
|
||||
|
||||
def = this->add("external_infill_margin", coFloat);
|
||||
@ -455,6 +456,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "top-layer-anchor=f";
|
||||
def->min = 0;
|
||||
def->mode = comExpert;
|
||||
def->default_value = new ConfigOptionFloat(1.5);
|
||||
|
||||
def = this->add("bridged_infill_margin", coFloat);
|
||||
@ -464,6 +466,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "top-layer-anchor=f";
|
||||
def->min = 0;
|
||||
def->mode = comExpert;
|
||||
def->default_value = new ConfigOptionFloat(2);
|
||||
|
||||
def = this->add("external_perimeter_extrusion_width", coFloatOrPercent);
|
||||
@ -504,6 +507,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->tooltip = L("Join the perimeters to create only one continuous extrusion without any z-hop."
|
||||
" Long inside travel (from external to holes) are not extruded to give some space to the infill.");
|
||||
def->cli = "loop-perimeter!";
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("perimeter_loop_seam", coEnum);
|
||||
@ -516,9 +520,10 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_values.push_back("rear");
|
||||
def->enum_labels.push_back(L("Nearest"));
|
||||
def->enum_labels.push_back(L("Rear"));
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionEnum<SeamPosition>(spRear);
|
||||
|
||||
def = this->add("extra_perimeters", coBool);
|
||||
def = this->add("extra_perimeters", coBool);avoid
|
||||
def->label = L("Extra perimeters if needed");
|
||||
def->category = L("Layers and Perimeters");
|
||||
def->tooltip = L("Add more perimeters when needed for avoiding gaps in sloping walls. "
|
||||
@ -903,7 +908,6 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_values.push_back("cubic");
|
||||
def->enum_values.push_back("line");
|
||||
def->enum_values.push_back("concentric");
|
||||
def->enum_values.push_back("concentricgapfill");
|
||||
def->enum_values.push_back("honeycomb");
|
||||
def->enum_values.push_back("3dhoneycomb");
|
||||
def->enum_values.push_back("gyroid");
|
||||
@ -917,7 +921,6 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_labels.push_back(L("Cubic"));
|
||||
def->enum_labels.push_back(L("Line"));
|
||||
def->enum_labels.push_back(L("Concentric"));
|
||||
def->enum_labels.push_back(L("Concentric (filled)"));
|
||||
def->enum_labels.push_back(L("Honeycomb"));
|
||||
def->enum_labels.push_back(L("3D Honeycomb"));
|
||||
def->enum_labels.push_back(L("Gyroid"));
|
||||
@ -969,7 +972,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->cli = "first-layer-height=s";
|
||||
def->ratio_over = "layer_height";
|
||||
def->default_value = new ConfigOptionFloatOrPercent(0.35, false);
|
||||
|
||||
|
||||
def = this->add("first_layer_speed", coFloatOrPercent);
|
||||
def->label = L("default");
|
||||
def->tooltip = L("If expressed as absolute value in mm/s, this speed will be applied to all the print moves "
|
||||
@ -993,6 +996,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->sidetext = L("mm/s or %");
|
||||
def->cli = "first-layer-infill-speed=s";
|
||||
def->min = 0;
|
||||
def->mode = comExpert;
|
||||
def->default_value = new ConfigOptionFloatOrPercent(30, false);
|
||||
|
||||
def = this->add("first_layer_temperature", coInts);
|
||||
@ -1090,6 +1094,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->tooltip = L("Enables the creation of a support layer under the first solid layer. This allows you to use a lower infill ratio without compromizing the top quality."
|
||||
" The dense infill is laid out with a 50% infill density.");
|
||||
def->cli = "infill-dense!";
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("infill_not_connected", coBool);
|
||||
@ -1097,6 +1102,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Infill");
|
||||
def->tooltip = L("If checked, the infill algorithm will try to not connect the lines near the infill. Can be useful for art or with high infill/perimeter overlap.");
|
||||
def->cli = "infill-not-connected!";
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("infill_dense_algo", coEnum);
|
||||
@ -1112,6 +1118,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_labels.push_back(L("Automatic"));
|
||||
def->enum_labels.push_back(L("Automatic, only for small areas"));
|
||||
def->enum_labels.push_back(L("Anchored"));
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionEnum<DenseInfillAlgo>(dfaAutomatic);
|
||||
|
||||
def = this->add("infill_extruder", coInt);
|
||||
@ -1522,6 +1529,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Layers and Perimeters");
|
||||
def->tooltip = L("Experimental option to remove perimeters where there is nothing under it and a bridged infill should be better.");
|
||||
def->cli = "no-perimeter-unsupported!";
|
||||
def->mode = comExpert;
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("min_perimeter_unsupported", coInt);
|
||||
@ -1530,6 +1538,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->tooltip = L("Number of permieter exluded from this option.");
|
||||
def->cli = "min-perimeter-unsupported=i";
|
||||
def->min = 0;
|
||||
def->mode = comExpert;
|
||||
def->default_value = new ConfigOptionInt(0);
|
||||
|
||||
def = this->add("noperi_bridge_only", coBool);
|
||||
@ -1537,6 +1546,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Layers and Perimeters");
|
||||
def->tooltip = L("Only remove perimeters over areas marked as 'bridge'. Can be useful to let perimeter run over overhangs, but it's not very reliable.");
|
||||
def->cli = "noperi-bridge-only!";
|
||||
def->mode = comExpert;
|
||||
def->default_value = new ConfigOptionBool(true);
|
||||
|
||||
def = this->add("parking_pos_retraction", coFloat);
|
||||
@ -1665,6 +1675,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Support material");
|
||||
def->tooltip = L("Use a solid layer instead of a raft for the layer that touch the build plate.");
|
||||
def->cli = "support-material-solid-first-layer!";
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("raft_layers", coInt);
|
||||
@ -1825,6 +1836,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->category = L("Layers and Perimeters");
|
||||
def->tooltip = L("Add a big cost to travel paths when possible (when going into a loop), so it will prefer a less optimal seam posistion if it's nearer.");
|
||||
def->cli = "seam-travel!";
|
||||
def->mode = comExpert;
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
#if 0
|
||||
@ -2463,7 +2475,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->cli = "wipe-tower-rotation-angle=f";
|
||||
def->mode = comAdvanced;
|
||||
def->default_value = new ConfigOptionFloat(0.);
|
||||
|
||||
|
||||
def = this->add("wipe_into_infill", coBool);
|
||||
def->category = L("Extruders");
|
||||
def->label = L("Wipe into this object's infill");
|
||||
@ -2509,6 +2521,7 @@ void PrintConfigDef::init_fff_params()
|
||||
" This might be useful for fine-tuning hole sizes.");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "hole-size-compensation=f";
|
||||
def->mode = comExpert;
|
||||
def->default_value = new ConfigOptionFloat(0);
|
||||
|
||||
def = this->add("z_offset", coFloat);
|
||||
|
@ -164,13 +164,12 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<FilamentType>::ge
|
||||
return keys_map;
|
||||
}
|
||||
|
||||
template<> inline t_config_enum_values& ConfigOptionEnum<DenseInfillAlgo>::get_enum_values() {
|
||||
static t_config_enum_values keys_map;
|
||||
if (keys_map.empty()) {
|
||||
keys_map["automatic"] = dfaAutomatic;
|
||||
keys_map["autosmall"] = dfaAutoNotFull;
|
||||
keys_map["enlarged"] = dfaEnlarged;
|
||||
}
|
||||
template<> inline const t_config_enum_values& ConfigOptionEnum<DenseInfillAlgo>::get_enum_values() {
|
||||
static const t_config_enum_values keys_map = {
|
||||
{ "automatic", dfaAutomatic },
|
||||
{ "autosmall", dfaAutoNotFull },
|
||||
{ "enlarged", dfaEnlarged }
|
||||
};
|
||||
return keys_map;
|
||||
}
|
||||
|
||||
|
@ -695,18 +695,18 @@ void PrintObject::count_distance_solid() {
|
||||
// sparse area = layer's fill area - solid area
|
||||
const float COEFF_SPLIT = 2;
|
||||
const int NB_DENSE_LAYERS = 1;
|
||||
for (int idx_region = 0; idx_region < this->_print->regions.size(); ++idx_region) {
|
||||
for (size_t idx_region = 0; idx_region < this->m_print->regions().size(); ++idx_region) {
|
||||
//count how many surface there are on each one
|
||||
LayerRegion *previousOne = NULL;
|
||||
if (this->layers.size() > 1) previousOne = this->layers[this->layers.size() - 1]->get_region(idx_region);
|
||||
if (previousOne != NULL && previousOne->region()->config.infill_dense.getBool() && previousOne->region()->config.fill_density<40) {
|
||||
if (this->layers().size() > 1) previousOne = this->layers()[this->layers().size() - 1]->get_region(idx_region);
|
||||
if (previousOne != NULL && previousOne->region()->config().infill_dense.getBool() && previousOne->region()->config().fill_density<40) {
|
||||
for (Surface &surf : previousOne->fill_surfaces.surfaces) {
|
||||
if (surf.is_solid()) {
|
||||
surf.maxNbSolidLayersOnTop = 0;
|
||||
}
|
||||
}
|
||||
for (int idx_layer = this->layers.size() - 2; idx_layer >= 0; --idx_layer){
|
||||
LayerRegion *layerm = this->layers[idx_layer]->get_region(idx_region);
|
||||
for (size_t idx_layer = this->layers().size() - 2; idx_layer >= 0; --idx_layer){
|
||||
LayerRegion *layerm = this->layers()[idx_layer]->get_region(idx_region);
|
||||
Surfaces surf_to_add;
|
||||
for (auto it_surf = layerm->fill_surfaces.surfaces.begin(); it_surf != layerm->fill_surfaces.surfaces.end(); ++it_surf) {
|
||||
Surface &surf = *it_surf;
|
||||
@ -721,7 +721,7 @@ void PrintObject::count_distance_solid() {
|
||||
// upp.expolygon.overlaps(surf.expolygon) or surf.expolygon.overlaps(upp.expolygon)
|
||||
ExPolygons intersect = intersection_ex(sparse_polys, offset_ex(upp.expolygon, -layerm->flow(frInfill).scaled_width()), true);
|
||||
if (!intersect.empty()) {
|
||||
if (layerm->region()->config.infill_dense_algo == dfaEnlarged) {
|
||||
if (layerm->region()->config().infill_dense_algo == dfaEnlarged) {
|
||||
uint16_t dist = (uint16_t)(upp.maxNbSolidLayersOnTop + 1);
|
||||
const int nb_dense_layers = 1;
|
||||
if (dist <= nb_dense_layers) {
|
||||
@ -729,11 +729,11 @@ void PrintObject::count_distance_solid() {
|
||||
uint64_t area_intersect = 0;
|
||||
for (ExPolygon poly_inter : intersect) area_intersect += poly_inter.area();
|
||||
//if it's in a dense area and the current surface isn't a dense one yet and the not-dense is too small.
|
||||
std::cout << idx_layer << " dfaEnlarged: " << layerm->region()->config.infill_dense_algo << "\n";
|
||||
std::cout << idx_layer << " dfaEnlarged: 1-" << (layerm->region()->config.infill_dense_algo == dfaEnlarged) << "\n";
|
||||
std::cout << idx_layer << " dfaEnlarged: " << layerm->region()->config().infill_dense_algo << "\n";
|
||||
std::cout << idx_layer << " dfaEnlarged: 1-" << (layerm->region()->config().infill_dense_algo == dfaEnlarged) << "\n";
|
||||
std::cout << idx_layer << " dfaEnlarged: 2-" << (surf.area() > area_intersect * COEFF_SPLIT) << "\n";
|
||||
std::cout << idx_layer << " dfaEnlarged: 3-" << (surf.maxNbSolidLayersOnTop > nb_dense_layers) << "\n";
|
||||
std::cout << idx_layer << " dfaEnlarged: surf.area()=" << unscale(unscale(surf.area())) << ", area_intersect=" << unscale(unscale(area_intersect)) << "\n";
|
||||
std::cout << idx_layer << " dfaEnlarged: surf.area()=" << unscale<double, double>(unscale<double, double>(surf.area())) << ", area_intersect=" << unscale<double, double>(unscale<double, double>(area_intersect)) << "\n";
|
||||
std::cout << idx_layer << " dfaEnlarged: surf.maxNbSolidLayersOnTop=" << surf.maxNbSolidLayersOnTop << ", NB_DENSE_LAYERS=" << NB_DENSE_LAYERS << "\n";
|
||||
if ((surf.area() > area_intersect * COEFF_SPLIT) &&
|
||||
surf.maxNbSolidLayersOnTop > nb_dense_layers) {
|
||||
@ -742,8 +742,7 @@ void PrintObject::count_distance_solid() {
|
||||
if (dist == 1) {
|
||||
//if just under the solid area, we can expand a bit
|
||||
//remove too small sections and grew a bit to anchor it into the part
|
||||
intersect = offset_ex(intersect,
|
||||
layerm->flow(frInfill).scaled_width() + scale_(layerm->region()->config.bridged_infill_margin));
|
||||
intersect = offset_ex(intersect, layerm->flow(frInfill).scaled_width() + scale_(layerm->region()->config().bridged_infill_margin));
|
||||
} else {
|
||||
//just remove too small sections
|
||||
intersect = offset_ex(intersect,
|
||||
@ -767,7 +766,7 @@ void PrintObject::count_distance_solid() {
|
||||
} else {
|
||||
surf.maxNbSolidLayersOnTop = std::min(surf.maxNbSolidLayersOnTop, dist);
|
||||
}
|
||||
} else if (layerm->region()->config.infill_dense_algo == dfaAutoNotFull || layerm->region()->config.infill_dense_algo == dfaAutomatic) {
|
||||
} else if (layerm->region()->config().infill_dense_algo == dfaAutoNotFull || layerm->region()->config().infill_dense_algo == dfaAutomatic) {
|
||||
double area_intersect = 0;
|
||||
for (ExPolygon poly_inter : intersect) area_intersect += poly_inter.area();
|
||||
//like intersect.empty() but more resilient
|
||||
@ -776,7 +775,7 @@ void PrintObject::count_distance_solid() {
|
||||
if (dist <= NB_DENSE_LAYERS) {
|
||||
// it will be a dense infill, split the surface if needed
|
||||
//if the not-dense is too big to do a full dense and the current surface isn't a dense one yet.
|
||||
if ((layerm->region()->config.infill_dense_algo == dfaAutomatic || surf.area() > area_intersect * COEFF_SPLIT) &&
|
||||
if ((layerm->region()->config().infill_dense_algo == dfaAutomatic || surf.area() > area_intersect * COEFF_SPLIT) &&
|
||||
surf.maxNbSolidLayersOnTop > NB_DENSE_LAYERS) {
|
||||
//split in two
|
||||
if (dist == 1) {
|
||||
@ -792,7 +791,7 @@ void PrintObject::count_distance_solid() {
|
||||
}
|
||||
intersect = offset_ex(cover_intersect,
|
||||
layerm->flow(frInfill).scaled_width());// +scale_(expandby));
|
||||
//layerm->region()->config.external_infill_margin));
|
||||
//layerm->region()->config().external_infill_margin));
|
||||
} else {
|
||||
//just remove too small sections
|
||||
intersect = offset_ex(intersect,
|
||||
@ -818,10 +817,10 @@ void PrintObject::count_distance_solid() {
|
||||
surf.maxNbSolidLayersOnTop = std::min(surf.maxNbSolidLayersOnTop, dist);
|
||||
}
|
||||
}
|
||||
} else if (layerm->region()->config.infill_dense_algo == dfaAutomatic) {
|
||||
} else if (layerm->region()->config().infill_dense_algo == dfaAutomatic) {
|
||||
double area_intersect = 0;
|
||||
for (ExPolygon poly_inter : intersect) area_intersect += poly_inter.area();
|
||||
std::cout << idx_layer << " dfaAutomatic: area_intersect=" << unscale(unscale(area_intersect)) << "\n";
|
||||
std::cout << idx_layer << " dfaAutomatic: area_intersect=" << unscale<double, double>(unscale<double, double>(area_intersect)) << "\n";
|
||||
//like intersect.empty() but more resilient
|
||||
if (area_intersect > layerm->flow(frInfill).scaled_width() * layerm->flow(frInfill).scaled_width() * 2) {
|
||||
std::cout << idx_layer << " dfaAutomatic: ok\n";
|
||||
@ -847,7 +846,7 @@ void PrintObject::count_distance_solid() {
|
||||
}
|
||||
intersect = offset_ex(cover_intersect,
|
||||
layerm->flow(frInfill).scaled_width());// +scale_(expandby));
|
||||
//layerm->region()->config.external_infill_margin));
|
||||
//layerm->region()->config().external_infill_margin));
|
||||
} else {
|
||||
std::cout << "dfaAutomatic: remove too small sections\n";
|
||||
//just remove too small sections
|
||||
@ -978,7 +977,7 @@ void PrintObject::detect_surfaces_type()
|
||||
// unless internal shells are requested
|
||||
Layer *upper_layer = (idx_layer + 1 < this->layer_count()) ? m_layers[idx_layer + 1] : nullptr;
|
||||
Layer *lower_layer = (idx_layer > 0) ? m_layers[idx_layer - 1] : nullptr;
|
||||
Layer *under_lower_layer = (idx_layer > 1) ? this->layers[idx_layer - 2] : nullptr;
|
||||
Layer *under_lower_layer = (idx_layer > 1) ? this->layers()[idx_layer - 2] : nullptr;
|
||||
// collapse very narrow parts (using the safety offset in the diff is not enough)
|
||||
float offset = layerm->flow(frExternalPerimeter).scaled_width() / 10.f;
|
||||
|
||||
@ -1672,15 +1671,16 @@ void PrintObject::replaceSurfaceType(SurfaceType st_to_replace, SurfaceType st_r
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "overextrude over Bridge...";
|
||||
|
||||
FOREACH_REGION(this->_print, region) {
|
||||
size_t region_id = region - this->_print->regions.begin();
|
||||
|
||||
FOREACH_LAYER(this, layer_it) {
|
||||
for (size_t region_id = 0; region_id < this->region_volumes.size(); ++region_id) {
|
||||
const PrintRegion ®ion = *m_print->regions()[region_id];
|
||||
|
||||
for (LayerPtrs::iterator layer_it = m_layers.begin(); layer_it != m_layers.end(); ++layer_it) {
|
||||
|
||||
// skip first layer
|
||||
if (layer_it == this->layers.begin()) continue;
|
||||
if (layer_it == this->layers().begin()) continue;
|
||||
|
||||
Layer* layer = *layer_it;
|
||||
LayerRegion* layerm = layer->regions[region_id];
|
||||
LayerRegion* layerm = layer->regions()[region_id];
|
||||
|
||||
// extract the stInternalSolid surfaces that might be transformed into bridges
|
||||
Polygons internal_solid;
|
||||
@ -1717,24 +1717,25 @@ void PrintObject::replaceSurfaceType(SurfaceType st_to_replace, SurfaceType st_r
|
||||
Polygons to_overextrude_pp = internal_solid;
|
||||
|
||||
// get previous layer
|
||||
if (int(layer_it - this->layers.begin()) - 1 >= 0) {
|
||||
const Layer* lower_layer = this->layers[int(layer_it - this->layers.begin()) - 1];
|
||||
if (int(layer_it - this->layers().begin()) - 1 >= 0) {
|
||||
const Layer* lower_layer = this->layers()[int(layer_it - this->layers().begin()) - 1];
|
||||
|
||||
// iterate through regions and collect internal surfaces
|
||||
Polygons lower_internal;
|
||||
FOREACH_LAYERREGION(lower_layer, lower_layerm_it){
|
||||
for (LayerRegion *lower_layerm : lower_layer->m_regions) {
|
||||
lower_layerm->fill_surfaces.filter_by_type(stInternal, &lower_internal);
|
||||
Polygons lower_internal_OK;
|
||||
Polygons lower_internal_Bridge;
|
||||
Polygons lower_internal_Over;
|
||||
(*lower_layerm_it)->fill_surfaces.filter_by_type(st_replacement, &lower_internal_OK);
|
||||
(*lower_layerm_it)->fill_surfaces.filter_by_type(st_under_it, &lower_internal_Bridge);
|
||||
(*lower_layerm_it)->fill_surfaces.filter_by_type(st_to_replace, &lower_internal_Over);
|
||||
lower_layerm->fill_surfaces.filter_by_type(st_replacement, &lower_internal_OK);
|
||||
lower_layerm->fill_surfaces.filter_by_type(st_under_it, &lower_internal_Bridge);
|
||||
lower_layerm->fill_surfaces.filter_by_type(st_to_replace, &lower_internal_Over);
|
||||
double okarea =0, bridgearea=0, overarea=0;
|
||||
for (ExPolygon &ex : union_ex(lower_internal_OK)) okarea+=ex.area();
|
||||
for (ExPolygon &ex : union_ex(lower_internal_Bridge)) bridgearea+=ex.area();
|
||||
for (ExPolygon &ex : union_ex(lower_internal_Over)) overarea+=ex.area();
|
||||
|
||||
(*lower_layerm_it)->fill_surfaces.filter_by_type(st_under_it, &lower_internal);
|
||||
lower_layerm->fill_surfaces.filter_by_type(st_under_it, &lower_internal);
|
||||
}
|
||||
double sumarea=0;
|
||||
for (ExPolygon &ex : union_ex(lower_internal)) sumarea+=ex.area();
|
||||
@ -1990,7 +1991,7 @@ end:
|
||||
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 hole_delta = float(scale_(this->config.hole_size_compensation.value));
|
||||
float hole_delta = float(scale_(this->config().hole_size_compensation.value));
|
||||
if (layer_id == 0)
|
||||
delta -= float(scale_(m_config.elefant_foot_compensation.value));
|
||||
bool scale = delta != 0.f;
|
||||
@ -2001,7 +2002,7 @@ end:
|
||||
LayerRegion *layerm = layer->m_regions.front();
|
||||
layerm->slices.set(offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), delta), stInternal);
|
||||
}
|
||||
_offsetHoles(hole_delta, layer->regions.front());
|
||||
_offsetHoles(hole_delta, layer->regions().front());
|
||||
} else if (scale || clip || hole_delta != 0.f) {
|
||||
// Multiple regions, growing, shrinking or just clipping one region by the other.
|
||||
// When clipping the regions, priority is given to the first regions.
|
||||
|
@ -1197,6 +1197,7 @@ static inline void remove_tangent_edges(std::vector<IntersectionLine> &lines)
|
||||
if (l1.edge_type == l2.edge_type) {
|
||||
l1.set_skip();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
assert(l1.a_id == l2.b_id && l1.b_id == l2.a_id);
|
||||
// If this edge joins two horizontal facets, remove both of them.
|
||||
@ -1212,21 +1213,24 @@ static inline void remove_tangent_edges(std::vector<IntersectionLine> &lines)
|
||||
}
|
||||
|
||||
|
||||
struct OpenPolyline {
|
||||
OpenPolyline() {};
|
||||
OpenPolyline(const IntersectionReference &start, const IntersectionReference &end, Points &&points) :
|
||||
start(start), end(end), points(std::move(points)), consumed(false) {}
|
||||
void reverse() {
|
||||
std::swap(start, end);
|
||||
std::reverse(points.begin(), points.end());
|
||||
}
|
||||
std::sort(out.begin(), out.end(), [](const OpenPolyline *lhs, const OpenPolyline *rhs){ return lhs->length > rhs->length; });
|
||||
return out;
|
||||
}
|
||||
struct OpenPolyline {
|
||||
OpenPolyline() {};
|
||||
OpenPolyline(const IntersectionReference &start, const IntersectionReference &end, Points &&points) :
|
||||
start(start), end(end), points(std::move(points)), consumed(false) { this->length = Slic3r::length(this->points); }
|
||||
void reverse() {
|
||||
std::swap(start, end);
|
||||
std::reverse(points.begin(), points.end());
|
||||
}
|
||||
IntersectionReference start;
|
||||
IntersectionReference end;
|
||||
Points points;
|
||||
double length;
|
||||
bool consumed;
|
||||
};
|
||||
|
||||
// called by TriangleMeshSlicer::make_loops() to connect remaining open polylines across shared triangle edges and vertices.
|
||||
// Depending on "try_connect_reversed", it may or may not connect segments crossing triangles of opposite orientation.
|
||||
static void chain_open_polylines_exact(std::vector<OpenPolyline> &open_polylines, Polygons &loops, bool try_connect_reversed)
|
||||
// called by TriangleMeshSlicer::make_loops() to connect sliced triangles into closed loops and open polylines by the triangle connectivity.
|
||||
// Only connects segments crossing triangles of the same orientation.
|
||||
static void chain_lines_by_triangle_connectivity(std::vector<IntersectionLine> &lines, Polygons &loops, std::vector<OpenPolyline> &open_polylines)
|
||||
{
|
||||
// Build a map of lines by edge_a_id and a_id.
|
||||
std::vector<IntersectionLine*> by_edge_a_id;
|
||||
@ -1256,13 +1260,20 @@ static void chain_open_polylines_exact(std::vector<OpenPolyline> &open_polylines
|
||||
first_line = &(*it_line_seed ++);
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto by_edge_lower = [](const IntersectionLine* il1, const IntersectionLine *il2) { return il1->edge_a_id < il2->edge_a_id; };
|
||||
auto by_vertex_lower = [](const IntersectionLine* il1, const IntersectionLine *il2) { return il1->a_id < il2->a_id; };
|
||||
std::sort(by_edge_a_id.begin(), by_edge_a_id.end(), by_edge_lower);
|
||||
std::sort(by_a_id.begin(), by_a_id.end(), by_vertex_lower);
|
||||
// Chain the segments with a greedy algorithm, collect the loops and unclosed polylines.
|
||||
IntersectionLines::iterator it_line_seed = lines.begin();
|
||||
if (first_line == nullptr)
|
||||
break;
|
||||
first_line->set_skip();
|
||||
Points loop_pts;
|
||||
loop_pts.emplace_back(first_line->a);
|
||||
IntersectionLine *last_line = first_line;
|
||||
|
||||
/*
|
||||
printf("first_line edge_a_id = %d, edge_b_id = %d, a_id = %d, b_id = %d, a = %d,%d, b = %d,%d\n",
|
||||
first_line->edge_a_id, first_line->edge_b_id, first_line->a_id, first_line->b_id,
|
||||
first_line->a.x, first_line->a.y, first_line->b.x, first_line->b.y);
|
||||
*/
|
||||
|
||||
IntersectionLine key;
|
||||
for (;;) {
|
||||
// find a line starting where last one finishes
|
||||
IntersectionLine* next_line = nullptr;
|
||||
@ -1308,37 +1319,121 @@ static void chain_open_polylines_exact(std::vector<OpenPolyline> &open_polylines
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Continue with the current loop.
|
||||
/*
|
||||
printf("next_line edge_a_id = %d, edge_b_id = %d, a_id = %d, b_id = %d, a = %d,%d, b = %d,%d\n",
|
||||
next_line->edge_a_id, next_line->edge_b_id, next_line->a_id, next_line->b_id,
|
||||
next_line->a.x, next_line->a.y, next_line->b.x, next_line->b.y);
|
||||
*/
|
||||
loop_pts.emplace_back(next_line->a);
|
||||
last_line = next_line;
|
||||
next_line->set_skip();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// called by TriangleMeshSlicer::make_loops() to connect remaining open polylines across shared triangle edges and vertices,
|
||||
// possibly closing small gaps.
|
||||
// Depending on "try_connect_reversed", it may or may not connect segments crossing triangles of opposite orientation.
|
||||
static void chain_open_polylines_close_gaps(std::vector<OpenPolyline> &open_polylines, Polygons &loops, double max_gap, bool try_connect_reversed)
|
||||
std::vector<OpenPolyline*> open_polylines_sorted(std::vector<OpenPolyline> &open_polylines, bool update_lengths)
|
||||
{
|
||||
const coord_t max_gap_scaled = (coord_t)scale_(max_gap);
|
||||
std::vector<OpenPolyline*> out;
|
||||
out.reserve(open_polylines.size());
|
||||
for (OpenPolyline &opl : open_polylines)
|
||||
if (! opl.consumed) {
|
||||
if (update_lengths)
|
||||
opl.length = Slic3r::length(opl.points);
|
||||
out.emplace_back(&opl);
|
||||
}
|
||||
std::sort(out.begin(), out.end(), [](const OpenPolyline *lhs, const OpenPolyline *rhs){ return lhs->length > rhs->length; });
|
||||
return out;
|
||||
}
|
||||
|
||||
// Try to connect the loops.
|
||||
for (OpenPolyline &opl : open_polylines) {
|
||||
if (opl.consumed)
|
||||
continue;
|
||||
opl.consumed = true;
|
||||
OpenPolylineEnd end(&opl, false);
|
||||
for (;;) {
|
||||
// find a line starting where last one finishes
|
||||
OpenPolylineEnd* next_start = nullptr;
|
||||
if (end.edge_id() != -1) {
|
||||
auto it_begin = std::lower_bound(by_edge_id.begin(), by_edge_id.end(), end, by_edge_lower);
|
||||
if (it_begin != by_edge_id.end()) {
|
||||
auto it_end = std::upper_bound(it_begin, by_edge_id.end(), end, by_edge_lower);
|
||||
for (auto it_edge = it_begin; it_edge != it_end; ++ it_edge)
|
||||
if (! it_edge->polyline->consumed) {
|
||||
next_start = &(*it_edge);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// called by TriangleMeshSlicer::make_loops() to connect remaining open polylines across shared triangle edges and vertices.
|
||||
// Depending on "try_connect_reversed", it may or may not connect segments crossing triangles of opposite orientation.
|
||||
static void chain_open_polylines_exact(std::vector<OpenPolyline> &open_polylines, Polygons &loops, bool try_connect_reversed)
|
||||
{
|
||||
// Store the end points of open_polylines into vectors sorted
|
||||
struct OpenPolylineEnd {
|
||||
OpenPolylineEnd(OpenPolyline *polyline, bool start) : polyline(polyline), start(start) {}
|
||||
OpenPolyline *polyline;
|
||||
// Is it the start or end point?
|
||||
bool start;
|
||||
const IntersectionReference& ipref() const { return start ? polyline->start : polyline->end; }
|
||||
// Return a unique ID for the intersection point.
|
||||
// Return a positive id for a point, or a negative id for an edge.
|
||||
int id() const { const IntersectionReference &r = ipref(); return (r.point_id >= 0) ? r.point_id : - r.edge_id; }
|
||||
bool operator==(const OpenPolylineEnd &rhs) const { return this->polyline == rhs.polyline && this->start == rhs.start; }
|
||||
};
|
||||
auto by_id_lower = [](const OpenPolylineEnd &ope1, const OpenPolylineEnd &ope2) { return ope1.id() < ope2.id(); };
|
||||
std::vector<OpenPolylineEnd> by_id;
|
||||
by_id.reserve(2 * open_polylines.size());
|
||||
for (OpenPolyline &opl : open_polylines) {
|
||||
if (opl.start.point_id != -1 || opl.start.edge_id != -1)
|
||||
by_id.emplace_back(OpenPolylineEnd(&opl, true));
|
||||
if (try_connect_reversed && (opl.end.point_id != -1 || opl.end.edge_id != -1))
|
||||
by_id.emplace_back(OpenPolylineEnd(&opl, false));
|
||||
}
|
||||
std::sort(by_id.begin(), by_id.end(), by_id_lower);
|
||||
// Find an iterator to by_id_lower for the particular end of OpenPolyline (by comparing the OpenPolyline pointer and the start attribute).
|
||||
auto find_polyline_end = [&by_id, by_id_lower](const OpenPolylineEnd &end) -> std::vector<OpenPolylineEnd>::iterator {
|
||||
for (auto it = std::lower_bound(by_id.begin(), by_id.end(), end, by_id_lower);
|
||||
it != by_id.end() && it->id() == end.id(); ++ it)
|
||||
if (*it == end)
|
||||
return it;
|
||||
return by_id.end();
|
||||
};
|
||||
// Try to connect the loops.
|
||||
std::vector<OpenPolyline*> sorted_by_length = open_polylines_sorted(open_polylines, false);
|
||||
for (OpenPolyline *opl : sorted_by_length) {
|
||||
if (opl->consumed)
|
||||
continue;
|
||||
opl->consumed = true;
|
||||
OpenPolylineEnd end(opl, false);
|
||||
for (;;) {
|
||||
// find a line starting where last one finishes
|
||||
auto it_next_start = std::lower_bound(by_id.begin(), by_id.end(), end, by_id_lower);
|
||||
for (; it_next_start != by_id.end() && it_next_start->id() == end.id(); ++ it_next_start)
|
||||
if (! it_next_start->polyline->consumed)
|
||||
goto found;
|
||||
// The current loop could not be closed. Unmark the segment.
|
||||
opl->consumed = false;
|
||||
break;
|
||||
found:
|
||||
// Attach this polyline to the end of the initial polyline.
|
||||
if (it_next_start->start) {
|
||||
auto it = it_next_start->polyline->points.begin();
|
||||
std::copy(++ it, it_next_start->polyline->points.end(), back_inserter(opl->points));
|
||||
} else {
|
||||
auto it = it_next_start->polyline->points.rbegin();
|
||||
std::copy(++ it, it_next_start->polyline->points.rend(), back_inserter(opl->points));
|
||||
}
|
||||
opl->length += it_next_start->polyline->length;
|
||||
// Mark the next polyline as consumed.
|
||||
it_next_start->polyline->points.clear();
|
||||
it_next_start->polyline->length = 0.;
|
||||
it_next_start->polyline->consumed = true;
|
||||
if (try_connect_reversed) {
|
||||
// Running in a mode, where the polylines may be connected by mixing their orientations.
|
||||
// Update the end point lookup structure after the end point of the current polyline was extended.
|
||||
auto it_end = find_polyline_end(end);
|
||||
auto it_next_end = find_polyline_end(OpenPolylineEnd(it_next_start->polyline, !it_next_start->start));
|
||||
// Swap the end points of the current and next polyline, but keep the polyline ptr and the start flag.
|
||||
std::swap(opl->end, it_next_end->start ? it_next_end->polyline->start : it_next_end->polyline->end);
|
||||
// Swap the positions of OpenPolylineEnd structures in the sorted array to match their respective end point positions.
|
||||
std::swap(*it_end, *it_next_end);
|
||||
}
|
||||
// Check whether we closed this loop.
|
||||
if ((opl->start.edge_id != -1 && opl->start.edge_id == opl->end.edge_id) ||
|
||||
(opl->start.point_id != -1 && opl->start.point_id == opl->end.point_id)) {
|
||||
// The current loop is complete. Add it to the output.
|
||||
//assert(opl->points.front().point_id == opl->points.back().point_id);
|
||||
//assert(opl->points.front().edge_id == opl->points.back().edge_id);
|
||||
// Remove the duplicate last point.
|
||||
opl->points.pop_back();
|
||||
if (opl->points.size() >= 3) {
|
||||
if (try_connect_reversed && area(opl->points) < 0)
|
||||
// The closed polygon is patched from pieces with messed up orientation, therefore
|
||||
// the orientation of the patched up polygon is not known.
|
||||
// Orient the patched up polygons CCW. This heuristic may close some holes and cavities.
|
||||
std::reverse(opl->points.begin(), opl->points.end());
|
||||
loops.emplace_back(std::move(opl->points));
|
||||
}
|
||||
opl->points.clear();
|
||||
break;
|
||||
@ -1680,7 +1775,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_(0.0001); // now a config value
|
||||
|
||||
/* The following line is commented out because it can generate wrong polygons,
|
||||
see for example issue #661 */
|
||||
|
@ -174,7 +174,7 @@ public:
|
||||
const float min_z, const float max_z, IntersectionLine *line_out) const;
|
||||
void cut(float z, TriangleMesh* upper, TriangleMesh* lower) const;
|
||||
|
||||
double safety_offset = scale_(0.0499);
|
||||
double safety_offset = scale_(0.02);
|
||||
private:
|
||||
const TriangleMesh *mesh;
|
||||
// Map from a facet to an edge index.
|
||||
|
@ -80,6 +80,8 @@ namespace Slic3r {
|
||||
template<typename T, typename Q>
|
||||
inline T unscale(Q v) { return T(v) * T(SCALING_FACTOR); }
|
||||
|
||||
inline double unscaled(double v) { return v * SCALING_FACTOR; }
|
||||
|
||||
enum Axis { X=0, Y, Z, E, F, NUM_AXES };
|
||||
|
||||
template <class T>
|
||||
|
@ -930,7 +930,7 @@ void TabPrint::build()
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Advanced")));
|
||||
optgroup->append_single_option_line("remove_small_gaps");
|
||||
line = { _(L("Avoid unsupported perimeters")), "" };
|
||||
line = { _(L("Seam")), "" };
|
||||
line.append_option(optgroup->get_option("seam_position"));
|
||||
line.append_option(optgroup->get_option("seam_travel"));
|
||||
optgroup->append_line(line);
|
||||
|
Loading…
x
Reference in New Issue
Block a user