mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-12 20:29:04 +08:00
Merge branch 'master' of https://github.com/Prusa-Development/PrusaSlicerPrivate
This commit is contained in:
commit
33e40512f8
@ -3,7 +3,6 @@
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#include "libslic3r.h"
|
||||
#include "ConflictChecker.hpp"
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
@ -94,6 +93,91 @@ inline Grids line_rasterization(const Line &line, int64_t xdist = RasteXDistance
|
||||
}
|
||||
} // 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)
|
||||
{
|
||||
if (_objsPtrToId.find(objPtr) == _objsPtrToId.end()) {
|
||||
@ -170,14 +254,14 @@ ExtrusionPaths getExtrusionPathsFromLayer(LayerRegionPtrs layerRegionPtrs)
|
||||
return paths;
|
||||
}
|
||||
|
||||
ExtrusionPaths getExtrusionPathsFromSupportLayer(SupportLayer *supportLayer)
|
||||
ExtrusionPaths getExtrusionPathsFromSupportLayer(const SupportLayer *supportLayer)
|
||||
{
|
||||
ExtrusionPaths paths;
|
||||
getExtrusionPathsFromEntity(&supportLayer->support_fills, 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;
|
||||
|
||||
@ -208,17 +292,23 @@ ConflictComputeOpt ConflictChecker::find_inter_of_lines(const LineWithIDs &lines
|
||||
return {};
|
||||
}
|
||||
|
||||
ConflictResultOpt ConflictChecker::find_inter_of_lines_in_diff_objs(PrintObjectPtrs objs,
|
||||
std::optional<const FakeWipeTower *> wtdptr) // find the first intersection point of lines in different objects
|
||||
ConflictResultOpt ConflictChecker::find_inter_of_lines_in_diff_objs(SpanOfConstPtrs<PrintObject> objs,
|
||||
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 {}; }
|
||||
|
||||
// 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;
|
||||
if (wtdptr.has_value()) { // wipe tower at 0 by default
|
||||
std::vector<ExtrusionPaths> wtpaths = (*wtdptr)->getFakeExtrusionPathsFromWipeTower();
|
||||
conflictQueue.emplace_back_bucket(std::move(wtpaths), *wtdptr, Points{Point((*wtdptr)->plate_origin)});
|
||||
if (! wipe_tower_data.z_and_depth_pairs.empty()) {
|
||||
// The wipe tower is being generated.
|
||||
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);
|
||||
|
||||
Points instances_shifts;
|
||||
@ -261,14 +351,12 @@ ConflictResultOpt ConflictChecker::find_inter_of_lines_in_diff_objs(PrintObjectP
|
||||
const void *ptr1 = conflictQueue.idToObjsPtr(conflict[0].first._obj1);
|
||||
const void *ptr2 = conflictQueue.idToObjsPtr(conflict[0].first._obj2);
|
||||
double conflictHeight = conflict[0].second;
|
||||
if (wtdptr.has_value()) {
|
||||
const FakeWipeTower* wtdp = *wtdptr;
|
||||
if (ptr1 == wtdp || ptr2 == wtdp) {
|
||||
if (ptr2 == wtdp) { std::swap(ptr1, ptr2); }
|
||||
if (ptr1 == &wtptr || ptr2 == &wtptr) {
|
||||
assert(! wipe_tower_data.z_and_depth_pairs.empty());
|
||||
if (ptr2 == &wtptr) { std::swap(ptr1, ptr2); }
|
||||
const PrintObject *obj2 = reinterpret_cast<const PrintObject *>(ptr2);
|
||||
return std::make_optional<ConflictResult>("WipeTower", obj2->model_object()->name, conflictHeight, nullptr, ptr2);
|
||||
}
|
||||
}
|
||||
const PrintObject *obj1 = reinterpret_cast<const PrintObject *>(ptr1);
|
||||
const PrintObject *obj2 = reinterpret_cast<const PrintObject *>(ptr2);
|
||||
return std::make_optional<ConflictResult>(obj1->model_object()->name, obj2->model_object()->name, conflictHeight, ptr1, ptr2);
|
||||
|
@ -6,10 +6,7 @@
|
||||
#ifndef slic3r_ConflictChecker_hpp_
|
||||
#define slic3r_ConflictChecker_hpp_
|
||||
|
||||
#include "../Utils.hpp"
|
||||
#include "../Model.hpp"
|
||||
#include "../Print.hpp"
|
||||
#include "../Layer.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
@ -124,7 +121,7 @@ using ConflictObjName = std::optional<std::pair<std::string, std::string>>;
|
||||
|
||||
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 line_intersect(const LineWithID &l1, const LineWithID &l2);
|
||||
};
|
||||
|
@ -1011,12 +1011,13 @@ void Print::process()
|
||||
this->set_done(psSkirtBrim);
|
||||
}
|
||||
|
||||
std::optional<const FakeWipeTower*> wipe_tower_opt = {};
|
||||
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);
|
||||
wipe_tower_opt = std::make_optional<const FakeWipeTower*>(&m_fake_wipe_tower);
|
||||
// These values have to be updated here, not during wipe tower generation.
|
||||
// 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;
|
||||
if (conflictRes.has_value())
|
||||
@ -1505,9 +1506,6 @@ void Print::_make_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());
|
||||
|
||||
//wipe_tower.set_retract();
|
||||
//wipe_tower.set_zhop();
|
||||
|
||||
// Set the extruder & material properties at the wipe tower object.
|
||||
for (size_t i = 0; i < m_config.nozzle_diameter.size(); ++ i)
|
||||
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.number_of_toolchanges = wipe_tower.get_number_of_toolchanges();
|
||||
const Vec3d origin = Vec3d::Zero();
|
||||
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.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.width = wipe_tower.width();
|
||||
m_wipe_tower_data.first_layer_height = config().first_layer_height;
|
||||
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
|
||||
@ -1668,80 +1665,5 @@ std::string PrintStatistics::finalize_output_path(const std::string &path_in) co
|
||||
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
|
||||
|
@ -439,38 +439,7 @@ private:
|
||||
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
|
||||
{
|
||||
@ -491,6 +460,13 @@ struct WipeTowerData
|
||||
float brim_width;
|
||||
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() {
|
||||
priming.reset(nullptr);
|
||||
tool_changes.clear();
|
||||
@ -499,6 +475,11 @@ struct WipeTowerData
|
||||
number_of_toolchanges = -1;
|
||||
depth = 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:
|
||||
@ -740,7 +721,6 @@ private:
|
||||
friend class PrintObject;
|
||||
|
||||
ConflictResultOpt m_conflict_result;
|
||||
FakeWipeTower m_fake_wipe_tower;
|
||||
};
|
||||
|
||||
} /* slic3r_Print_hpp_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user