Merge branch 'master' into fs_emboss

# Conflicts:
#	src/libslic3r/Format/3mf.cpp
#	src/slic3r/GUI/Selection.cpp
This commit is contained in:
Filip Sykala 2022-05-24 23:04:36 +02:00
commit ca848b0a14
11 changed files with 342 additions and 157 deletions

View File

@ -43,14 +43,6 @@ set(SLIC3R_GTK "2" CACHE STRING "GTK version to use with wxWidgets on Linux")
set(IS_CROSS_COMPILE FALSE) set(IS_CROSS_COMPILE FALSE)
if (SLIC3R_STATIC)
# Prefer config scripts over find modules. This is helpful when building with
# the static dependencies. Many libraries have their own export scripts
# while having a Find<PkgName> module in standard cmake installation.
# (e.g. CURL)
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
endif ()
if (APPLE) if (APPLE)
set(CMAKE_FIND_FRAMEWORK LAST) set(CMAKE_FIND_FRAMEWORK LAST)
set(CMAKE_FIND_APPBUNDLE LAST) set(CMAKE_FIND_APPBUNDLE LAST)
@ -458,19 +450,10 @@ if (NOT EIGEN3_FOUND)
endif () endif ()
include_directories(BEFORE SYSTEM ${EIGEN3_INCLUDE_DIR}) include_directories(BEFORE SYSTEM ${EIGEN3_INCLUDE_DIR})
# Find expat or use bundled version # Find expat. We have our overriden FindEXPAT which exports libexpat target
# Always use the system libexpat on Linux. # no matter what.
find_package(EXPAT REQUIRED) find_package(EXPAT REQUIRED)
add_library(libexpat INTERFACE)
if (TARGET EXPAT::EXPAT )
target_link_libraries(libexpat INTERFACE EXPAT::EXPAT)
elseif(TARGET expat::expat)
target_link_libraries(libexpat INTERFACE expat::expat)
endif ()
find_package(PNG REQUIRED) find_package(PNG REQUIRED)
set(OpenGL_GL_PREFERENCE "LEGACY") set(OpenGL_GL_PREFERENCE "LEGACY")

View File

