mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-21 06:21:16 +00:00
Merge upstream main: belt printing, texture displacement color mixing, 3MF component cycle checks, undo blocked during background jobs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
f970a607ae
227 files changed
+14506
-1079
No files matched your search
@@ -38,6 +38,11 @@
|
||||
#include <exception>
|
||||
#include "libslic3r/LifecycleEvents.hpp"
|
||||
#include <optional>
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
#define SAVE_ARRANGE_POLY 0
|
||||
|
||||
@@ -86,6 +91,14 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// The belt purge prism is generated from the arranged parts (ensure_belt_purge_tower),
|
||||
// so arrange neither moves it nor packs around it; it reserves the prism's strip instead.
|
||||
static bool is_belt_purge_prism(const ModelObject *mo)
|
||||
{
|
||||
const ConfigOption *opt = mo->config.option("belt_purge_tower_object");
|
||||
return opt != nullptr && opt->getBool();
|
||||
}
|
||||
|
||||
// BBS: add partplate logic
|
||||
static WipeTower get_wipe_tower(const Plater &plater, int plate_idx)
|
||||
{
|
||||
@@ -100,6 +113,63 @@ arrangement::ArrangePolygon get_wipetower_arrange_poly(WipeTower* tower)
|
||||
return ap;
|
||||
}
|
||||
|
||||
// Belt printers pack their parts against the edges of the bed, so what has to stay
|
||||
// free there is reserved with fixed virtual items on every plate, the way the bed's
|
||||
// own exclusion areas are:
|
||||
// - the strip the purge prism comes back to, flush with the far lateral edge (see
|
||||
// ensure_belt_purge_tower), when the parts use more than one filament;
|
||||
// - the brim along every edge: a belt brim is printed brim_width wide for every brim
|
||||
// type but none. Between parts the brims may overlap, as on any printer.
|
||||
void ArrangeJob::prepare_belt_regions(int num_plates)
|
||||
{
|
||||
if (!params.is_belt || params.is_seq_print)
|
||||
return;
|
||||
const DynamicPrintConfig &config = wxGetApp().preset_bundle->full_config();
|
||||
const BoundingBoxf bed = get_extents(config.opt<ConfigOptionPoints>("printable_area")->values);
|
||||
const bool belt_is_y = params.belt_axis == 1;
|
||||
std::vector<BoundingBoxf> regions;
|
||||
|
||||
std::set<int> filaments;
|
||||
for (const ArrangePolygons *items : { &m_selected, &m_unselected })
|
||||
for (const ArrangePolygon &ap : *items)
|
||||
if (!ap.is_virt_object)
|
||||
filaments.insert(ap.extrude_ids.begin(), ap.extrude_ids.end());
|
||||
if (config.opt_bool("enable_belt_purge_tower") && filaments.size() > 1) {
|
||||
// The prism is at least one millimetre per island plus the gaps between them.
|
||||
const int islands = int(filaments.size()) - 1;
|
||||
const double width = std::max(config.opt_float("belt_purge_tower_width"), 2. * islands - 1.) + 1.; // + the prism's edge inset
|
||||
BoundingBoxf strip = bed;
|
||||
if (belt_is_y)
|
||||
strip.min.x() = std::max(bed.min.x(), bed.max.x() - width);
|
||||
else
|
||||
strip.min.y() = std::max(bed.min.y(), bed.max.y() - width);
|
||||
regions.push_back(strip);
|
||||
}
|
||||
|
||||
// Virtual items are inflated by the one millimetre exclusion gap already.
|
||||
const double brim = config.opt_enum<BrimType>("brim_type") == btNoBrim ? 0. :
|
||||
config.opt_float("brim_width") + config.opt_float("brim_object_gap") + config.opt_float("extra_brim_width") - 1.;
|
||||
if (brim > 0.) {
|
||||
regions.emplace_back(bed.min, Vec2d(bed.min.x() + brim, bed.max.y()));
|
||||
regions.emplace_back(Vec2d(bed.max.x() - brim, bed.min.y()), bed.max);
|
||||
regions.emplace_back(bed.min, Vec2d(bed.max.x(), bed.min.y() + brim));
|
||||
regions.emplace_back(Vec2d(bed.min.x(), bed.max.y() - brim), bed.max);
|
||||
}
|
||||
|
||||
for (int j = 0; j < num_plates; ++j)
|
||||
for (size_t i = 0; i < regions.size(); ++i) {
|
||||
ArrangePolygon ap;
|
||||
ap.poly.contour = scaled(regions[i]).polygon();
|
||||
ap.translation = Vec2crd(0, 0);
|
||||
ap.rotation = 0.f;
|
||||
ap.is_virt_object = true;
|
||||
ap.bed_idx = j;
|
||||
ap.height = 1;
|
||||
ap.name = "BeltRegion" + std::to_string(i);
|
||||
m_unselected.emplace_back(std::move(ap));
|
||||
}
|
||||
}
|
||||
|
||||
void ArrangeJob::clear_input()
|
||||
{
|
||||
const Model &model = m_plater->model();
|
||||
@@ -151,6 +221,8 @@ void ArrangeJob::prepare_selected() {
|
||||
for (size_t oidx = 0; oidx < model.objects.size(); ++oidx) {
|
||||
const Selection::InstanceIdxsList* instlist = obj_sel[oidx];
|
||||
ModelObject* mo = model.objects[oidx];
|
||||
if (is_belt_purge_prism(mo))
|
||||
continue;
|
||||
|
||||
std::vector<bool> inst_sel(mo->instances.size(), false);
|
||||
|
||||
@@ -199,6 +271,7 @@ void ArrangeJob::prepare_selected() {
|
||||
}
|
||||
|
||||
prepare_wipe_tower();
|
||||
prepare_belt_regions(MAX_NUM_PLATES);
|
||||
|
||||
|
||||
// The strides have to be removed from the fixed items. For the
|
||||
@@ -229,6 +302,8 @@ void ArrangeJob::prepare_all() {
|
||||
// Go through the objects and check if inside the selection
|
||||
for (size_t oidx = 0; oidx < model.objects.size(); ++oidx) {
|
||||
ModelObject *mo = model.objects[oidx];
|
||||
if (is_belt_purge_prism(mo))
|
||||
continue;
|
||||
|
||||
for (size_t i = 0; i < mo->instances.size(); ++i) {
|
||||
ModelInstance * mi = mo->instances[i];
|
||||
@@ -275,6 +350,7 @@ void ArrangeJob::prepare_all() {
|
||||
|
||||
// add the virtual object into unselect list if has
|
||||
plate_list.preprocess_exclude_areas(m_unselected, enable_wrapping, MAX_NUM_PLATES);
|
||||
prepare_belt_regions(MAX_NUM_PLATES);
|
||||
}
|
||||
|
||||
arrangement::ArrangePolygon estimate_wipe_tower_info(int plate_index, std::set<int>& extruder_ids)
|
||||
@@ -313,6 +389,11 @@ void ArrangeJob::prepare_wipe_tower()
|
||||
bool enable_prime_tower = op && op->getBool();
|
||||
if (!enable_prime_tower || params.is_seq_print) return;
|
||||
|
||||
// Belt printers have no classic wipe tower; purging goes into the belt purge
|
||||
// prism, whose strip prepare_belt_regions() reserves.
|
||||
if (params.is_belt)
|
||||
return;
|
||||
|
||||
bool smooth_timelapse = false;
|
||||
auto sop = current_config.option("timelapse_type");
|
||||
if (sop) { smooth_timelapse = sop->getInt() == TimelapseType::tlSmooth; }
|
||||
@@ -416,6 +497,8 @@ void ArrangeJob::prepare_partplate() {
|
||||
for (size_t oidx = 0; oidx < model.objects.size(); ++oidx)
|
||||
{
|
||||
ModelObject* mo = model.objects[oidx];
|
||||
if (is_belt_purge_prism(mo))
|
||||
continue;
|
||||
for (size_t inst_idx = 0; inst_idx < mo->instances.size(); ++inst_idx)
|
||||
{
|
||||
bool in_plate = plate->contain_instance(oidx, inst_idx) || plate->intersect_instance(oidx, inst_idx);
|
||||
@@ -451,6 +534,7 @@ void ArrangeJob::prepare_partplate() {
|
||||
|
||||
// add the virtual object into unselect list if has
|
||||
plate_list.preprocess_exclude_areas(m_unselected, enable_wrapping, current_plate_index + 1);
|
||||
prepare_belt_regions(current_plate_index + 1);
|
||||
}
|
||||
|
||||
//BBS: add partplate logic
|
||||
@@ -858,6 +942,19 @@ arrangement::ArrangeParams init_arrange_params(Plater *p)
|
||||
params.is_seq_print = settings.is_seq_print;
|
||||
params.min_obj_distance = scaled(settings.distance);
|
||||
params.align_to_y_axis = settings.align_to_y_axis;
|
||||
if (print_config.belt_printer.value) {
|
||||
// Parts print in belt order: the belt runs across the gantry's tilt axis, a
|
||||
// rotation about X prints toward +Y and one about Y toward -X (see
|
||||
// BeltTransform), a negative angle flips that, and a tilted layer reaches
|
||||
// cot(angle) * height past a part's far edge.
|
||||
const BeltRotationAxis axis = print_config.belt_slice_rotation.value;
|
||||
const double angle = print_config.belt_slice_rotation_angle.value;
|
||||
const bool tilted = (axis == BeltRotationAxis::X || axis == BeltRotationAxis::Y) && std::abs(angle) > EPSILON;
|
||||
params.is_belt = true;
|
||||
params.belt_axis = axis == BeltRotationAxis::Y ? 0 : 1;
|
||||
params.belt_reversed = tilted && ((axis == BeltRotationAxis::Y) != (angle < 0.));
|
||||
params.belt_tilt_slope = tilted ? float(1. / std::tan(Geometry::deg2rad(std::clamp(std::abs(angle), 5., 90.)))) : 0.f;
|
||||
}
|
||||
|
||||
int state = p->get_prepare_state();
|
||||
if (state == Job::JobPrepareState::PREPARE_STATE_MENU) {
|
||||
|
||||
Reference in new issue
Block a user