Organic supports: Fixed order & orientation of two perimeter loops:
1) All contours are CCW oriented. 2) Inner contours are printed before outer contours.
This commit is contained in:
parent
4c3599fac1
commit
a97b950c3d
@ -288,12 +288,12 @@ inline void extrusion_entities_append_paths(ExtrusionEntitiesPtr &dst, const Pol
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void extrusion_entities_append_paths(ExtrusionEntitiesPtr &dst, Polylines &&polylines, ExtrusionRole role, double mm3_per_mm, float width, float height)
|
inline void extrusion_entities_append_paths(ExtrusionEntitiesPtr &dst, Polylines &&polylines, ExtrusionRole role, double mm3_per_mm, float width, float height, bool can_reverse = true)
|
||||||
{
|
{
|
||||||
dst.reserve(dst.size() + polylines.size());
|
dst.reserve(dst.size() + polylines.size());
|
||||||
for (Polyline &polyline : polylines)
|
for (Polyline &polyline : polylines)
|
||||||
if (polyline.is_valid()) {
|
if (polyline.is_valid()) {
|
||||||
ExtrusionPath *extrusion_path = new ExtrusionPath(role, mm3_per_mm, width, height);
|
ExtrusionPath *extrusion_path = can_reverse ? new ExtrusionPath(role, mm3_per_mm, width, height) : new ExtrusionPathOriented(role, mm3_per_mm, width, height);
|
||||||
dst.push_back(extrusion_path);
|
dst.push_back(extrusion_path);
|
||||||
extrusion_path->polyline = std::move(polyline);
|
extrusion_path->polyline = std::move(polyline);
|
||||||
}
|
}
|
||||||
|
@ -3246,6 +3246,10 @@ static Polylines draw_perimeters(const ExPolygon &expoly, double clip_length)
|
|||||||
for (size_t i = 0; i <= expoly.holes.size(); ++ i) {
|
for (size_t i = 0; i <= expoly.holes.size(); ++ i) {
|
||||||
Polyline pl(i == 0 ? expoly.contour.points : expoly.holes[i - 1].points);
|
Polyline pl(i == 0 ? expoly.contour.points : expoly.holes[i - 1].points);
|
||||||
pl.points.emplace_back(pl.points.front());
|
pl.points.emplace_back(pl.points.front());
|
||||||
|
if (i > 0)
|
||||||
|
// It is a hole, reverse it.
|
||||||
|
pl.reverse();
|
||||||
|
// so that all contours are CCW oriented.
|
||||||
pl.clip_end(clip_length);
|
pl.clip_end(clip_length);
|
||||||
polylines.emplace_back(std::move(pl));
|
polylines.emplace_back(std::move(pl));
|
||||||
}
|
}
|
||||||
@ -3351,13 +3355,17 @@ static inline void tree_supports_generate_paths(
|
|||||||
const double anchor_length = spacing * 6.;
|
const double anchor_length = spacing * 6.;
|
||||||
ClipperLib_Z::Paths anchor_candidates;
|
ClipperLib_Z::Paths anchor_candidates;
|
||||||
for (ExPolygon& expoly : closing_ex(polygons, float(SCALED_EPSILON), float(SCALED_EPSILON + 0.5 * flow.scaled_width()))) {
|
for (ExPolygon& expoly : closing_ex(polygons, float(SCALED_EPSILON), float(SCALED_EPSILON + 0.5 * flow.scaled_width()))) {
|
||||||
|
std::unique_ptr<ExtrusionEntityCollection> eec;
|
||||||
double area = expoly.area();
|
double area = expoly.area();
|
||||||
if (area > sqr(scaled<double>(5.))) {
|
if (area > sqr(scaled<double>(5.))) {
|
||||||
|
eec = std::make_unique<ExtrusionEntityCollection>();
|
||||||
|
// Don't reoder internal / external loops of the same island, always start with the internal loop.
|
||||||
|
eec->no_sort = true;
|
||||||
// Make the tree branch stable by adding another perimeter.
|
// Make the tree branch stable by adding another perimeter.
|
||||||
ExPolygons level2 = offset2_ex({ expoly }, -1.5 * flow.scaled_width(), 0.5 * flow.scaled_width());
|
ExPolygons level2 = offset2_ex({ expoly }, -1.5 * flow.scaled_width(), 0.5 * flow.scaled_width());
|
||||||
if (level2.size() == 1) {
|
if (level2.size() == 1) {
|
||||||
Polylines polylines;
|
Polylines polylines;
|
||||||
extrusion_entities_append_paths(dst, draw_perimeters(expoly, clip_length), ExtrusionRole::SupportMaterial, flow.mm3_per_mm(), flow.width(), flow.height(),
|
extrusion_entities_append_paths(eec->entities, draw_perimeters(expoly, clip_length), ExtrusionRole::SupportMaterial, flow.mm3_per_mm(), flow.width(), flow.height(),
|
||||||
// Disable reversal of the path, always start with the anchor, always print CCW.
|
// Disable reversal of the path, always start with the anchor, always print CCW.
|
||||||
false);
|
false);
|
||||||
expoly = level2.front();
|
expoly = level2.front();
|
||||||
@ -3369,20 +3377,21 @@ static inline void tree_supports_generate_paths(
|
|||||||
// The anchor candidate points are annotated with an index of the source contour or with -1 if on intersection.
|
// The anchor candidate points are annotated with an index of the source contour or with -1 if on intersection.
|
||||||
anchor_candidates.clear();
|
anchor_candidates.clear();
|
||||||
shrink_expolygon_with_contour_idx(expoly, flow.scaled_width(), DefaultJoinType, 1.2, anchor_candidates);
|
shrink_expolygon_with_contour_idx(expoly, flow.scaled_width(), DefaultJoinType, 1.2, anchor_candidates);
|
||||||
// Orient all contours CCW.
|
// Orient all contours CW.
|
||||||
for (auto &path : anchor_candidates)
|
for (auto &path : anchor_candidates)
|
||||||
if (ClipperLib_Z::Area(path) < 0)
|
if (ClipperLib_Z::Area(path) > 0)
|
||||||
std::reverse(path.begin(), path.end());
|
std::reverse(path.begin(), path.end());
|
||||||
|
|
||||||
// Draw the perimeters.
|
// Draw the perimeters.
|
||||||
Polylines polylines;
|
Polylines polylines;
|
||||||
polylines.reserve(expoly.holes.size() + 1);
|
polylines.reserve(expoly.holes.size() + 1);
|
||||||
for (size_t idx_loop = 0; idx_loop <= expoly.holes.size(); ++ idx_loop) {
|
for (size_t idx_loop = 0; idx_loop < expoly.num_contours(); ++ idx_loop) {
|
||||||
// Open the loop with a seam.
|
// Open the loop with a seam.
|
||||||
const Polygon &loop = idx_loop == 0 ? expoly.contour : expoly.holes[idx_loop - 1];
|
const Polygon &loop = expoly.contour_or_hole(idx_loop);
|
||||||
Polyline pl(loop.points);
|
Polyline pl(loop.points);
|
||||||
// Orient all contours CCW.
|
// Orient all contours CW, because the anchor will be added to the end of polyline while we want to start a loop with the anchor.
|
||||||
if (loop.area() < 0)
|
if (idx_loop == 0)
|
||||||
|
// It is an outer contour.
|
||||||
pl.reverse();
|
pl.reverse();
|
||||||
pl.points.emplace_back(pl.points.front());
|
pl.points.emplace_back(pl.points.front());
|
||||||
pl.clip_end(clip_length);
|
pl.clip_end(clip_length);
|
||||||
@ -3421,7 +3430,7 @@ static inline void tree_supports_generate_paths(
|
|||||||
}
|
}
|
||||||
if (d2min < sqr(flow.scaled_width() * 3.)) {
|
if (d2min < sqr(flow.scaled_width() * 3.)) {
|
||||||
// Try to cut an anchor from the closest_contour.
|
// Try to cut an anchor from the closest_contour.
|
||||||
// Both closest_contour and pl are CCW oriented.
|
// Both closest_contour and pl are CW oriented.
|
||||||
pl.points.emplace_back(closest_point.cast<coord_t>());
|
pl.points.emplace_back(closest_point.cast<coord_t>());
|
||||||
const ClipperLib_Z::Path &path = *closest_contour;
|
const ClipperLib_Z::Path &path = *closest_contour;
|
||||||
double remaining_length = anchor_length - (seam_pt - closest_point).norm();
|
double remaining_length = anchor_length - (seam_pt - closest_point).norm();
|
||||||
@ -3460,9 +3469,15 @@ static inline void tree_supports_generate_paths(
|
|||||||
pl.reverse();
|
pl.reverse();
|
||||||
polylines.emplace_back(std::move(pl));
|
polylines.emplace_back(std::move(pl));
|
||||||
}
|
}
|
||||||
extrusion_entities_append_paths(dst, polylines, ExtrusionRole::SupportMaterial, flow.mm3_per_mm(), flow.width(), flow.height(),
|
|
||||||
|
ExtrusionEntitiesPtr &out = eec ? eec->entities : dst;
|
||||||
|
extrusion_entities_append_paths(out, std::move(polylines), ExtrusionRole::SupportMaterial, flow.mm3_per_mm(), flow.width(), flow.height(),
|
||||||
// Disable reversal of the path, always start with the anchor, always print CCW.
|
// Disable reversal of the path, always start with the anchor, always print CCW.
|
||||||
false);
|
false);
|
||||||
|
if (eec) {
|
||||||
|
std::reverse(eec->entities.begin(), eec->entities.end());
|
||||||
|
dst.emplace_back(eec.release());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user