This commit is contained in:
enricoturri1966 2023-10-19 10:33:52 +02:00
commit 33e40512f8
4 changed files with 126 additions and 139 deletions

View File

@ -3,7 +3,6 @@
///|/ ///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher ///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/ ///|/
#include "libslic3r.h"
#include "ConflictChecker.hpp" #include "ConflictChecker.hpp"
#include <tbb/parallel_for.h> #include <tbb/parallel_for.h>
@ -94,6 +93,91 @@ inline Grids line_rasterization(const Line &line, int64_t xdist = RasteXDistance
} }
} // namespace RasterizationImpl } // namespace RasterizationImpl
static std::vector<ExtrusionPaths> getFakeExtrusionPathsFromWipeTower(const WipeTowerData& wtd)
{
float h = wtd.height;
float lh = wtd.first_layer_height;
int d = scale_(wtd.depth);
int w = scale_(wtd.width);
int bd = scale_(wtd.brim_width);
Point minCorner = { -wtd.brim_width, -wtd.brim_width };
Point maxCorner = { minCorner.x() + w + bd, minCorner.y() + d + bd };
float width = wtd.width;
float depth = wtd.depth;
float height = wtd.height;
float cone_angle = wtd.cone_angle;
const auto& z_and_depth_pairs = wtd.z_and_depth_pairs;
const auto [cone_base_R, cone_scale_x] = WipeTower::get_wipe_tower_cone_base(width, height, depth, cone_angle);
std::vector<ExtrusionPaths> paths;
for (float hh = 0.f; hh < h; hh += lh) {
if (hh != 0.f) {
// The wipe tower may be getting smaller. Find the depth for this layer.
size_t i = 0;
for (i=0; i<z_and_depth_pairs.size()-1; ++i)
if (hh >= z_and_depth_pairs[i].first && hh < z_and_depth_pairs[i+1].first)
break;
d = scale_(z_and_depth_pairs[i].second);
minCorner = {0.f, -d/2 + scale_(z_and_depth_pairs.front().second/2.f)};
maxCorner = { minCorner.x() + w, minCorner.y() + d };
}
ExtrusionPath path({ minCorner, {maxCorner.x(), minCorner.y()}, maxCorner, {minCorner.x(), maxCorner.y()}, minCorner },
ExtrusionAttributes{ ExtrusionRole::WipeTower, ExtrusionFlow{ 0.0, 0.0, lh } });
paths.push_back({ path });
// We added the border, now add several parallel lines so we can detect an object that is fully inside the tower.
// For now, simply use fixed spacing of 3mm.
for (coord_t y=minCorner.y()+scale_(3.); y<maxCorner.y(); y+=scale_(3.)) {
path.polyline = { {minCorner.x(), y}, {maxCorner.x(), y} };
paths.back().emplace_back(path);
}
// And of course the stabilization cone and its base...
if (cone_base_R > 0.) {
path.polyline.clear();
double r = cone_base_R * (1 - hh/height);
for (double alpha=0; alpha<2.01*M_PI; alpha+=2*M_PI/20.)
path.polyline.points.emplace_back(Point::new_scale(width/2. + r * std::cos(alpha)/cone_scale_x, depth/2. + r * std::sin(alpha)));
paths.back().emplace_back(path);
if (hh == 0.f) { // Cone brim.
for (float bw=wtd.brim_width; bw>0.f; bw-=3.f) {
path.polyline.clear();
for (double alpha=0; alpha<2.01*M_PI; alpha+=2*M_PI/20.) // see load_wipe_tower_preview, where the same is a bit clearer
path.polyline.points.emplace_back(Point::new_scale(
width/2. + cone_base_R * std::cos(alpha)/cone_scale_x * (1. + cone_scale_x*bw/cone_base_R),
depth/2. + cone_base_R * std::sin(alpha) * (1. + bw/cone_base_R))
);
paths.back().emplace_back(path);
}
}
}
// Only the first layer has brim.
if (hh == 0.f) {
minCorner = minCorner + Point(bd, bd);
maxCorner = maxCorner - Point(bd, bd);
}
}
// Rotate and translate the tower into the final position.
for (ExtrusionPaths& ps : paths) {
for (ExtrusionPath& p : ps) {
p.polyline.rotate(Geometry::deg2rad(wtd.rotation_angle));
p.polyline.translate(scale_(wtd.position.x()), scale_(wtd.position.y()));
}
}
return paths;
}
void LinesBucketQueue::emplace_back_bucket(std::vector<ExtrusionPaths> &&paths, const void *objPtr, Points offsets) void LinesBucketQueue::emplace_back_bucket(std::vector<ExtrusionPaths> &&paths, const void *objPtr, Points offsets)
{ {
if (_objsPtrToId.find(objPtr) == _objsPtrToId.end()) { if (_objsPtrToId.find(objPtr) == _objsPtrToId.end()) {
@ -170,14 +254,14 @@ ExtrusionPaths getExtrusionPathsFromLayer(LayerRegionPtrs layerRegionPtrs)
return paths; return paths;
} }
ExtrusionPaths getExtrusionPathsFromSupportLayer(SupportLayer *supportLayer) ExtrusionPaths getExtrusionPathsFromSupportLayer(const SupportLayer *supportLayer)
{ {
ExtrusionPaths paths; ExtrusionPaths paths;
getExtrusionPathsFromEntity(&supportLayer->support_fills, paths); getExtrusionPathsFromEntity(&supportLayer->support_fills, paths);
return paths; return paths;
} }
std::pair<std::vector<ExtrusionPaths>, std::vector<ExtrusionPaths>> getAllLayersExtrusionPathsFromObject(PrintObject *obj) std::pair<std::vector<ExtrusionPaths>, std::vector<ExtrusionPaths>> getAllLayersExtrusionPathsFromObject(const PrintObject *obj)
{ {
std::vector<ExtrusionPaths> objPaths, supportPaths; std::vector<ExtrusionPaths> objPaths, supportPaths;
@ -208,17 +292,23 @@ ConflictComputeOpt ConflictChecker::find_inter_of_lines(const LineWithIDs &lines
return {}; return {};
} }
ConflictResultOpt ConflictChecker::find_inter_of_lines_in_diff_objs(PrintObjectPtrs objs, ConflictResultOpt ConflictChecker::find_inter_of_lines_in_diff_objs(SpanOfConstPtrs<PrintObject> objs,
std::optional<const FakeWipeTower *> wtdptr) // find the first intersection point of lines in different objects const WipeTowerData& wipe_tower_data) // find the first intersection point of lines in different objects
{ {
if (objs.empty() || (objs.size() == 1 && objs.front()->instances().size() == 1)) { return {}; } if (objs.empty() || (objs.size() == 1 && objs.front()->instances().size() == 1)) { return {}; }
// The code ported from BS uses void* to identify objects...
// Let's use the address of this variable to represent the wipe tower.
int wtptr = 0;
LinesBucketQueue conflictQueue; LinesBucketQueue conflictQueue;
if (wtdptr.has_value()) { // wipe tower at 0 by default if (! wipe_tower_data.z_and_depth_pairs.empty()) {
std::vector<ExtrusionPaths> wtpaths = (*wtdptr)->getFakeExtrusionPathsFromWipeTower(); // The wipe tower is being generated.
conflictQueue.emplace_back_bucket(std::move(wtpaths), *wtdptr, Points{Point((*wtdptr)->plate_origin)}); const Vec2d plate_origin = Vec2d::Zero();
std::vector<ExtrusionPaths> wtpaths = getFakeExtrusionPathsFromWipeTower(wipe_tower_data);
conflictQueue.emplace_back_bucket(std::move(wtpaths), &wtptr, Points{Point(plate_origin)});
} }
for (PrintObject *obj : objs) { for (const PrintObject *obj : objs) {
std::pair<std::vector<ExtrusionPaths>, std::vector<ExtrusionPaths>> layers = getAllLayersExtrusionPathsFromObject(obj); std::pair<std::vector<ExtrusionPaths>, std::vector<ExtrusionPaths>> layers = getAllLayersExtrusionPathsFromObject(obj);
Points instances_shifts; Points instances_shifts;
@ -261,13 +351,11 @@ ConflictResultOpt ConflictChecker::find_inter_of_lines_in_diff_objs(PrintObjectP
const void *ptr1 = conflictQueue.idToObjsPtr(conflict[0].first._obj1); const void *ptr1 = conflictQueue.idToObjsPtr(conflict[0].first._obj1);
const void *ptr2 = conflictQueue.idToObjsPtr(conflict[0].first._obj2); const void *ptr2 = conflictQueue.idToObjsPtr(conflict[0].first._obj2);
double conflictHeight = conflict[0].second; double conflictHeight = conflict[0].second;
if (wtdptr.has_value()) { if (ptr1 == &wtptr || ptr2 == &wtptr) {
const FakeWipeTower* wtdp = *wtdptr; assert(! wipe_tower_data.z_and_depth_pairs.empty());
if (ptr1 == wtdp || ptr2 == wtdp) { if (ptr2 == &wtptr) { std::swap(ptr1, ptr2); }
if (ptr2 == wtdp) { std::swap(ptr1, ptr2); } const PrintObject *obj2 = reinterpret_cast<const PrintObject *>(ptr2);
const PrintObject *obj2 = reinterpret_cast<const PrintObject *>(ptr2); return std::make_optional<ConflictResult>("WipeTower", obj2->model_object()->name, conflictHeight, nullptr, ptr2);
return std::make_optional<ConflictResult>("WipeTower", obj2->model_object()->name, conflictHeight, nullptr, ptr2);
}
} }
const PrintObject *obj1 = reinterpret_cast<const PrintObject *>(ptr1); const PrintObject *obj1 = reinterpret_cast<const PrintObject *>(ptr1);
const PrintObject *obj2 = reinterpret_cast<const PrintObject *>(ptr2); const PrintObject *obj2 = reinterpret_cast<const PrintObject *>(ptr2);

View File

@ -6,10 +6,7 @@
#ifndef slic3r_ConflictChecker_hpp_ #ifndef slic3r_ConflictChecker_hpp_
#define slic3r_ConflictChecker_hpp_ #define slic3r_ConflictChecker_hpp_
#include "../Utils.hpp" #include "libslic3r/Print.hpp"
#include "../Model.hpp"
#include "../Print.hpp"
#include "../Layer.hpp"
#include <queue> #include <queue>
#include <vector> #include <vector>
@ -124,7 +121,7 @@ using ConflictObjName = std::optional<std::pair<std::string, std::string>>;
struct ConflictChecker struct ConflictChecker
{ {
static ConflictResultOpt find_inter_of_lines_in_diff_objs(PrintObjectPtrs objs, std::optional<const FakeWipeTower *> wtdptr); static ConflictResultOpt find_inter_of_lines_in_diff_objs(SpanOfConstPtrs<PrintObject> objs, const WipeTowerData& wtd);
static ConflictComputeOpt find_inter_of_lines(const LineWithIDs &lines); static ConflictComputeOpt find_inter_of_lines(const LineWithIDs &lines);
static ConflictComputeOpt line_intersect(const LineWithID &l1, const LineWithID &l2); static ConflictComputeOpt line_intersect(const LineWithID &l1, const LineWithID &l2);
}; };

View File

@ -1011,12 +1011,13 @@ void Print::process()
this->set_done(psSkirtBrim); this->set_done(psSkirtBrim);
} }
std::optional<const FakeWipeTower*> wipe_tower_opt = {};
if (this->has_wipe_tower()) { if (this->has_wipe_tower()) {
m_fake_wipe_tower.set_pos_and_rotation({ m_config.wipe_tower_x, m_config.wipe_tower_y }, m_config.wipe_tower_rotation_angle); // These values have to be updated here, not during wipe tower generation.
wipe_tower_opt = std::make_optional<const FakeWipeTower*>(&m_fake_wipe_tower); // When the wipe tower is moved/rotated, it is not regenerated.
m_wipe_tower_data.position = { m_config.wipe_tower_x, m_config.wipe_tower_y };
m_wipe_tower_data.rotation_angle = m_config.wipe_tower_rotation_angle;
} }
auto conflictRes = ConflictChecker::find_inter_of_lines_in_diff_objs(m_objects, wipe_tower_opt); auto conflictRes = ConflictChecker::find_inter_of_lines_in_diff_objs(objects(), m_wipe_tower_data);
m_conflict_result = conflictRes; m_conflict_result = conflictRes;
if (conflictRes.has_value()) if (conflictRes.has_value())
@ -1505,9 +1506,6 @@ void Print::_make_wipe_tower()
// Initialize the wipe tower. // Initialize the wipe tower.
WipeTower wipe_tower(m_config, m_default_region_config, wipe_volumes, m_wipe_tower_data.tool_ordering.first_extruder()); WipeTower wipe_tower(m_config, m_default_region_config, wipe_volumes, m_wipe_tower_data.tool_ordering.first_extruder());
//wipe_tower.set_retract();
//wipe_tower.set_zhop();
// Set the extruder & material properties at the wipe tower object. // Set the extruder & material properties at the wipe tower object.
for (size_t i = 0; i < m_config.nozzle_diameter.size(); ++ i) for (size_t i = 0; i < m_config.nozzle_diameter.size(); ++ i)
wipe_tower.set_extruder(i, m_config); wipe_tower.set_extruder(i, m_config);
@ -1576,10 +1574,9 @@ void Print::_make_wipe_tower()
m_wipe_tower_data.used_filament = wipe_tower.get_used_filament(); m_wipe_tower_data.used_filament = wipe_tower.get_used_filament();
m_wipe_tower_data.number_of_toolchanges = wipe_tower.get_number_of_toolchanges(); m_wipe_tower_data.number_of_toolchanges = wipe_tower.get_number_of_toolchanges();
const Vec3d origin = Vec3d::Zero(); m_wipe_tower_data.width = wipe_tower.width();
m_fake_wipe_tower.set_fake_extrusion_data(wipe_tower.position(), wipe_tower.width(), wipe_tower.get_wipe_tower_height(), config().first_layer_height, m_wipe_tower_data.depth, m_wipe_tower_data.first_layer_height = config().first_layer_height;
m_wipe_tower_data.z_and_depth_pairs, m_wipe_tower_data.brim_width, config().wipe_tower_rotation_angle, config().wipe_tower_cone_angle, {scale_(origin.x()), scale_(origin.y())}); m_wipe_tower_data.cone_angle = config().wipe_tower_cone_angle;
} }
// Generate a recommended G-code output file name based on the format template, default extension, and template parameters // Generate a recommended G-code output file name based on the format template, default extension, and template parameters
@ -1668,80 +1665,5 @@ std::string PrintStatistics::finalize_output_path(const std::string &path_in) co
return final_path; return final_path;
} }
std::vector<ExtrusionPaths> FakeWipeTower::getFakeExtrusionPathsFromWipeTower() const
{
float h = height;
float lh = layer_height;
int d = scale_(depth);
int w = scale_(width);
int bd = scale_(brim_width);
Point minCorner = { -bd, -bd };
Point maxCorner = { minCorner.x() + w + bd, minCorner.y() + d + bd };
const auto [cone_base_R, cone_scale_x] = WipeTower::get_wipe_tower_cone_base(width, height, depth, cone_angle);
std::vector<ExtrusionPaths> paths;
for (float hh = 0.f; hh < h; hh += lh) {
if (hh != 0.f) {
// The wipe tower may be getting smaller. Find the depth for this layer.
size_t i = 0;
for (i=0; i<z_and_depth_pairs.size()-1; ++i)
if (hh >= z_and_depth_pairs[i].first && hh < z_and_depth_pairs[i+1].first)
break;
d = scale_(z_and_depth_pairs[i].second);
minCorner = {0.f, -d/2 + scale_(z_and_depth_pairs.front().second/2.f)};
maxCorner = { minCorner.x() + w, minCorner.y() + d };
}
ExtrusionPath path({ minCorner, {maxCorner.x(), minCorner.y()}, maxCorner, {minCorner.x(), maxCorner.y()}, minCorner },
ExtrusionAttributes{ ExtrusionRole::WipeTower, ExtrusionFlow{ 0.0, 0.0, lh } });
paths.push_back({ path });
// We added the border, now add several parallel lines so we can detect an object that is fully inside the tower.
// For now, simply use fixed spacing of 3mm.
for (coord_t y=minCorner.y()+scale_(3.); y<maxCorner.y(); y+=scale_(3.)) {
path.polyline = { {minCorner.x(), y}, {maxCorner.x(), y} };
paths.back().emplace_back(path);
}
// And of course the stabilization cone and its base...
if (cone_base_R > 0.) {
path.polyline.clear();
double r = cone_base_R * (1 - hh/height);
for (double alpha=0; alpha<2.01*M_PI; alpha+=2*M_PI/20.)
path.polyline.points.emplace_back(Point::new_scale(width/2. + r * std::cos(alpha)/cone_scale_x, depth/2. + r * std::sin(alpha)));
paths.back().emplace_back(path);
if (hh == 0.f) { // Cone brim.
for (float bw=brim_width; bw>0.f; bw-=3.f) {
path.polyline.clear();
for (double alpha=0; alpha<2.01*M_PI; alpha+=2*M_PI/20.) // see load_wipe_tower_preview, where the same is a bit clearer
path.polyline.points.emplace_back(Point::new_scale(
width/2. + cone_base_R * std::cos(alpha)/cone_scale_x * (1. + cone_scale_x*bw/cone_base_R),
depth/2. + cone_base_R * std::sin(alpha) * (1. + bw/cone_base_R))
);
paths.back().emplace_back(path);
}
}
}
// Only the first layer has brim.
if (hh == 0.f) {
minCorner = minCorner + Point(bd, bd);
maxCorner = maxCorner - Point(bd, bd);
}
}
// Rotate and translate the tower into the final position.
for (ExtrusionPaths& ps : paths) {
for (ExtrusionPath& p : ps) {
p.polyline.rotate(Geometry::deg2rad(rotation_angle));
p.polyline.translate(scale_(pos.x()), scale_(pos.y()));
}
}
return paths;
}
} // namespace Slic3r } // namespace Slic3r

View File

@ -439,38 +439,7 @@ private:
FillLightning::GeneratorPtr m_lightning_generator; FillLightning::GeneratorPtr m_lightning_generator;
}; };
struct FakeWipeTower
{
// generate fake extrusion
Vec2f pos;
float width;
float height;
float layer_height;
float depth;
std::vector<std::pair<float, float>> z_and_depth_pairs;
float brim_width;
float rotation_angle;
float cone_angle;
Vec2d plate_origin;
void set_fake_extrusion_data(const Vec2f& p, float w, float h, float lh, float d, const std::vector<std::pair<float, float>>& zad, float bd, float ra, float ca, const Vec2d& o)
{
pos = p;
width = w;
height = h;
layer_height = lh;
depth = d;
z_and_depth_pairs = zad;
brim_width = bd;
rotation_angle = ra;
cone_angle = ca;
plate_origin = o;
}
void set_pos_and_rotation(const Vec2f& p, float rotation) { pos = p; rotation_angle = rotation; }
std::vector<ExtrusionPaths> getFakeExtrusionPathsFromWipeTower() const;
};
struct WipeTowerData struct WipeTowerData
{ {
@ -491,6 +460,13 @@ struct WipeTowerData
float brim_width; float brim_width;
float height; float height;
// Data needed to generate fake extrusions for conflict checking.
float width;
float first_layer_height;
float cone_angle;
Vec2d position;
float rotation_angle;
void clear() { void clear() {
priming.reset(nullptr); priming.reset(nullptr);
tool_changes.clear(); tool_changes.clear();
@ -499,6 +475,11 @@ struct WipeTowerData
number_of_toolchanges = -1; number_of_toolchanges = -1;
depth = 0.f; depth = 0.f;
brim_width = 0.f; brim_width = 0.f;
width = 0.f;
first_layer_height = 0.f;
cone_angle = 0.f;
position = Vec2d::Zero();
rotation_angle = 0.f;
} }
private: private:
@ -740,7 +721,6 @@ private:
friend class PrintObject; friend class PrintObject;
ConflictResultOpt m_conflict_result; ConflictResultOpt m_conflict_result;
FakeWipeTower m_fake_wipe_tower;
}; };
} /* slic3r_Print_hpp_ */ } /* slic3r_Print_hpp_ */