mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-18 06:22:56 +00:00
Merge main
This commit is contained in:
@@ -154,8 +154,8 @@ void simplify(Polygon &thiss, const int64_t smallest_line_segment_squared, const
|
||||
//h^2 = L^2 / b^2 [factor the divisor]
|
||||
const int64_t height_2 = double(area_removed_so_far) * double(area_removed_so_far) / double(base_length_2);
|
||||
// Orca: The value of `height_2` is squared, so we need to compare it with the squared value
|
||||
if ((height_2 <= Slic3r::sqr(scaled<coord_t>(0.005)) //Almost exactly colinear (barring rounding errors).
|
||||
&& Line::distance_to_infinite(current, previous, next) <= scaled<double>(0.005))) // make sure that height_2 is not small because of cancellation of positive and negative areas
|
||||
if ((height_2 <= Slic3r::sqr(colinear_vertex_tolerance()) //Almost exactly colinear (barring rounding errors).
|
||||
&& Line::distance_to_infinite(current, previous, next) <= double(colinear_vertex_tolerance()))) // make sure that height_2 is not small because of cancellation of positive and negative areas
|
||||
continue;
|
||||
|
||||
if (length2 < smallest_line_segment_squared
|
||||
|
||||
@@ -133,8 +133,8 @@ void ExtrusionLine::simplify(const int64_t smallest_line_segment_squared, const
|
||||
const auto height_2 = int64_t(double(area_removed_so_far) * double(area_removed_so_far) / double(base_length_2));
|
||||
const int64_t extrusion_area_error = calculateExtrusionAreaDeviationError(previous, current, next);
|
||||
// Orca: The value of `height_2` is squared, so we need to compare it with the squared value
|
||||
if ((height_2 <= Slic3r::sqr(scaled<coord_t>(0.005)) // Almost exactly colinear (barring rounding errors).
|
||||
&& Line::distance_to_infinite(current.p, previous.p, next.p) <= scaled<double>(0.005)) // Make sure that height_2 is not small because of cancellation of positive and negative areas
|
||||
if ((height_2 <= Slic3r::sqr(colinear_vertex_tolerance()) // Almost exactly colinear (barring rounding errors).
|
||||
&& Line::distance_to_infinite(current.p, previous.p, next.p) <= double(colinear_vertex_tolerance())) // Make sure that height_2 is not small because of cancellation of positive and negative areas
|
||||
// We shouldn't remove middle junctions of colinear segments if the area changed for the C-P segment is exceeding the maximum allowed
|
||||
&& extrusion_area_error <= maximum_extrusion_area_deviation)
|
||||
{
|
||||
|
||||
@@ -32,6 +32,14 @@ class Flow;
|
||||
namespace Slic3r::Arachne
|
||||
{
|
||||
|
||||
// ORCA: Tolerance of the "almost exactly colinear" early-out shared by the two simplify() passes
|
||||
// (this file and WallToolPaths.cpp). That test drops a vertex regardless of the user's Maximum wall
|
||||
// resolution/deviation, so it has to stay at the scale of coordinate rounding noise. A larger value
|
||||
// silently decimates finely tessellated curves: on a circle, one vertex may be removed whenever the
|
||||
// sagitta of the resulting chord falls below the tolerance, which halves the point count and turns
|
||||
// smooth arcs into corners the firmware has to decelerate through.
|
||||
inline coord_t colinear_vertex_tolerance() { return coord_t(SCALED_EPSILON); }
|
||||
|
||||
/*!
|
||||
* Represents a polyline (not just a line) that is to be extruded with variable
|
||||
* line width.
|
||||
|
||||
@@ -682,7 +682,7 @@ Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perim
|
||||
return fuzzified;
|
||||
}
|
||||
|
||||
void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerator& perimeter_generator, const bool is_contour)
|
||||
void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerator& perimeter_generator, const bool is_contour, const bool closed)
|
||||
{
|
||||
const auto slice_z = perimeter_generator.slice_z;
|
||||
const auto& regions = perimeter_generator.regions_by_fuzzify;
|
||||
@@ -690,7 +690,7 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
|
||||
const auto& config = regions.begin()->first;
|
||||
const bool fuzzify = should_fuzzify(config, perimeter_generator.layer_id, extrusion->inset_idx, is_contour);
|
||||
if (fuzzify)
|
||||
fuzzy_extrusion_line(extrusion->junctions, slice_z, config);
|
||||
fuzzy_extrusion_line(extrusion->junctions, slice_z, config, closed);
|
||||
} else {
|
||||
// Merge regions that produce identical fuzzy effects (differ only in type).
|
||||
// When the style (e.g. External) and a painted region (All) both fuzzify this loop
|
||||
@@ -701,10 +701,19 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
|
||||
|
||||
// Fast path: single merged region — apply directly without splitting
|
||||
if (merged_regions.size() == 1 && merged_regions.front().expolygons.empty()) {
|
||||
fuzzy_extrusion_line(extrusion->junctions, slice_z, *merged_regions.front().config);
|
||||
fuzzy_extrusion_line(extrusion->junctions, slice_z, *merged_regions.front().config, closed);
|
||||
return;
|
||||
}
|
||||
|
||||
// Open path means this is a thin wall that collapsed into a single thick line, in this case the path will go exactly
|
||||
// between the middle two sides of the object. And since the paint segmentation never goes beyond the middle line because
|
||||
// it uses voronoi diagram, we need to expand the segmentation a little bit to make sure it covers the path.
|
||||
if (!closed) {
|
||||
for (auto& r : merged_regions) {
|
||||
r.expolygons = offset_ex(r.expolygons, perimeter_generator.ext_perimeter_flow.scaled_width() / 10);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FUZZY
|
||||
{
|
||||
int i = 0;
|
||||
@@ -752,7 +761,7 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
|
||||
// Fuzzy splitted extrusion
|
||||
if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) {
|
||||
// The entire polygon is fuzzified
|
||||
fuzzy_extrusion_line(extrusion->junctions, slice_z, *r.config);
|
||||
fuzzy_extrusion_line(extrusion->junctions, slice_z, *r.config, closed);
|
||||
continue;
|
||||
} else {
|
||||
const auto current_ext = extrusion->junctions;
|
||||
@@ -803,7 +812,7 @@ void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerato
|
||||
}
|
||||
|
||||
//Orca: ensure the loop is closed after fuzzy
|
||||
if (!extrusion->junctions.empty() && extrusion->junctions.front().p != extrusion->junctions.back().p) {
|
||||
if (closed && !extrusion->junctions.empty() && extrusion->junctions.front().p != extrusion->junctions.back().p) {
|
||||
extrusion->junctions.back().p = extrusion->junctions.front().p;
|
||||
extrusion->junctions.back().w = extrusion->junctions.front().w;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ void group_region_by_fuzzify(PerimeterGenerator& g);
|
||||
bool should_fuzzify(const FuzzySkinConfig& config, int layer_id, size_t loop_idx, bool is_contour);
|
||||
|
||||
Polygon apply_fuzzy_skin(const Polygon& polygon, const PerimeterGenerator& perimeter_generator, size_t loop_idx, bool is_contour);
|
||||
void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerator& perimeter_generator, bool is_contour);
|
||||
void apply_fuzzy_skin(Arachne::ExtrusionLine* extrusion, const PerimeterGenerator& perimeter_generator, bool is_contour, bool closed = true);
|
||||
|
||||
} // namespace Slic3r::Feature::FuzzySkin
|
||||
|
||||
|
||||
@@ -351,19 +351,23 @@ void Node::convertToPolylines(Polylines &output, const coord_t line_overlap) con
|
||||
{
|
||||
Polylines result;
|
||||
result.emplace_back();
|
||||
convertToPolylines(0, result);
|
||||
// Orca: the layers are filled in parallel, so they would consume a shared generator in a
|
||||
// different order every run, and a model would not slice the same way twice. Each tree seeds
|
||||
// its own from where it is rooted; one constant seed would start them all on the same pick.
|
||||
std::mt19937_64 rng { uint64_t(PointHash{}(m_p)) };
|
||||
convertToPolylines(0, result, rng);
|
||||
removeJunctionOverlap(result, line_overlap);
|
||||
append(output, std::move(result));
|
||||
}
|
||||
|
||||
void Node::convertToPolylines(size_t long_line_idx, Polylines &output) const
|
||||
void Node::convertToPolylines(size_t long_line_idx, Polylines &output, std::mt19937_64 &rng) const
|
||||
{
|
||||
if (m_children.empty()) {
|
||||
output[long_line_idx].points.push_back(m_p);
|
||||
return;
|
||||
}
|
||||
size_t first_child_idx = rand() % m_children.size();
|
||||
m_children[first_child_idx]->convertToPolylines(long_line_idx, output);
|
||||
const size_t first_child_idx = rng() % m_children.size();
|
||||
m_children[first_child_idx]->convertToPolylines(long_line_idx, output, rng);
|
||||
output[long_line_idx].points.push_back(m_p);
|
||||
|
||||
for (size_t idx_offset = 1; idx_offset < m_children.size(); idx_offset++) {
|
||||
@@ -371,7 +375,7 @@ void Node::convertToPolylines(size_t long_line_idx, Polylines &output) const
|
||||
const Node& child = *m_children[child_idx];
|
||||
output.emplace_back();
|
||||
size_t child_line_idx = output.size() - 1;
|
||||
child.convertToPolylines(child_line_idx, output);
|
||||
child.convertToPolylines(child_line_idx, output, rng);
|
||||
output[child_line_idx].points.emplace_back(m_p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
#include "../../EdgeGrid.hpp"
|
||||
@@ -259,8 +260,9 @@ protected:
|
||||
*
|
||||
* \param long_line a reference to a polyline in \p output which to continue building on in the recursion
|
||||
* \param output all branches in this tree connected into polylines
|
||||
* \param rng the generator the junctions draw from, carried through the recursion
|
||||
*/
|
||||
void convertToPolylines(size_t long_line_idx, Polylines &output) const;
|
||||
void convertToPolylines(size_t long_line_idx, Polylines &output, std::mt19937_64 &rng) const;
|
||||
|
||||
void removeJunctionOverlap(Polylines &polylines, coord_t line_overlap) const;
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ using ThumbnailsList = std::vector<ThumbnailData>;
|
||||
|
||||
struct ThumbnailsParams
|
||||
{
|
||||
const Vec2ds sizes;
|
||||
const Vec2ds sizes{};
|
||||
bool printable_only;
|
||||
bool parts_only;
|
||||
bool show_bed;
|
||||
|
||||
@@ -229,6 +229,22 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
|
||||
|
||||
// Append thin walls to the nearest-neighbor search (only for first iteration)
|
||||
if (! thin_walls.empty()) {
|
||||
// Orca: apply fuzzy skin to thin walls as well
|
||||
for (auto& thin_wall : thin_walls) {
|
||||
// First, we convert the ThickPolyline into Arachne::ExtrusionLine so we could reuse our existing fuzzy code
|
||||
Arachne::ExtrusionLine el(0, true);
|
||||
el.junctions.reserve(thin_wall.points.size());
|
||||
for (int i = 0; i < thin_wall.points.size(); i++) {
|
||||
el.junctions.emplace_back(thin_wall.points[i], thin_wall.width[i], 0);
|
||||
}
|
||||
|
||||
// Then we fuzzy it
|
||||
apply_fuzzy_skin(&el, perimeter_generator, true, thin_wall.is_closed());
|
||||
|
||||
// Then convert the result back to ThickPolyline
|
||||
thin_wall = Arachne::to_thick_polyline(el);
|
||||
}
|
||||
|
||||
variable_width(thin_walls, erExternalPerimeter, perimeter_generator.ext_perimeter_flow, coll.entities);
|
||||
thin_walls.clear();
|
||||
}
|
||||
|
||||
@@ -1499,6 +1499,13 @@ static std::vector<Polygons> make_loops(
|
||||
Polygons &polygons = layers[line_idx];
|
||||
polygons = make_loops(lines[line_idx]);
|
||||
|
||||
// Orca: A planar quad represented by two triangles contributes a point where the
|
||||
// slicing plane crosses the shared diagonal. After rounding to coord_t this
|
||||
// point may be very slightly off the otherwise straight contour edge. Apart
|
||||
// from being redundant, such points make the subsequent contour
|
||||
// simplification depend on the slice height (and may move seam candidates).
|
||||
remove_collinear(polygons);
|
||||
|
||||
auto this_mode = line_idx < params.slicing_mode_normal_below_layer ? params.mode_below : params.mode;
|
||||
if (! polygons.empty()) {
|
||||
if (this_mode == MeshSlicingParams::SlicingMode::Positive) {
|
||||
|
||||
@@ -420,7 +420,7 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode
|
||||
if (properties_shown) {
|
||||
float label_w = 0.0f;
|
||||
float value_w = 0.0f;
|
||||
properties_rows.reserve(13);
|
||||
properties_rows.reserve(14);
|
||||
auto add_row = [&properties_rows, &label_w, &value_w](std::string label, std::string value) {
|
||||
label_w = std::max(label_w, ImGui::CalcTextSize(label.c_str()).x);
|
||||
value_w = std::max(value_w, ImGui::CalcTextSize(value.c_str()).x);
|
||||
@@ -433,6 +433,27 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode
|
||||
add_row(_u8L("Width"), buff);
|
||||
if (is_extrusion) sprintf(buff, ("%.3f " + _u8L("mm")).c_str(), vertex.height); else strcpy(buff, NA_CSTR);
|
||||
add_row(_u8L("Height"), buff);
|
||||
// ORCA: Length of the move ending at the current vertex. Arc moves (G2/G3) are discretized
|
||||
// into several vertices sharing the same gcode line id, so accumulate the whole run to report
|
||||
// the arc length instead of the length of a single chord.
|
||||
if (vertex_id > 0 && (is_extrusion || vertex.is_travel() || vertex.is_wipe())) {
|
||||
const size_t vertices_count = viewer->get_vertices_count();
|
||||
size_t first_id = vertex_id;
|
||||
while (first_id > 0 && viewer->get_vertex_at(first_id - 1).gcode_id == vertex.gcode_id)
|
||||
--first_id;
|
||||
size_t last_id = vertex_id;
|
||||
while (last_id + 1 < vertices_count && viewer->get_vertex_at(last_id + 1).gcode_id == vertex.gcode_id)
|
||||
++last_id;
|
||||
float length = 0.0f;
|
||||
for (size_t i = std::max<size_t>(first_id, 1); i <= last_id; ++i) {
|
||||
length += (libvgcode::convert(viewer->get_vertex_at(i).position) -
|
||||
libvgcode::convert(viewer->get_vertex_at(i - 1).position)).norm();
|
||||
}
|
||||
sprintf(buff, ("%.3f " + _u8L("mm")).c_str(), length);
|
||||
}
|
||||
else
|
||||
strcpy(buff, NA_CSTR);
|
||||
add_row(_u8L("Length"), buff);
|
||||
sprintf(buff, "%d", vertex.layer_id + 1);
|
||||
add_row(_u8L("Layer"), buff);
|
||||
sprintf(buff, ("%.1f " + _u8L("mm/s")).c_str(), vertex.feedrate);
|
||||
|
||||
Reference in New Issue
Block a user