3089{
3090 BOOST_LOG_TRIVIAL(info) <<
"Bridge over infill - Start" <<
log_memory_info();
3091 struct CandidateSurface
3092 {
3093 CandidateSurface(const Surface *original_surface,
3094 int layer_index,
3095 Polygons new_polys,
3096 const LayerRegion *region,
3097 double bridge_angle)
3098 : original_surface(original_surface)
3099 , layer_index(layer_index)
3100 , new_polys(new_polys)
3101 , region(region)
3102 , bridge_angle(bridge_angle)
3103 {}
3104 const Surface *original_surface;
3105 int layer_index;
3107 const LayerRegion *region;
3108 double bridge_angle;
3109 };
3110
3111 std::map<size_t, std::vector<CandidateSurface>> surfaces_by_layer;
3112
3113
3114 bool has_lightning_infill = false;
3117 has_lightning_infill = true;
3118 break;
3119 }
3120 }
3121
3122
3123 {
3124 tbb::concurrent_vector<CandidateSurface> candidate_surfaces;
3125 tbb::parallel_for(tbb::blocked_range<size_t>(0, this->
layers().
size()), [po =
static_cast<const PrintObject *
>(
this), &candidate_surfaces](tbb::blocked_range<size_t> r) {
3127 for (size_t lidx = r.begin(); lidx < r.end(); lidx++) {
3128 const Layer *layer = po->get_layer(lidx);
3129 if (layer->lower_layer == nullptr) {
3130 continue;
3131 }
3132 double spacing = layer->regions().front()->flow(
frSolidInfill).scaled_spacing();
3133
3136
3137
3138 bool dense_below = true;
3139 for (const LayerRegion *region : layer->lower_layer->regions()) {
3141
3142 unsupported_area.insert(unsupported_area.end(), fill_polys.begin(), fill_polys.end());
3143 for (const Surface &surface : region->fill_surfaces) {
3144 if (surface.surface_type !=
stInternal || region->region().config().sparse_infill_density.value == 100) {
3146 lower_layer_solids.insert(lower_layer_solids.end(), p.begin(), p.end());
3147 }
3148 dense_below = dense_below &&
prints_dense(surface, region->region().config(), po->config(), layer->lower_layer->id());
3149 }
3150 }
3152
3153
3154
3155 double expansion_multiplier = 3;
3156 if(po->config().dont_filter_internal_bridges.value !=
ibfDisabled){
3157 expansion_multiplier = 1;
3158 }
3159
3160
3161 lower_layer_solids =
shrink(lower_layer_solids, 1 * spacing);
3162
3163 unsupported_area =
shrink(unsupported_area, expansion_multiplier * spacing);
3164
3165
3166
3167
3168 const float reach = float((1 + expansion_multiplier) * spacing);
3169 unsupported_area = dense_below ?
diff_expanded(unsupported_area, lower_layer_solids, reach) :
3170 diff(unsupported_area,
expand(lower_layer_solids, reach));
3171
3172 for (const LayerRegion *region : layer->regions()) {
3173 SurfacesPtr region_internal_solids = region->fill_surfaces.filter_by_type(stInternalSolid);
3174 for (const Surface *s : region_internal_solids) {
3175 Polygons unsupported = intersection(to_polygons(s->expolygon), unsupported_area);
3176
3177
3178
3179 if (po->config().dont_filter_internal_bridges.value == ibfNofilter){
3180
3181 unsupported = expand(unsupported, 4 * spacing);
3182 candidate_surfaces.push_back(CandidateSurface(s, lidx, unsupported, region, 0));
3183 }else{
3184
3185
3186 bool partially_supported = area(unsupported) < area(to_polygons(s->expolygon)) - EPSILON;
3187 if (!unsupported.empty() && (!partially_supported || area(unsupported) > 3 * 3 * spacing * spacing)) {
3188 Polygons worth_bridging = intersection(to_polygons(s->expolygon), expand(unsupported, 4 * spacing));
3189
3190 for (const Polygon& p : diff(to_polygons(s->expolygon), expand(worth_bridging, spacing))) {
3191 double area = p.area();
3192 if (area < spacing * scale_(12.0) && area > spacing * spacing) {
3193 worth_bridging.push_back(p);
3194 }
3195 }
3196 worth_bridging = intersection(closing(worth_bridging, float(SCALED_EPSILON)), s->expolygon);
3197 candidate_surfaces.push_back(CandidateSurface(s, lidx, worth_bridging, region, 0));
3198
3199#ifdef DEBUG_BRIDGE_OVER_INFILL
3200 debug_draw(std::to_string(lidx) + "_candidate_surface_" + std::to_string(area(s->expolygon)),
3201 to_lines(region->layer()->lslices), to_lines(s->expolygon), to_lines(worth_bridging),
3202 to_lines(unsupported_area));
3203#endif
3204#ifdef DEBUG_BRIDGE_OVER_INFILL
3205 debug_draw(std::to_string(lidx) + "_candidate_processing_" + std::to_string(area(unsupported)),
3206 to_lines(unsupported), to_lines(intersection(to_polygons(s->expolygon), expand(unsupported, 5 * spacing))),
3207 to_lines(diff(to_polygons(s->expolygon), expand(worth_bridging, spacing))),
3208 to_lines(unsupported_area));
3209#endif
3210 }
3211 }
3212 }
3213 }
3214 }
3215 });
3216
3217 for (const CandidateSurface &c : candidate_surfaces) {
3218 surfaces_by_layer[c.layer_index].push_back(c);
3219 }
3220 }
3221
3222
3223
3224
3225 if (has_lightning_infill) {
3226
3227
3228
3229 std::map<size_t, std::map<const LayerRegion *, SurfaceCollection>> backup_surfaces;
3230 for (
size_t lidx = 0; lidx < this->
layer_count(); lidx++) {
3231 backup_surfaces[lidx] = {};
3232 }
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269 std::vector<char> needs_lightning_expansion(this->
layers().
size(), 0);
3270 tbb::parallel_for(tbb::blocked_range<size_t>(0, this->
layers().
size()), [po =
this, &surfaces_by_layer,
3271 &needs_lightning_expansion](tbb::blocked_range<size_t> r) {
3273 for (size_t lidx = r.begin(); lidx < r.end(); lidx++) {
3274 if (surfaces_by_layer.find(lidx) == surfaces_by_layer.end())
3275 continue;
3276 const Layer *layer = po->get_layer(lidx);
3277 const Layer *lower_layer = layer->lower_layer;
3278 if (lower_layer == nullptr)
3279 continue;
3280 for (const LayerRegion *region : lower_layer->regions()) {
3281 if (region->region().config().sparse_infill_pattern ==
ipLightning
3282 && ! region->fill_surfaces.filter_by_type(
stInternal).empty()) {
3283 needs_lightning_expansion[lidx] = 1;
3284 break;
3285 }
3286 }
3287 }
3288 });
3289
3290
3291
3292
3293
3294 tbb::parallel_for(tbb::blocked_range<size_t>(0, this->
layers().
size()), [po =
this, &backup_surfaces,
3295 &surfaces_by_layer,
3296 &needs_lightning_expansion](tbb::blocked_range<size_t> r) {
3298 for (size_t lidx = r.begin(); lidx < r.end(); lidx++) {
3299 if (! needs_lightning_expansion[lidx])
3300 continue;
3301
3302 Layer *layer = po->get_layer(lidx);
3303
3304 for (LayerRegion *region : layer->regions()) {
3305 backup_surfaces[lidx][region] = std::move(
3306 region->fill_surfaces);
3307
3308 region->fill_surfaces = backup_surfaces[lidx][region];
3309 }
3310
3311 for (LayerRegion *region : layer->regions()) {
3314
3315 if (sparse_infill.empty()) {
3316 break;
3317 }
3318 for (const auto &surface : surfaces_by_layer[lidx]) {
3319 if (surface.region != region)
3320 continue;
3322 solid_infill.insert(solid_infill.end(), expansion.begin(), expansion.end());
3323 }
3324
3326 sparse_infill =
diff_ex(sparse_infill, solid_infill);
3327
3329 for (const ExPolygon &ep : solid_infill) {
3331 }
3332 for (const ExPolygon &ep : sparse_infill) {
3333 region->fill_surfaces.surfaces.emplace_back(
stInternal, ep);
3334 }
3335 }
3336 }
3337 });
3338
3339
3341
3342
3343
3344 for (
size_t lidx = 0; lidx < this->
layer_count(); lidx++) {
3346 for (LayerRegion *region : layer->regions()) {
3347 if (backup_surfaces[lidx].
find(region) != backup_surfaces[lidx].
end()) {
3348 region->fill_surfaces = std::move(backup_surfaces[lidx][region]);
3349 }
3350 }
3351 }
3352 }
3353
3354 std::map<size_t, Polylines> infill_lines;
3355
3356 {
3357 std::vector<std::pair<const Surface *, const Layer *>> surfaces_w_layer;
3358 for (const auto &pair : surfaces_by_layer) {
3359 for (const CandidateSurface &c : pair.second) {
3360 surfaces_w_layer.emplace_back(c.original_surface, c.region->m_layer);
3361 }
3362 }
3363
3366
3367 std::vector<size_t> layers_to_generate_infill;
3368 for (const auto &pair : surfaces_by_layer) {
3369 assert(pair.first > 0);
3370 infill_lines[pair.first - 1] = {};
3371 layers_to_generate_infill.push_back(pair.first - 1);
3372 }
3373
3374 tbb::parallel_for(tbb::blocked_range<size_t>(0, layers_to_generate_infill.size()), [po =
static_cast<const PrintObject *
>(
this),
3375 &layers_to_generate_infill,
3376 &infill_lines](tbb::blocked_range<size_t> r) {
3377 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
3378 for (size_t job_idx = r.begin(); job_idx < r.end(); job_idx++) {
3379 size_t lidx = layers_to_generate_infill[job_idx];
3380 infill_lines.at(
3381 lidx) = po->get_layer(lidx)->generate_sparse_infill_polylines_for_anchoring(&po->m_adaptive_fill_octrees,
3382 po->m_lightning_generator.get());
3383 }
3384 });
3385#ifdef DEBUG_BRIDGE_OVER_INFILL
3386 for (const auto &il : infill_lines) {
3388 }
3389#endif
3390 }
3391
3392
3393 std::vector<std::vector<size_t>> clustered_layers_for_threads;
3394 float target_flow_height_factor = 0.9f;
3395 {
3396 std::vector<size_t> layers_with_candidates;
3397 std::map<size_t, Polygons> layer_area_covered_by_candidates;
3398 for (const auto& pair : surfaces_by_layer) {
3399 layers_with_candidates.push_back(pair.first);
3400 layer_area_covered_by_candidates[pair.first] = {};
3401 }
3402
3403
3404
3405 tbb::parallel_for(tbb::blocked_range<size_t>(0, layers_with_candidates.size()), [&layers_with_candidates, &surfaces_by_layer,
3406 &layer_area_covered_by_candidates](
3407 tbb::blocked_range<size_t> r) {
3408 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
3409 for (size_t job_idx = r.begin(); job_idx < r.end(); job_idx++) {
3410 size_t lidx = layers_with_candidates[job_idx];
3411 for (const auto &candidate : surfaces_by_layer.at(lidx)) {
3412 Polygon candiate_inflated_aabb = get_extents(candidate.new_polys).inflated(scale_(7)).polygon();
3413 layer_area_covered_by_candidates.at(lidx) = union_(layer_area_covered_by_candidates.at(lidx),
3414 Polygons{candiate_inflated_aabb});
3415 }
3416 }
3417 });
3418
3419
3420 for (auto pair : surfaces_by_layer) {
3421 if (clustered_layers_for_threads.empty() ||
3422 this->get_layer(clustered_layers_for_threads.back().back())->print_z <
3423 this->get_layer(pair.first)->print_z -
3424 this->get_layer(pair.first)->regions()[0]->bridging_flow(
frSolidInfill,
true).height() * target_flow_height_factor -
3426 intersection(layer_area_covered_by_candidates[clustered_layers_for_threads.back().back()],
3427 layer_area_covered_by_candidates[pair.first])
3428 .empty()) {
3429 clustered_layers_for_threads.push_back({pair.first});
3430 } else {
3431 clustered_layers_for_threads.back().push_back(pair.first);
3432 }
3433 }
3434
3435#ifdef DEBUG_BRIDGE_OVER_INFILL
3436 std::cout << "BRIDGE OVER INFILL CLUSTERED LAYERS FOR SINGLE THREAD" << std::endl;
3437 for (auto cluster : clustered_layers_for_threads) {
3438 std::cout << "CLUSTER: ";
3439 for (auto l : cluster) {
3440 std::cout << l << " ";
3441 }
3442 std::cout << std::endl;
3443 }
3444#endif
3445 }
3446
3447
3448 auto gather_areas_w_depth = [target_flow_height_factor](
const PrintObject *po,
int lidx,
float target_flow_height) {
3449
3452 double bottom_z = po->get_layer(lidx)->print_z - target_flow_height * target_flow_height_factor -
EPSILON;
3453 for (int i = int(lidx) - 1; i >= 0; --i) {
3454
3455 const Layer *layer = po->get_layer(i);
3456 if (layer->print_z < bottom_z && i < int(lidx) - 1)
3457 break;
3458
3459 for (const LayerRegion *region : layer->regions()) {
3460 bool has_low_density = region->region().config().sparse_infill_density.value < 100;
3461 for (const Surface &surface : region->fill_surfaces) {
3463 layers_sparse_infill.push_back(surface.expolygon);
3464 } else {
3465 not_sparse_infill.push_back(surface.expolygon);
3466 }
3467 }
3468 }
3469 }
3470 layers_sparse_infill =
union_ex(layers_sparse_infill);
3472 not_sparse_infill =
union_ex(not_sparse_infill);
3474 return diff(layers_sparse_infill, not_sparse_infill);
3475 };
3476
3477
3478
3479
3480 auto determine_bridging_angle = [](
const Polygons &bridged_area,
const Lines &anchors) {
3481 AABBTreeLines::LinesDistancer<Line> lines_tree(anchors);
3482
3483 std::map<double, int> counted_directions;
3484 for (const Polygon &p : bridged_area) {
3485 double acc_distance = 0;
3486 for (int point_idx = 0; point_idx < int(p.points.size()) - 1; ++point_idx) {
3487 Vec2d start = p.points[point_idx].cast<
double>();
3488 Vec2d next = p.points[point_idx + 1].cast<
double>();
3489 Vec2d v = next - start;
3490 double dist_to_next = v.norm();
3491 acc_distance += dist_to_next;
3492 if (acc_distance >
scaled(2.0)) {
3493 acc_distance = 0.0;
3494 v.normalize();
3495 int lines_count = int(std::ceil(dist_to_next /
scaled(2.0)));
3496 float step_size = dist_to_next / lines_count;
3497 for (int i = 0; i < lines_count; ++i) {
3499 auto [
distance, index, p] = lines_tree.distance_from_lines_extra<
false>(a);
3500 double angle = lines_tree.get_line(index).orientation();
3503 }
3505 counted_directions[
angle]++;
3506 }
3507 }
3508 }
3509 }
3510
3511 std::pair<double, int> best_dir{0, 0};
3512
3513 for (const auto &dir : counted_directions) {
3514 int score_acc = 0;
3515 double dir_acc = 0;
3516 double window_start_angle = dir.first -
PI * 0.1;
3517 double window_end_angle = dir.first +
PI * 0.1;
3518 for (auto dirs_window = counted_directions.lower_bound(window_start_angle);
3519 dirs_window != counted_directions.upper_bound(window_end_angle); dirs_window++) {
3520 dir_acc += dirs_window->first * dirs_window->second;
3521 score_acc += dirs_window->second;
3522 }
3523
3524
3525 if (window_start_angle < 0.5 *
PI) {
3526 for (
auto dirs_window = counted_directions.lower_bound(1.5 *
PI - (0.5 *
PI - window_start_angle));
3527 dirs_window != counted_directions.end(); dirs_window++) {
3528 dir_acc += (dirs_window->first -
PI) * dirs_window->second;
3529 score_acc += dirs_window->second;
3530 }
3531 }
3532 if (window_start_angle > 1.5 *
PI) {
3533 for (auto dirs_window = counted_directions.begin();
3534 dirs_window != counted_directions.upper_bound(window_start_angle - 1.5 *
PI); dirs_window++) {
3535 dir_acc += (dirs_window->first +
PI) * dirs_window->second;
3536 score_acc += dirs_window->second;
3537 }
3538 }
3539
3540 if (score_acc > best_dir.second) {
3541 best_dir = {dir_acc / score_acc, score_acc};
3542 }
3543 }
3544 double bridging_angle = best_dir.first;
3545 if (bridging_angle == 0) {
3546 bridging_angle = 0.001;
3547 }
3548
3549 return bridging_angle;
3550 };
3551
3552
3553
3554
3555 auto construct_anchored_polygon = [](
Polygons bridged_area,
Lines anchors,
const Flow &bridging_flow,
double bridging_angle,
3556 coord_t scan_spacing,
bool restore_anchors =
false) {
3557 auto lines_rotate = [](
Lines &lines,
double cos_angle,
double sin_angle) {
3558 for (Line &l : lines) {
3559 double ax = double(l.a.x());
3560 double ay = double(l.a.y());
3561 l.a.x() =
coord_t(round(cos_angle * ax - sin_angle * ay));
3562 l.a.y() =
coord_t(round(cos_angle * ay + sin_angle * ax));
3563 double bx = double(l.b.x());
3564 double by = double(l.b.y());
3565 l.b.x() =
coord_t(round(cos_angle * bx - sin_angle * by));
3566 l.b.y() =
coord_t(round(cos_angle * by + sin_angle * bx));
3567 }
3568 };
3569
3571 return (alow >= blow && alow <= bhigh) || (ahigh >= blow && ahigh <= bhigh) || (blow >= alow && blow <= ahigh) ||
3572 (bhigh >= alow && bhigh <= ahigh);
3573 };
3574
3576 double aligning_angle = -bridging_angle +
PI * 0.5;
3577 {
3579 lines_rotate(anchors, cos(aligning_angle), sin(aligning_angle));
3582
3583 const size_t n_vlines = (bb_x.max.x() - bb_x.min.x() + scan_spacing - 1) / scan_spacing;
3584 std::vector<Line> vertical_lines(n_vlines);
3585 for (size_t i = 0; i < n_vlines; i++) {
3586
3587
3588 coord_t x = bb_x.min.x() + (i + 0.5) * scan_spacing;
3589 coord_t y_min = bb_y.min.y() - bridging_flow.scaled_spacing();
3590 coord_t y_max = bb_y.max.y() + bridging_flow.scaled_spacing();
3591 vertical_lines[i].a =
Point{x, y_min};
3592 vertical_lines[i].b =
Point{x, y_max};
3593 }
3594
3595
3596
3597
3598 const coord_t scan_x_min = bb_x.min.x();
3599 const coord_t scan_x_max = bb_x.min.x() +
coord_t(n_vlines) * scan_spacing;
3600 anchors.erase(std::remove_if(anchors.begin(), anchors.end(),
3601 [scan_x_min, scan_x_max](const Line &l) {
3602 return std::max(l.a.x(), l.b.x()) < scan_x_min || std::min(l.a.x(), l.b.x()) > scan_x_max;
3603 }),
3604 anchors.end());
3605 auto anchors_and_walls_tree = AABBTreeLines::LinesDistancer<Line>{std::move(anchors)};
3606 auto bridged_area_tree = AABBTreeLines::LinesDistancer<Line>{
to_lines(bridged_area)};
3607
3608 std::vector<std::vector<Line>> polygon_sections(n_vlines);
3609 for (size_t i = 0; i < n_vlines; i++) {
3610 auto area_intersections = bridged_area_tree.intersections_with_line<true>(vertical_lines[i]);
3611 for (int intersection_idx = 0; intersection_idx < int(area_intersections.size()) - 1; intersection_idx++) {
3612 if (bridged_area_tree.outside(
3613 (area_intersections[intersection_idx].first + area_intersections[intersection_idx + 1].first) / 2) < 0) {
3614 polygon_sections[i].emplace_back(area_intersections[intersection_idx].first,
3615 area_intersections[intersection_idx + 1].first);
3616 }
3617 }
3618 auto anchors_intersections = anchors_and_walls_tree.intersections_with_line<true>(vertical_lines[i]);
3619
3620 for (Line §ion : polygon_sections[i]) {
3621
3622
3623
3625 auto maybe_below_anchor = std::upper_bound(anchors_intersections.rbegin(), anchors_intersections.rend(), section.a + Point{0, overlap},
3626 [](const Point &a, const std::pair<Point, size_t> &b) {
3627 return a.y() > b.first.y();
3628 });
3629 if (maybe_below_anchor != anchors_intersections.rend()) {
3630 section.a = maybe_below_anchor->first;
3631 section.a.y() -= bridging_flow.scaled_width() * (0.5 + 0.5);
3632 }
3633
3634 auto maybe_upper_anchor = std::upper_bound(anchors_intersections.begin(), anchors_intersections.end(), section.b - Point{0, overlap},
3635 [](const Point &a, const std::pair<Point, size_t> &b) {
3636 return a.y() < b.first.y();
3637 });
3638 if (maybe_upper_anchor != anchors_intersections.end()) {
3639 section.b = maybe_upper_anchor->first;
3640 section.b.y() += bridging_flow.scaled_width() * (0.5 + 0.5);
3641 }
3642 }
3643
3644 for (
int section_idx = 0; section_idx < int(polygon_sections[i].
size()) - 1; section_idx++) {
3645 Line §ion_a = polygon_sections[i][section_idx];
3646 Line §ion_b = polygon_sections[i][section_idx + 1];
3647 if (segments_overlap(section_a.a.y(), section_a.b.y(), section_b.a.y(), section_b.b.y())) {
3648 section_b.a = section_a.a.y() < section_b.a.y() ? section_a.a : section_b.a;
3649 section_b.b = section_a.b.y() < section_b.b.y() ? section_b.b : section_a.b;
3650 section_a.a = section_a.b;
3651 }
3652 }
3653
3654 polygon_sections[i].erase(std::remove_if(polygon_sections[i].
begin(), polygon_sections[i].
end(),
3655 [](const Line &s) { return s.a == s.b; }),
3656 polygon_sections[i].end());
3657 std::sort(polygon_sections[i].
begin(), polygon_sections[i].
end(),
3658 [](const Line &a, const Line &b) {
3659 if (a == b) return false;
3660 return a.a.y() < b.b.y();
3661 });
3662 }
3663
3664
3665
3666
3667 struct TracedPoly
3668 {
3671 };
3672
3673 std::vector<TracedPoly> current_traced_polys;
3674 for (const auto &polygon_slice : polygon_sections) {
3675 std::unordered_set<const Line *> used_segments;
3676 for (TracedPoly &traced_poly : current_traced_polys) {
3677 auto candidates_begin = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_poly.lows.back(),
3678 [](const Point &low, const Line &seg) { return seg.b.y() > low.y(); });
3679 auto candidates_end = std::upper_bound(polygon_slice.begin(), polygon_slice.end(), traced_poly.highs.back(),
3680 [](const Point &high, const Line &seg) { return seg.a.y() > high.y(); });
3681
3682 bool segment_added = false;
3683 for (auto candidate = candidates_begin; candidate != candidates_end && !segment_added; candidate++) {
3684 if (used_segments.find(&(*candidate)) != used_segments.end()) {
3685 continue;
3686 }
3687
3688 if ((traced_poly.lows.back() - candidate->a).cast<double>().squaredNorm() <
3689 36.0 * double(bridging_flow.scaled_spacing()) * bridging_flow.scaled_spacing()) {
3690 traced_poly.lows.push_back(candidate->a);
3691 } else {
3692 traced_poly.lows.push_back(traced_poly.lows.back() + Point{scan_spacing / 2, 0});
3693 traced_poly.lows.push_back(candidate->a - Point{scan_spacing / 2, 0});
3694 traced_poly.lows.push_back(candidate->a);
3695 }
3696
3697 if ((traced_poly.highs.back() - candidate->b).cast<double>().squaredNorm() <
3698 36.0 * double(bridging_flow.scaled_spacing()) * bridging_flow.scaled_spacing()) {
3699 traced_poly.highs.push_back(candidate->b);
3700 } else {
3701 traced_poly.highs.push_back(traced_poly.highs.back() + Point{scan_spacing / 2, 0});
3702 traced_poly.highs.push_back(candidate->b - Point{scan_spacing / 2, 0});
3703 traced_poly.highs.push_back(candidate->b);
3704 }
3705 segment_added = true;
3706 used_segments.insert(&(*candidate));
3707 }
3708
3709 if (!segment_added) {
3710
3711 traced_poly.lows.push_back(traced_poly.lows.back() + Point{scan_spacing / 2, 0});
3712 traced_poly.highs.push_back(traced_poly.highs.back() + Point{scan_spacing / 2, 0});
3713 Polygon &new_poly = expanded_bridged_area.emplace_back(std::move(traced_poly.lows));
3714 new_poly.
points.insert(new_poly.points.end(), traced_poly.highs.rbegin(), traced_poly.highs.rend());
3715 traced_poly.lows.clear();
3716 traced_poly.highs.clear();
3717 }
3718 }
3719
3720 current_traced_polys.erase(std::remove_if(current_traced_polys.begin(), current_traced_polys.end(),
3721 [](const TracedPoly &tp) { return tp.lows.empty(); }),
3722 current_traced_polys.end());
3723
3724 for (const auto &segment : polygon_slice) {
3725 if (used_segments.find(&segment) == used_segments.end()) {
3726 TracedPoly &new_tp = current_traced_polys.emplace_back();
3727 new_tp.lows.push_back(
segment.a - Point{scan_spacing / 2, 0});
3728 new_tp.lows.push_back(
segment.a);
3729 new_tp.highs.push_back(
segment.b - Point{scan_spacing / 2, 0});
3730 new_tp.highs.push_back(
segment.b);
3731 }
3732 }
3733 }
3734
3735
3736 for (TracedPoly &traced_poly : current_traced_polys) {
3737 Polygon &new_poly = expanded_bridged_area.emplace_back(std::move(traced_poly.lows));
3738 new_poly.
points.insert(new_poly.points.end(), traced_poly.highs.rbegin(), traced_poly.highs.rend());
3739 }
3741 }
3742
3744 return expanded_bridged_area;
3745 };
3746
3747 tbb::parallel_for(tbb::blocked_range<size_t>(0, clustered_layers_for_threads.size()), [po =
static_cast<const PrintObject *
>(
this),
3748 target_flow_height_factor, &surfaces_by_layer,
3749 &clustered_layers_for_threads,
3750 gather_areas_w_depth, &infill_lines,
3751 determine_bridging_angle,
3752 construct_anchored_polygon](
3753 tbb::blocked_range<size_t> r) {
3754 PRINT_OBJECT_TIME_LIMIT_MILLIS(PRINT_OBJECT_TIME_LIMIT_DEFAULT);
3755 for (size_t cluster_idx = r.begin(); cluster_idx < r.end(); cluster_idx++) {
3756 for (size_t job_idx = 0; job_idx < clustered_layers_for_threads[cluster_idx].size(); job_idx++) {
3757 size_t lidx = clustered_layers_for_threads[cluster_idx][job_idx];
3758 const Layer *layer = po->get_layer(lidx);
3759
3760
3761
3762
3763
3764 std::sort(surfaces_by_layer[lidx].begin(), surfaces_by_layer[lidx].end(),
3765 [](const CandidateSurface &left, const CandidateSurface &right) {
3766 auto a = get_extents(left.new_polys);
3767 auto b = get_extents(right.new_polys);
3768
3769 if (a.min.x() == b.min.x()) {
3770 return a.min.y() < b.min.y();
3771 };
3772 return a.min.x() < b.min.x();
3773 });
3774 if (surfaces_by_layer[lidx].size() > 2) {
3775 Vec2d origin = get_extents(surfaces_by_layer[lidx].front().new_polys).max.cast<double>();
3776 std::stable_sort(surfaces_by_layer[lidx].begin() + 1, surfaces_by_layer[lidx].end(),
3777 [origin](const CandidateSurface &left, const CandidateSurface &right) {
3778 auto a = get_extents(left.new_polys);
3779 auto b = get_extents(right.new_polys);
3780
3781 return (origin - a.min.cast<double>()).squaredNorm() <
3782 (origin - b.min.cast<double>()).squaredNorm();
3783 });
3784 }
3785
3786
3787 coordf_t spacing = surfaces_by_layer[lidx].front().region->bridging_flow(frSolidInfill, true).scaled_spacing();
3788 coordf_t target_flow_height = surfaces_by_layer[lidx].front().region->bridging_flow(frSolidInfill, true).height() *
3789 target_flow_height_factor;
3790 Polygons deep_infill_area = gather_areas_w_depth(po, lidx, target_flow_height);
3791
3792 {
3793
3794
3795 Polygons filled_polyons_on_lower_layers;
3796 double bottom_z = layer->print_z - target_flow_height - EPSILON;
3797 if (job_idx > 0) {
3798 for (int lower_job_idx = job_idx - 1; lower_job_idx >= 0; lower_job_idx--) {
3799 size_t lower_layer_idx = clustered_layers_for_threads[cluster_idx][lower_job_idx];
3800 const Layer *lower_layer = po->get_layer(lower_layer_idx);
3801 if (lower_layer->print_z >= bottom_z) {
3802 for (const auto &c : surfaces_by_layer[lower_layer_idx]) {
3803 filled_polyons_on_lower_layers.insert(filled_polyons_on_lower_layers.end(), c.new_polys.begin(),
3804 c.new_polys.end());
3805 }
3806 } else {
3807 break;
3808 }
3809 }
3810 }
3811 deep_infill_area = diff(deep_infill_area, filled_polyons_on_lower_layers);
3812 }
3813
3814 deep_infill_area = expand(deep_infill_area, spacing * 1.5);
3815
3816
3817 Polygons lightning_area;
3818 Polygons expansion_area;
3819 Polygons total_fill_area;
3820 Polygons total_top_area;
3821 for (const LayerRegion *region : layer->regions()) {
3822 Polygons top_polys = to_polygons(region->fill_surfaces.filter_by_types({stTop}));
3823 total_top_area.insert(total_top_area.end(), top_polys.begin(), top_polys.end());
3824 Polygons internal_polys = to_polygons(region->fill_surfaces.filter_by_types({stInternal, stInternalSolid}));
3825 expansion_area.insert(expansion_area.end(), internal_polys.begin(), internal_polys.end());
3826 Polygons fill_polys = to_polygons(region->fill_expolygons);
3827 total_fill_area.insert(total_fill_area.end(), fill_polys.begin(), fill_polys.end());
3828 if (region->region().config().sparse_infill_pattern == ipLightning) {
3829 Polygons l = to_polygons(region->fill_surfaces.filter_by_type(stInternal));
3830 lightning_area.insert(lightning_area.end(), l.begin(), l.end());
3831 }
3832 }
3833 total_fill_area = closing(total_fill_area, float(SCALED_EPSILON));
3834 expansion_area = closing(expansion_area, float(SCALED_EPSILON));
3835 expansion_area = intersection(expansion_area, deep_infill_area);
3836
3837
3838
3839 const Polylines anchors = intersection_pl(infill_lines[lidx - 1], shrink(expansion_area, spacing));
3840 Polygons internal_unsupported_area = shrink(deep_infill_area, spacing * 4.5);
3841
3842#ifdef DEBUG_BRIDGE_OVER_INFILL
3843 debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" + "_total_area",
3844 to_lines(total_fill_area), to_lines(expansion_area), to_lines(deep_infill_area), to_lines(anchors));
3845#endif
3846
3847 std::vector<CandidateSurface> expanded_surfaces;
3848 expanded_surfaces.reserve(surfaces_by_layer[lidx].size());
3849
3850
3851
3852 std::map<coord_t, Polylines> boundary_by_spacing;
3853
3854
3855
3856
3857
3858 const auto split_near = [](const Polygons &polys, const BoundingBox &bbox, Polygons &rest) {
3859 Polygons nearby;
3860 for (const Polygon &p : polys)
3861 (get_extents(p).overlap(bbox) ? nearby : rest).emplace_back(p);
3862 return nearby;
3863 };
3864 for (const CandidateSurface &candidate : surfaces_by_layer[lidx]) {
3865 const auto ®ion_config = candidate.region->region().config();
3866 const bool turning_pattern = region_config.sparse_infill_pattern == ipHilbertCurve ||
3867 region_config.sparse_infill_pattern == ipOctagramSpiral;
3868 const Flow &flow = candidate.region->bridging_flow(frSolidInfill, true);
3869 const Polygons expanded_polys = expand(candidate.new_polys, flow.scaled_spacing());
3870
3871
3872 ExPolygons bridge_components;
3873 if (!expanded_polys.empty())
3874 bridge_components = intersection_ex(expanded_polys,
3875 ClipperUtils::clip_clipper_polygons_with_subject_bbox(
3876 deep_infill_area, get_extents(expanded_polys).inflated(SCALED_EPSILON)));
3877
3878 bridge_components.erase(std::remove_if(bridge_components.begin(), bridge_components.end(),
3879 [&internal_unsupported_area](const ExPolygon &component) {
3880 return intersection_ex(component, ClipperUtils::clip_clipper_polygons_with_subject_bbox(
3881 internal_unsupported_area,
3882 get_extents(component).inflated(SCALED_EPSILON)))
3883 .empty();
3884 }),
3885 bridge_components.end());
3886 Polygons area_to_be_bridge = to_polygons(std::move(bridge_components));
3887
3888 if (area_to_be_bridge.empty())
3889 continue;
3890
3891
3892
3893 Polygons limiting_area = union_(area_to_be_bridge, expansion_area);
3894
3895 auto boundary_it = boundary_by_spacing.find(flow.scaled_spacing());
3896 if (boundary_it == boundary_by_spacing.end())
3897 boundary_it = boundary_by_spacing
3898 .emplace(flow.scaled_spacing(), to_polylines(expand(total_fill_area, 1.3f * flow.scaled_spacing())))
3899 .first;
3900 Polylines boundary_plines = boundary_it->second;
3901 {
3902 Polylines limiting_plines = to_polylines(expand(limiting_area, 0.3f * flow.scaled_spacing()));
3903 boundary_plines.insert(boundary_plines.end(), limiting_plines.begin(), limiting_plines.end());
3904 }
3905
3906#ifdef DEBUG_BRIDGE_OVER_INFILL
3907 int r = rand();
3908 debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" +
3909 "_anchors_" + std::to_string(r),
3910 to_lines(area_to_be_bridge), to_lines(boundary_plines), to_lines(anchors), to_lines(expansion_area));
3911#endif
3912
3913 double bridging_angle = -1.;
3914 if (!anchors.empty() && turning_pattern) {
3915
3916
3917
3918 for (const LayerRegion *lower_region : layer->lower_layer->regions()) {
3919
3920
3921
3922 if (&lower_region->region() != &candidate.region->region() ||
3923 intersection(area_to_be_bridge, to_polygons(lower_region->fill_surfaces.filter_by_type(stInternal))).empty())
3924 continue;
3925 bridging_angle = calculate_infill_rotation_angle(po, layer->lower_layer->id(), region_config.infill_direction.value,
3926 region_config.sparse_infill_rotate_template.value) + 0.5 * PI;
3927
3928
3929 if (region_config.align_infill_direction_to_model) {
3930 const auto &m = po->trafo().matrix();
3931 bridging_angle += std::atan2(double(m(1, 0)), double(m(0, 0)));
3932 }
3933 bridging_angle = std::fmod(bridging_angle, PI);
3934 if (bridging_angle < 0.)
3935 bridging_angle += PI;
3936 break;
3937 }
3938 }
3939
3940
3941 if (bridging_angle < 0.)
3942 bridging_angle = determine_bridging_angle(area_to_be_bridge, to_lines(anchors.empty() ? boundary_plines : anchors));
3943
3944
3945
3946 if (candidate.region->region().config().internal_bridge_angle.value > 0) {
3947 const double custom_angle_rad = Geometry::deg2rad(region_config.internal_bridge_angle.value);
3948 if (region_config.relative_bridge_angle.value)
3949 bridging_angle += custom_angle_rad;
3950 else {
3951 bridging_angle = custom_angle_rad;
3952 if (region_config.align_infill_direction_to_model) {
3953 auto m = po->trafo().matrix();
3954 bridging_angle += std::atan2((double)m(1, 0), (double)m(0, 0));
3955 }
3956 }
3957 }
3958
3959
3960
3961
3962 boundary_plines.insert(boundary_plines.end(), anchors.begin(), anchors.end());
3963 if (!lightning_area.empty() && !intersection(area_to_be_bridge, lightning_area).empty()) {
3964 boundary_plines = intersection_pl(boundary_plines, expand(area_to_be_bridge, scale_(10)));
3965 }
3966
3967
3968
3969
3970 const coord_t scan_spacing = std::max(coord_t(1), flow.scaled_spacing() / (turning_pattern ? 4 : 1));
3971 Polygons bridging_area = construct_anchored_polygon(area_to_be_bridge, to_lines(boundary_plines), flow, bridging_angle, scan_spacing);
3972
3973
3974 {
3975 bool reconstruct = false;
3976 Polygons tmp_expanded_area = expand(bridging_area, 3.0 * flow.scaled_spacing());
3977 const BoundingBox tmp_expanded_bbox = get_extents(tmp_expanded_area);
3978 for (const CandidateSurface &s : expanded_surfaces) {
3979
3980 if (get_extents(s.new_polys).overlap(tmp_expanded_bbox) &&
3981 !intersection(s.new_polys, tmp_expanded_area).empty()) {
3982 bridging_angle = s.bridge_angle;
3983 reconstruct = true;
3984 break;
3985 }
3986 }
3987 if (reconstruct) {
3988
3989
3990 bridging_area = construct_anchored_polygon(area_to_be_bridge, to_lines(boundary_plines), flow, bridging_angle, scan_spacing);
3991 }
3992 }
3993
3994
3995
3996 bridging_area = opening(bridging_area, flow.scaled_spacing() * 0.75f);
3997 bridging_area = closing(bridging_area, flow.scaled_spacing());
3998
3999
4000
4001 if (turning_pattern && !bridging_area.empty()) {
4002 bridging_area = union_(bridging_area, construct_anchored_polygon(bridging_area, to_lines(boundary_plines), flow,
4003 bridging_angle, scan_spacing, true));
4004 }
4005
4006
4007 if (!bridging_area.empty()) {
4008 const BoundingBox bridging_bbox = get_extents(bridging_area).inflated(SCALED_EPSILON);
4009 bridging_area = intersection(bridging_area, ClipperUtils::clip_clipper_polygons_with_subject_bbox(limiting_area, bridging_bbox));
4010 bridging_area = intersection(bridging_area, ClipperUtils::clip_clipper_polygons_with_subject_bbox(total_fill_area, bridging_bbox));
4011 bridging_area = diff(bridging_area, ClipperUtils::clip_clipper_polygons_with_subject_bbox(total_top_area, bridging_bbox));
4012 }
4013 if (!bridging_area.empty()) {
4014 Polygons kept;
4015 const Polygons cut = split_near(expansion_area, get_extents(bridging_area).inflated(SCALED_EPSILON), kept);
4016 append(kept, diff(cut, bridging_area));
4017 expansion_area = std::move(kept);
4018 }
4019
4020#ifdef DEBUG_BRIDGE_OVER_INFILL
4021 debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" + "_expanded_bridging" + std::to_string(r),
4022 to_lines(layer->lslices), to_lines(boundary_plines), to_lines(candidate.new_polys), to_lines(bridging_area));
4023#endif
4024
4025 expanded_surfaces.push_back(CandidateSurface(candidate.original_surface, candidate.layer_index, bridging_area,
4026 candidate.region, bridging_angle));
4027 }
4028 surfaces_by_layer[lidx].swap(expanded_surfaces);
4029 expanded_surfaces.clear();
4030 }
4031 }
4032 });
4033
4034 BOOST_LOG_TRIVIAL(info) <<
"Bridge over infill - Directions and expanded surfaces computed" <<
log_memory_info();
4035
4036 tbb::parallel_for(tbb::blocked_range<size_t>(0, this->
layers().
size()), [po =
this, &surfaces_by_layer](tbb::blocked_range<size_t> r) {
4038 for (size_t lidx = r.begin(); lidx < r.end(); lidx++) {
4039 if (surfaces_by_layer.find(lidx) == surfaces_by_layer.end() && surfaces_by_layer.find(lidx + 1) == surfaces_by_layer.end())
4040 continue;
4041 Layer *layer = po->get_layer(lidx);
4042
4044 if (surfaces_by_layer.find(lidx) != surfaces_by_layer.end()) {
4045 for (const auto &surface : surfaces_by_layer.at(lidx)) {
4046 cut_from_infill.insert(cut_from_infill.end(), surface.new_polys.begin(), surface.new_polys.end());
4047 }
4048 }
4049
4050 Polygons additional_ensuring_areas{};
4051 if (surfaces_by_layer.find(lidx + 1) != surfaces_by_layer.end()) {
4052 for (const auto &surface : surfaces_by_layer.at(lidx + 1)) {
4053 auto additional_area =
diff(surface.new_polys,
4055 additional_ensuring_areas.insert(additional_ensuring_areas.end(), additional_area.begin(), additional_area.end());
4056 }
4057 }
4058
4059 for (LayerRegion *region : layer->regions()) {
4061
4063 near_perimeters =
diff(near_perimeters,
shrink(near_perimeters, region->flow(
frSolidInfill).scaled_spacing()));
4065
4068 new_internal_infills =
diff_ex(new_internal_infills, additional_ensuring);
4069 for (const ExPolygon &ep : new_internal_infills) {
4071 }
4072
4074 if (surfaces_by_layer.find(lidx) != surfaces_by_layer.end()) {
4075 for (const CandidateSurface &cs : surfaces_by_layer.at(lidx)) {
4076 for (const Surface *surface : internal_solids) {
4077 if (cs.original_surface == surface) {
4078 Surface tmp{*surface, {}};
4080 tmp.bridge_angle = cs.bridge_angle;
4081 for (
const ExPolygon &ep :
union_ex(cs.new_polys)) {
4082 new_surfaces.emplace_back(tmp, ep);
4083 }
4084 break;
4085 }
4086 }
4087 }
4088 }
4090 new_internal_solids.insert(new_internal_solids.end(), additional_ensuring.begin(), additional_ensuring.end());
4091 new_internal_solids =
diff_ex(new_internal_solids, cut_from_infill);
4093 for (const ExPolygon &ep : new_internal_solids) {
4095 }
4096
4097#ifdef DEBUG_BRIDGE_OVER_INFILL
4098 debug_draw(
"Aensuring_" + std::to_string(
reinterpret_cast<uint64_t
>(®ion)),
to_polylines(additional_ensuring),
4101 debug_draw(
"Aensuring_" + std::to_string(
reinterpret_cast<uint64_t
>(®ion)) +
"_new",
to_polylines(additional_ensuring),
4104#endif
4105
4107 region->fill_surfaces.append(new_surfaces);
4108 }
4109 }
4110 });
4111
4112
4113
4114
4116
4117
4118
4119
4120
4121 struct LayerBridgeCache {
4124 float offset_distance = 0.0f;
4125 bool has_bridge = false;
4126 };
4127
4128
4130 std::vector<LayerBridgeCache> caches(this->
layers().
size());
4131
4132 tbb::parallel_for( tbb::blocked_range<size_t>(0, last), [this, &caches](const tbb::blocked_range<size_t>& r) {
4133 for (size_t lidx = r.begin(); lidx < r.end(); ++lidx) {
4135 LayerBridgeCache &cache = caches[lidx];
4136
4137 if (!layer->regions().empty())
4138
4139 cache.offset_distance = layer->regions().front()->flow(
frSolidInfill).scaled_width();
4140 for (LayerRegion *region : layer->regions()) {
4141 for (const Surface &surf : region->fill_surfaces.surfaces) {
4143 cache.polys.push_back(surf.expolygon);
4144 cache.angle = surf.bridge_angle;
4145 cache.has_bridge = true;
4146 }
4147 }
4148 }
4149
4150 if (!cache.has_bridge || cache.polys.empty()) {
4151 cache.has_bridge = false;
4152 continue;
4153 }
4154
4155
4156 cache.polys =
offset_ex(
shrink_ex(cache.polys, cache.offset_distance), cache.offset_distance);
4157 if (cache.polys.empty())
4158 cache.has_bridge = false;
4159 }
4160 });
4161
4162
4163
4164
4165 tbb::parallel_for( tbb::blocked_range<size_t>(0, last), [this, &caches](const tbb::blocked_range<size_t>& r) {
4166 for (size_t lidx = r.begin(); lidx < r.end(); ++lidx)
4167 {
4168 const LayerBridgeCache &cache = caches[lidx];
4169
4170
4171 if (!cache.has_bridge || cache.polys.empty())
4172 continue;
4173
4174
4176 Layer* next_layer = this->
get_layer(lidx + 1);
4177
4178
4179
4180 double bridging_angle_second = cache.angle +
M_PI / 2.0;
4181
4183 const float offset_distance = cache.offset_distance;
4184
4185 for (LayerRegion *next_region : next_layer->regions()) {
4188
4189
4190 for (const Surface &s : next_region->fill_surfaces.surfaces) {
4192 keep_surfaces.push_back(s);
4193 }
4194 }
4195
4196
4197
4199
4200
4201 for (const Surface *s : next_internals) {
4202
4204
4205
4207
4208
4209 if (!overlap.empty()) {
4210
4211 Surface tmp{*s, {}};
4213 tmp.bridge_angle = bridging_angle_second;
4214
4215
4216 for (const ExPolygon &ep : overlap) {
4217 next_new_surfaces.emplace_back(tmp, ep);
4218 }
4219
4220
4222
4224
4225
4226 if (!leftover.empty()) {
4228 for (const ExPolygon &ep : unified_leftover) {
4229
4230 Surface leftover_surf{*s, {}};
4231 leftover_surf.surface_type = s->surface_type;
4232 leftover_surf.bridge_angle = s->bridge_angle;
4233 next_new_surfaces.emplace_back(leftover_surf, ep);
4234 }
4235 }
4236 }
4237 else {
4238
4239 keep_surfaces.push_back(*s);
4240 }
4241 }
4242
4243
4244 next_region->fill_surfaces.surfaces.clear();
4245 next_region->fill_surfaces.append(keep_surfaces);
4246 next_region->fill_surfaces.append(next_new_surfaces);
4247 }
4248 }
4249 }
4250 });
4251
4252
4253
4254
4255
4256
4257 for (
size_t lidx = 0; lidx < this->
layers().
size(); ++lidx) {
4259 for (LayerRegion* region : layer->regions()) {
4260 for (Surface &surf : region->fill_surfaces.surfaces) {
4263 }
4264 }
4265 }
4266 }
4267 }
4268
4269
4270
4271
4272 BOOST_LOG_TRIVIAL(info) <<
"Bridge over infill - End" <<
log_memory_info();
4273
4274}
#define PRINT_OBJECT_TIME_LIMIT_MILLIS(limit)
Definition PrintObject.cpp:113
size_t size() const
Definition Print.hpp:210
ExPolygons lslices
Definition Layer.hpp:170
FillAdaptive::RegionOctrees m_adaptive_fill_octrees
Definition Print.hpp:707
PrintObject(Print *print, ModelObject *model_object, const Transform3d &trafo, PrintInstances &&instances)
Definition PrintObject.cpp:134
FillLightning::GeneratorPtr m_lightning_generator
Definition Print.hpp:709
AdaptiveInfillFields prepare_adaptive_infill_fields() const
Definition PrintObject.cpp:1274
FillAdaptive::RegionOctrees prepare_adaptive_infill_data(const std::vector< std::pair< const Surface *, const Layer * > > &surfaces_w_layer) const
Definition PrintObject.cpp:1169
size_t layer_count() const
Definition Print.hpp:454
const Layer * get_layer(int idx) const
Definition Print.hpp:456
FillLightning::GeneratorPtr prepare_lightning_infill_data()
Definition PrintObject.cpp:1262
static constexpr double PI
Definition libslic3r.h:81
T * end(Slic3r::Mat< N, M, T > &mat)
Definition Point.hpp:841
void segment(CGALMesh &src, std::vector< CGALMesh > &dst, double smoothing_alpha=0.5, int segment_number=5)
Definition MeshBoolean.cpp:480
float distance(SpiralVase::SpiralPoint a, SpiralVase::SpiralPoint b)
Definition SpiralVase.cpp:19
@ ipLightning
Definition PrintConfig.hpp:131
std::vector< Line > Lines
Definition Line.hpp:20
std::vector< const Surface * > SurfacesPtr
Definition Surface.hpp:124
Polylines to_polylines(const ExPolygon &src)
Definition ExPolygon.hpp:235
Slic3r::Polygons expand(const Slic3r::Polygon &polygon, const float delta, JoinType joinType=DefaultJoinType, double miterLimit=DefaultMiterLimit)
Definition ClipperUtils.hpp:397
@ frSolidInfill
Definition Flow.hpp:22
BoundingBox get_extents(const ExPolygonsWithIds &e)
Definition Emboss.cpp:1374
Slic3r::Polygons intersection(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:769
Lines to_lines(const ExPolygon &src)
Definition ExPolygon.hpp:124
@ eblInternalBridgeOnly
Definition PrintConfig.hpp:420
@ eblApplyToAll
Definition PrintConfig.hpp:420
@ ibfDisabled
Definition PrintConfig.hpp:415
double angle(const Eigen::MatrixBase< Derived > &v1, const Eigen::MatrixBase< Derived2 > &v2)
Definition Point.hpp:138
std::string log_memory_info(bool ignore_loglevel)
Definition utils.cpp:1749
Slic3r::Polygons closing(const Slic3r::Polygons &polygons, const float delta1, const float delta2, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:670
Polygons to_polygons(const ExPolygon &src)
Definition ExPolygon.hpp:307
std::vector< Surface > Surfaces
Definition Surface.hpp:123
Slic3r::ExPolygons union_safety_offset_ex(const Slic3r::Polygons &polygons)
Definition ClipperUtils.hpp:388
static bool prints_dense(const Surface &surface, const PrintRegionConfig ®ion_config, const PrintObjectConfig &object_config, size_t layer_id)
Definition PrintObject.cpp:3063
Slic3r::Polygons shrink(const Slic3r::Polygons &polygons, const float delta, JoinType joinType=DefaultJoinType, double miterLimit=DefaultMiterLimit)
Definition ClipperUtils.hpp:406
Slic3r::Polygons diff_expanded(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, float delta)
Definition ClipperUtils.cpp:751
std::vector< Point, PointsAllocator< Point > > Points
Definition Point.hpp:73
Slic3r::Polygons union_safety_offset(const Slic3r::Polygons &polygons)
Definition ClipperUtils.hpp:386
@ stInternalSolid
Definition Surface.hpp:28
@ stSecondInternalBridge
Definition Surface.hpp:32
@ stInternalBridge
Definition Surface.hpp:30
@ stInternalVoid
Definition Surface.hpp:35
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > Vec2d
Definition Point.hpp:67
void polygons_rotate(Polygons &polys, double angle)
Definition Polygon.hpp:169
Slic3r::ExPolygons shrink_ex(const Slic3r::Polygons &polygons, const float delta, JoinType joinType=DefaultJoinType, double miterLimit=DefaultMiterLimit)
Definition ClipperUtils.hpp:408
auto cast(const BoundingBoxBase< Tin > &b)
Definition BoundingBox.hpp:299
Slic3r::Polygons diff(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:731
Slic3r::ExPolygons closing_ex(const Slic3r::Polygons &polygons, const float delta1, const float delta2, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:678
RaycastManager::TrItems::iterator find(RaycastManager::TrItems &items, const RaycastManager::TrKey &key)
Definition RaycastManager.cpp:298