Merge branch 'main' into dev/arachen-sync

This commit is contained in:
Noisyfox 2024-12-25 08:54:30 +08:00 committed by GitHub
commit 91fbd1a417
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 475 additions and 424 deletions

View File

@ -411,12 +411,14 @@ if(SLIC3R_STATIC)
set(Boost_USE_STATIC_LIBS ON)
# Use boost libraries linked statically to the C++ runtime.
# set(Boost_USE_STATIC_RUNTIME ON)
else()
add_definitions(-DBOOST_LOG_DYN_LINK)
endif()
#set(Boost_DEBUG ON)
# set(Boost_COMPILER "-mgw81")
# boost::process was introduced first in version 1.64.0,
# boost::beast::detail::base64 was introduced first in version 1.66.0
find_package(Boost 1.66 REQUIRED COMPONENTS system filesystem thread log locale regex chrono atomic date_time iostreams program_options)
find_package(Boost 1.66 REQUIRED COMPONENTS system filesystem thread log log_setup locale regex chrono atomic date_time iostreams program_options)
add_library(boost_libs INTERFACE)
add_library(boost_headeronly INTERFACE)

View File

@ -2,7 +2,6 @@
PROJECT_ROOT=$(cd -P -- "$(dirname -- "$0")" && printf '%s\n' "$(pwd -P)")
set -x
# Wishlist hint: For developers, creating a Docker Compose
# setup with persistent volumes for the build & deps directories
# would speed up recompile times significantly. For end users,

View File

@ -5,6 +5,8 @@ set -x
# -h $HOSTNAME \
# If there's problems with the X display, try this
# -v /tmp/.X11-unix:/tmp/.X11-unix \
# If you get an error like "Authorization required, but no authorization protocol specified," run line 9 in your terminal before rerunning this program
# xhost +local:docker
docker run \
`# Use the hosts networking. Printer wifi and also dbus communication` \
--net=host \

View File

@ -68,14 +68,14 @@ WORKDIR OrcaSlicer
RUN ./BuildLinux.sh -u
# Build dependencies in ./deps
RUN ./BuildLinux.sh -d
RUN ./BuildLinux.sh -dr
# Build slic3r
RUN ./BuildLinux.sh -s
RUN ./BuildLinux.sh -sr
# Build AppImage
ENV container podman
RUN ./BuildLinux.sh -i
RUN ./BuildLinux.sh -ir
# It's easier to run Orca Slicer as the same username,
# UID and GID as your workstation. Since we bind mount

View File

