Improve scheduling. Use beam search only on combined regions. Add buffer distance when prime towers are clamped to edge

This commit is contained in:
sentientstardust
2026-06-01 16:30:16 +01:00
parent 5540971e7f
commit 94accf7a94
9 changed files with 460 additions and 114 deletions

View File

@@ -2070,14 +2070,17 @@ public:
bool run_one() override
{
int depth = -1;
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_error || m_next >= m_depths.size())
return false;
depth = m_depths[m_next++];
++m_active;
m_active.fetch_add(1, std::memory_order_acq_rel);
if (m_has_error.load(std::memory_order_acquire)) {
finish_active_call();
return false;
}
const size_t work_idx = m_next.fetch_add(1, std::memory_order_acq_rel);
if (work_idx >= m_depths.size()) {
finish_active_call();
return false;
}
const int depth = m_depths[work_idx];
std::vector<TopSurfaceImageContoningVectorRegion> regions;
std::exception_ptr error;
@@ -2088,19 +2091,10 @@ public:
error = std::current_exception();
}
int completed = 0;
bool done = false;
{
std::lock_guard<std::mutex> lock(m_mutex);
if (error && !m_error)
m_error = error;
--m_active;
completed = ++m_completed;
done = (m_error || m_next >= m_depths.size()) && m_active == 0;
m_done = m_done || done;
}
if (done)
m_cv.notify_all();
if (error)
store_error(error);
const int completed = int(m_completed.fetch_add(1, std::memory_order_acq_rel) + 1);
finish_active_call();
if (!error && m_progress)
m_progress(completed);
return true;
@@ -2109,22 +2103,47 @@ public:
void wait()
{
std::unique_lock<std::mutex> lock(m_mutex);
m_cv.wait(lock, [this]() { return m_done; });
m_cv.wait(lock, [this]() { return done(); });
if (m_error)
std::rethrow_exception(m_error);
}
private:
bool done() const
{
return (m_has_error.load(std::memory_order_acquire) ||
m_next.load(std::memory_order_acquire) >= m_depths.size()) &&
m_active.load(std::memory_order_acquire) == 0;
}
void store_error(std::exception_ptr error)
{
{
std::lock_guard<std::mutex> lock(m_mutex);
if (!m_error)
m_error = error;
}
m_has_error.store(true, std::memory_order_release);
m_cv.notify_all();
}
void finish_active_call()
{
m_active.fetch_sub(1, std::memory_order_acq_rel);
if (done())
m_cv.notify_all();
}
std::mutex m_mutex;
std::condition_variable m_cv;
std::vector<int> m_depths;
BuildFn m_build;
StoreFn m_store;
ProgressFn m_progress;
size_t m_next { 0 };
int m_active { 0 };
int m_completed { 0 };
bool m_done { false };
std::atomic<size_t> m_next { 0 };
std::atomic<int> m_active { 0 };
std::atomic<int> m_completed { 0 };
std::atomic<bool> m_has_error { false };
std::exception_ptr m_error;
};
@@ -2134,46 +2153,53 @@ public:
using RunFn = std::function<void(size_t)>;
using ProgressFn = std::function<void(size_t)>;
TopSurfaceImageContoningAnchoredIndexWork(size_t count, RunFn run, ProgressFn progress)
TopSurfaceImageContoningAnchoredIndexWork(size_t count, RunFn run, ProgressFn progress, size_t chunk_size = 64)
: m_count(count)
, m_run(std::move(run))
, m_progress(std::move(progress))
, m_chunk_size(std::max<size_t>(1, chunk_size))
{
m_done = m_count == 0;
}
size_t task_count() const
{
return (m_count + m_chunk_size - 1) / m_chunk_size;
}
bool run_one() override
{
size_t idx = 0;
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_error || m_next >= m_count)
return false;
idx = m_next++;
++m_active;
m_active.fetch_add(1, std::memory_order_acq_rel);
if (m_has_error.load(std::memory_order_acquire)) {
finish_active_call();
return false;
}
const size_t begin = m_next.fetch_add(m_chunk_size, std::memory_order_acq_rel);
if (begin >= m_count) {
finish_active_call();
return false;
}
const size_t end = std::min(begin + m_chunk_size, m_count);
std::exception_ptr error;
size_t processed = 0;
try {
m_run(idx);
for (size_t idx = begin; idx < end; ++idx) {
if (m_has_error.load(std::memory_order_acquire))
break;
m_run(idx);
++processed;
}
} catch (...) {
error = std::current_exception();
}
size_t completed = 0;
bool done = false;
{
std::lock_guard<std::mutex> lock(m_mutex);
if (error && !m_error)
m_error = error;
--m_active;
completed = ++m_completed;
done = (m_error || m_next >= m_count) && m_active == 0;
m_done = m_done || done;
}
if (done)
m_cv.notify_all();
if (!error && m_progress)
if (error)
store_error(error);
const size_t completed = processed == 0 ?
m_completed.load(std::memory_order_acquire) :
m_completed.fetch_add(processed, std::memory_order_acq_rel) + processed;
finish_active_call();
if (!error && processed > 0 && m_progress)
m_progress(completed);
return true;
}
@@ -2181,21 +2207,47 @@ public:
void wait()
{
std::unique_lock<std::mutex> lock(m_mutex);
m_cv.wait(lock, [this]() { return m_done; });
m_cv.wait(lock, [this]() { return done(); });
if (m_error)
std::rethrow_exception(m_error);
}
private:
bool done() const
{
return (m_has_error.load(std::memory_order_acquire) ||
m_next.load(std::memory_order_acquire) >= m_count) &&
m_active.load(std::memory_order_acquire) == 0;
}
void store_error(std::exception_ptr error)
{
{
std::lock_guard<std::mutex> lock(m_mutex);
if (!m_error)
m_error = error;
}
m_has_error.store(true, std::memory_order_release);
m_cv.notify_all();
}
void finish_active_call()
{
m_active.fetch_sub(1, std::memory_order_acq_rel);
if (done())
m_cv.notify_all();
}
std::mutex m_mutex;
std::condition_variable m_cv;
size_t m_count { 0 };
RunFn m_run;
ProgressFn m_progress;
size_t m_next { 0 };
int m_active { 0 };
size_t m_completed { 0 };
bool m_done { false };
size_t m_chunk_size { 1 };
std::atomic<size_t> m_next { 0 };
std::atomic<int> m_active { 0 };
std::atomic<size_t> m_completed { 0 };
std::atomic<bool> m_has_error { false };
std::exception_ptr m_error;
};
@@ -2307,6 +2359,8 @@ struct TopSurfaceImageContoningStackPlanKey {
bool variable_layer_height_compensation { false };
bool beam_search_stack_expansion { false };
int mix_model { TextureMappingZone::DefaultGenericSolverMixModel };
int color_prediction_mode { TextureMappingZone::DefaultTopSurfaceContoningColorPredictionMode };
std::string calibrated_stack_model_key;
bool operator<(const TopSurfaceImageContoningStackPlanKey &rhs) const
{
@@ -2343,7 +2397,9 @@ struct TopSurfaceImageContoningStackPlanKey {
td_effective_alpha_correction,
variable_layer_height_compensation,
beam_search_stack_expansion,
mix_model) <
mix_model,
color_prediction_mode,
calibrated_stack_model_key) <
std::tie(rhs.source_layer,
rhs.source_layer_id,
rhs.target_layer,
@@ -2377,7 +2433,9 @@ struct TopSurfaceImageContoningStackPlanKey {
rhs.td_effective_alpha_correction,
rhs.variable_layer_height_compensation,
rhs.beam_search_stack_expansion,
rhs.mix_model);
rhs.mix_model,
rhs.color_prediction_mode,
rhs.calibrated_stack_model_key);
}
};
@@ -4606,6 +4664,31 @@ static std::optional<TopSurfaceImageContoningSolvedLabel> top_surface_image_cont
label_by_stack);
}
static std::optional<TopSurfaceImageContoningSolvedLabel> top_surface_image_contoning_solve_provisional_label(
const std::array<float, 3> &rgb,
int solve_layers,
const TextureMappingContoningSolver &solver,
bool lower_surface,
const std::vector<float> &surface_to_deep_layer_heights_mm,
std::vector<TopSurfaceImageContoningVectorLabel> &labels,
std::map<std::pair<std::vector<unsigned int>, int>, int> &label_by_stack)
{
const int visible_layers = solve_layers;
TextureMappingContoningStack stack =
solver.solve_without_beam_search_stack_expansion(rgb,
solve_layers,
lower_surface,
visible_layers,
surface_to_deep_layer_heights_mm);
return top_surface_image_contoning_label_for_stack(stack,
solver,
lower_surface,
visible_layers,
surface_to_deep_layer_heights_mm,
labels,
label_by_stack);
}
static void top_surface_image_contoning_resolve_merged_grid_regions(
std::vector<int> &grid,
int cols,
@@ -4926,11 +5009,12 @@ static void top_surface_image_contoning_solve_anchored_region(
cell_samples[grid_idx] = sample;
cell_available_depths[grid_idx] = sample->available_depth;
++debug_sampled_cell_count;
cell_stacks[grid_idx] = solver.solve(sample->rgb,
sample->solve_layers,
lower_surface,
sample->available_depth,
source_context.surface_to_deep_layer_heights_mm);
cell_stacks[grid_idx] =
solver.solve_without_beam_search_stack_expansion(sample->rgb,
sample->solve_layers,
lower_surface,
sample->solve_layers,
source_context.surface_to_deep_layer_heights_mm);
if (debug_stride > 0 &&
row % debug_stride == 0 &&
col % debug_stride == 0) {
@@ -4969,7 +5053,7 @@ static void top_surface_image_contoning_solve_anchored_region(
if (build_state != nullptr)
build_state->set_work(sample_work);
try {
tbb::parallel_for(tbb::blocked_range<size_t>(0, grid_cells, 32),
tbb::parallel_for(tbb::blocked_range<size_t>(0, sample_work->task_count(), 1),
[&](const tbb::blocked_range<size_t> &range) {
for (size_t idx = range.begin(); idx != range.end(); ++idx)
sample_work->run_one();
@@ -4990,7 +5074,7 @@ static void top_surface_image_contoning_solve_anchored_region(
const size_t grid_idx = size_t(row * cols + col);
if (!cell_samples[grid_idx])
continue;
label_cell(row, col, cell_stacks[grid_idx], cell_samples[grid_idx]->available_depth);
label_cell(row, col, cell_stacks[grid_idx], cell_samples[grid_idx]->solve_layers);
}
}
if (debug_enabled) {
@@ -5542,6 +5626,8 @@ static TopSurfaceImageContoningStackPlanKey top_surface_image_contoning_anchored
key.variable_layer_height_compensation = plan.contoning_variable_layer_height_compensation_enabled;
key.beam_search_stack_expansion = plan.contoning_beam_search_stack_expansion_enabled;
key.mix_model = plan.contoning_generic_solver_mix_model;
key.color_prediction_mode = zone.effective_top_surface_contoning_color_prediction_mode();
key.calibrated_stack_model_key = solver.calibrated_stack_model_key();
return key;
}
@@ -5667,17 +5753,16 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
std::vector<TopSurfaceImageContoningVectorLabel> labels;
std::map<std::pair<std::vector<unsigned int>, int>, int> label_by_stack;
auto solve_cell = [&](int row, int col, const std::array<float, 3> &target_rgb, int solve_layers, int available_depth) {
auto solve_cell = [&](int row, int col, const std::array<float, 3> &target_rgb, int solve_layers, int) {
std::optional<TopSurfaceImageContoningSolvedLabel> solved =
top_surface_image_contoning_solve_label(target_rgb,
solve_layers,
available_depth,
solver,
source_surface == TopSurfaceImageSourceSurface::Bottom &&
plan.contoning_td_adjustment_enabled,
source->surface_to_deep_layer_heights_mm,
labels,
label_by_stack);
top_surface_image_contoning_solve_provisional_label(target_rgb,
solve_layers,
solver,
source_surface == TopSurfaceImageSourceSurface::Bottom &&
plan.contoning_td_adjustment_enabled,
source->surface_to_deep_layer_heights_mm,
labels,
label_by_stack);
if (!solved)
return std::optional<TopSurfaceImageContoningSolvedLabel>();
grid[size_t(row * cols + col)] = solved->label;
@@ -5884,15 +5969,14 @@ static std::shared_ptr<const TopSurfaceImageContoningStackPlan> top_surface_imag
auto solve_cell = [&](int row, int col, const std::array<float, 3> &target_rgb, int solve_layers, int available_depth) {
std::optional<TopSurfaceImageContoningSolvedLabel> solved =
top_surface_image_contoning_solve_label(target_rgb,
solve_layers,
available_depth,
solver,
source_surface == TopSurfaceImageSourceSurface::Bottom &&
plan.contoning_td_adjustment_enabled,
source_context->surface_to_deep_layer_heights_mm,
out->labels,
label_by_stack);
top_surface_image_contoning_solve_provisional_label(target_rgb,
solve_layers,
solver,
source_surface == TopSurfaceImageSourceSurface::Bottom &&
plan.contoning_td_adjustment_enabled,
source_context->surface_to_deep_layer_heights_mm,
out->labels,
label_by_stack);
if (!solved)
return std::optional<TopSurfaceImageContoningSolvedLabel>();
TopSurfaceImageContoningStackPlanCell &cell = out->cells[size_t(row * cols + col)];
@@ -6088,6 +6172,8 @@ static TopSurfaceImageContoningStackPlanKey top_surface_image_contoning_stack_pl
key.variable_layer_height_compensation = plan.contoning_variable_layer_height_compensation_enabled;
key.beam_search_stack_expansion = plan.contoning_beam_search_stack_expansion_enabled;
key.mix_model = plan.contoning_generic_solver_mix_model;
key.color_prediction_mode = zone.effective_top_surface_contoning_color_prediction_mode();
key.calibrated_stack_model_key = solver.calibrated_stack_model_key();
return key;
}
@@ -9826,6 +9912,41 @@ void export_group_fills_to_svg(const char *path, const std::vector<SurfaceFill>
#endif
// friend to Layer
void Layer::prebuild_contoning_stack_plan_cache(std::function<void()> throw_if_canceled,
TopSurfaceImageContoningStackPlanCache *contoning_stack_plan_cache) const
{
if (contoning_stack_plan_cache == nullptr)
return;
const ThrowIfCanceled *throw_if_canceled_ptr = throw_if_canceled ? &throw_if_canceled : nullptr;
check_canceled(throw_if_canceled_ptr);
const PrintObject *object = this->object();
if (object == nullptr || object->print() == nullptr)
return;
const TextureMappingManager &texture_mgr = object->print()->texture_mapping_manager();
bool has_surface_anchored_contoning = false;
for (const LayerRegion *layerm : m_regions) {
check_canceled(throw_if_canceled_ptr);
if (layerm == nullptr)
continue;
const int raw_zone_id = layerm->region().config().solid_infill_filament.value;
if (raw_zone_id <= 0)
continue;
const TextureMappingZone *zone = texture_mgr.zone_from_id(unsigned(raw_zone_id));
if (zone != nullptr &&
zone->enabled &&
!zone->deleted &&
zone->top_surface_image_printing_active() &&
zone->top_surface_contoning_active() &&
zone->effective_top_surface_contoning_surface_anchored_stacks_enabled()) {
has_surface_anchored_contoning = true;
break;
}
}
if (!has_surface_anchored_contoning)
return;
top_surface_image_region_plans(*this, contoning_stack_plan_cache, throw_if_canceled_ptr);
}
void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree,
FillAdaptive::Octree* support_fill_octree,
FillLightning::Generator* lightning_generator,

View File

@@ -204,6 +204,8 @@ public:
FillLightning::Generator* lightning_generator = nullptr,
std::function<void()> throw_if_canceled = {},
TopSurfaceImageContoningStackPlanCache *contoning_stack_plan_cache = nullptr);
void prebuild_contoning_stack_plan_cache(std::function<void()> throw_if_canceled,
TopSurfaceImageContoningStackPlanCache *contoning_stack_plan_cache) const;
Polylines generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Octree *adaptive_fill_octree,
FillAdaptive::Octree *support_fill_octree,
FillLightning::Generator* lightning_generator) const;

View File

@@ -992,6 +992,23 @@ void PrintObject::infill()
const auto& support_fill_octree = this->m_adaptive_fill_octrees.second;
const std::function<void()> throw_if_canceled = [print]() { print->throw_if_canceled(); };
auto contoning_stack_plan_cache = make_top_surface_image_contoning_stack_plan_cache();
const bool prebuild_contoning_stack_plans =
std::any_of(print->texture_mapping_manager().zones().begin(),
print->texture_mapping_manager().zones().end(),
[](const TextureMappingZone &zone) {
return zone.enabled &&
!zone.deleted &&
zone.top_surface_image_printing_active() &&
zone.top_surface_contoning_active() &&
zone.effective_top_surface_contoning_surface_anchored_stacks_enabled();
});
if (prebuild_contoning_stack_plans) {
for (Layer *layer : m_layers) {
print->throw_if_canceled();
layer->prebuild_contoning_stack_plan_cache(throw_if_canceled, contoning_stack_plan_cache.get());
}
m_print->throw_if_canceled();
}
BOOST_LOG_TRIVIAL(debug) << "Filling layers in parallel - start";
tbb::parallel_for(

View File

@@ -672,6 +672,37 @@ TextureMappingContoningStack TextureMappingContoningSolver::solve(const std::arr
bool lower_surface,
int visible_stack_layers,
const std::vector<float> &surface_to_deep_layer_heights_mm) const
{
return solve_impl(target_rgb,
stack_layers,
lower_surface,
visible_stack_layers,
surface_to_deep_layer_heights_mm,
m_beam_search_stack_expansion_enabled);
}
TextureMappingContoningStack TextureMappingContoningSolver::solve_without_beam_search_stack_expansion(
const std::array<float, 3> &target_rgb,
int stack_layers,
bool lower_surface,
int visible_stack_layers,
const std::vector<float> &surface_to_deep_layer_heights_mm) const
{
return solve_impl(target_rgb,
stack_layers,
lower_surface,
visible_stack_layers,
surface_to_deep_layer_heights_mm,
false);
}
TextureMappingContoningStack TextureMappingContoningSolver::solve_impl(
const std::array<float, 3> &target_rgb,
int stack_layers,
bool lower_surface,
int visible_stack_layers,
const std::vector<float> &surface_to_deep_layer_heights_mm,
bool beam_search_stack_expansion_enabled) const
{
TextureMappingContoningStack out;
if (!valid())
@@ -706,7 +737,7 @@ TextureMappingContoningStack TextureMappingContoningSolver::solve(const std::arr
m_beer_lambert_rgb_correction_enabled,
m_td_effective_alpha_correction_enabled,
m_component_roles,
m_beam_search_stack_expansion_enabled,
beam_search_stack_expansion_enabled,
depth_layer_opacities,
m_calibrated_stack_model.valid() ? &m_calibrated_stack_model : nullptr);
}

View File

@@ -12,6 +12,7 @@
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <vector>
namespace Slic3r {
@@ -35,12 +36,19 @@ public:
bool valid() const { return !m_component_ids.empty() && m_component_ids.size() == m_component_colors.size(); }
const std::vector<unsigned int>& component_ids() const { return m_component_ids; }
const std::vector<unsigned int>& components_bottom_to_top() const { return m_components_bottom_to_top; }
std::string calibrated_stack_model_key() const { return m_calibrated_stack_model.valid() ? m_calibrated_stack_model.cache_key() : std::string(); }
TextureMappingContoningStack solve(const std::array<float, 3> &target_rgb,
int stack_layers,
bool lower_surface = false,
int visible_stack_layers = 0,
const std::vector<float> &surface_to_deep_layer_heights_mm = {}) const;
TextureMappingContoningStack solve_without_beam_search_stack_expansion(
const std::array<float, 3> &target_rgb,
int stack_layers,
bool lower_surface = false,
int visible_stack_layers = 0,
const std::vector<float> &surface_to_deep_layer_heights_mm = {}) const;
unsigned int component_for_depth(const std::array<float, 3> &target_rgb, int stack_layers, int depth_from_top, bool lower_surface = false) const;
std::optional<std::array<float, 3>> stack_rgb(const std::vector<unsigned int> &bottom_to_top,
bool lower_surface = false,
@@ -61,6 +69,12 @@ private:
std::optional<size_t> component_index(unsigned int component_id) const;
std::vector<float> layer_opacities_by_depth(const std::vector<float> &surface_to_deep_layer_heights_mm,
int visible_depth) const;
TextureMappingContoningStack solve_impl(const std::array<float, 3> &target_rgb,
int stack_layers,
bool lower_surface,
int visible_stack_layers,
const std::vector<float> &surface_to_deep_layer_heights_mm,
bool beam_search_stack_expansion_enabled) const;
std::vector<unsigned int> m_component_ids;
std::vector<unsigned int> m_components_bottom_to_top;

View File

@@ -90,6 +90,7 @@ extern wxPopupWindow* wxCurrentPopupWindow;
#endif
static constexpr const float TRACKBALLSIZE = 0.8f;
static constexpr float WIPE_TOWER_EDGE_BUFFER = 20.f;
static Slic3r::ColorRGBA DEFAULT_BG_LIGHT_COLOR = { 0.906f, 0.906f, 0.906f, 1.0f };
static Slic3r::ColorRGBA DEFAULT_BG_LIGHT_COLOR_DARK = { 0.329f, 0.329f, 0.353f, 1.0f };
@@ -2877,7 +2878,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
const float texture_z_max = float(wipe_tower_size(2));
{
const float margin = WIPE_TOWER_MARGIN + brim_width;
const float margin = WIPE_TOWER_MARGIN + brim_width + WIPE_TOWER_EDGE_BUFFER;
BoundingBoxf3 plate_bbox = part_plate->get_bounding_box();
BoundingBoxf plate_bbox_2d(Vec2d(plate_bbox.min(0), plate_bbox.min(1)), Vec2d(plate_bbox.max(0), plate_bbox.max(1)));
const std::vector<Pointfs> &extruder_areas = part_plate->get_extruder_areas();

View File

@@ -43,6 +43,8 @@ constexpr size_t k_simulated_texture_preview_max_pixels = 2048ull * 2048ull;
constexpr unsigned int k_temporary_simulated_texture_preview_max_edge = 1024;
constexpr size_t k_temporary_simulated_texture_preview_max_pixels = 1024ull * 1024ull;
constexpr size_t k_temporary_simulated_texture_preview_min_source_pixels = k_temporary_simulated_texture_preview_max_pixels * 3 / 2;
constexpr unsigned int k_temporary_contoning_flat_surface_preview_max_edge = 384;
constexpr size_t k_temporary_contoning_flat_surface_preview_max_pixels = 384ull * 384ull;
constexpr size_t k_surface_gradient_preview_max_components = 10;
constexpr size_t k_surface_gradient_preview_lut_size = 33;
constexpr size_t k_contoning_flat_surface_preview_max_candidates = 250000;
@@ -99,6 +101,7 @@ struct TexturePreviewSimulationSettings
bool contoning_flat_surface_beer_lambert_rgb_correction = false;
bool contoning_flat_surface_td_effective_alpha_correction = false;
bool contoning_flat_surface_beam_search_stack_expansion = false;
bool contoning_flat_surface_force_low_resolution = false;
int contoning_flat_surface_pattern_filaments = TextureMappingZone::DefaultTopSurfaceContoningPatternFilaments;
bool simulate_top_surface_lod = false;
float top_surface_lod_pitch_mm = 0.f;
@@ -176,6 +179,12 @@ struct TexturePreviewSimulationCacheEntry
std::shared_ptr<TexturePreviewSimulationJobState> pending_job_state;
};
struct TexturePreviewSizeLimit
{
unsigned int max_edge { k_simulated_texture_preview_max_edge };
size_t max_pixels { k_simulated_texture_preview_max_pixels };
};
struct TexturePreviewVertexColorSimulationResult
{
size_t signature { 0 };
@@ -891,6 +900,16 @@ std::array<unsigned int, 2> simulated_texture_preview_size(unsigned int width,
limited_simulated_texture_preview_size(width, height) :
std::array<unsigned int, 2>{ width, height };
if (settings.contoning_flat_surface_force_low_resolution) {
const std::array<unsigned int, 2> low_size =
limited_simulated_texture_preview_size(width,
height,
k_temporary_contoning_flat_surface_preview_max_edge,
k_temporary_contoning_flat_surface_preview_max_pixels);
size[0] = std::min(size[0], low_size[0]);
size[1] = std::min(size[1], low_size[1]);
}
if (settings.contoning_flat_surface_quantization &&
settings.simulate_top_surface_lod &&
std::isfinite(settings.texture_preview_mm_per_pixel) &&
@@ -922,26 +941,52 @@ bool simulated_texture_preview_needs_temporary_result(unsigned int width,
unsigned int height,
const TexturePreviewSimulationSettings &settings)
{
auto final_and_temporary_pixels = [&settings, width, height]() {
const std::array<unsigned int, 2> final_size = simulated_texture_preview_size(width, height, settings);
const TexturePreviewSizeLimit temporary_limit =
settings.contoning_flat_surface_quantization ?
TexturePreviewSizeLimit{ k_temporary_contoning_flat_surface_preview_max_edge,
k_temporary_contoning_flat_surface_preview_max_pixels } :
TexturePreviewSizeLimit{ k_temporary_simulated_texture_preview_max_edge,
k_temporary_simulated_texture_preview_max_pixels };
const std::array<unsigned int, 2> temporary_size =
simulated_texture_preview_size(width,
height,
settings,
temporary_limit.max_edge,
temporary_limit.max_pixels);
return std::array<size_t, 2>{
size_t(final_size[0]) * size_t(final_size[1]),
size_t(temporary_size[0]) * size_t(temporary_size[1])
};
};
if (settings.contoning_flat_surface_quantization) {
const std::array<size_t, 2> pixels = final_and_temporary_pixels();
return pixels[0] > pixels[1] && pixels[0] > pixels[1] * 5 / 4;
}
const size_t source_pixels = size_t(width) * size_t(height);
if (source_pixels <= k_temporary_simulated_texture_preview_min_source_pixels)
return false;
const std::array<unsigned int, 2> final_size = simulated_texture_preview_size(width, height, settings);
const std::array<unsigned int, 2> temporary_size =
simulated_texture_preview_size(width,
height,
settings,
k_temporary_simulated_texture_preview_max_edge,
k_temporary_simulated_texture_preview_max_pixels);
return size_t(final_size[0]) * size_t(final_size[1]) > size_t(temporary_size[0]) * size_t(temporary_size[1]);
const std::array<size_t, 2> pixels = final_and_temporary_pixels();
return pixels[0] > pixels[1];
}
size_t temporary_simulated_texture_preview_signature(size_t signature)
TexturePreviewSizeLimit temporary_simulated_texture_preview_size_limit(const TexturePreviewSimulationSettings &settings)
{
if (settings.contoning_flat_surface_quantization)
return { k_temporary_contoning_flat_surface_preview_max_edge, k_temporary_contoning_flat_surface_preview_max_pixels };
return { k_temporary_simulated_texture_preview_max_edge, k_temporary_simulated_texture_preview_max_pixels };
}
size_t temporary_simulated_texture_preview_signature(size_t signature, const TexturePreviewSizeLimit &limit)
{
signature ^= 0x4a7c15f17e315123ull + (signature << 6) + (signature >> 2);
signature ^= std::hash<unsigned int>{}(k_temporary_simulated_texture_preview_max_edge) + 0x9e3779b97f4a7c15ull +
signature ^= std::hash<unsigned int>{}(limit.max_edge) + 0x9e3779b97f4a7c15ull +
(signature << 6) + (signature >> 2);
signature ^= std::hash<size_t>{}(k_temporary_simulated_texture_preview_max_pixels) + 0x9e3779b97f4a7c15ull +
signature ^= std::hash<size_t>{}(limit.max_pixels) + 0x9e3779b97f4a7c15ull +
(signature << 6) + (signature >> 2);
return signature;
}
@@ -2782,6 +2827,8 @@ std::optional<TexturePreviewSimulationSettings> texture_preview_simulation_setti
const int effective_color_prediction_mode =
TextureMappingZone::effective_top_surface_contoning_color_prediction_mode(
zone->top_surface_contoning_color_prediction_mode);
const bool calibrated_color_prediction =
TextureMappingZone::top_surface_contoning_color_prediction_mode_is_calibrated(effective_color_prediction_mode);
settings.contoning_flat_surface_beer_lambert_rgb_correction =
settings.contoning_flat_surface_td_adjustment &&
effective_color_prediction_mode == int(TextureMappingZone::ContoningColorPredictionBeerLambertRgb);
@@ -2791,6 +2838,8 @@ std::optional<TexturePreviewSimulationSettings> texture_preview_simulation_setti
effective_color_prediction_mode == int(TextureMappingZone::ContoningColorPredictionCalibratedCurrentLinearAffine));
settings.contoning_flat_surface_beam_search_stack_expansion =
zone->effective_top_surface_contoning_beam_search_stack_expansion_enabled();
settings.contoning_flat_surface_force_low_resolution =
settings.contoning_flat_surface_td_adjustment && calibrated_color_prediction;
settings.contoning_flat_surface_surface_scatter =
zone->effective_top_surface_contoning_surface_scatter_enabled() ?
k_contoning_preview_surface_scatter :
@@ -2908,6 +2957,7 @@ size_t texture_preview_simulation_signature(const ModelVolume &model_volume,
mix(std::hash<int>{}(settings.contoning_flat_surface_beer_lambert_rgb_correction ? 1 : 0));
mix(std::hash<int>{}(settings.contoning_flat_surface_td_effective_alpha_correction ? 1 : 0));
mix(std::hash<int>{}(settings.contoning_flat_surface_beam_search_stack_expansion ? 1 : 0));
mix(std::hash<int>{}(settings.contoning_flat_surface_force_low_resolution ? 1 : 0));
if (settings.contoning_flat_surface_quantization) {
mix(std::hash<int>{}(settings.contoning_flat_surface_pattern_filaments));
mix(std::hash<int>{}(settings.simulate_top_surface_lod ? 1 : 0));
@@ -3732,8 +3782,9 @@ const GUI::GLTexture *simulated_texture_preview_texture_for_filament(const Model
const unsigned int width = model_volume.imported_texture_width;
const unsigned int height = model_volume.imported_texture_height;
const bool needs_temporary_result = simulated_texture_preview_needs_temporary_result(width, height, *settings);
const TexturePreviewSizeLimit temporary_size_limit = temporary_simulated_texture_preview_size_limit(*settings);
const size_t temporary_signature = needs_temporary_result ?
temporary_simulated_texture_preview_signature(simulation_signature) :
temporary_simulated_texture_preview_signature(simulation_signature, temporary_size_limit) :
size_t(0);
consume_temporary_simulated_texture_preview_result(entry);
@@ -3783,10 +3834,9 @@ const GUI::GLTexture *simulated_texture_preview_texture_for_filament(const Model
source_raw_component_channels = std::move(source_raw_component_channels),
background_color,
job_state,
temporary_size_limit,
simulation_settings = std::move(simulation_settings)]() mutable {
if (temporary_signature != 0 && job_state != nullptr) {
const unsigned int temp_edge = k_temporary_simulated_texture_preview_max_edge;
const size_t temp_pixels = k_temporary_simulated_texture_preview_max_pixels;
TexturePreviewSimulationResult temporary_result =
build_simulated_texture_preview_result(temporary_signature,
width,
@@ -3797,8 +3847,8 @@ const GUI::GLTexture *simulated_texture_preview_texture_for_filament(const Model
source_raw_component_channels,
background_color,
simulation_settings,
temp_edge,
temp_pixels);
temporary_size_limit.max_edge,
temporary_size_limit.max_pixels);
std::lock_guard<std::mutex> lock(job_state->mutex);
job_state->temporary_result = std::move(temporary_result);
}
@@ -5837,6 +5887,7 @@ static size_t texture_preview_settings_signature_impl(size_t num_physical,
signature_mix(std::hash<int>{}(zone.top_surface_contoning_pattern_filaments));
signature_mix(std::hash<int>{}(zone.top_surface_contoning_color_lower_surfaces ? 1 : 0));
signature_mix(std::hash<int>{}(zone.top_surface_contoning_td_adjustment_enabled ? 1 : 0));
signature_mix(std::hash<int>{}(zone.effective_top_surface_contoning_color_prediction_mode()));
signature_mix(std::hash<int>{}(zone.effective_top_surface_contoning_surface_scatter_enabled() ? 1 : 0));
signature_mix(std::hash<int>{}(zone.top_surface_contoning_beer_lambert_rgb_correction_enabled ? 1 : 0));
signature_mix(std::hash<int>{}(zone.top_surface_contoning_td_effective_alpha_correction_enabled ? 1 : 0));
@@ -5994,6 +6045,7 @@ static void texture_preview_mix_zone_baked_model_settings(size_t &signature,
signature_mix(std::hash<int>{}(zone.top_surface_contoning_pattern_filaments));
signature_mix(std::hash<int>{}(zone.top_surface_contoning_color_lower_surfaces ? 1 : 0));
signature_mix(std::hash<int>{}(zone.top_surface_contoning_td_adjustment_enabled ? 1 : 0));
signature_mix(std::hash<int>{}(zone.effective_top_surface_contoning_color_prediction_mode()));
signature_mix(std::hash<int>{}(zone.effective_top_surface_contoning_surface_scatter_enabled() ? 1 : 0));
signature_mix(std::hash<int>{}(zone.top_surface_contoning_beer_lambert_rgb_correction_enabled ? 1 : 0));
signature_mix(std::hash<int>{}(zone.top_surface_contoning_td_effective_alpha_correction_enabled ? 1 : 0));
@@ -6186,7 +6238,7 @@ void render_model_texture_preview_models(
const bool force_original_texture =
color_match_active || texture_preview_halftone_simulation_enabled_for_filament(filament_ids[idx], num_physical, texture_mgr);
const GUI::GLTexture *preview_texture = force_original_texture ?
const GUI::GLTexture *base_preview_texture = force_original_texture ?
&texture :
simulated_texture_preview_texture_for_filament(model_volume,
model_matrix,
@@ -6195,15 +6247,9 @@ void render_model_texture_preview_models(
texture_mgr,
texture_signature,
texture);
if (preview_texture == nullptr || preview_texture->get_id() == 0)
if (base_preview_texture == nullptr || base_preview_texture->get_id() == 0)
continue;
if (preview_texture->get_id() != bound_texture_id) {
glsafe(::glActiveTexture(GL_TEXTURE0));
glsafe(::glBindTexture(GL_TEXTURE_2D, preview_texture->get_id()));
bound_texture_id = preview_texture->get_id();
}
bool contoning_flat_top_ready = false;
bool contoning_flat_bottom_ready = false;
bool contoning_flat_top_quantization = false;
@@ -6256,6 +6302,20 @@ void render_model_texture_preview_models(
contoning_flat_top_ready && contoning_flat_texture != nullptr && contoning_flat_texture->get_id() != 0;
const bool contoning_flat_bottom_enabled =
contoning_flat_bottom_ready && contoning_flat_bottom_texture != nullptr && contoning_flat_bottom_texture->get_id() != 0;
const bool contoning_flat_pending =
use_contoning_flat_texture &&
((!contoning_flat_enabled && (contoning_flat_top_quantization || contoning_flat_top_pattern_blend)) ||
(!contoning_flat_bottom_enabled && (contoning_flat_bottom_quantization || contoning_flat_bottom_pattern_blend)));
const GUI::GLTexture *preview_texture = contoning_flat_pending ? &texture : base_preview_texture;
if (preview_texture == nullptr || preview_texture->get_id() == 0)
continue;
if (preview_texture->get_id() != bound_texture_id) {
glsafe(::glActiveTexture(GL_TEXTURE0));
glsafe(::glBindTexture(GL_TEXTURE_2D, preview_texture->get_id()));
bound_texture_id = preview_texture->get_id();
}
if (contoning_flat_enabled && contoning_flat_texture->get_id() != bound_contoning_flat_texture_id) {
glsafe(::glActiveTexture(GL_TEXTURE1));
glsafe(::glBindTexture(GL_TEXTURE_2D, contoning_flat_texture->get_id()));
@@ -6324,7 +6384,7 @@ void render_model_texture_preview_model(
const size_t texture_signature = model_volume_texture_preview_signature(model_volume);
const bool force_original_texture =
color_match_active || texture_preview_halftone_simulation_enabled_for_filament(filament_id, num_physical, texture_mgr);
const GUI::GLTexture *preview_texture = force_original_texture ?
const GUI::GLTexture *base_preview_texture = force_original_texture ?
&texture :
simulated_texture_preview_texture_for_filament(model_volume,
model_matrix,
@@ -6333,7 +6393,7 @@ void render_model_texture_preview_model(
texture_mgr,
texture_signature,
texture);
if (preview_texture == nullptr || preview_texture->get_id() == 0)
if (base_preview_texture == nullptr || base_preview_texture->get_id() == 0)
return;
const TexturePreviewRenderState render_state = begin_render_state(opaque);
@@ -6349,8 +6409,6 @@ void render_model_texture_preview_model(
print_volume_z);
set_color_match_preview_uniforms(*shader, color_match);
glsafe(::glActiveTexture(GL_TEXTURE0));
glsafe(::glBindTexture(GL_TEXTURE_2D, preview_texture->get_id()));
shader->set_uniform("uniform_texture", 0);
shader->set_uniform("contoning_flat_surface_texture", 1);
shader->set_uniform("contoning_flat_surface_bottom_texture", 2);
@@ -6406,6 +6464,19 @@ void render_model_texture_preview_model(
contoning_flat_top_ready && contoning_flat_texture != nullptr && contoning_flat_texture->get_id() != 0;
const bool contoning_flat_bottom_enabled =
contoning_flat_bottom_ready && contoning_flat_bottom_texture != nullptr && contoning_flat_bottom_texture->get_id() != 0;
const bool contoning_flat_pending =
use_contoning_flat_texture &&
((!contoning_flat_enabled && (contoning_flat_top_quantization || contoning_flat_top_pattern_blend)) ||
(!contoning_flat_bottom_enabled && (contoning_flat_bottom_quantization || contoning_flat_bottom_pattern_blend)));
const GUI::GLTexture *preview_texture = contoning_flat_pending ? &texture : base_preview_texture;
if (preview_texture == nullptr || preview_texture->get_id() == 0) {
shader->stop_using();
restore_render_state(render_state);
return;
}
glsafe(::glActiveTexture(GL_TEXTURE0));
glsafe(::glBindTexture(GL_TEXTURE_2D, preview_texture->get_id()));
if (contoning_flat_enabled) {
glsafe(::glActiveTexture(GL_TEXTURE1));
glsafe(::glBindTexture(GL_TEXTURE_2D, contoning_flat_texture->get_id()));

View File

@@ -64,6 +64,7 @@ static const int PARTPLATE_TEXT_OFFSET_X1 = 3;
static const int PARTPLATE_TEXT_OFFSET_X2 = 1;
static const int PARTPLATE_TEXT_OFFSET_Y = 1;
static const int PARTPLATE_PLATENAME_OFFSET_Y = 10;
static const float WIPE_TOWER_EDGE_BUFFER = 20.f;
const float WIPE_TOWER_DEFAULT_X_POS = 165.;
const float WIPE_TOWER_DEFAULT_Y_POS = 250.; // Max y
@@ -4443,7 +4444,7 @@ void PartPlateList::set_default_wipe_tower_pos_for_plate(int plate_idx, bool ini
brim_width = brim_opt->value;
if (brim_width < 0) brim_width = WipeTower::get_auto_brim_by_height((float) wipe_tower_size.z());
}
const float margin = WIPE_TOWER_MARGIN + brim_width;
const float margin = WIPE_TOWER_MARGIN + brim_width + WIPE_TOWER_EDGE_BUFFER;
// clamp wipe tower position within plate boundaries
{

View File

@@ -84,6 +84,7 @@
#include "libslic3r/Polygon.hpp"
#include "libslic3r/Print.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/GCode/WipeTower.hpp"
#include "libslic3r/SLAPrint.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/PresetBundle.hpp"
@@ -242,6 +243,7 @@ wxDEFINE_EVENT(EVT_DEL_FILAMENT, SimpleEvent);
wxDEFINE_EVENT(EVT_ADD_CUSTOM_FILAMENT, ColorEvent);
wxDEFINE_EVENT(EVT_NOTICE_CHILDE_SIZE_CHANGED, SimpleEvent);
wxDEFINE_EVENT(EVT_NOTICE_FULL_SCREEN_CHANGED, IntEvent);
static constexpr float WIPE_TOWER_EDGE_BUFFER = 20.f;
#define PRINTER_THUMBNAIL_SIZE (wxSize(40, 40)) // ORCA
#define PRINTER_PANEL_SIZE ( wxSize(70, 60)) // ORCA
#define PRINTER_PANEL_RADIUS (6) // ORCA
@@ -378,6 +380,90 @@ static wxString temp_dir;
namespace {
static void clamp_wipe_tower_positions_for_slicing(PartPlateList &partplate_list, PresetBundle &preset_bundle)
{
DynamicPrintConfig &proj_cfg = preset_bundle.project_config;
ConfigOptionFloats *wipe_tower_x = proj_cfg.option<ConfigOptionFloats>("wipe_tower_x", true);
ConfigOptionFloats *wipe_tower_y = proj_cfg.option<ConfigOptionFloats>("wipe_tower_y", true);
if (wipe_tower_x == nullptr || wipe_tower_y == nullptr || wipe_tower_x->values.empty() || wipe_tower_y->values.empty())
return;
const DynamicPrintConfig &print_cfg = preset_bundle.prints.get_edited_preset().config;
const ConfigOptionBool *enable_prime_tower = print_cfg.option<ConfigOptionBool>("enable_prime_tower");
if (enable_prime_tower == nullptr || !enable_prime_tower->value)
return;
wipe_tower_x->values.resize(partplate_list.get_plate_count(), wipe_tower_x->values.front());
wipe_tower_y->values.resize(partplate_list.get_plate_count(), wipe_tower_y->values.front());
const ConfigOptionEnum<PrintSequence> *print_sequence = print_cfg.option<ConfigOptionEnum<PrintSequence>>("print_sequence");
const ConfigOptionEnum<TimelapseType> *timelapse_type = print_cfg.option<ConfigOptionEnum<TimelapseType>>("timelapse_type");
const ConfigOptionBool *wrapping_opt = print_cfg.option<ConfigOptionBool>("enable_wrapping_detection");
const bool need_wipe_tower = (timelapse_type != nullptr && timelapse_type->value == TimelapseType::tlSmooth) ||
(wrapping_opt != nullptr && wrapping_opt->value);
const float width = print_cfg.opt_float("prime_tower_width");
const float prime_volume = print_cfg.opt_float("prime_volume");
const int nozzle_nums = preset_bundle.get_printer_extruder_count();
for (int plate_id = 0; plate_id < partplate_list.get_plate_count(); ++plate_id) {
PartPlate *part_plate = partplate_list.get_plate(plate_id);
if (part_plate == nullptr || part_plate->get_objects_on_this_plate().empty())
continue;
if (part_plate->get_print_seq() == PrintSequence::ByObject ||
(part_plate->get_print_seq() == PrintSequence::ByDefault && print_sequence != nullptr && print_sequence->value == PrintSequence::ByObject)) {
if (part_plate->printable_instance_size() != 1)
continue;
}
const size_t texture_mapping_filaments_count = part_plate->estimate_wipe_tower_filaments_count(&proj_cfg);
const size_t wipe_tower_filaments_count = need_wipe_tower ?
std::max<size_t>(1, texture_mapping_filaments_count) :
texture_mapping_filaments_count;
if (!need_wipe_tower && wipe_tower_filaments_count < 2)
continue;
Vec3d wipe_tower_size = part_plate->estimate_wipe_tower_size(print_cfg,
width,
prime_volume,
nozzle_nums,
int(wipe_tower_filaments_count),
false,
wrapping_opt != nullptr && wrapping_opt->value);
if (wipe_tower_size(0) <= EPSILON || wipe_tower_size(1) <= EPSILON)
continue;
float brim_width = print_cfg.opt_float("prime_tower_brim_width");
if (brim_width < 0)
brim_width = WipeTower::get_auto_brim_by_height((float) wipe_tower_size.z());
const float margin = float(WIPE_TOWER_MARGIN) + brim_width + WIPE_TOWER_EDGE_BUFFER;
const Vec3d plate_origin = part_plate->get_origin();
BoundingBoxf3 plate_bbox = part_plate->get_bounding_box();
BoundingBoxf plate_bbox_2d(Vec2d(plate_bbox.min(0), plate_bbox.min(1)), Vec2d(plate_bbox.max(0), plate_bbox.max(1)));
const std::vector<Pointfs> &extruder_areas = part_plate->get_extruder_areas();
for (const Pointfs &points : extruder_areas) {
BoundingBoxf bboxf(points);
plate_bbox_2d.min = plate_bbox_2d.min(0) >= bboxf.min(0) ? plate_bbox_2d.min : bboxf.min;
plate_bbox_2d.max = plate_bbox_2d.max(0) <= bboxf.max(0) ? plate_bbox_2d.max : bboxf.max;
}
const coordf_t min_x = plate_bbox_2d.min(0) - plate_origin(0);
const coordf_t max_x = plate_bbox_2d.max(0) - plate_origin(0);
const coordf_t min_y = plate_bbox_2d.min(1) - plate_origin(1);
const coordf_t max_y = plate_bbox_2d.max(1) - plate_origin(1);
auto clamp_axis = [](float value, coordf_t min_value, coordf_t max_value, double size, float margin) {
const float axis_min = float(min_value) + margin;
const float axis_max = float(max_value) - margin - float(size);
return axis_max < axis_min ? axis_min : std::min(std::max(value, axis_min), axis_max);
};
ConfigOptionFloat x_opt(clamp_axis(wipe_tower_x->get_at(plate_id), min_x, max_x, wipe_tower_size(0), margin));
ConfigOptionFloat y_opt(clamp_axis(wipe_tower_y->get_at(plate_id), min_y, max_y, wipe_tower_size(1), margin));
wipe_tower_x->set_at(&x_opt, plate_id, 0);
wipe_tower_y->set_at(&y_opt, plate_id, 0);
}
}
static std::map<uint64_t, unsigned int> active_texture_zone_ids_by_stable_id_for_import(const TextureMappingManager &manager)
{
std::map<uint64_t, unsigned int> ids;
@@ -14541,8 +14627,10 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
this->preview->update_gcode_result(partplate_list.get_current_slice_result());
}
if (PresetBundle *preset_bundle = wxGetApp().preset_bundle; preset_bundle != nullptr)
if (PresetBundle *preset_bundle = wxGetApp().preset_bundle; preset_bundle != nullptr) {
canonicalize_texture_mapping_config(*preset_bundle, true);
clamp_wipe_tower_positions_for_slicing(this->partplate_list, *preset_bundle);
}
background_process.fff_print()->set_check_multi_filaments_compatibility(wxGetApp().app_config->get("enable_high_low_temp_mixed_printing") == "false");