Draws circles around each node of the tree into the final support.
This also handles the areas that have to become support roof, support bottom, the Z distances, etc.
2134{
2136 const Print* print =
m_object->print();
2137 bool has_brim = print->has_brim();
2139 const coordf_t branch_radius = config.tree_support_branch_diameter.value / 2;
2141 bool on_buildplate_only =
m_object_config->support_on_build_plate_only.value;
2143
2144
2145
2147 const int CIRCLE_RESOLUTION = SQUARE_SUPPORT ? 4 : 100;
2148
2149
2150 for (int i = 0; i < CIRCLE_RESOLUTION; i++)
2151 {
2153 if (SQUARE_SUPPORT)
2155 else
2156 angle = (double) i / CIRCLE_RESOLUTION *
TAU;
2157 branch_circle.append(
Point(cos(
angle) * branch_radius_scaled, sin(
angle) * branch_radius_scaled));
2158 }
2159
2160
2161 size_t brim_skirt_layers = has_brim ? 1 : 0;
2162 const PrintConfig& print_config = print->config();
2163 for (const PrintObject* object : print->objects())
2164 {
2165 size_t skirt_layers = print->has_infinite_skirt() ? object->layer_count() : std::min(size_t(print_config.skirt_height.value), object->layer_count());
2166 brim_skirt_layers = std::max(brim_skirt_layers, skirt_layers);
2167 }
2168
2169
2171 const size_t top_interface_layers =
m_support_params.num_top_interface_layers;
2172 const int top_base_interface_layers = std::min<int>(
2174 top_interface_layers > 0 ? int(top_interface_layers) - 1 : 0);
2181 const float tree_brim_width = config.tree_support_brim_width.value;
2182
2183
2185
2186
2187
2188
2189
2190
2191 BeltFloorContext belt_ctx;
2193
2195 return;
2196 BOOST_LOG_TRIVIAL(info) <<
"draw_circles for object: " <<
m_object->model_object()->name;
2197
2198 tbb::parallel_for(tbb::blocked_range<size_t>(0,
m_ts_data->layer_heights.size()),
2199 [&](
const tbb::blocked_range<size_t>&
range)
2200 {
2201 for (size_t layer_nr = range.begin(); layer_nr < range.end(); layer_nr++)
2202 {
2203 if (print->canceled())
2204 break;
2205
2206 const std::vector<SupportNode*>& curr_layer_nodes = contact_nodes[layer_nr];
2207 SupportLayer* ts_layer = m_object->get_support_layer(layer_nr + m_raft_layers);
2208 assert(ts_layer != nullptr);
2209
2210
2211 if (curr_layer_nodes.empty()) {
2212 ts_layer->print_z = 0.0;
2213 ts_layer->height = 0.0;
2214 continue;
2215 }
2216
2217 ts_layer->print_z = m_ts_data->layer_heights[layer_nr].print_z;
2218 ts_layer->height = m_ts_data->layer_heights[layer_nr].height;
2219 size_t obj_layer_nr = m_ts_data->layer_heights[layer_nr].obj_layer_nr;
2220 if (ts_layer->height < EPSILON) {
2221 continue;
2222 }
2223
2224 ExPolygons& base_areas = ts_layer->base_areas;
2225 ExPolygons& roof_areas = ts_layer->roof_areas;
2226 ExPolygons roof_base_areas;
2227 ExPolygons& roof_1st_layer = ts_layer->roof_1st_layer;
2228 ExPolygons& floor_areas = ts_layer->floor_areas;
2229 ExPolygons& roof_gap_areas = ts_layer->roof_gap_areas;
2230 coordf_t max_layers_above_base = 0;
2231 coordf_t max_layers_above_roof = 0;
2232 coordf_t max_layers_above_roof1 = 0;
2233 size_t first_base_roof_area = 0;
2234 bool floor_interface_as_base = false;
2235 bool has_circle_node = false;
2236 ExPolygons extra_wall_areas;
2237 ExPolygons collision_sharp_tails;
2238 ExPolygons collision_base;
2239 auto get_collision = [&](bool sharp_tail) -> ExPolygons &{
2240 ExPolygons &collision = sharp_tail ? collision_sharp_tails : collision_base;
2241 if (collision.empty()) {
2242 collision = offset_ex(m_ts_data->m_layer_outlines[obj_layer_nr],
2243 sharp_tail ? scale_(top_z_distance) :
2244 scale_((obj_layer_nr == 0) ? config.support_object_first_layer_gap : m_ts_data->m_xy_distance));
2245
2246 if (top_z_distance > EPSILON) {
2247 float accum_height = 0;
2248 for (size_t layer_id = obj_layer_nr + 1;
2249 layer_id < m_ts_data->m_layer_outlines.size() && (accum_height += m_object->get_layer(layer_id)->height) && accum_height <= top_z_distance;
2250 layer_id++) {
2251 collision = union_ex(collision, offset_ex(m_ts_data->m_layer_outlines[layer_id], scale_(top_z_distance)));
2252 }
2253 }
2254 }
2255 return collision;
2256 };
2257
2258 BOOST_LOG_TRIVIAL(debug) << "circles at layer " << layer_nr << " contact nodes size=" << curr_layer_nodes.size();
2259
2260 ts_layer->lslices.reserve(curr_layer_nodes.size());
2261 ExPolygons area_poly;
2262 for (const SupportNode* p_node : curr_layer_nodes)
2263 {
2264 if (print->canceled())
2265 break;
2266
2267 const SupportNode& node = *p_node;
2268 ExPolygons area;
2269
2270
2271
2272 if (node.type == ePolygon || (node.distance_to_top<0 && !node.is_sharp_tail)) {
2273 if (node.overhang.contour.size() > 100 || node.overhang.holes.size()>1)
2274 area.emplace_back(node.overhang);
2275 else {
2276 area = offset_ex({ node.overhang }, scale_(m_ts_data->m_xy_distance));
2277 }
2278 area = diff_clipped(area, get_collision(node.is_sharp_tail && node.distance_to_top <= 0));
2279 if (node.type == ePolygon) append(area_poly, area);
2280 }
2281 else {
2282 Polygon circle(branch_circle);
2283 double scale = node.radius / branch_radius;
2284 double moveX = node.movement.x() / (scale * branch_radius_scaled);
2285 double moveY = node.movement.y() / (scale * branch_radius_scaled);
2286
2287
2288 if (!SQUARE_SUPPORT && std::abs(moveX)>0.001 && std::abs(moveY)>0.001) {
2289 const double vsize_inv = 0.5 / (0.01 + std::sqrt(moveX * moveX + moveY * moveY));
2290 double matrix[2*2] = {
2291 scale * (1 + moveX * moveX * vsize_inv),scale * (0 + moveX * moveY * vsize_inv),
2292 scale * (0 + moveX * moveY * vsize_inv),scale * (1 + moveY * moveY * vsize_inv),
2293 };
2294 int i = 0;
2295 for (auto vertex: branch_circle.points) {
2296 vertex = Point(matrix[0] * vertex.x() + matrix[1] * vertex.y(), matrix[2] * vertex.x() + matrix[3] * vertex.y());
2297 circle.points[i++] = node.position + vertex;
2298 }
2299 } else {
2300 for (int i = 0;i< circle.points.size(); i++) {
2301 circle.points[i] = circle.points[i] * scale + node.position;
2302 }
2303 }
2304 if (obj_layer_nr == 0 && m_raft_layers == 0 && !belt_floor_active) {
2305 double brim_width = !config.tree_support_auto_brim ? tree_brim_width : std::max(MIN_BRANCH_RADIUS_FIRST_LAYER, std::min(node.radius + node.dist_mm_to_top / (scale * branch_radius) * 0.5, MAX_BRANCH_RADIUS_FIRST_LAYER) - node.radius);
2306 auto tmp=offset(circle, scale_(brim_width));
2307 if(!tmp.empty())
2308 circle = tmp[0];
2309 }
2310 area = avoid_object_remove_extra_small_parts(ExPolygon(circle), get_collision(node.is_sharp_tail && node.distance_to_top <= 0));
2311
2312
2313 if (!area.empty()) has_circle_node = true;
2314
2315
2316
2317 if (top_interface_layers > 0 && node.support_roof_layers_below > 0 && !on_buildplate_only && !node.is_sharp_tail) {
2318 ExPolygons overhang_expanded;
2319 if (node.overhang.contour.size() > 100 || node.overhang.holes.size()>1)
2320 overhang_expanded.emplace_back(node.overhang);
2321 else {
2322 overhang_expanded = offset_ex({ node.overhang }, scale_(m_ts_data->m_xy_distance));
2323 }
2324 append(area, overhang_expanded);
2325 }
2326 }
2327
2328
2329 if (node.is_processed && node.movement.cast<double>().squaredNorm() > max_move_sq)
2330 append(extra_wall_areas, area);
2331
2332 if (obj_layer_nr>0 && node.distance_to_top < 0)
2333 append(roof_gap_areas, area);
2334 else if (obj_layer_nr > 0 && node.support_roof_layers_below == 1 &&
2335 node.is_sharp_tail == false)
2336 {
2337 append(roof_1st_layer, area);
2338 max_layers_above_roof1 = std::max(max_layers_above_roof1, node.dist_mm_to_top);
2339 }
2340 else if (obj_layer_nr > 0 && node.support_roof_layers_below > 1 &&
2341 node.is_sharp_tail == false)
2342 {
2343 append(node.support_roof_layers_below <= top_base_interface_layers ? roof_base_areas : roof_areas, area);
2344 max_layers_above_roof = std::max(max_layers_above_roof, node.dist_mm_to_top);
2345 }
2346 else
2347 {
2348 append(base_areas, area);
2349 max_layers_above_base = std::max(max_layers_above_base, node.dist_mm_to_top);
2350 }
2351
2352 }
2353
2354
2355
2356
2357 roof_areas = diff_clipped(closing_ex(roof_areas, line_width_scaled), get_collision(false));
2358 roof_areas = intersection_ex(roof_areas, m_machine_border);
2359 roof_base_areas = diff_clipped(closing_ex(roof_base_areas, line_width_scaled), get_collision(false));
2360 roof_base_areas = intersection_ex(roof_base_areas, m_machine_border);
2361 if (!roof_base_areas.empty() && !roof_areas.empty())
2362 roof_base_areas = diff_ex(roof_base_areas,
2363 ClipperUtils::clip_clipper_polygons_with_subject_bbox(roof_areas, get_extents(roof_base_areas)));
2364
2365 first_base_roof_area = roof_areas.size();
2366 append(roof_areas, std::move(roof_base_areas));
2367 roof_1st_layer = diff_clipped(closing_ex(roof_1st_layer, line_width_scaled), get_collision(false));
2368
2369
2370 roof_1st_layer = diff_ex(roof_1st_layer, ClipperUtils::clip_clipper_polygons_with_subject_bbox(roof_areas,get_extents(roof_1st_layer)));
2371 roof_1st_layer = intersection_ex(roof_1st_layer, m_machine_border);
2372
2373 ExPolygons roofs; append(roofs, roof_1st_layer); append(roofs, roof_areas);append(roofs, roof_gap_areas);
2374 base_areas = diff_ex(base_areas, ClipperUtils::clip_clipper_polygons_with_subject_bbox(roofs, get_extents(base_areas)));
2375 base_areas = intersection_ex(base_areas, m_machine_border);
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388 {
2389 BeltFloorContext ctx;
2390 if (ctx.init(m_slicing_params, *m_print_config)) {
2391 Polygons belt_surface = ctx.surface_polygon(ts_layer->print_z);
2392 base_areas = diff_ex(base_areas, belt_surface);
2393 roof_areas = diff_ex(roof_areas, belt_surface);
2394 roof_1st_layer = diff_ex(roof_1st_layer, belt_surface);
2395 floor_areas = diff_ex(floor_areas, belt_surface);
2396 roof_gap_areas = diff_ex(roof_gap_areas, belt_surface);
2397 }
2398 }
2399
2400 if (SQUARE_SUPPORT) {
2401
2402 ExPolygons base_areas_simplified;
2403 for (auto &area : base_areas) { area.simplify(scale_(line_width / 2), &base_areas_simplified); }
2404 base_areas = std::move(base_areas_simplified);
2405 }
2406
2407
2408
2409
2410
2411
2412 if (!base_areas.empty() && !m_object_config->support_on_build_plate_only.value &&
2413 (bottom_gap_height > EPSILON || bottom_interface_layers > 0))
2414 {
2415 const coordf_t interface_height =
2416 bottom_interface_layers > 0 ? coordf_t(bottom_interface_layers) * m_slicing_params.layer_height : 0.0;
2417
2418 const coordf_t layer_top_z = ts_layer->print_z;
2419 const coordf_t layer_bottom_z = ts_layer->bottom_z();
2420 ExPolygons new_base_areas;
2421 ExPolygons new_floor_areas;
2422 struct ContactBand {
2423 coordf_t z = 0.0;
2424 Polygons surfaces;
2425 };
2426 for (const ExPolygon& comp : base_areas) {
2427 ExPolygons comp_poly { comp };
2428 bool found_contact = false;
2429 std::vector<ContactBand> bands;
2430
2431
2432 for (size_t idx = obj_layer_nr + 1; idx-- > 0;) {
2433 const Layer* below_layer = m_object->get_layer(idx);
2434 Polygons top_surfaces = collect_region_slices_by_type(*below_layer, stTop);
2435 Polygons bottom_surfaces = collect_region_slices_by_type(*below_layer, stBottom);
2436 Polygons surf_union = top_surfaces;
2437 polygons_append(surf_union, bottom_surfaces);
2438 if (surf_union.empty())
2439 continue;
2440
2441 ExPolygons inter = intersection_ex(comp_poly, surf_union);
2442 if (!inter.empty()) {
2443 bands.push_back(ContactBand{ below_layer->print_z, std::move(surf_union) });
2444 found_contact = true;
2445 }
2446 }
2447
2448 if (found_contact) {
2449 std::sort(bands.begin(), bands.end(), [](const ContactBand &a, const ContactBand &b) {
2450 return a.z < b.z;
2451 });
2452 }
2453
2454 if (!found_contact) {
2455 append(new_base_areas, comp_poly);
2456 continue;
2457 }
2458
2459 bool interface_id_set = false;
2460 bool any_gap_cleared = false;
2461
2462 for (const ContactBand &band : bands) {
2463 const coordf_t band_gap_top = band.z + bottom_gap_height;
2464 const coordf_t band_iface_start = band_gap_top;
2465 const bool band_applies = layer_top_z >= band.z - EPSILON;
2466 if (!band_applies)
2467 continue;
2468
2469
2470
2471 if (bottom_gap_height > EPSILON && layer_bottom_z < band_gap_top - EPSILON) {
2472 any_gap_cleared = true;
2473 comp_poly = diff_ex(comp_poly, band.surfaces);
2474 }
2475
2476
2477 if (bottom_interface_layers > 0 &&
2478 layer_bottom_z >= band_iface_start - EPSILON &&
2479 layer_bottom_z < band_iface_start + interface_height - EPSILON) {
2480 if (!interface_id_set) {
2481 size_t first_interface_layer = layer_nr;
2482 while (first_interface_layer > 0) {
2483 if (m_ts_data->layer_heights[first_interface_layer - 1].print_z <= band_iface_start + EPSILON)
2484 break;
2485 --first_interface_layer;
2486 }
2487
2488 if (m_support_params.num_bottom_base_interface_layers > 0) {
2489 const int bottom_interface_idx =
2490 std::max(0, int(layer_nr) - int(first_interface_layer));
2491 const int bottom_base_start_idx =
2492 std::max(0, int(bottom_interface_layers) - int(m_support_params.num_bottom_base_interface_layers));
2493 floor_interface_as_base = bottom_interface_idx >= bottom_base_start_idx;
2494 }
2495 interface_id_set = true;
2496 }
2497
2498 ExPolygons band_ex = union_ex(band.surfaces);
2499 if (!band_ex.empty()) {
2500 const coordf_t margin = scale_(m_support_params.support_extrusion_width);
2501 ExPolygons comp_margin = offset_ex(comp_poly, margin);
2502 ExPolygons band_clipped = intersection_ex(band_ex, comp_margin);
2503 band_ex = std::move(band_clipped);
2504 }
2505 ExPolygons comp_interface = band_ex.empty() ? ExPolygons {} : intersection_ex(comp_poly, band_ex);
2506 if (!comp_interface.empty()) {
2507 append(new_floor_areas, comp_interface);
2508 comp_poly = diff_ex(comp_poly, offset_ex(comp_interface, 10));
2509 }
2510 }
2511
2512 }
2513
2514 if (any_gap_cleared && comp_poly.empty()) {
2515 continue;
2516 }
2517
2518 if (!comp_poly.empty())
2519 append(new_base_areas, comp_poly);
2520
2521 }
2522
2523
2524 base_areas = std::move(new_base_areas);
2525 floor_areas = std::move(new_floor_areas);
2526 }
2527
2528
2529
2530
2531
2532 if (layer_nr == 0 && m_raft_layers == 0 && !belt_floor_active && m_support_params.support_style == smsTreeHybrid &&
2533 m_object_config->raft_first_layer_expansion.value > 0.f) {
2534 ExPolygons expanded_base_areas;
2535 const float inflate_factor_1st_layer = float(scale_(m_object_config->raft_first_layer_expansion.value));
2536 Polygons trimming = offset(m_object->layers().front()->lslices, float(scale_(m_support_params.gap_xy_first_layer)),
2537 SUPPORT_SURFACES_OFFSET_PARAMETERS);
2538
2539 const int nsteps = std::max(5, int(ceil(inflate_factor_1st_layer / m_support_params.first_layer_flow.scaled_width())));
2540 const float step = inflate_factor_1st_layer / nsteps;
2541 for (const ExPolygon &expoly : ts_layer->base_areas) {
2542 if (overlaps({ expoly }, area_poly)) {
2543 Polygons expanded = to_polygons(expoly);
2544 for (int i = 0; i < nsteps; ++i)
2545 expanded = diff(expand(expanded, step), trimming);
2546 append(expanded_base_areas, union_ex(expanded));
2547 } else
2548 expanded_base_areas.emplace_back(expoly);
2549 }
2550 ts_layer->base_areas = std::move(expanded_base_areas);
2551 }
2552
2553
2554
2555 if (!ts_layer->base_areas.empty()) {
2556 const Polygons trimming = get_trim_support_regions(
2557 *m_object, ts_layer, 0., m_slicing_params.gap_object_support, 0);
2558 if (!trimming.empty())
2559 ts_layer->base_areas = diff_ex(ts_layer->base_areas, trimming);
2560 }
2561
2562 auto &area_groups = ts_layer->area_groups;
2563
2564 for (auto& expoly : ts_layer->base_areas) {
2565
2566 area_groups.emplace_back(&expoly, SupportLayer::BaseType, max_layers_above_base);
2567 area_groups.back().need_infill = overlaps({ expoly }, area_poly);
2568 area_groups.back().need_extra_wall = !area_groups.back().need_infill &&
2569 !extra_wall_areas.empty() && overlaps({expoly}, extra_wall_areas);
2570 }
2571 for (size_t roof_idx = 0; roof_idx < ts_layer->roof_areas.size(); ++roof_idx) {
2572 auto &expoly = ts_layer->roof_areas[roof_idx];
2573
2574 area_groups.emplace_back(&expoly, SupportLayer::RoofType, max_layers_above_roof);
2575 area_groups.back().interface_as_base = roof_idx >= first_base_roof_area;
2576 }
2577 for (auto &expoly : ts_layer->floor_areas) {
2578
2579 area_groups.emplace_back(&expoly, SupportLayer::FloorType, 10000);
2580 area_groups.back().interface_as_base = floor_interface_as_base;
2581 }
2582 for (auto &expoly : ts_layer->roof_1st_layer) {
2583
2584 area_groups.emplace_back(&expoly, SupportLayer::Roof1stLayer, max_layers_above_roof1);
2585 area_groups.back().interface_as_base = top_base_interface_layers > 0;
2586 }
2587
2588 for (auto &area_group : area_groups) {
2589 auto& expoly = area_group.area;
2590 expoly->holes.erase(std::remove_if(expoly->holes.begin(), expoly->holes.end(),
2591 [](auto &hole) {
2592 auto bbox_size = get_extents(hole).size();
2593 return bbox_size[0] < scale_(2) && bbox_size[1] < scale_(2);
2594 }),
2595 expoly->holes.end());
2596
2597 if (layer_nr < brim_skirt_layers)
2598 ts_layer->lslices.emplace_back(*expoly);
2599 }
2600
2601 ts_layer->lslices = union_ex(ts_layer->lslices);
2602
2603 ts_layer->lslices_bboxes.clear();
2604 ts_layer->lslices_bboxes.reserve(ts_layer->lslices.size());
2605
2606 for (const ExPolygon& expoly : ts_layer->lslices)
2607 ts_layer->lslices_bboxes.emplace_back(get_extents(expoly));
2608
2609 ts_layer->backup_untyped_slices();
2610
2611 }
2612 });
2613
2615 int roof_interface_id = 0;
2616 int floor_interface_id = 0;
2617 bool has_roof_interface;
2618 bool has_floor_interface;
2619
2620 for (
size_t layer_nr = 0; layer_nr <
m_ts_data->layer_heights.size(); ++layer_nr) {
2622 if (ts_layer == nullptr)
2623 continue;
2624
2625 has_roof_interface = false;
2626 has_floor_interface = false;
2627
2628 for (auto &area_group : ts_layer->area_groups) {
2630 if (interlaced)
2631 area_group.interface_id = roof_interface_id;
2632 has_roof_interface = true;
2634 if (interlaced)
2635 area_group.interface_id = floor_interface_id;
2636 has_floor_interface = true;
2637 }
2638 }
2639
2640 if (has_roof_interface)
2641 ++roof_interface_id;
2642
2643 if (has_floor_interface)
2644 ++floor_interface_id;
2645 }
2646
2647 if (with_lightning_infill)
2648 {
2649 const bool global_lightning_infill = true;
2650
2651 std::vector<Polygons> contours;
2652 std::vector<Polygons> overhangs;
2653 for (
int layer_nr = 1; layer_nr <
contact_nodes.size(); layer_nr++) {
2654 if (print->canceled()) break;
2655 const std::vector<SupportNode*>& curr_layer_nodes =
contact_nodes[layer_nr];
2657 assert(ts_layer != nullptr);
2658
2659
2660 if (curr_layer_nodes.empty()) continue;
2661 if (ts_layer->height <
EPSILON)
continue;
2662 if (ts_layer->area_groups.empty()) continue;
2663
2664 ExPolygons& base_areas = ts_layer->base_areas;
2665
2666 int layer_nr_lower = layer_nr - 1;
2667 for (; layer_nr_lower >= 0; layer_nr_lower--) {
2669 }
2670 if (layer_nr_lower <= 0) continue;
2671
2673 ExPolygons& base_areas_lower = lower_layer->base_areas;
2674
2676 if (global_lightning_infill)
2677 {
2678
2680 }
2681 else
2682 {
2683
2684 for (auto& base_area : base_areas)
2685 for (auto& hole : base_area.holes)
2686 {
2690 ex_hole.emplace_back(ExPolygon(rev_hole));
2691 for (auto& other_area : base_areas)
2692
2693 ex_hole =
diff_ex(ex_hole, other_area);
2694 overhang =
union_ex(overhang, ex_hole);
2695 }
2697 }
2698
2700 contours.emplace_back(
to_polygons(base_areas_lower));
2702 }
2703
2704
2706 coordf_t support_spacing =
m_object_config->support_base_pattern_spacing.value + m_support_material_flow.spacing();
2707 coordf_t support_density = std::min(1., m_support_material_flow.spacing() / support_spacing * 2);
2708 generator = std::make_unique<FillLightning::Generator>(
m_object, contours, overhangs, []() {}, support_density);
2709 }
2710
2712
2713
2714
2715 auto intersects_contour = [](
Polygon poly, ExPolygon expoly,
Point& pt_on_poly,
Point& pt_on_expoly,
Point& pt_far_on_poly,
float dist_thresh = 0.01) {
2717 if (pl_out.empty()) return false;
2718 float min_dist = std::numeric_limits<float>::max();
2719 float max_dist = 0;
2720 for (
auto from :
poly.points) {
2721 for (int i = 0; i < expoly.num_contours(); i++) {
2722 const Point* candidate = expoly.contour_or_hole(i).closest_point(from);
2724 if (dist2 < min_dist) {
2725 min_dist = dist2;
2726 pt_on_poly = from;
2727 pt_on_expoly = *candidate;
2728 }
2729 if (dist2 > max_dist) {
2730 max_dist = dist2;
2731 pt_far_on_poly = from;
2732 }
2733 if (dist2 < dist_thresh) { return true; }
2734 }
2735 }
2736 return false;
2737 };
2738
2739
2740 std::map<const Polygon*, std::tuple<int, Point, Point>> holePropagationInfos;
2741 for (
int layer_nr =
contact_nodes.size() - 1; layer_nr > 0; layer_nr--) {
2742 if (print->canceled()) break;
2743
2744
2745 const std::vector<SupportNode*>& curr_layer_nodes =
contact_nodes[layer_nr];
2747 assert(ts_layer != nullptr);
2748
2749
2750 if (curr_layer_nodes.empty()) continue;
2751 if (ts_layer->height <
EPSILON)
continue;
2752 if (ts_layer->area_groups.empty()) continue;
2753
2754 int layer_nr_lower = layer_nr - 1;
2755 for (; layer_nr_lower >= 0; layer_nr_lower--) {
2757 }
2758 if (layer_nr_lower < 0) continue;
2760
2761 for (const auto& area_group : ts_layer->area_groups) {
2763 const auto&
area = area_group.area;
2764 for (
const auto& hole :
area->holes) {
2765
2766 for (auto& area_group_lower : area_groups_lower) {
2768 auto& base_area_lower = *area_group_lower.area;
2769 Point pt_on_poly, pt_on_expoly, pt_far_on_poly;
2770
2771 if (base_area_lower.contour.contains(hole.points.front()) && !intersects_contour(hole, base_area_lower, pt_on_poly, pt_on_expoly, pt_far_on_poly)) {
2773 Point direction =
normal(pt_on_expoly - pt_on_poly, line_width_scaled / 2);
2774 hole_lower.translate(direction);
2775
2776 auto hole_expanded =
offset(hole_lower, -line_width_scaled / 4,
jtSquare);
2777 if (!hole_expanded.empty()) {
2778 base_area_lower.holes.push_back(std::move(hole_expanded[0]));
2779 holePropagationInfos.insert({ &base_area_lower.holes.back(), {25, direction, pt_far_on_poly} });
2780 }
2781 break;
2782 }
2783 else if (holePropagationInfos.find(&hole) != holePropagationInfos.end() && std::get<0>(holePropagationInfos[&hole]) > 0 &&
2784 base_area_lower.contour.contains(std::get<2>(holePropagationInfos[&hole]))) {
2786 auto&& direction = std::get<1>(holePropagationInfos[&hole]);
2787 hole_lower.translate(direction);
2788
2789 auto hole_expanded =
offset(hole_lower, line_width_scaled / 2,
jtSquare);
2790 Point farPoint = std::get<2>(holePropagationInfos[&hole]) + direction * 2;
2791 if (!hole_expanded.empty()) {
2792 base_area_lower.holes.push_back(std::move(hole_expanded[0]));
2793 holePropagationInfos.insert({ &base_area_lower.holes.back(), {std::get<0>(holePropagationInfos[&hole]) - 1, direction, farPoint} });
2794 }
2795 break;
2796 }
2797 }
2798 {
2799
2800 for (auto& roof1 : ts_layer->roof_1st_layer) {
2801
2802 bool is_inside_hole = std::all_of(roof1.contour.points.begin(), roof1.contour.points.end(), [&hole](Point& pt) { return hole.contains(pt); });
2803 if (is_inside_hole) {
2804 Polygon hole_reoriented = hole;
2805 if (roof1.contour.is_counter_clockwise())
2807 else if (roof1.contour.is_clockwise())
2808 hole_reoriented.make_clockwise();
2809 auto tmp =
union_({ roof1.contour }, { hole_reoriented });
2810 if (!tmp.empty()) roof1.contour = tmp[0];
2811
2812
2813
2814
2816 tmp1 =
diff_ex(tmp1, ts_layer->roof_areas);
2817 if (!tmp1.empty()) {
2818 roof1.contour = std::move(tmp1[0].
contour);
2819 roof1.holes = std::move(tmp1[0].
holes);
2820 }
2821 break;
2822 }
2823 }
2824 }
2825 }
2826 }
2827 }
2828 }
2829
2830
2831#ifdef SUPPORT_TREE_DEBUG_TO_SVG
2832 for (
int layer_nr =
m_object->support_layer_count() - 1; layer_nr >= 0; layer_nr--) {
2834 ExPolygons& base_areas = ts_layer->base_areas;
2835 ExPolygons& roof_areas = ts_layer->roof_areas;
2836 ExPolygons& roof_1st_layer = ts_layer->roof_1st_layer;
2838 if (base_areas.empty() && roof_areas.empty() && roof_1st_layer.empty()) continue;
2839 draw_contours_and_nodes_to_svg(
debug_out_path(
"circles_%d_%.2f.svg", layer_nr, ts_layer->print_z), base_areas, roofs, ts_layer->lslices_extrudable, {}, {}, {
"base",
"roof",
"lslices"}, {
"blue",
"red",
"black"});
2840 }
2841#endif
2842
2844
2845
2846
2847 auto iter = std::stable_partition(ts_layers.begin(), ts_layers.end(), [](SupportLayer* ts_layer) { return !(ts_layer->height < EPSILON); });
2848 for (auto it = iter; it != ts_layers.end(); ++it)
2849 delete *it;
2850 ts_layers.erase(iter, ts_layers.end());
2851 for (int layer_nr = 0; layer_nr < ts_layers.size(); layer_nr++) {
2852 ts_layers[layer_nr]->upper_layer = layer_nr != ts_layers.size() - 1 ? ts_layers[layer_nr + 1] : nullptr;
2853 ts_layers[layer_nr]->lower_layer = layer_nr > 0 ? ts_layers[layer_nr - 1] : nullptr;
2854 }
2855}
#define TAU
Definition TreeSupport.cpp:80
bool make_counter_clockwise()
Definition Polygon.cpp:94
@ RoofType
Definition Layer.hpp:341
@ FloorType
Definition Layer.hpp:341
@ BaseType
Definition Layer.hpp:341
@ Roof1stLayer
Definition Layer.hpp:341
float nodes_angle
Definition TreeSupport.hpp:408
const ExPolygons & get_collision(coordf_t radius, size_t layer_nr)
Definition TreeSupport.cpp:2015
int avg_node_per_layer
Definition TreeSupport.hpp:407
std::unordered_map< double, size_t > printZ_to_lightninglayer
Definition TreeSupport.hpp:415
std::unique_ptr< FillLightning::Generator > generator
Definition TreeSupport.hpp:414
std::vector< std::vector< SupportNode * > > contact_nodes
Generator for model collision, avoidance and internal guide volumes.
Definition TreeSupport.hpp:436
@ jtSquare
Definition ClipperUtils.hpp:21
@ smipRectilinearInterlaced
Definition PrintConfig.hpp:374
Polylines to_polylines(const ExPolygon &src)
Definition ExPolygon.hpp:235
layer_height((ConfigOptionInt, faded_layers))((ConfigOptionFloat
std::vector< Polyline > Polylines
Definition Polyline.hpp:22
double vsize2_with_unscale(const Point pt)
Definition MinimumSpanningTree.cpp:22
int number_of_support_interface_bottom_layers(const PrintObjectConfig &object_config)
Definition SupportParameters.hpp:21
double angle(const Eigen::MatrixBase< Derived > &v1, const Eigen::MatrixBase< Derived2 > &v2)
Definition Point.hpp:138
Flow support_material_flow(const PrintObject *object, float layer_height)
Definition Flow.cpp:239
std::vector< SupportLayer * > SupportLayerPtrs
Definition Print.hpp:228
Polygons to_polygons(const ExPolygon &src)
Definition ExPolygon.hpp:307
constexpr T sqr(T x)
Definition libslic3r.h:301
Point normal(Point pt, double scale)
Definition TreeSupport.cpp:112
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip)
Definition ClipperUtils.cpp:1111
const Polygon & contour(const ExPolygon &p)
Definition AGGRaster.hpp:30
const Polygons & holes(const ExPolygon &p)
Definition AGGRaster.hpp:31
Slic3r::Polygon Polygon
Definition Emboss.cpp:101