@ -103,11 +103,19 @@ Explore the latest developments in Orca Slicer with our nightly builds. Feedback
- Run => Options tab => Document Versions: uncheck `Allow debugging when browsing versions`
- menu bar: Product => Run
- Ubuntu
- Dependencies **Will be auto-installed with the shell script**: `libmspack-dev libgstreamerd-3-dev libsecret-1-dev libwebkit2gtk-4.0-dev libosmesa6-dev libssl-dev libcurl4-openssl-dev eglexternalplatform-dev libudev-dev libdbus-1-dev extra-cmake-modules libgtk2.0-dev libglew-dev libudev-dev libdbus-1-dev cmake git texinfo`
- run 'sudo ./BuildLinux.sh -u'
- run './BuildLinux.sh -dsir'
- Linux (All Distros)
- Docker
- Dependencies: Docker [Installation Instructions](https://www.docker.com/get-started/), git
- clone this repository `git clone https://github.com/SoftFever/OrcaSlicer`
- run `cd OrcaSlicer`
- run `./DockerBuild.sh`
- To run OrcaSlicer:
- run `./DockerRun.sh`
- For most common errors, open `DockerRun.sh` and read the comments.
- Ubuntu
- Dependencies **Will be auto installed with the shell script**: `libmspack-dev libgstreamerd-3-dev libsecret-1-dev libwebkit2gtk-4.0-dev libosmesa6-dev libssl-dev libcurl4-openssl-dev eglexternalplatform-dev libudev-dev libdbus-1-dev extra-cmake-modules libgtk2.0-dev libglew-dev libudev-dev libdbus-1-dev cmake git texinfo`
- run 'sudo ./BuildLinux.sh -u'
- run './BuildLinux.sh -dsir'
# Note:
If you're running Klipper, it's recommended to add the following configuration to your `printer.cfg` file.

File diff suppressed because it is too large Load Diff

View File

@ -1,128 +0,0 @@
#ifndef SRC_LIBSLIC3R_PATH_SORTING_HPP_
#define SRC_LIBSLIC3R_PATH_SORTING_HPP_
#include "AABBTreeLines.hpp"
#include "BoundingBox.hpp"
#include "Line.hpp"
#include "ankerl/unordered_dense.h"
#include <algorithm>
#include <iterator>
#include <libslic3r/Point.hpp>
#include <libslic3r/Polygon.hpp>
#include <libslic3r/ExPolygon.hpp>
#include <limits>
#include <type_traits>
#include <unordered_set>
namespace Slic3r {
namespace Algorithm {
//Sorts the paths such that all paths between begin and last_seed are printed first, in some order. The rest of the paths is sorted
// such that the paths that are touching some of the already printed are printed first, sorted secondary by the distance to the last point of the last
// printed path.
// begin, end, and last_seed are random access iterators. touch_limit_distance is used to check if the paths are touching - if any part of the path gets this close
// to the second, then they touch.
// convert_to_lines is a lambda that should accept the path as argument and return it as Lines vector, in correct order.
template<typename RandomAccessIterator, typename ToLines>
void sort_paths(RandomAccessIterator begin, RandomAccessIterator end, Point start, double touch_limit_distance, ToLines convert_to_lines)
{
size_t paths_count = std::distance(begin, end);
if (paths_count <= 1)
return;
auto paths_touch = [touch_limit_distance](const AABBTreeLines::LinesDistancer<Line> &left,
const AABBTreeLines::LinesDistancer<Line> &right) {
for (const Line &l : left.get_lines()) {
if (right.distance_from_lines<false>(l.a) < touch_limit_distance) {
return true;
}
}
if (right.distance_from_lines<false>(left.get_lines().back().b) < touch_limit_distance) {
return true;
}
for (const Line &l : right.get_lines()) {
if (left.distance_from_lines<false>(l.a) < touch_limit_distance) {
return true;
}
}
if (left.distance_from_lines<false>(right.get_lines().back().b) < touch_limit_distance) {
return true;
}
return false;
};
std::vector<AABBTreeLines::LinesDistancer<Line>> distancers(paths_count);
for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
distancers[path_idx] = AABBTreeLines::LinesDistancer<Line>{convert_to_lines(*std::next(begin, path_idx))};
}
std::vector<std::unordered_set<size_t>> dependencies(paths_count);
for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
for (size_t next_path_idx = path_idx + 1; next_path_idx < paths_count; next_path_idx++) {
if (paths_touch(distancers[path_idx], distancers[next_path_idx])) {
dependencies[next_path_idx].insert(path_idx);
}
}
}
Point current_point = start;
std::vector<std::pair<size_t, bool>> correct_order_and_direction(paths_count);
size_t unsorted_idx = 0;
size_t null_idx = size_t(-1);
size_t next_idx = null_idx;
bool reverse = false;
while (unsorted_idx < paths_count) {
next_idx = null_idx;
double lines_dist = std::numeric_limits<double>::max();
for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
if (!dependencies[path_idx].empty())
continue;
double ldist = distancers[path_idx].distance_from_lines<false>(current_point);
if (ldist < lines_dist) {
const auto &lines = distancers[path_idx].get_lines();
double dist_a = (lines.front().a - current_point).cast<double>().squaredNorm();
double dist_b = (lines.back().b - current_point).cast<double>().squaredNorm();
next_idx = path_idx;
reverse = dist_b < dist_a;
lines_dist = ldist;
}
}
// we have valid next_idx, sort it, update dependencies, update current point
correct_order_and_direction[next_idx] = {unsorted_idx, reverse};
unsorted_idx++;
current_point = reverse ? distancers[next_idx].get_lines().front().a : distancers[next_idx].get_lines().back().b;
dependencies[next_idx].insert(null_idx); // prevent it from being selected again
for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
dependencies[path_idx].erase(next_idx);
}
}
for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
if (correct_order_and_direction[path_idx].second) {
std::next(begin, path_idx)->reverse();
}
}
for (size_t i = 0; i < correct_order_and_direction.size() - 1; i++) {
bool swapped = false;
for (size_t j = 0; j < correct_order_and_direction.size() - i - 1; j++) {
if (correct_order_and_direction[j].first > correct_order_and_direction[j + 1].first) {
std::swap(correct_order_and_direction[j], correct_order_and_direction[j + 1]);
std::iter_swap(std::next(begin, j), std::next(begin, j + 1));
swapped = true;
}
}
if (swapped == false) {
break;
}
}
}
}} // namespace Slic3r::Algorithm
#endif /*SRC_LIBSLIC3R_PATH_SORTING_HPP_*/

