@@ -1121,10 +1121,62 @@ void PerimeterGenerator::process_arachne(
1121
1121
loop_number = 0 ;
1122
1122
1123
1123
ExPolygons last = offset_ex (surface.expolygon .simplify_p (params.scaled_resolution ), - float (ext_perimeter_width / 2 . - ext_perimeter_spacing / 2 .));
1124
- Polygons last_p = to_polygons (last);
1125
1124
1125
+ // Orca
1126
+ std::vector<Arachne::VariableWidthLines> out_shell;
1127
+ ExPolygons top_fills;
1128
+ if (loop_number > 0 && params.config .only_one_perimeter_top && !surface.is_bridge () && upper_slices != nullptr ) {
1129
+ // Check if current layer has surfaces that are not covered by upper layer (i.e., top surfaces)
1130
+ ExPolygons non_top_polygons;
1131
+ ExPolygons fill_clip;
1132
+
1133
+ split_top_surfaces (params, lower_slices, upper_slices, last, top_fills, non_top_polygons, fill_clip);
1134
+
1135
+ if (top_fills.empty ()) {
1136
+ // No top surfaces, no special handling needed
1137
+ } else {
1138
+ // First we slice the outer shell
1139
+ Polygons last_p = to_polygons (last);
1140
+ Arachne::WallToolPaths wallToolPaths (last_p, ext_perimeter_spacing, perimeter_spacing, coord_t (1 ),
1141
+ 0 , params.layer_height , params.object_config , params.print_config );
1142
+ out_shell = wallToolPaths.getToolPaths ();
1143
+ // Make sure infill not overlap with wall
1144
+ top_fills = intersection_ex (top_fills, wallToolPaths.getInnerContour ());
1145
+
1146
+ if (!top_fills.empty ()) {
1147
+ // Then get the inner part that needs more walls
1148
+ last = intersection_ex (non_top_polygons, wallToolPaths.getInnerContour ());
1149
+ loop_number--;
1150
+ } else {
1151
+ // Give up the outer shell because we don't have any meaningful top surface
1152
+ out_shell.clear ();
1153
+ }
1154
+ }
1155
+ }
1156
+
1157
+ Polygons last_p = to_polygons (last);
1126
1158
Arachne::WallToolPaths wallToolPaths (last_p, ext_perimeter_spacing, perimeter_spacing, coord_t (loop_number + 1 ), 0 , params.layer_height , params.object_config , params.print_config );
1127
1159
std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths ();
1160
+
1161
+ // Orca
1162
+ if (!out_shell.empty ()) {
1163
+ // Combine outer shells
1164
+ size_t inset_offset = 0 ;
1165
+ for (auto &p : out_shell) {
1166
+ for (auto &l : p) {
1167
+ if (l.inset_idx + 1 > inset_offset) {
1168
+ inset_offset = l.inset_idx + 1 ;
1169
+ }
1170
+ }
1171
+ }
1172
+ for (auto &p : perimeters) {
1173
+ for (auto &l : p) {
1174
+ l.inset_idx += inset_offset;
1175
+ }
1176
+ }
1177
+ perimeters.insert (perimeters.begin (), out_shell.begin (), out_shell.end ());
1178
+ }
1179
+
1128
1180
loop_number = int (perimeters.size ()) - 1 ;
1129
1181
1130
1182
#ifdef ARACHNE_DEBUG
@@ -1307,6 +1359,11 @@ void PerimeterGenerator::process_arachne(
1307
1359
float (- min_perimeter_infill_spacing / 2 .),
1308
1360
float (inset + min_perimeter_infill_spacing / 2 .));
1309
1361
1362
+ // append infill areas to fill_surfaces
1363
+ if (!top_fills.empty ()) {
1364
+ infill_areas = union_ex (infill_areas, offset_ex (top_fills, double (inset)));
1365
+ }
1366
+
1310
1367
if (lower_slices != nullptr && params.config .overhangs && params.config .extra_perimeters_on_overhangs &&
1311
1368
params.config .perimeters > 0 && params.layer_id > params.object_config .raft_layers ) {
1312
1369
// Generate extra perimeters on overhang areas, and cut them to these parts only, to save print time and material
@@ -1685,4 +1742,90 @@ void PerimeterGenerator::process_classic(
1685
1742
append (out_fill_expolygons, std::move (infill_areas));
1686
1743
}
1687
1744
1745
+ // Orca
1746
+ void PerimeterGenerator::split_top_surfaces (const Parameters ¶ms,const ExPolygons *lower_slices,const ExPolygons *upper_slices,const ExPolygons &orig_polygons, ExPolygons &top_fills,
1747
+ ExPolygons &non_top_polygons, ExPolygons &fill_clip) {
1748
+ // other perimeters
1749
+ coord_t perimeter_width = params.perimeter_flow .scaled_width ();
1750
+ coord_t perimeter_spacing = params.perimeter_flow .scaled_spacing ();
1751
+
1752
+ // external perimeters
1753
+ coord_t ext_perimeter_width = params.ext_perimeter_flow .scaled_width ();
1754
+ coord_t ext_perimeter_spacing = params.ext_perimeter_flow .scaled_spacing ();
1755
+
1756
+ bool has_gap_fill = params.config .gap_fill_enabled ;
1757
+
1758
+ // split the polygons with top/not_top
1759
+ // get the offset from solid surface anchor
1760
+ coord_t offset_top_surface = ext_perimeter_width;
1761
+
1762
+ // don't takes into account too thin areas
1763
+ // skip if the exposed area is smaller than "min_width_top_surface"
1764
+ double min_width_top_surface = std::max (double (ext_perimeter_spacing / 2 + 10 ), scale_ (params.config .min_width_top_surface .get_abs_value (unscale_ (perimeter_width))));
1765
+
1766
+ Polygons grown_upper_slices = offset (*upper_slices, min_width_top_surface);
1767
+
1768
+ // get boungding box of last
1769
+ BoundingBox last_box = get_extents (orig_polygons);
1770
+ last_box.offset (SCALED_EPSILON);
1771
+
1772
+ // get the Polygons upper the polygon this layer
1773
+ Polygons upper_polygons_series_clipped =
1774
+ ClipperUtils::clip_clipper_polygons_with_subject_bbox (grown_upper_slices, last_box);
1775
+
1776
+ // set the clip to a virtual "second perimeter"
1777
+ fill_clip = offset_ex (orig_polygons, -double (ext_perimeter_spacing));
1778
+ // get the real top surface
1779
+ ExPolygons grown_lower_slices;
1780
+ ExPolygons bridge_checker;
1781
+ auto nozzle_diameter = params.print_config .nozzle_diameter .get_at (params.config .perimeter_extruder );
1782
+ // Check whether surface be bridge or not
1783
+ if (lower_slices != NULL ) {
1784
+ // BBS: get the Polygons below the polygon this layer
1785
+ Polygons lower_polygons_series_clipped =
1786
+ ClipperUtils::clip_clipper_polygons_with_subject_bbox (*lower_slices, last_box);
1787
+ double bridge_offset = std::max (double (ext_perimeter_spacing), (double (perimeter_width)));
1788
+ // SoftFever: improve bridging
1789
+ const float bridge_margin =
1790
+ std::min (float (scale_ (BRIDGE_INFILL_MARGIN)), float (scale_ (nozzle_diameter * BRIDGE_INFILL_MARGIN / 0.4 )));
1791
+ bridge_checker = offset_ex (diff_ex (orig_polygons, lower_polygons_series_clipped, ApplySafetyOffset::Yes),
1792
+ 1.5 * bridge_offset + bridge_margin + perimeter_spacing / 2 );
1793
+ }
1794
+ ExPolygons delete_bridge = diff_ex (orig_polygons, bridge_checker, ApplySafetyOffset::Yes);
1795
+
1796
+ ExPolygons top_polygons = diff_ex (delete_bridge, upper_polygons_series_clipped, ApplySafetyOffset::Yes);
1797
+ // get the not-top surface, from the "real top" but enlarged by external_infill_margin (and the
1798
+ // min_width_top_surface we removed a bit before)
1799
+ ExPolygons temp_gap = diff_ex (top_polygons, fill_clip);
1800
+ ExPolygons inner_polygons =
1801
+ diff_ex (orig_polygons,
1802
+ offset_ex (top_polygons, offset_top_surface + min_width_top_surface - double (ext_perimeter_spacing / 2 )),
1803
+ ApplySafetyOffset::Yes);
1804
+ // get the enlarged top surface, by using inner_polygons instead of upper_slices, and clip it for it to be exactly
1805
+ // the polygons to fill.
1806
+ top_polygons = diff_ex (fill_clip, inner_polygons, ApplySafetyOffset::Yes);
1807
+ // increase by half peri the inner space to fill the frontier between last and stored.
1808
+ top_fills = union_ex (top_fills, top_polygons);
1809
+ // set the clip to the external wall but go back inside by infill_extrusion_width/2 to be sure the extrusion won't go outside even with a 100% overlap.
1810
+ double infill_spacing_unscaled = params.config .infill_extrusion_width .get_abs_value (nozzle_diameter);
1811
+ if (infill_spacing_unscaled == 0 ) infill_spacing_unscaled = Flow::auto_extrusion_width (frInfill, nozzle_diameter);
1812
+ fill_clip = offset_ex (orig_polygons, double (ext_perimeter_spacing / 2 ) - scale_ (infill_spacing_unscaled / 2 ));
1813
+ // ExPolygons oldLast = last;
1814
+
1815
+ non_top_polygons = intersection_ex (inner_polygons, orig_polygons);
1816
+ if (has_gap_fill)
1817
+ non_top_polygons = union_ex (non_top_polygons, temp_gap);
1818
+ // {
1819
+ // std::stringstream stri;
1820
+ // stri << this->layer_id << "_1_"<< i <<"_only_one_peri"<< ".svg";
1821
+ // SVG svg(stri.str());
1822
+ // svg.draw(to_polylines(top_fills), "green");
1823
+ // svg.draw(to_polylines(inner_polygons), "yellow");
1824
+ // svg.draw(to_polylines(top_polygons), "cyan");
1825
+ // svg.draw(to_polylines(oldLast), "orange");
1826
+ // svg.draw(to_polylines(last), "red");
1827
+ // svg.Close();
1828
+ // }
1829
+ }
1830
+
1688
1831
}
0 commit comments