1089{
1090
1092
1096
1098
1099
1100 if (params.
config.overhangs && lower_slices !=
nullptr && lower_slices_polygons_cache.empty()) {
1101
1102
1103
1104 double nozzle_diameter = params.
print_config.nozzle_diameter.get_at(params.
config.perimeter_extruder-1);
1105 lower_slices_polygons_cache = offset(*lower_slices,
float(
scale_(+nozzle_diameter/2)));
1106 }
1107
1108
1109
1110
1114
1116 std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
1117 loop_number = int(perimeters.size()) - 1;
1118
1119#ifdef ARACHNE_DEBUG
1120 {
1121 static int iRun = 0;
1122 export_perimeters_to_svg(
debug_out_path(
"arachne-perimeters-%d-%d.svg", layer_id, iRun++),
to_polygons(last), perimeters,
union_ex(wallToolPaths.getInnerContour()));
1123 }
1124#endif
1125
1126
1127
1128
1129 assert([&perimeters = std::as_const(perimeters)]() -> bool {
1130 for (const Arachne::VariableWidthLines &perimeter : perimeters)
1131 for (
const Arachne::ExtrusionLine &el : perimeter)
1132 if (el.is_closed && el.junctions.front().p != el.junctions.back().p)
1133 return false;
1134 return true;
1135 }());
1136
1137 int start_perimeter = int(perimeters.size()) - 1;
1138 int end_perimeter = -1;
1139 int direction = -1;
1140
1141 if (params.
config.external_perimeters_first) {
1142 start_perimeter = 0;
1143 end_perimeter = int(perimeters.size());
1144 direction = 1;
1145 }
1146
1147 std::vector<Arachne::ExtrusionLine *> all_extrusions;
1148 for (int perimeter_idx = start_perimeter; perimeter_idx != end_perimeter; perimeter_idx += direction) {
1149 if (perimeters[perimeter_idx].
empty())
1150 continue;
1151 for (Arachne::ExtrusionLine &wall : perimeters[perimeter_idx])
1152 all_extrusions.emplace_back(&wall);
1153 }
1154
1155
1156 std::vector<size_t> blocked(all_extrusions.size(), 0);
1157 std::vector<std::vector<size_t>> blocking(all_extrusions.size());
1158 ankerl::unordered_dense::map<const Arachne::ExtrusionLine *, size_t> map_extrusion_to_idx;
1159 for (size_t idx = 0; idx < all_extrusions.size(); idx++)
1160 map_extrusion_to_idx.emplace(all_extrusions[idx], idx);
1161
1162 Arachne::WallToolPaths::ExtrusionLineSet extrusions_constrains = Arachne::WallToolPaths::getRegionOrder(all_extrusions, params.
config.external_perimeters_first);
1163 for (auto [before, after] : extrusions_constrains) {
1164 auto after_it = map_extrusion_to_idx.find(after);
1165 ++blocked[after_it->second];
1166 blocking[map_extrusion_to_idx.find(before)->second].emplace_back(after_it->second);
1167 }
1168
1169 std::vector<bool> processed(all_extrusions.size(), false);
1170 Point current_position = all_extrusions.empty() ? Point::Zero() : all_extrusions.
front()->junctions.
front().p;
1171 std::vector<PerimeterGeneratorArachneExtrusion> ordered_extrusions;
1172 ordered_extrusions.reserve(all_extrusions.size());
1173
1174 while (ordered_extrusions.size() < all_extrusions.size()) {
1175 size_t best_candidate = 0;
1176 double best_distance_sqr = std::numeric_limits<double>::max();
1177 bool is_best_closed = false;
1178
1179 std::vector<size_t> available_candidates;
1180 for (size_t candidate = 0; candidate < all_extrusions.size(); ++candidate) {
1181 if (processed[candidate] || blocked[candidate])
1182 continue;
1183 available_candidates.push_back(candidate);
1184 }
1185
1186 std::sort(available_candidates.begin(), available_candidates.end(), [&all_extrusions](const size_t a_idx, const size_t b_idx) -> bool {
1187 return all_extrusions[a_idx]->is_closed < all_extrusions[b_idx]->is_closed;
1188 });
1189
1190 for (const size_t candidate_path_idx : available_candidates) {
1191 auto& path = all_extrusions[candidate_path_idx];
1192
1193 if (path->junctions.empty()) {
1194 if (best_distance_sqr == std::numeric_limits<double>::max()) {
1195 best_candidate = candidate_path_idx;
1196 is_best_closed = path->is_closed;
1197 }
1198 continue;
1199 }
1200
1201 const Point candidate_position = path->junctions.front().p;
1202 double distance_sqr = (current_position - candidate_position).cast<double>().norm();
1203 if (distance_sqr < best_distance_sqr) {
1204 if (path->is_closed || (!path->is_closed && best_distance_sqr != std::numeric_limits<double>::max()) || (!path->is_closed && !is_best_closed)) {
1205 best_candidate = candidate_path_idx;
1206 best_distance_sqr = distance_sqr;
1207 is_best_closed = path->is_closed;
1208 }
1209 }
1210 }
1211
1212 auto &best_path = all_extrusions[best_candidate];
1213 ordered_extrusions.push_back({best_path, best_path->is_contour(), false});
1214 processed[best_candidate] = true;
1215 for (size_t unlocked_idx : blocking[best_candidate])
1216 blocked[unlocked_idx]--;
1217
1218 if (!best_path->junctions.empty()) {
1219 if(best_path->is_closed)
1220 current_position = best_path->junctions[0].p;
1221 else
1222 current_position = best_path->junctions.back().p;
1223 }
1224 }
1225
1226 if (params.
layer_id > 0 && params.
config.fuzzy_skin != FuzzySkinType::None) {
1227 std::vector<PerimeterGeneratorArachneExtrusion *> closed_loop_extrusions;
1228 for (PerimeterGeneratorArachneExtrusion &extrusion : ordered_extrusions)
1229 if (extrusion.extrusion->inset_idx == 0) {
1230 if (extrusion.extrusion->is_closed && params.
config.fuzzy_skin == FuzzySkinType::External) {
1231 closed_loop_extrusions.emplace_back(&extrusion);
1232 } else {
1233 extrusion.fuzzify = true;
1234 }
1235 }
1236
1237 if (params.
config.fuzzy_skin == FuzzySkinType::External) {
1238 ClipperLib_Z::Paths loops_paths;
1239 loops_paths.reserve(closed_loop_extrusions.size());
1240 for (const auto &cl_extrusion : closed_loop_extrusions) {
1241 assert(cl_extrusion->extrusion->junctions.front() == cl_extrusion->extrusion->junctions.back());
1242 size_t loop_idx = &cl_extrusion - &closed_loop_extrusions.front();
1243 ClipperLib_Z::Path loop_path;
1244 loop_path.reserve(cl_extrusion->extrusion->junctions.size() - 1);
1245 for (auto junction_it = cl_extrusion->extrusion->junctions.begin(); junction_it != std::prev(cl_extrusion->extrusion->junctions.end()); ++junction_it)
1246 loop_path.emplace_back(junction_it->p.x(), junction_it->p.y(), loop_idx);
1247 loops_paths.emplace_back(loop_path);
1248 }
1249
1250 ClipperLib_Z::Clipper clipper;
1251 clipper.AddPaths(loops_paths, ClipperLib_Z::ptSubject, true);
1252 ClipperLib_Z::PolyTree loops_polytree;
1253 clipper.Execute(ClipperLib_Z::ctUnion, loops_polytree, ClipperLib_Z::pftEvenOdd, ClipperLib_Z::pftEvenOdd);
1254
1255 for (const ClipperLib_Z::PolyNode *child_node : loops_polytree.Childs) {
1256
1257 coord_t polygon_idx = child_node->Contour.front().z();
1258 bool has_same_idx = std::all_of(child_node->Contour.begin(), child_node->Contour.end(),
1259 [&polygon_idx](const ClipperLib_Z::IntPoint &point) -> bool { return polygon_idx == point.z(); });
1260 if (has_same_idx)
1261 closed_loop_extrusions[polygon_idx]->fuzzify = true;
1262 }
1263 }
1264 }
1265
1266 if (ExtrusionEntityCollection extrusion_coll =
traverse_extrusions(params, lower_slices_polygons_cache, ordered_extrusions); !extrusion_coll.
empty())
1267 out_loops.
append(extrusion_coll);
1268
1270 const coord_t spacing = (perimeters.size() == 1) ? ext_perimeter_spacing2 : perimeter_spacing;
1272 infill_contour.clear();
1273
1274
1275
1276
1277
1279 (loop_number < 0) ? 0 :
1280 (loop_number == 0) ?
1281
1282 ext_perimeter_spacing:
1283
1284 perimeter_spacing;
1285
1286 inset =
coord_t(
scale_(params.
config.get_abs_value(
"infill_overlap", unscale<double>(inset))));
1288 for (ExPolygon &ex : infill_contour)
1289 ex.simplify_p(params.scaled_resolution, &pp);
1290
1292
1296 float(- min_perimeter_infill_spacing / 2.),
1297 float(inset + min_perimeter_infill_spacing / 2.));
1298
1299 if (lower_slices !=
nullptr && params.
config.overhangs && params.
config.extra_perimeters_on_overhangs &&
1301
1303 lower_slices_polygons_cache,
1304 loop_number + 1,
1307 if (!extra_perimeters.empty()) {
1308 ExtrusionEntityCollection &this_islands_perimeters =
static_cast<ExtrusionEntityCollection&
>(*out_loops.
entities.back());
1310 old_entities.swap(this_islands_perimeters.entities);
1311 for (ExtrusionPaths &paths : extra_perimeters)
1312 this_islands_perimeters.
append(
std::move(paths));
1313 append(this_islands_perimeters.entities, old_entities);
1314 infill_areas =
diff_ex(infill_areas, filled_area);
1315 }
1316 }
1317
1318 append(out_fill_expolygons, std::move(infill_areas));
1319}
void simplify_p(double tolerance, Polygons *polygons) const
Definition ExPolygon.cpp:173
void append(const ExtrusionEntity &entity)
Definition ExtrusionEntityCollection.hpp:68
bool empty() const
Definition ExtrusionEntityCollection.hpp:65
ExtrusionEntitiesPtr entities
Definition ExtrusionEntityCollection.hpp:32
coord_t scaled_width() const
Definition Flow.hpp:61
float spacing() const
Definition Flow.hpp:66
coord_t scaled_spacing() const
Definition Flow.hpp:67
unsigned short extra_perimeters
Definition Surface.hpp:39
ExPolygon expolygon
Definition Surface.hpp:35
#define const
Definition getopt.c:38
if(!(yy_init))
Definition lexer.c:1190
#define scale_(val)
Definition libslic3r.h:69
int32_t coord_t
Definition libslic3r.h:39
static constexpr double INSET_OVERLAP_TOLERANCE
Definition libslic3r.h:63
std::vector< Polygon, PointsAllocator< Polygon > > Polygons
Definition Polygon.hpp:15
std::tuple< std::vector< ExtrusionPaths >, Polygons > generate_extra_perimeters_over_overhangs(ExPolygons infill_area, const Polygons &lower_slices_polygons, int perimeter_count, const Flow &overhang_flow, double scaled_resolution, const PrintObjectConfig &object_config, const PrintConfig &print_config)
Definition PerimeterGenerator.cpp:871
std::string debug_out_path(const char *name,...)
Definition utils.cpp:218
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:726
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, ClipperLib::PolyFillType fill_type)
Definition ClipperUtils.cpp:774
std::vector< ExPolygon > ExPolygons
Definition ExPolygon.hpp:13
Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:421
Polygons to_polygons(const ExPolygon &src)
Definition ExPolygon.hpp:281
static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::Parameters ¶ms, const Polygons &lower_slices_polygons_cache, std::vector< PerimeterGeneratorArachneExtrusion > &pg_extrusions)
Definition PerimeterGenerator.cpp:503
std::vector< ExtrusionEntity * > ExtrusionEntitiesPtr
Definition ExtrusionEntity.hpp:58
ExPolygons offset2_ex(const ExPolygons &expolygons, const float delta1, const float delta2, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:576
bool empty(const BoundingBoxBase< PointType, PointsType > &bb)
Definition BoundingBox.hpp:229
TPoint< P > front(const P &p)
Definition geometry_traits.hpp:872
void append(SurfaceCut &sc, SurfaceCut &&sc_add)
Merge two surface cuts together Added surface cut will be consumed.
Definition CutSurface.cpp:3550
Kernel::Point_2 Point
Definition point_areas.cpp:20
Flow ext_perimeter_flow
Definition PerimeterGenerator.hpp:50
double scaled_resolution
Definition PerimeterGenerator.hpp:59
Flow perimeter_flow
Definition PerimeterGenerator.hpp:49
int layer_id
Definition PerimeterGenerator.hpp:48
Flow solid_infill_flow
Definition PerimeterGenerator.hpp:52
Flow overhang_flow
Definition PerimeterGenerator.hpp:51
const PrintObjectConfig & object_config
Definition PerimeterGenerator.hpp:54
const PrintRegionConfig & config
Definition PerimeterGenerator.hpp:53
const PrintConfig & print_config
Definition PerimeterGenerator.hpp:55
double layer_height
Definition PerimeterGenerator.hpp:47