View File

@ -32,7 +32,6 @@ set(lisbslic3r_sources
AABBMesh.cpp
Algorithm/LineSplit.hpp
Algorithm/LineSplit.cpp
Algorithm/PathSorting.hpp
Algorithm/RegionExpansion.hpp
Algorithm/RegionExpansion.cpp
AnyPtr.hpp
@ -505,7 +504,7 @@ if (_opts)
target_compile_options(libslic3r_cgal PRIVATE "${_opts_bad}")
endif()
target_link_libraries(libslic3r_cgal PRIVATE ${_cgal_tgt} libigl mcut)
target_link_libraries(libslic3r_cgal PRIVATE ${_cgal_tgt} libigl mcut boost_libs)
if (MSVC AND "${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") # 32 bit MSVC workaround
target_compile_definitions(libslic3r_cgal PRIVATE CGAL_DO_NOT_USE_MPZF)
@ -581,10 +580,6 @@ target_link_libraries(libslic3r
opencv_world
)
if(NOT SLIC3R_STATIC)
target_compile_definitions(libslic3r PUBLIC BOOST_ALL_DYN_LINK)
endif()
if(NOT WIN32)
target_link_libraries(libslic3r freetype)
if (NOT APPLE)

View File

@ -130,7 +130,252 @@ struct SurfaceFill {
// Detect narrow infill regions
// Based on the anti-vibration algorithm from PrusaSlicer:
// https://github.com/prusa3d/PrusaSlicer/blob/94290e09d75f23719c3d2ab2398737c8be4c3fd6/src/libslic3r/Fill/FillEnsuring.cpp#L100-L289
// https://github.com/prusa3d/PrusaSlicer/blob/5dc04b4e8f14f65bbcc5377d62cad3e86c2aea36/src/libslic3r/Fill/FillEnsuring.cpp#L37-L273
static coord_t _MAX_LINE_LENGTH_TO_FILTER() // 4 mm.
{
return scaled<coord_t>(4.);
}
const constexpr size_t MAX_SKIPS_ALLOWED = 2; // Skip means propagation through long line.
const constexpr size_t MIN_DEPTH_FOR_LINE_REMOVING = 5;
struct LineNode
{
struct State
{
// The total number of long lines visited before this node was reached.
// We just need the minimum number of all possible paths to decide whether we can remove the line or not.
int min_skips_taken = 0;
// The total number of short lines visited before this node was reached.
int total_short_lines = 0;
// Some initial line is touching some long line. This information is propagated to neighbors.
bool initial_touches_long_lines = false;
bool initialized = false;
void reset() {
this->min_skips_taken = 0;
this->total_short_lines = 0;
this->initial_touches_long_lines = false;
this->initialized = false;
}
};
explicit LineNode(const Line &line) : line(line) {}
Line line;
// Pointers to line nodes in the previous and the next section that overlap with this line.
std::vector<LineNode*> next_section_overlapping_lines;
std::vector<LineNode*> prev_section_overlapping_lines;
bool is_removed = false;
State state;
// Return true if some initial line is touching some long line and this information was propagated into the current line.
bool is_initial_line_touching_long_lines() const {
if (prev_section_overlapping_lines.empty())
return false;
for (LineNode *line_node : prev_section_overlapping_lines) {
if (line_node->state.initial_touches_long_lines)
return true;
}
return false;
}
// Return true if the current line overlaps with some long line in the previous section.
bool is_touching_long_lines_in_previous_layer() const {
if (prev_section_overlapping_lines.empty())
return false;
const auto MAX_LINE_LENGTH_TO_FILTER = _MAX_LINE_LENGTH_TO_FILTER();
for (LineNode *line_node : prev_section_overlapping_lines) {
if (!line_node->is_removed && line_node->line.length() >= MAX_LINE_LENGTH_TO_FILTER)
return true;
}
return false;
}
// Return true if the current line overlaps with some line in the next section.
bool has_next_layer_neighbours() const {
if (next_section_overlapping_lines.empty())
return false;
for (LineNode *line_node : next_section_overlapping_lines) {
if (!line_node->is_removed)
return true;
}
return false;
}
};
using LineNodes = std::vector<LineNode>;
inline bool are_lines_overlapping_in_y_axes(const Line &first_line, const Line &second_line) {
return (second_line.a.y() <= first_line.a.y() && first_line.a.y() <= second_line.b.y())
|| (second_line.a.y() <= first_line.b.y() && first_line.b.y() <= second_line.b.y())
|| (first_line.a.y() <= second_line.a.y() && second_line.a.y() <= first_line.b.y())
|| (first_line.a.y() <= second_line.b.y() && second_line.b.y() <= first_line.b.y());
}
bool can_line_note_be_removed(const LineNode &line_node) {
const auto MAX_LINE_LENGTH_TO_FILTER = _MAX_LINE_LENGTH_TO_FILTER();
return (line_node.line.length() < MAX_LINE_LENGTH_TO_FILTER)
&& (line_node.state.total_short_lines > int(MIN_DEPTH_FOR_LINE_REMOVING)
|| (!line_node.is_initial_line_touching_long_lines() && !line_node.has_next_layer_neighbours()));
}
// Remove the node and propagate its removal to the previous sections.
void propagate_line_node_remove(const LineNode &line_node) {
std::queue<LineNode *> line_node_queue;
for (LineNode *prev_line : line_node.prev_section_overlapping_lines) {
if (prev_line->is_removed)
continue;
line_node_queue.emplace(prev_line);
}
for (; !line_node_queue.empty(); line_node_queue.pop()) {
LineNode &line_to_check = *line_node_queue.front();
if (can_line_note_be_removed(line_to_check)) {
line_to_check.is_removed = true;
for (LineNode *prev_line : line_to_check.prev_section_overlapping_lines) {
if (prev_line->is_removed)
continue;
line_node_queue.emplace(prev_line);
}
}
}
}
// Filter out short extrusions that could create vibrations.
static std::vector<Lines> filter_vibrating_extrusions(const std::vector<Lines> &lines_sections) {
// Initialize all line nodes.
std::vector<LineNodes> line_nodes_sections(lines_sections.size());
for (const Lines &lines_section : lines_sections) {
const size_t section_idx = &lines_section - lines_sections.data();
line_nodes_sections[section_idx].reserve(lines_section.size());
for (const Line &line : lines_section) {
line_nodes_sections[section_idx].emplace_back(line);
}
}
// Precalculate for each line node which line nodes in the previous and next section this line node overlaps.
for (auto curr_lines_section_it = line_nodes_sections.begin(); curr_lines_section_it != line_nodes_sections.end(); ++curr_lines_section_it) {
if (curr_lines_section_it != line_nodes_sections.begin()) {
const auto prev_lines_section_it = std::prev(curr_lines_section_it);
for (LineNode &curr_line : *curr_lines_section_it) {
for (LineNode &prev_line : *prev_lines_section_it) {
if (are_lines_overlapping_in_y_axes(curr_line.line, prev_line.line)) {
curr_line.prev_section_overlapping_lines.emplace_back(&prev_line);
}
}
}
}
if (std::next(curr_lines_section_it) != line_nodes_sections.end()) {
const auto next_lines_section_it = std::next(curr_lines_section_it);
for (LineNode &curr_line : *curr_lines_section_it) {
for (LineNode &next_line : *next_lines_section_it) {
if (are_lines_overlapping_in_y_axes(curr_line.line, next_line.line)) {
curr_line.next_section_overlapping_lines.emplace_back(&next_line);
}
}
}
}
}
const auto MAX_LINE_LENGTH_TO_FILTER = _MAX_LINE_LENGTH_TO_FILTER();
// Select each section as the initial lines section and propagate line node states from this initial lines section to the last lines section.
// During this propagation, we remove those lines that meet the conditions for its removal.
// When some line is removed, we propagate this removal to previous layers.
for (size_t initial_line_section_idx = 0; initial_line_section_idx < line_nodes_sections.size(); ++initial_line_section_idx) {
// Stars from non-removed short lines.
for (LineNode &initial_line : line_nodes_sections[initial_line_section_idx]) {
if (initial_line.is_removed || initial_line.line.length() >= MAX_LINE_LENGTH_TO_FILTER)
continue;
initial_line.state.reset();
initial_line.state.total_short_lines = 1;
initial_line.state.initial_touches_long_lines = initial_line.is_touching_long_lines_in_previous_layer();
initial_line.state.initialized = true;
}
// Iterate from the initial lines section until the last lines section.
for (size_t propagation_line_section_idx = initial_line_section_idx; propagation_line_section_idx < line_nodes_sections.size(); ++propagation_line_section_idx) {
// Before we propagate node states into next lines sections, we reset the state of all line nodes in the next line section.
if (propagation_line_section_idx + 1 < line_nodes_sections.size()) {
for (LineNode &propagation_line : line_nodes_sections[propagation_line_section_idx + 1]) {
propagation_line.state.reset();
}
}
for (LineNode &propagation_line : line_nodes_sections[propagation_line_section_idx]) {
if (propagation_line.is_removed || !propagation_line.state.initialized)
continue;
for (LineNode *neighbour_line : propagation_line.next_section_overlapping_lines) {
if (neighbour_line->is_removed)
continue;
const bool is_short_line = neighbour_line->line.length() < MAX_LINE_LENGTH_TO_FILTER;
const bool is_skip_allowed = propagation_line.state.min_skips_taken < int(MAX_SKIPS_ALLOWED);
if (!is_short_line && !is_skip_allowed)
continue;
const int neighbour_total_short_lines = propagation_line.state.total_short_lines + int(is_short_line);
const int neighbour_min_skips_taken = propagation_line.state.min_skips_taken + int(!is_short_line);
if (neighbour_line->state.initialized) {
// When the state of the node was previously filled, then we need to update data in such a way
// that will maximize the possibility of removing this node.
neighbour_line->state.min_skips_taken = std::max(neighbour_line->state.min_skips_taken, neighbour_total_short_lines);
neighbour_line->state.min_skips_taken = std::min(neighbour_line->state.min_skips_taken, neighbour_min_skips_taken);
// We will keep updating neighbor initial_touches_long_lines until it is equal to false.
if (neighbour_line->state.initial_touches_long_lines) {
neighbour_line->state.initial_touches_long_lines = propagation_line.state.initial_touches_long_lines;
}
} else {
neighbour_line->state.total_short_lines = neighbour_total_short_lines;
neighbour_line->state.min_skips_taken = neighbour_min_skips_taken;
neighbour_line->state.initial_touches_long_lines = propagation_line.state.initial_touches_long_lines;
neighbour_line->state.initialized = true;
}
}
if (can_line_note_be_removed(propagation_line)) {
// Remove the current node and propagate its removal to the previous sections.
propagation_line.is_removed = true;
propagate_line_node_remove(propagation_line);
}
}
}
}
// Create lines sections without filtered-out lines.
std::vector<Lines> lines_sections_out(line_nodes_sections.size());
for (const std::vector<LineNode> &line_nodes_section : line_nodes_sections) {
const size_t section_idx = &line_nodes_section - line_nodes_sections.data();
for (const LineNode &line_node : line_nodes_section) {
if (!line_node.is_removed) {
lines_sections_out[section_idx].emplace_back(line_node.line);
}
}
}
return lines_sections_out;
}
void split_solid_surface(size_t layer_id, const SurfaceFill &fill, ExPolygons &normal_infill, ExPolygons &narrow_infill)
{
assert(fill.surface.surface_type == stInternalSolid);
@ -152,11 +397,6 @@ void split_solid_surface(size_t layer_id, const SurfaceFill &fill, ExPolygons &n
constexpr double connect_extrusions = true;
auto segments_overlap = [](coord_t alow, coord_t ahigh, coord_t blow, coord_t bhigh) {
return (alow >= blow && alow <= bhigh) || (ahigh >= blow && ahigh <= bhigh) || (blow >= alow && blow <= ahigh) ||
(bhigh >= alow && bhigh <= ahigh);
};
const coord_t scaled_spacing = scaled<coord_t>(fill.params.spacing);
double distance_limit_reconnection = 2.0 * double(scaled_spacing);
double squared_distance_limit_reconnection = distance_limit_reconnection * distance_limit_reconnection;
@ -180,22 +420,23 @@ void split_solid_surface(size_t layer_id, const SurfaceFill &fill, ExPolygons &n
AABBTreeLines::LinesDistancer<Line> area_walls{to_lines(inner_area)};
const size_t n_vlines = (bb.max.x() - bb.min.x() + scaled_spacing - 1) / scaled_spacing;
std::vector<Line> vertical_lines(n_vlines);
coord_t y_min = bb.min.y();
coord_t y_max = bb.max.y();
const size_t n_vlines = (bb.max.x() - bb.min.x() + scaled_spacing - 1) / scaled_spacing;
const coord_t y_min = bb.min.y();
const coord_t y_max = bb.max.y();
Lines vertical_lines(n_vlines);
for (size_t i = 0; i < n_vlines; i++) {
coord_t x = bb.min.x() + i * double(scaled_spacing);
vertical_lines[i].a = Point{x, y_min};
vertical_lines[i].b = Point{x, y_max};
}
if (vertical_lines.size() > 0) {
if (!vertical_lines.empty()) {
vertical_lines.push_back(vertical_lines.back());
vertical_lines.back().a = Point{coord_t(bb.min.x() + n_vlines * double(scaled_spacing) + scaled_spacing * 0.5), y_min};
vertical_lines.back().b = Point{vertical_lines.back().a.x(), y_max};
}
std::vector<std::vector<Line>> polygon_sections(n_vlines);
std::vector<Lines> polygon_sections(n_vlines);
for (size_t i = 0; i < n_vlines; i++) {
const auto intersections = area_walls.intersections_with_line<true>(vertical_lines[i]);
@ -211,88 +452,7 @@ void split_solid_surface(size_t layer_id, const SurfaceFill &fill, ExPolygons &n
}
}
struct Node
{
int section_idx;
int line_idx;
int skips_taken = 0;
bool neighbours_explored = false;
std::vector<std::pair<int, int>> neighbours{};
};
coord_t length_filter = scale_(4);
size_t skips_allowed = 2;
size_t min_removal_conut = 5;
for (int section_idx = 0; section_idx < int(polygon_sections.size()); ++section_idx) {
for (int line_idx = 0; line_idx < int(polygon_sections[section_idx].size()); ++line_idx) {
if (const Line &line = polygon_sections[section_idx][line_idx]; line.a != line.b && line.length() < length_filter) {
std::set<std::pair<int, int>> to_remove{{section_idx, line_idx}};
std::vector<Node> to_visit{{section_idx, line_idx}};
bool initial_touches_long_lines = false;
if (section_idx > 0) {
for (int prev_line_idx = 0; prev_line_idx < int(polygon_sections[section_idx - 1].size()); ++prev_line_idx) {
if (const Line &nl = polygon_sections[section_idx - 1][prev_line_idx];
nl.a != nl.b && segments_overlap(line.a.y(), line.b.y(), nl.a.y(), nl.b.y())) {
initial_touches_long_lines = true;
}
}
}
while (!to_visit.empty()) {
Node curr = to_visit.back();
const Line &curr_l = polygon_sections[curr.section_idx][curr.line_idx];
if (curr.neighbours_explored) {
bool is_valid_for_removal = (curr_l.length() < length_filter) &&
((int(to_remove.size()) - curr.skips_taken > int(min_removal_conut)) ||
(curr.neighbours.empty() && !initial_touches_long_lines));
if (!is_valid_for_removal) {
for (const auto &n : curr.neighbours) {
if (to_remove.find(n) != to_remove.end()) {
is_valid_for_removal = true;
break;
}
}
}
if (!is_valid_for_removal) {
to_remove.erase({curr.section_idx, curr.line_idx});
}
to_visit.pop_back();
} else {
to_visit.back().neighbours_explored = true;
int curr_index = to_visit.size() - 1;
bool can_use_skip = curr_l.length() <= length_filter && curr.skips_taken < int(skips_allowed);
if (curr.section_idx + 1 < int(polygon_sections.size())) {
for (int lidx = 0; lidx < int(polygon_sections[curr.section_idx + 1].size()); ++lidx) {
if (const Line &nl = polygon_sections[curr.section_idx + 1][lidx];
nl.a != nl.b && segments_overlap(curr_l.a.y(), curr_l.b.y(), nl.a.y(), nl.b.y()) &&
(nl.length() < length_filter || can_use_skip)) {
to_visit[curr_index].neighbours.push_back({curr.section_idx + 1, lidx});
to_remove.insert({curr.section_idx + 1, lidx});
Node next_node{curr.section_idx + 1, lidx, curr.skips_taken + (nl.length() >= length_filter)};
to_visit.push_back(next_node);
}
}
}
}
}
for (const auto &pair : to_remove) {
Line &l = polygon_sections[pair.first][pair.second];
l.a = l.b;
}
}
}
}
for (size_t section_idx = 0; section_idx < polygon_sections.size(); section_idx++) {
polygon_sections[section_idx].erase(std::remove_if(polygon_sections[section_idx].begin(), polygon_sections[section_idx].end(),
[](const Line &s) { return s.a == s.b; }),
polygon_sections[section_idx].end());
std::sort(polygon_sections[section_idx].begin(), polygon_sections[section_idx].end(),
[](const Line &a, const Line &b) { if (a == b) return false; // Ensure irreflexivity
return a.a.y() < b.b.y(); });
}
polygon_sections = filter_vibrating_extrusions(polygon_sections);
Polygons reconstructed_area{};
// reconstruct polygon from polygon sections

View File

@ -50,7 +50,11 @@ float get_axis_value(const std::string& line, char axis)
char match[3] = " X";
match[1] = axis;
size_t pos = line.find(match) + 2;
size_t pos = line.find(match);
if (pos == std::string::npos) {
return NAN;
}
pos += 2;
//size_t end = std::min(line.find(' ', pos + 1), line.find(';', pos + 1));
// Try to parse the numeric value.
const char* c = line.c_str();
@ -83,6 +87,15 @@ int16_t get_fan_speed(const std::string &line, GCodeFlavor flavor) {
if (flavor == (gcfMach3) || flavor == (gcfMachinekit)) {
return (int16_t)get_axis_value(line, 'P');
} else {
// Bambu machines use both M106 P1(not P0!) and M106 for part cooling fan.
// Non-bambu machines usually use M106 (without P parameter) for part cooling fan.
// P2 is reserved for auxiliary fan regardless of bambu or not.
// To keep compatibility with Bambu machines, we accept M106 and M106 P1 as the only two valid form
// of gcode that control the part cooling fan. Any other command will be ignored!
const auto idx = get_axis_value(line, 'P');
if (!isnan(idx) && idx != 1.0f) {
return -1;
}
return (int16_t)get_axis_value(line, 'S');
}
} else if (line.compare(0, 4, "M127") == 0 || line.compare(0, 4, "M107") == 0) {

View File

@ -2785,7 +2785,6 @@ std::vector<size_t> ModelVolume::get_extruders_from_multi_material_painting() co
if (!this->is_mm_painted())
return {};
assert(static_cast<size_t>(EnforcerBlockerType::Extruder1) - 1 == 0);
const TriangleSelector::TriangleSplittingData &data = this->mmu_segmentation_facets.get_data();
std::vector<size_t> extruders;