@ -30,82 +30,101 @@
# ``CURL_VERSION_STRING`` # ``CURL_VERSION_STRING``
# The version of curl found. # The version of curl found.
# Look for the header file. # First, prefer config scripts
find_path(CURL_INCLUDE_DIR NAMES curl/curl.h) set(_q "")
mark_as_advanced(CURL_INCLUDE_DIR) if(CURL_FIND_QUIETLY)
set(_q QUIET)
endif()
find_package(CURL ${CURL_FIND_VERSION} CONFIG ${_q})
if(NOT CURL_LIBRARY) if(NOT CURL_FIND_QUIETLY)
# Look for the library (sorted from most current/relevant entry to least). if (NOT CURL_FOUND)
find_library(CURL_LIBRARY_RELEASE NAMES message(STATUS "Falling back to MODULE search for CURL...")
curl else()
# Windows MSVC prebuilts: message(STATUS "CURL found in ${CURL_DIR}")
curllib endif()
libcurl_imp
curllib_static
# Windows older "Win32 - MSVC" prebuilts (libcurl.lib, e.g. libcurl-7.15.5-win32-msvc.zip):
libcurl
# Static library on Windows
libcurl_a
)
mark_as_advanced(CURL_LIBRARY_RELEASE)
find_library(CURL_LIBRARY_DEBUG NAMES
# Windows MSVC CMake builds in debug configuration on vcpkg:
libcurl-d_imp
libcurl-d
# Static library on Windows, compiled in debug mode
libcurl_a_debug
)
mark_as_advanced(CURL_LIBRARY_DEBUG)
include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations_SLIC3R.cmake)
select_library_configurations_SLIC3R(CURL)
endif() endif()
if(CURL_INCLUDE_DIR) if (NOT CURL_FOUND)
foreach(_curl_version_header curlver.h curl.h)
if(EXISTS "${CURL_INCLUDE_DIR}/curl/${_curl_version_header}")
file(STRINGS "${CURL_INCLUDE_DIR}/curl/${_curl_version_header}" curl_version_str REGEX "^#define[\t ]+LIBCURL_VERSION[\t ]+\".*\"")
string(REGEX REPLACE "^#define[\t ]+LIBCURL_VERSION[\t ]+\"([^\"]*)\".*" "\\1" CURL_VERSION_STRING "${curl_version_str}") # Look for the header file.
unset(curl_version_str) find_path(CURL_INCLUDE_DIR NAMES curl/curl.h)
break() mark_as_advanced(CURL_INCLUDE_DIR)
endif()
endforeach()
endif()
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs_SLIC3R.cmake) if(NOT CURL_LIBRARY)
FIND_PACKAGE_HANDLE_STANDARD_ARGS_SLIC3R(CURL # Look for the library (sorted from most current/relevant entry to least).
REQUIRED_VARS CURL_LIBRARY CURL_INCLUDE_DIR find_library(CURL_LIBRARY_RELEASE NAMES
VERSION_VAR CURL_VERSION_STRING) curl
# Windows MSVC prebuilts:
curllib
libcurl_imp
curllib_static
# Windows older "Win32 - MSVC" prebuilts (libcurl.lib, e.g. libcurl-7.15.5-win32-msvc.zip):
libcurl
# Static library on Windows
libcurl_a
)
mark_as_advanced(CURL_LIBRARY_RELEASE)
if(CURL_FOUND) find_library(CURL_LIBRARY_DEBUG NAMES
set(CURL_LIBRARIES ${CURL_LIBRARY}) # Windows MSVC CMake builds in debug configuration on vcpkg:
set(CURL_INCLUDE_DIRS ${CURL_INCLUDE_DIR}) libcurl-d_imp
libcurl-d
# Static library on Windows, compiled in debug mode
libcurl_a_debug
)
mark_as_advanced(CURL_LIBRARY_DEBUG)
if(NOT TARGET CURL::libcurl) include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations_SLIC3R.cmake)
add_library(CURL::libcurl UNKNOWN IMPORTED) select_library_configurations_SLIC3R(CURL)
set_target_properties(CURL::libcurl PROPERTIES endif()
INTERFACE_INCLUDE_DIRECTORIES "${CURL_INCLUDE_DIRS}")
if(EXISTS "${CURL_LIBRARY}") if(CURL_INCLUDE_DIR)
foreach(_curl_version_header curlver.h curl.h)
if(EXISTS "${CURL_INCLUDE_DIR}/curl/${_curl_version_header}")
file(STRINGS "${CURL_INCLUDE_DIR}/curl/${_curl_version_header}" curl_version_str REGEX "^#define[\t ]+LIBCURL_VERSION[\t ]+\".*\"")
string(REGEX REPLACE "^#define[\t ]+LIBCURL_VERSION[\t ]+\"([^\"]*)\".*" "\\1" CURL_VERSION_STRING "${curl_version_str}")
unset(curl_version_str)
break()
endif()
endforeach()
endif()
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs_SLIC3R.cmake)
FIND_PACKAGE_HANDLE_STANDARD_ARGS_SLIC3R(CURL
REQUIRED_VARS CURL_LIBRARY CURL_INCLUDE_DIR
VERSION_VAR CURL_VERSION_STRING)
if(CURL_FOUND)
set(CURL_LIBRARIES ${CURL_LIBRARY})
set(CURL_INCLUDE_DIRS ${CURL_INCLUDE_DIR})
if(NOT TARGET CURL::libcurl)
add_library(CURL::libcurl UNKNOWN IMPORTED)
set_target_properties(CURL::libcurl PROPERTIES set_target_properties(CURL::libcurl PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "C" INTERFACE_INCLUDE_DIRECTORIES "${CURL_INCLUDE_DIRS}")
IMPORTED_LOCATION "${CURL_LIBRARY}")
endif() if(EXISTS "${CURL_LIBRARY}")
if(CURL_LIBRARY_RELEASE) set_target_properties(CURL::libcurl PROPERTIES
set_property(TARGET CURL::libcurl APPEND PROPERTY IMPORTED_LINK_INTERFACE_LANGUAGES "C"
IMPORTED_CONFIGURATIONS RELEASE) IMPORTED_LOCATION "${CURL_LIBRARY}")
set_target_properties(CURL::libcurl PROPERTIES endif()
IMPORTED_LINK_INTERFACE_LANGUAGES "C" if(CURL_LIBRARY_RELEASE)
IMPORTED_LOCATION_RELEASE "${CURL_LIBRARY_RELEASE}") set_property(TARGET CURL::libcurl APPEND PROPERTY
endif() IMPORTED_CONFIGURATIONS RELEASE)
if(CURL_LIBRARY_DEBUG) set_target_properties(CURL::libcurl PROPERTIES
set_property(TARGET CURL::libcurl APPEND PROPERTY IMPORTED_LINK_INTERFACE_LANGUAGES "C"
IMPORTED_CONFIGURATIONS DEBUG) IMPORTED_LOCATION_RELEASE "${CURL_LIBRARY_RELEASE}")
set_target_properties(CURL::libcurl PROPERTIES endif()
IMPORTED_LINK_INTERFACE_LANGUAGES "C" if(CURL_LIBRARY_DEBUG)
IMPORTED_LOCATION_DEBUG "${CURL_LIBRARY_DEBUG}") set_property(TARGET CURL::libcurl APPEND PROPERTY
IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(CURL::libcurl PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
IMPORTED_LOCATION_DEBUG "${CURL_LIBRARY_DEBUG}")
endif()
endif() endif()
endif() endif()
endif()
endif (NOT CURL_FOUND)

View File

@ -66,16 +66,25 @@ public:
return this->success; return this->success;
} }
void unload_opengl_dll() bool unload_opengl_dll()
{ {
if (this->hOpenGL) { if (this->hOpenGL != nullptr) {
BOOL released = FreeLibrary(this->hOpenGL); if (::FreeLibrary(this->hOpenGL) != FALSE) {
if (released) if (::GetModuleHandle(L"opengl32.dll") == nullptr) {
printf("System OpenGL library released\n"); printf("System OpenGL library successfully released\n");
this->hOpenGL = nullptr;
return true;
}
else
printf("System OpenGL library released but not removed\n");
}
else else
printf("System OpenGL library NOT released\n"); printf("System OpenGL library NOT released\n");
this->hOpenGL = nullptr;
return false;
} }
return true;
} }
bool is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const bool is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const
@ -270,20 +279,26 @@ int wmain(int argc, wchar_t **argv)
// https://wiki.qt.io/Cross_compiling_Mesa_for_Windows // https://wiki.qt.io/Cross_compiling_Mesa_for_Windows
// http://download.qt.io/development_releases/prebuilt/llvmpipe/windows/ // http://download.qt.io/development_releases/prebuilt/llvmpipe/windows/
if (load_mesa) { if (load_mesa) {
opengl_version_check.unload_opengl_dll(); bool res = opengl_version_check.unload_opengl_dll();
wchar_t path_to_mesa[MAX_PATH + 1] = { 0 }; if (!res) {
wcscpy(path_to_mesa, path_to_exe); MessageBox(nullptr, L"PrusaSlicer was unable to automatically switch to MESA OpenGL library\nPlease, try to run the application using the '--sw-renderer' option.\n",
wcscat(path_to_mesa, L"mesa\\opengl32.dll"); L"PrusaSlicer Warning", MB_OK);
printf("Loading MESA OpenGL library: %S\n", path_to_mesa); return -1;
HINSTANCE hInstance_OpenGL = LoadLibraryExW(path_to_mesa, nullptr, 0); }
if (hInstance_OpenGL == nullptr) { else {
printf("MESA OpenGL library was not loaded\n"); wchar_t path_to_mesa[MAX_PATH + 1] = { 0 };
} else wcscpy(path_to_mesa, path_to_exe);
printf("MESA OpenGL library was loaded sucessfully\n"); wcscat(path_to_mesa, L"mesa\\opengl32.dll");
printf("Loading MESA OpenGL library: %S\n", path_to_mesa);
HINSTANCE hInstance_OpenGL = LoadLibraryExW(path_to_mesa, nullptr, 0);
if (hInstance_OpenGL == nullptr)
printf("MESA OpenGL library was not loaded\n");
else
printf("MESA OpenGL library was loaded sucessfully\n");
}
} }
#endif /* SLIC3R_GUI */ #endif /* SLIC3R_GUI */
wchar_t path_to_slic3r[MAX_PATH + 1] = { 0 }; wchar_t path_to_slic3r[MAX_PATH + 1] = { 0 };
wcscpy(path_to_slic3r, path_to_exe); wcscpy(path_to_slic3r, path_to_exe);
wcscat(path_to_slic3r, L"PrusaSlicer.dll"); wcscat(path_to_slic3r, L"PrusaSlicer.dll");

