mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-24 02:17:57 +00:00
Compare commits
11 Commits
feature/fi
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d61e0cb7bf | ||
|
|
07b81cfdc9 | ||
|
|
d7fed95390 | ||
|
|
c72908e377 | ||
|
|
ea376e858c | ||
|
|
877180829c | ||
|
|
550e234a37 | ||
|
|
3b4e65d8a9 | ||
|
|
4b397fc2cc | ||
|
|
90f76fa28c | ||
|
|
f05444dc94 |
@@ -59,6 +59,13 @@ if (APPLE)
|
||||
message(STATUS "CMAKE_OSX_DEPLOYMENT_TARGET: ${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
endif ()
|
||||
|
||||
# Keep MSVC's default /W3 out of CMAKE_<LANG>_FLAGS so it can be applied to our own
|
||||
# targets only. Silencing a bundled target would otherwise override a warning level,
|
||||
# which cl reports as D9025 for every file it compiles.
|
||||
if (POLICY CMP0092)
|
||||
cmake_policy(SET CMP0092 NEW)
|
||||
endif ()
|
||||
|
||||
project(OrcaSlicer)
|
||||
|
||||
# Backward compatibility for old CMake versions
|
||||
@@ -126,6 +133,8 @@ option(SLIC3R_GUI "Compile OrcaSlicer with GUI components (OpenGL,
|
||||
option(SLIC3R_FHS "Assume OrcaSlicer is to be installed in a FHS directory structure" 0)
|
||||
option(SLIC3R_PROFILE "Compile OrcaSlicer with an invasive Shiny profiler" 0)
|
||||
option(SLIC3R_PCH "Use precompiled headers" 1)
|
||||
option(SLIC3R_WARNINGS "Emit compiler warnings for OrcaSlicer sources" 1)
|
||||
option(SLIC3R_BUNDLED_WARNINGS "Emit compiler warnings for bundled third-party sources" 0)
|
||||
option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1)
|
||||
option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1)
|
||||
option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0)
|
||||
@@ -335,15 +344,20 @@ if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL Clang)
|
||||
|
||||
# clang-cl can interpret SYSTEM header paths if -imsvc is used
|
||||
set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-imsvc")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall \
|
||||
-Wno-old-style-cast -Wno-reserved-id-macro -Wno-c++98-compat-pedantic")
|
||||
else ()
|
||||
set(IS_CLANG_CL FALSE)
|
||||
endif ()
|
||||
|
||||
if (MSVC)
|
||||
if (SLIC3R_MSVC_COMPILE_PARALLEL AND NOT IS_CLANG_CL)
|
||||
# CMP0092 only applies when the cache is created; an existing tree keeps its /W3,
|
||||
# which a silenced bundled target would then override (D9025, once per file).
|
||||
string(REGEX REPLACE "/W[0-4]" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
|
||||
# /MP only matters for the VS generators, where CMake turns it into the
|
||||
# MultiProcessorCompilation property. Ninja parallelises on its own, and
|
||||
# clang-cl warns "argument unused" if the flag reaches it.
|
||||
if (SLIC3R_MSVC_COMPILE_PARALLEL AND CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||
add_compile_options(/MP)
|
||||
endif ()
|
||||
# /bigobj (Increase Number of Sections in .Obj file)
|
||||
@@ -523,8 +537,15 @@ if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fext-numeric-literals" )
|
||||
endif()
|
||||
|
||||
if (NOT MSVC AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))
|
||||
if (NOT MINGW)
|
||||
if ((NOT MSVC OR IS_CLANG_CL) AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))
|
||||
if (IS_CLANG_CL)
|
||||
# clang-cl reads -Wall as MSVC /Wall, which clang maps to -Weverything. /W4 is
|
||||
# its -Wall -Wextra and, unlike /clang:-Wall, is ordered with the -Wno-* below
|
||||
# instead of after them. The -Wextra-only warnings are dropped again so the set
|
||||
# matches what -Wall gives the GNU/Clang builds.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4" )
|
||||
add_compile_options(-Wno-unused-parameter -Wno-ignored-qualifiers -Wno-missing-field-initializers)
|
||||
elseif (NOT MINGW)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall" )
|
||||
endif ()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder" )
|
||||
@@ -1086,8 +1107,57 @@ function(orcaslicer_copy_dlls target config postfix output_dlls)
|
||||
endfunction()
|
||||
|
||||
|
||||
# Bundled sources set their own warning flags, and a plain -Wall there means /Wall
|
||||
# (= -Weverything) under clang-cl. Target options are applied after the ones a target
|
||||
# set on itself, so these win. Targets are discovered rather than listed so a newly
|
||||
# bundled library needs no maintenance here.
|
||||
function(orcaslicer_silence_third_party_warnings _dir)
|
||||
get_property(_subdirs DIRECTORY "${_dir}" PROPERTY SUBDIRECTORIES)
|
||||
foreach (_subdir IN LISTS _subdirs)
|
||||
orcaslicer_silence_third_party_warnings("${_subdir}")
|
||||
endforeach ()
|
||||
get_property(_targets DIRECTORY "${_dir}" PROPERTY BUILDSYSTEM_TARGETS)
|
||||
foreach (_target IN LISTS _targets)
|
||||
get_target_property(_type ${_target} TYPE)
|
||||
if (NOT _type STREQUAL "INTERFACE_LIBRARY" AND NOT _type STREQUAL "UTILITY")
|
||||
if (MSVC AND NOT IS_CLANG_CL)
|
||||
# Drop any level the target set for itself, or -w overrides it and cl
|
||||
# reports D9025 once per file.
|
||||
get_target_property(_opts ${_target} COMPILE_OPTIONS)
|
||||
if (_opts)
|
||||
string(REGEX REPLACE "/W[0-4]|/Wall" "" _opts "${_opts}")
|
||||
string(REGEX REPLACE ";;+" ";" _opts "${_opts}")
|
||||
set_target_properties(${_target} PROPERTIES COMPILE_OPTIONS "${_opts}")
|
||||
endif ()
|
||||
# CMake maps a level into the VS generator's WarningLevel element, while a
|
||||
# bare -w stays on the command line and trips D9025 there, once per file.
|
||||
target_compile_options(${_target} PRIVATE /W0)
|
||||
else ()
|
||||
target_compile_options(${_target} PRIVATE -w)
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
endfunction()
|
||||
|
||||
|
||||
# libslic3r, OrcaSlicer GUI and the OrcaSlicer executable.
|
||||
add_subdirectory(deps_src)
|
||||
|
||||
if (NOT SLIC3R_BUNDLED_WARNINGS)
|
||||
orcaslicer_silence_third_party_warnings("${CMAKE_CURRENT_SOURCE_DIR}/deps_src")
|
||||
endif ()
|
||||
|
||||
# Warning level for the targets added below: our sources, plus glad and libvgcode,
|
||||
# which are vendored but live under src/. The deps_src libraries were configured just
|
||||
# above. CMP0092 left MSVC without a default level, so it is set here.
|
||||
if (NOT SLIC3R_WARNINGS)
|
||||
add_compile_options(-w)
|
||||
elseif (MSVC AND NOT IS_CLANG_CL)
|
||||
# /we4715 is C4715, no return from a non-void function, matching the
|
||||
# -Werror=return-type the GNU/Clang builds apply.
|
||||
add_compile_options(/W3 /we4715)
|
||||
endif ()
|
||||
|
||||
add_subdirectory(src)
|
||||
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT OrcaSlicer_app_gui)
|
||||
|
||||
@@ -1099,6 +1169,10 @@ endif()
|
||||
|
||||
if(BUILD_TESTS)
|
||||
add_subdirectory(tests)
|
||||
if (NOT SLIC3R_BUNDLED_WARNINGS)
|
||||
# Catch2 is vendored under tests/ and sets its own warning flags too.
|
||||
orcaslicer_silence_third_party_warnings("${CMAKE_CURRENT_SOURCE_DIR}/tests/catch2")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
if (NOT WIN32 AND NOT APPLE)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4142,10 +4142,10 @@ msgid "PA Profile"
|
||||
msgstr "Профіль PA"
|
||||
|
||||
msgid "Factor K"
|
||||
msgstr "Коэф. K"
|
||||
msgstr "Коеф. K"
|
||||
|
||||
msgid "Factor N"
|
||||
msgstr "Коэф. N"
|
||||
msgstr "Коеф. N"
|
||||
|
||||
msgid "Setting AMS slot information while printing is not supported"
|
||||
msgstr "Зміна інформації про слоти AMS під час друку не підтримується"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Qidi",
|
||||
"version": "02.04.00.10",
|
||||
"version": "02.04.00.11",
|
||||
"force_update": "0",
|
||||
"description": "Qidi configurations",
|
||||
"machine_model_list": [
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
"close_fan_the_first_x_layers": [
|
||||
"3"
|
||||
],
|
||||
"during_print_exhaust_fan_speed": [
|
||||
"0"
|
||||
],
|
||||
"fan_cooling_layer_time": [
|
||||
"10"
|
||||
],
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
"close_fan_the_first_x_layers": [
|
||||
"3"
|
||||
],
|
||||
"during_print_exhaust_fan_speed": [
|
||||
"0"
|
||||
],
|
||||
"fan_cooling_layer_time": [
|
||||
"10"
|
||||
],
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
"close_fan_the_first_x_layers": [
|
||||
"3"
|
||||
],
|
||||
"during_print_exhaust_fan_speed": [
|
||||
"0"
|
||||
],
|
||||
"fan_cooling_layer_time": [
|
||||
"10"
|
||||
],
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -755,6 +755,9 @@ struct SparseInfillShape {
|
||||
size_t sharp_turns { 0 };
|
||||
size_t path_count { 0 };
|
||||
double length { 0. };
|
||||
// Digest of every point in the order it is printed. The counts above all survive the same
|
||||
// extrusions being joined into different polylines, so only this tells two such fills apart.
|
||||
uint64_t sequence { 14695981039346656037ull };
|
||||
};
|
||||
|
||||
static SparseInfillShape sparse_infill_shape(const Print &print)
|
||||
@@ -767,6 +770,9 @@ static SparseInfillShape sparse_infill_shape(const Print &print)
|
||||
const Points3 &pts = path.polyline.points;
|
||||
++shape.path_count;
|
||||
shape.point_count += pts.size();
|
||||
for (const auto &pt : pts)
|
||||
for (const coord_t coordinate : {pt.x(), pt.y(), pt.z()})
|
||||
shape.sequence = (shape.sequence ^ uint64_t(coordinate)) * 1099511628211ull;
|
||||
for (size_t i = 1; i < pts.size(); ++i)
|
||||
shape.length += (pts[i] - pts[i - 1]).head<2>().cast<double>().norm();
|
||||
for (size_t i = 1; i + 1 < pts.size(); ++i) {
|
||||
@@ -793,6 +799,33 @@ static SparseInfillShape sparse_infill_shape(const Print &print)
|
||||
return shape;
|
||||
}
|
||||
|
||||
TEST_CASE("Lightning infill slices the same model the same way twice", "[Fill][Regression]")
|
||||
{
|
||||
// Slicing twice in one process catches a generator that carries state from one slice to the
|
||||
// next, or whose result depends on how the parallel layer fill interleaves.
|
||||
auto shape = [] {
|
||||
Print print;
|
||||
Slic3r::Test::init_and_process_print({Slic3r::Test::cube(20)}, print,
|
||||
{{"sparse_infill_pattern", "lightning"},
|
||||
{"sparse_infill_density", "50%"},
|
||||
{"layer_height", 0.2}});
|
||||
return sparse_infill_shape(print);
|
||||
};
|
||||
|
||||
const SparseInfillShape first = shape();
|
||||
const SparseInfillShape second = shape();
|
||||
|
||||
REQUIRE(first.path_count > 0);
|
||||
REQUIRE(second.path_count == first.path_count);
|
||||
REQUIRE(second.point_count == first.point_count);
|
||||
REQUIRE(second.sharp_turns == first.sharp_turns);
|
||||
// No tolerance: the same extrusions in the same order add up to the very same number.
|
||||
REQUIRE_THAT(second.length, Catch::Matchers::WithinAbs(first.length, 0.));
|
||||
// All of the above agree when the same branches are joined into different polylines, so the
|
||||
// point sequence is what actually decides whether the two slices produced the same infill.
|
||||
REQUIRE(second.sequence == first.sequence);
|
||||
}
|
||||
|
||||
TEST_CASE("Lightning infill rounds the turns of its branches with the smooth factor", "[Fill]")
|
||||
{
|
||||
auto shape_for = [](const std::string &smooth_factor) {
|
||||
|
||||
Reference in New Issue
Block a user