View File

@ -5,6 +5,8 @@
#include "../FillRectilinear.hpp" #include "../FillRectilinear.hpp"
#include "../../ClipperUtils.hpp" #include "../../ClipperUtils.hpp"
#include <tbb/parallel_for.h>
namespace Slic3r::FillLightning namespace Slic3r::FillLightning
{ {
@ -18,33 +20,42 @@ DistanceField::DistanceField(const coord_t& radius, const Polygons& current_outl
m_supporting_radius2 = Slic3r::sqr(int64_t(radius)); m_supporting_radius2 = Slic3r::sqr(int64_t(radius));
// Sample source polygons with a regular grid sampling pattern. // Sample source polygons with a regular grid sampling pattern.
for (const ExPolygon &expoly : union_ex(current_overhang)) { for (const ExPolygon &expoly : union_ex(current_overhang)) {
for (const Point &p : sample_grid_pattern(expoly, m_cell_size)) { const Points sampled_points = sample_grid_pattern(expoly, m_cell_size);
// Find a squared distance to the source expolygon boundary. const size_t unsupported_points_prev_size = m_unsupported_points.size();
double d2 = std::numeric_limits<double>::max(); m_unsupported_points.resize(unsupported_points_prev_size + sampled_points.size());
for (size_t icontour = 0; icontour <= expoly.holes.size(); ++icontour) {
const Polygon &contour = icontour == 0 ? expoly.contour : expoly.holes[icontour - 1]; tbb::parallel_for(tbb::blocked_range<size_t>(0, sampled_points.size()), [&self = *this, &expoly = std::as_const(expoly), &sampled_points = std::as_const(sampled_points), &unsupported_points_prev_size = std::as_const(unsupported_points_prev_size)](const tbb::blocked_range<size_t> &range) -> void {
if (contour.size() > 2) { for (size_t sp_idx = range.begin(); sp_idx < range.end(); ++sp_idx) {
Point prev = contour.points.back(); const Point &sp = sampled_points[sp_idx];
for (const Point &p2 : contour.points) { // Find a squared distance to the source expolygon boundary.
d2 = std::min(d2, Line::distance_to_squared(p, prev, p2)); double d2 = std::numeric_limits<double>::max();
prev = p2; for (size_t icontour = 0; icontour <= expoly.holes.size(); ++icontour) {
const Polygon &contour = icontour == 0 ? expoly.contour : expoly.holes[icontour - 1];
if (contour.size() > 2) {
Point prev = contour.points.back();
for (const Point &p2 : contour.points) {
d2 = std::min(d2, Line::distance_to_squared(sp, prev, p2));
prev = p2;
}
} }
} }
self.m_unsupported_points[unsupported_points_prev_size + sp_idx] = {sp, coord_t(std::sqrt(d2))};
assert(self.m_unsupported_points_bbox.contains(sp));
} }
m_unsupported_points.emplace_back(p, sqrt(d2)); }); // end of parallel_for
assert(m_unsupported_points_bbox.contains(p));
}
} }
m_unsupported_points.sort([&radius](const UnsupportedCell &a, const UnsupportedCell &b) { std::stable_sort(m_unsupported_points.begin(), m_unsupported_points.end(), [&radius](const UnsupportedCell &a, const UnsupportedCell &b) {
constexpr coord_t prime_for_hash = 191; constexpr coord_t prime_for_hash = 191;
return std::abs(b.dist_to_boundary - a.dist_to_boundary) > radius ? return std::abs(b.dist_to_boundary - a.dist_to_boundary) > radius ?
a.dist_to_boundary < b.dist_to_boundary : a.dist_to_boundary < b.dist_to_boundary :
(PointHash{}(a.loc) % prime_for_hash) < (PointHash{}(b.loc) % prime_for_hash); (PointHash{}(a.loc) % prime_for_hash) < (PointHash{}(b.loc) % prime_for_hash);
}); });
for (auto it = m_unsupported_points.begin(); it != m_unsupported_points.end(); ++it) {
UnsupportedCell& cell = *it; m_unsupported_points_erased.resize(m_unsupported_points.size());
m_unsupported_points_grid.emplace(this->to_grid_point(cell.loc), it); std::fill(m_unsupported_points_erased.begin(), m_unsupported_points_erased.end(), false);
}
m_unsupported_points_grid.initialize(m_unsupported_points, [&self = std::as_const(*this)](const Point &p) -> Point { return self.to_grid_point(p); });
// Because the distance between two points is at least one axis equal to m_cell_size, every cell // Because the distance between two points is at least one axis equal to m_cell_size, every cell
// in m_unsupported_points_grid contains exactly one point. // in m_unsupported_points_grid contains exactly one point.
assert(m_unsupported_points.size() == m_unsupported_points_grid.size()); assert(m_unsupported_points.size() == m_unsupported_points_grid.size());
@ -96,12 +107,11 @@ void DistanceField::update(const Point& to_node, const Point& added_leaf)
} }
// Inside a circle at the end of the new leaf, or inside a rotated rectangle. // Inside a circle at the end of the new leaf, or inside a rotated rectangle.
// Remove unsupported leafs at this grid location. // Remove unsupported leafs at this grid location.
if (auto it = m_unsupported_points_grid.find(grid_addr); it != m_unsupported_points_grid.end()) { if (const size_t cell_idx = m_unsupported_points_grid.find_cell_idx(grid_addr); cell_idx != std::numeric_limits<size_t>::max()) {
std::list<UnsupportedCell>::iterator& list_it = it->second; const UnsupportedCell &cell = m_unsupported_points[cell_idx];
UnsupportedCell& cell = *list_it;
if ((cell.loc - added_leaf).cast<int64_t>().squaredNorm() <= m_supporting_radius2) { if ((cell.loc - added_leaf).cast<int64_t>().squaredNorm() <= m_supporting_radius2) {
m_unsupported_points.erase(list_it); m_unsupported_points_erased[cell_idx] = true;
m_unsupported_points_grid.erase(it); m_unsupported_points_grid.mark_erased(grid_addr);
} }
} }
} }

View File

@ -38,11 +38,17 @@ public:
* \return ``true`` if successful, or ``false`` if there are no more points * \return ``true`` if successful, or ``false`` if there are no more points
* to consider. * to consider.
*/ */
bool tryGetNextPoint(Point* p) const { bool tryGetNextPoint(Point *out_unsupported_location, size_t *out_unsupported_cell_idx, const size_t start_idx = 0) const
if (m_unsupported_points.empty()) {
return false; for (size_t point_idx = start_idx; point_idx < m_unsupported_points.size(); ++point_idx) {
*p = m_unsupported_points.front().loc; if (!m_unsupported_points_erased[point_idx]) {
return true; *out_unsupported_cell_idx = point_idx;
*out_unsupported_location = m_unsupported_points[point_idx].loc;
return true;
}
}
return false;
} }
/*! /*!
@ -77,7 +83,6 @@ protected:
*/ */
struct UnsupportedCell struct UnsupportedCell
{ {
UnsupportedCell(const Point &loc, coord_t dist_to_boundary) : loc(loc), dist_to_boundary(dist_to_boundary) {}
// The position of the center of this cell. // The position of the center of this cell.
Point loc; Point loc;
// How far this cell is removed from the ``current_outline`` polygon, the edge of the infill area. // How far this cell is removed from the ``current_outline`` polygon, the edge of the infill area.
@ -87,7 +92,8 @@ protected:
/*! /*!
* Cells which still need to be supported at some point. * Cells which still need to be supported at some point.
*/ */
std::list<UnsupportedCell> m_unsupported_points; std::vector<UnsupportedCell> m_unsupported_points;
std::vector<bool> m_unsupported_points_erased;
/*! /*!
* BoundingBox of all points in m_unsupported_points. Used for mapping of sign integer numbers to positive integer numbers. * BoundingBox of all points in m_unsupported_points. Used for mapping of sign integer numbers to positive integer numbers.
@ -98,7 +104,84 @@ protected:
* Links the unsupported points to a grid point, so that we can quickly look * Links the unsupported points to a grid point, so that we can quickly look
* up the cell belonging to a certain position in the grid. * up the cell belonging to a certain position in the grid.
*/ */
std::unordered_map<Point, std::list<UnsupportedCell>::iterator, PointHash> m_unsupported_points_grid;
class UnsupportedPointsGrid
{
public:
UnsupportedPointsGrid() = default;
void initialize(const std::vector<UnsupportedCell> &unsupported_points, const std::function<Point(const Point &)> &map_cell_to_grid)
{
if (unsupported_points.empty())
return;
BoundingBox unsupported_points_bbox;
for (const UnsupportedCell &cell : unsupported_points)
unsupported_points_bbox.merge(cell.loc);
m_size = unsupported_points.size();
m_grid_range = BoundingBox(map_cell_to_grid(unsupported_points_bbox.min), map_cell_to_grid(unsupported_points_bbox.max));
m_grid_size = m_grid_range.size() + Point::Ones();
m_data.assign(m_grid_size.y() * m_grid_size.x(), std::numeric_limits<size_t>::max());
m_data_erased.assign(m_grid_size.y() * m_grid_size.x(), true);
for (size_t cell_idx = 0; cell_idx < unsupported_points.size(); ++cell_idx) {
const size_t flat_idx = map_to_flat_array(map_cell_to_grid(unsupported_points[cell_idx].loc));
assert(m_data[flat_idx] == std::numeric_limits<size_t>::max());
m_data[flat_idx] = cell_idx;
m_data_erased[flat_idx] = false;
}
}
size_t size() const { return m_size; }
size_t find_cell_idx(const Point &grid_addr)
{
if (!m_grid_range.contains(grid_addr))
return std::numeric_limits<size_t>::max();
if (const size_t flat_idx = map_to_flat_array(grid_addr); !m_data_erased[flat_idx]) {
assert(m_data[flat_idx] != std::numeric_limits<size_t>::max());
return m_data[flat_idx];
}
return std::numeric_limits<size_t>::max();
}
void mark_erased(const Point &grid_addr)
{
assert(m_grid_range.contains(grid_addr));
if (!m_grid_range.contains(grid_addr))
return;
const size_t flat_idx = map_to_flat_array(grid_addr);
assert(!m_data_erased[flat_idx] && m_data[flat_idx] != std::numeric_limits<size_t>::max());
assert(m_size != 0);
m_data_erased[flat_idx] = true;
--m_size;
}
private:
size_t m_size = 0;
BoundingBox m_grid_range;
Point m_grid_size;
std::vector<size_t> m_data;
std::vector<bool> m_data_erased;
inline size_t map_to_flat_array(const Point &loc) const
{
const Point offset_loc = loc - m_grid_range.min;
const size_t flat_idx = m_grid_size.x() * offset_loc.y() + offset_loc.x();
assert(offset_loc.x() >= 0 && offset_loc.y() >= 0);
assert(flat_idx < m_grid_size.y() * m_grid_size.x());
return flat_idx;
}
};
UnsupportedPointsGrid m_unsupported_points_grid;
/*! /*!
* Maps the point to the grid coordinates. * Maps the point to the grid coordinates.

View File

@ -125,6 +125,8 @@ void Generator::generateTrees(const PrintObject &print_object, const std::functi
if (const BoundingBox &outlines_locator_bbox = outlines_locator.bbox(); outlines_locator_bbox.defined) if (const BoundingBox &outlines_locator_bbox = outlines_locator.bbox(); outlines_locator_bbox.defined)
below_outlines_bbox.merge(outlines_locator_bbox); below_outlines_bbox.merge(outlines_locator_bbox);
below_outlines_bbox.merge(get_extents(current_lightning_layer.tree_roots).inflated(SCALED_EPSILON));
outlines_locator.set_bbox(below_outlines_bbox); outlines_locator.set_bbox(below_outlines_bbox);
outlines_locator.create(below_outlines, locator_cell_size); outlines_locator.create(below_outlines, locator_cell_size);

View File

@ -10,6 +10,10 @@
#include "../../Geometry.hpp" #include "../../Geometry.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include <tbb/parallel_for.h>
#include <tbb/blocked_range2d.h>
#include <mutex>
namespace Slic3r::FillLightning { namespace Slic3r::FillLightning {
coord_t Layer::getWeightedDistance(const Point& boundary_loc, const Point& unsupported_location) coord_t Layer::getWeightedDistance(const Point& boundary_loc, const Point& unsupported_location)
@ -56,8 +60,9 @@ void Layer::generateNewTrees
// Until no more points need to be added to support all: // Until no more points need to be added to support all:
// Determine next point from tree/outline areas via distance-field // Determine next point from tree/outline areas via distance-field
Point unsupported_location; size_t unsupported_cell_idx = 0;
while (distance_field.tryGetNextPoint(&unsupported_location)) { Point unsupported_location;
while (distance_field.tryGetNextPoint(&unsupported_location, &unsupported_cell_idx, unsupported_cell_idx)) {
throw_on_cancel_callback(); throw_on_cancel_callback();
GroundingLocation grounding_loc = getBestGroundingLocation( GroundingLocation grounding_loc = getBestGroundingLocation(
unsupported_location, current_outlines, current_outlines_bbox, outlines_locator, supporting_radius, wall_supporting_radius, tree_node_locator); unsupported_location, current_outlines, current_outlines_bbox, outlines_locator, supporting_radius, wall_supporting_radius, tree_node_locator);
@ -141,30 +146,52 @@ GroundingLocation Layer::getBestGroundingLocation
const auto within_dist = coord_t((node_location - unsupported_location).cast<double>().norm()); const auto within_dist = coord_t((node_location - unsupported_location).cast<double>().norm());
NodeSPtr sub_tree{ nullptr }; NodeSPtr sub_tree{nullptr};
coord_t current_dist = getWeightedDistance(node_location, unsupported_location); coord_t current_dist = getWeightedDistance(node_location, unsupported_location);
if (current_dist >= wall_supporting_radius) { // Only reconnect tree roots to other trees if they are not already close to the outlines. if (current_dist >= wall_supporting_radius) { // Only reconnect tree roots to other trees if they are not already close to the outlines.
const coord_t search_radius = std::min(current_dist, within_dist); const coord_t search_radius = std::min(current_dist, within_dist);
BoundingBox region(unsupported_location - Point(search_radius, search_radius), unsupported_location + Point(search_radius + locator_cell_size, search_radius + locator_cell_size)); BoundingBox region(unsupported_location - Point(search_radius, search_radius), unsupported_location + Point(search_radius + locator_cell_size, search_radius + locator_cell_size));
region.min = to_grid_point(region.min, current_outlines_bbox); region.min = to_grid_point(region.min, current_outlines_bbox);
region.max = to_grid_point(region.max, current_outlines_bbox); region.max = to_grid_point(region.max, current_outlines_bbox);
Point grid_addr;
for (grid_addr.y() = region.min.y(); grid_addr.y() < region.max.y(); ++ grid_addr.y()) Point current_dist_grid_addr{std::numeric_limits<coord_t>::lowest(), std::numeric_limits<coord_t>::lowest()};
for (grid_addr.x() = region.min.x(); grid_addr.x() < region.max.x(); ++ grid_addr.x()) { std::mutex current_dist_mutex;
auto it_range = tree_node_locator.equal_range(grid_addr); tbb::parallel_for(tbb::blocked_range2d<coord_t>(region.min.y(), region.max.y(), region.min.x(), region.max.x()), [&current_dist, current_dist_copy = current_dist, &current_dist_mutex, &sub_tree, &current_dist_grid_addr, &exclude_tree = std::as_const(exclude_tree), &outline_locator = std::as_const(outline_locator), &supporting_radius = std::as_const(supporting_radius), &tree_node_locator = std::as_const(tree_node_locator), &unsupported_location = std::as_const(unsupported_location)](const tbb::blocked_range2d<coord_t> &range) -> void {
for (auto it = it_range.first; it != it_range.second; ++ it) { for (coord_t grid_addr_y = range.rows().begin(); grid_addr_y < range.rows().end(); ++grid_addr_y)
auto candidate_sub_tree = it->second.lock(); for (coord_t grid_addr_x = range.cols().begin(); grid_addr_x < range.cols().end(); ++grid_addr_x) {
if ((candidate_sub_tree && candidate_sub_tree != exclude_tree) && const Point local_grid_addr{grid_addr_x, grid_addr_y};
!(exclude_tree && exclude_tree->hasOffspring(candidate_sub_tree)) && NodeSPtr local_sub_tree{nullptr};
!polygonCollidesWithLineSegment(unsupported_location, candidate_sub_tree->getLocation(), outline_locator)) { coord_t local_current_dist = current_dist_copy;
const coord_t candidate_dist = candidate_sub_tree->getWeightedDistance(unsupported_location, supporting_radius); const auto it_range = tree_node_locator.equal_range(local_grid_addr);
if (candidate_dist < current_dist) { for (auto it = it_range.first; it != it_range.second; ++it) {
current_dist = candidate_dist; const NodeSPtr candidate_sub_tree = it->second.lock();
sub_tree = candidate_sub_tree; if ((candidate_sub_tree && candidate_sub_tree != exclude_tree) &&
!(exclude_tree && exclude_tree->hasOffspring(candidate_sub_tree)) &&
!polygonCollidesWithLineSegment(unsupported_location, candidate_sub_tree->getLocation(), outline_locator)) {
if (const coord_t candidate_dist = candidate_sub_tree->getWeightedDistance(unsupported_location, supporting_radius); candidate_dist < local_current_dist) {
local_current_dist = candidate_dist;
local_sub_tree = candidate_sub_tree;
}
}
}
// To always get the same result in a parallel version as in a non-parallel version,
// we need to preserve that for the same current_dist, we select the same sub_tree
// as in the non-parallel version. For this purpose, inside the variable
// current_dist_grid_addr is stored from with 2D grid position assigned sub_tree comes.
// And when there are two sub_tree with the same current_dist, one which will be found
// the first in the non-parallel version is selected.
{
std::lock_guard<std::mutex> lock(current_dist_mutex);
if (local_current_dist < current_dist ||
(local_current_dist == current_dist && (grid_addr_y < current_dist_grid_addr.y() ||
(grid_addr_y == current_dist_grid_addr.y() && grid_addr_x < current_dist_grid_addr.x())))) {
current_dist = local_current_dist;
sub_tree = local_sub_tree;
current_dist_grid_addr = local_grid_addr;
} }
} }
} }
} }); // end of parallel_for
} }
return ! sub_tree ? return ! sub_tree ?

View File

@ -269,6 +269,9 @@ protected:
std::optional<Point> m_last_grounding_location; //<! The last known grounding location, see 'getLastGroundingLocation()'. std::optional<Point> m_last_grounding_location; //<! The last known grounding location, see 'getLastGroundingLocation()'.
friend BoundingBox get_extents(const NodeSPtr &root_node);
friend BoundingBox get_extents(const std::vector<NodeSPtr> &tree_roots);
#ifdef LIGHTNING_TREE_NODE_DEBUG_OUTPUT #ifdef LIGHTNING_TREE_NODE_DEBUG_OUTPUT
friend void export_to_svg(const NodeSPtr &root_node, Slic3r::SVG &svg); friend void export_to_svg(const NodeSPtr &root_node, Slic3r::SVG &svg);
friend void export_to_svg(const std::string &path, const Polygons &contour, const std::vector<NodeSPtr> &root_nodes); friend void export_to_svg(const std::string &path, const Polygons &contour, const std::vector<NodeSPtr> &root_nodes);
@ -278,6 +281,23 @@ protected:
bool inside(const Polygons &polygons, const Point &p); bool inside(const Polygons &polygons, const Point &p);
bool lineSegmentPolygonsIntersection(const Point& a, const Point& b, const EdgeGrid::Grid& outline_locator, Point& result, coord_t within_max_dist); bool lineSegmentPolygonsIntersection(const Point& a, const Point& b, const EdgeGrid::Grid& outline_locator, Point& result, coord_t within_max_dist);
inline BoundingBox get_extents(const NodeSPtr &root_node)
{
BoundingBox bbox;
for (const NodeSPtr &children : root_node->m_children)
bbox.merge(get_extents(children));
bbox.merge(root_node->getLocation());
return bbox;
}
inline BoundingBox get_extents(const std::vector<NodeSPtr> &tree_roots)
{
BoundingBox bbox;
for (const NodeSPtr &root_node : tree_roots)
bbox.merge(get_extents(root_node));
return bbox;
}
#ifdef LIGHTNING_TREE_NODE_DEBUG_OUTPUT #ifdef LIGHTNING_TREE_NODE_DEBUG_OUTPUT
void export_to_svg(const NodeSPtr &root_node, SVG &svg); void export_to_svg(const NodeSPtr &root_node, SVG &svg);
void export_to_svg(const std::string &path, const Polygons &contour, const std::vector<NodeSPtr> &root_nodes); void export_to_svg(const std::string &path, const Polygons &contour, const std::vector<NodeSPtr> &root_nodes);

View File

@ -846,6 +846,29 @@ namespace Slic3r {
return false; return false;
} }
// If instances contain a single volume, the volume offset should be 0,0,0
// This equals to say that instance world position and volume world position should match
// Correct all instances/volumes for which this does not hold
for (int obj_id = 0; obj_id < int(model.objects.size()); ++obj_id) {
ModelObject* o = model.objects[obj_id];
if (o->volumes.size() == 1) {
ModelVolume* v = o->volumes.front();
const Slic3r::Geometry::Transformation& first_inst_trafo = o->instances.front()->get_transformation();
const Vec3d world_vol_offset = (first_inst_trafo * v->get_transformation()).get_offset();
const Vec3d world_inst_offset = first_inst_trafo.get_offset();
if (!world_vol_offset.isApprox(world_inst_offset)) {
const Slic3r::Geometry::Transformation& vol_trafo = v->get_transformation();
for (int inst_id = 0; inst_id < int(o->instances.size()); ++inst_id) {
ModelInstance* i = o->instances[inst_id];
const Slic3r::Geometry::Transformation& inst_trafo = i->get_transformation();
i->set_offset((inst_trafo * vol_trafo).get_offset());
}
v->set_offset(Vec3d::Zero());
}
}
}
#if ENABLE_RELOAD_FROM_DISK_REWORK #if ENABLE_RELOAD_FROM_DISK_REWORK
for (int obj_id = 0; obj_id < int(model.objects.size()); ++obj_id) { for (int obj_id = 0; obj_id < int(model.objects.size()); ++obj_id) {
ModelObject* o = model.objects[obj_id]; ModelObject* o = model.objects[obj_id];

View File

@ -903,6 +903,9 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_
const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), new_rotation); const double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), new_rotation);
volume.set_instance_offset(m_cache.dragging_center + Eigen::AngleAxisd(z_diff, Vec3d::UnitZ()) * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); volume.set_instance_offset(m_cache.dragging_center + Eigen::AngleAxisd(z_diff, Vec3d::UnitZ()) * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
} }
else if (!(m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center).isApprox(Vec3d::Zero()))
volume.set_instance_offset(m_cache.dragging_center + Geometry::assemble_transform(Vec3d::Zero(), new_rotation) * m_cache.volumes_data[i].get_instance_rotation_matrix().inverse() * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center));
#endif // ENABLE_WORLD_COORDINATE #endif // ENABLE_WORLD_COORDINATE
volume.set_instance_rotation(new_rotation); volume.set_instance_rotation(new_rotation);
object_instance_first[volume.object_idx()] = i; object_instance_first[volume.object_idx()] = i;
@ -1340,7 +1343,7 @@ int Selection::bake_transform_if_needed() const
if (needs_baking) { if (needs_baking) {
MessageDialog dlg((wxWindow*)wxGetApp().mainframe, MessageDialog dlg((wxWindow*)wxGetApp().mainframe,
_L("The currently manipulated object is tilted or contains tilted parts (rotation angles are not multiples of 90°). " _L("The currently manipulated object is tilted or contains tilted parts (rotation angles are not multiples of 90<EFBFBD>). "
"Non-uniform scaling of tilted objects is only possible in non-local coordinate systems, " "Non-uniform scaling of tilted objects is only possible in non-local coordinate systems, "
"once the rotation is embedded into the object coordinates.") + "\n" + "once the rotation is embedded into the object coordinates.") + "\n" +
_L("This operation is irreversible.") + "\n" + _L("This operation is irreversible.") + "\n" +

View File

@ -3,7 +3,7 @@
set(SLIC3R_APP_NAME "PrusaSlicer") set(SLIC3R_APP_NAME "PrusaSlicer")
set(SLIC3R_APP_KEY "PrusaSlicer") set(SLIC3R_APP_KEY "PrusaSlicer")
set(SLIC3R_VERSION "2.5.0-alpha0") set(SLIC3R_VERSION "2.6.0-alpha0")
set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN") set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN")
set(SLIC3R_RC_VERSION "2,5,0,0") set(SLIC3R_RC_VERSION "2,6,0,0")
set(SLIC3R_RC_VERSION_DOTS "2.5.0.0") set(SLIC3R_RC_VERSION_DOTS "2.6.0.0")