Create top-surface images with variable line widths (experimental)
This commit is contained in:
@@ -20,6 +20,12 @@ void filter_by_extrusion_role_in_place(ExtrusionEntitiesPtr &extrusion_entities,
|
||||
|
||||
ExtrusionEntityCollection::ExtrusionEntityCollection(const ExtrusionPaths &paths)
|
||||
: no_sort(false)
|
||||
, texture_mapping_extruder_override(-1)
|
||||
, texture_mapping_top_surface_image(false)
|
||||
, texture_mapping_top_surface_zone_id(0)
|
||||
, texture_mapping_top_surface_desired_component_id(0)
|
||||
, texture_mapping_top_surface_stack_depth(-1)
|
||||
, texture_mapping_top_surface_fixed_coloring(true)
|
||||
{
|
||||
this->append(paths);
|
||||
}
|
||||
@@ -32,6 +38,11 @@ ExtrusionEntityCollection& ExtrusionEntityCollection::operator=(const ExtrusionE
|
||||
this->entities[i] = this->entities[i]->clone();
|
||||
this->no_sort = other.no_sort;
|
||||
this->texture_mapping_extruder_override = other.texture_mapping_extruder_override;
|
||||
this->texture_mapping_top_surface_image = other.texture_mapping_top_surface_image;
|
||||
this->texture_mapping_top_surface_zone_id = other.texture_mapping_top_surface_zone_id;
|
||||
this->texture_mapping_top_surface_desired_component_id = other.texture_mapping_top_surface_desired_component_id;
|
||||
this->texture_mapping_top_surface_stack_depth = other.texture_mapping_top_surface_stack_depth;
|
||||
this->texture_mapping_top_surface_fixed_coloring = other.texture_mapping_top_surface_fixed_coloring;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -40,6 +51,11 @@ void ExtrusionEntityCollection::swap(ExtrusionEntityCollection &c)
|
||||
std::swap(this->entities, c.entities);
|
||||
std::swap(this->no_sort, c.no_sort);
|
||||
std::swap(this->texture_mapping_extruder_override, c.texture_mapping_extruder_override);
|
||||
std::swap(this->texture_mapping_top_surface_image, c.texture_mapping_top_surface_image);
|
||||
std::swap(this->texture_mapping_top_surface_zone_id, c.texture_mapping_top_surface_zone_id);
|
||||
std::swap(this->texture_mapping_top_surface_desired_component_id, c.texture_mapping_top_surface_desired_component_id);
|
||||
std::swap(this->texture_mapping_top_surface_stack_depth, c.texture_mapping_top_surface_stack_depth);
|
||||
std::swap(this->texture_mapping_top_surface_fixed_coloring, c.texture_mapping_top_surface_fixed_coloring);
|
||||
}
|
||||
|
||||
void ExtrusionEntityCollection::clear()
|
||||
|
||||
@@ -32,9 +32,41 @@ public:
|
||||
ExtrusionEntitiesPtr entities; // we own these entities
|
||||
bool no_sort;
|
||||
int texture_mapping_extruder_override;
|
||||
ExtrusionEntityCollection(): no_sort(false), texture_mapping_extruder_override(-1) {}
|
||||
ExtrusionEntityCollection(const ExtrusionEntityCollection &other) : no_sort(other.no_sort), texture_mapping_extruder_override(other.texture_mapping_extruder_override), is_reverse(other.is_reverse) { this->append(other.entities); }
|
||||
ExtrusionEntityCollection(ExtrusionEntityCollection &&other) : entities(std::move(other.entities)), no_sort(other.no_sort), texture_mapping_extruder_override(other.texture_mapping_extruder_override), is_reverse(other.is_reverse) {}
|
||||
bool texture_mapping_top_surface_image;
|
||||
unsigned int texture_mapping_top_surface_zone_id;
|
||||
unsigned int texture_mapping_top_surface_desired_component_id;
|
||||
int texture_mapping_top_surface_stack_depth;
|
||||
bool texture_mapping_top_surface_fixed_coloring;
|
||||
ExtrusionEntityCollection()
|
||||
: no_sort(false)
|
||||
, texture_mapping_extruder_override(-1)
|
||||
, texture_mapping_top_surface_image(false)
|
||||
, texture_mapping_top_surface_zone_id(0)
|
||||
, texture_mapping_top_surface_desired_component_id(0)
|
||||
, texture_mapping_top_surface_stack_depth(-1)
|
||||
, texture_mapping_top_surface_fixed_coloring(true)
|
||||
{}
|
||||
ExtrusionEntityCollection(const ExtrusionEntityCollection &other)
|
||||
: no_sort(other.no_sort)
|
||||
, texture_mapping_extruder_override(other.texture_mapping_extruder_override)
|
||||
, texture_mapping_top_surface_image(other.texture_mapping_top_surface_image)
|
||||
, texture_mapping_top_surface_zone_id(other.texture_mapping_top_surface_zone_id)
|
||||
, texture_mapping_top_surface_desired_component_id(other.texture_mapping_top_surface_desired_component_id)
|
||||
, texture_mapping_top_surface_stack_depth(other.texture_mapping_top_surface_stack_depth)
|
||||
, texture_mapping_top_surface_fixed_coloring(other.texture_mapping_top_surface_fixed_coloring)
|
||||
, is_reverse(other.is_reverse)
|
||||
{ this->append(other.entities); }
|
||||
ExtrusionEntityCollection(ExtrusionEntityCollection &&other)
|
||||
: entities(std::move(other.entities))
|
||||
, no_sort(other.no_sort)
|
||||
, texture_mapping_extruder_override(other.texture_mapping_extruder_override)
|
||||
, texture_mapping_top_surface_image(other.texture_mapping_top_surface_image)
|
||||
, texture_mapping_top_surface_zone_id(other.texture_mapping_top_surface_zone_id)
|
||||
, texture_mapping_top_surface_desired_component_id(other.texture_mapping_top_surface_desired_component_id)
|
||||
, texture_mapping_top_surface_stack_depth(other.texture_mapping_top_surface_stack_depth)
|
||||
, texture_mapping_top_surface_fixed_coloring(other.texture_mapping_top_surface_fixed_coloring)
|
||||
, is_reverse(other.is_reverse)
|
||||
{}
|
||||
explicit ExtrusionEntityCollection(const ExtrusionPaths &paths);
|
||||
ExtrusionEntityCollection& operator=(const ExtrusionEntityCollection &other);
|
||||
ExtrusionEntityCollection& operator=(ExtrusionEntityCollection &&other)
|
||||
@@ -42,6 +74,11 @@ public:
|
||||
this->entities = std::move(other.entities);
|
||||
this->no_sort = other.no_sort;
|
||||
this->texture_mapping_extruder_override = other.texture_mapping_extruder_override;
|
||||
this->texture_mapping_top_surface_image = other.texture_mapping_top_surface_image;
|
||||
this->texture_mapping_top_surface_zone_id = other.texture_mapping_top_surface_zone_id;
|
||||
this->texture_mapping_top_surface_desired_component_id = other.texture_mapping_top_surface_desired_component_id;
|
||||
this->texture_mapping_top_surface_stack_depth = other.texture_mapping_top_surface_stack_depth;
|
||||
this->texture_mapping_top_surface_fixed_coloring = other.texture_mapping_top_surface_fixed_coloring;
|
||||
is_reverse = other.is_reverse;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -3,11 +3,15 @@
|
||||
#include <memory>
|
||||
|
||||
#include "../ClipperUtils.hpp"
|
||||
#include "../Color.hpp"
|
||||
#include "../ColorSolver.hpp"
|
||||
#include "../Geometry.hpp"
|
||||
#include "../Layer.hpp"
|
||||
#include "../Print.hpp"
|
||||
#include "../PrintConfig.hpp"
|
||||
#include "../Surface.hpp"
|
||||
#include "../TextureMapping.hpp"
|
||||
#include "../TextureMappingOffset.hpp"
|
||||
|
||||
#include "AABBTreeLines.hpp"
|
||||
#include "ExtrusionEntity.hpp"
|
||||
@@ -20,6 +24,10 @@
|
||||
#include "FillConcentric.hpp"
|
||||
#include "libslic3r.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Calculate infill rotation angle (in radians) for a given layer from a rotation template.
|
||||
@@ -271,6 +279,17 @@ struct SurfaceFillParams
|
||||
// Params for Lateral honeycomb
|
||||
float infill_overhang_angle = 60.f;
|
||||
|
||||
bool texture_mapping_top_surface_image = false;
|
||||
unsigned int texture_mapping_top_surface_zone_id = 0;
|
||||
unsigned int texture_mapping_top_surface_component_id = 0;
|
||||
int texture_mapping_top_surface_stack_depth = -1;
|
||||
bool texture_mapping_top_surface_fixed_coloring = true;
|
||||
float texture_mapping_top_surface_min_width_mm = TextureMappingZone::DefaultTopSurfaceImageMinLineWidthMm;
|
||||
float texture_mapping_top_surface_max_width_mm = TextureMappingZone::DefaultTopSurfaceImageMaxLineWidthMm;
|
||||
bool texture_mapping_top_surface_same_layer_partition = false;
|
||||
int texture_mapping_top_surface_component_index = 0;
|
||||
int texture_mapping_top_surface_component_count = 0;
|
||||
|
||||
bool operator<(const SurfaceFillParams &rhs) const {
|
||||
#define RETURN_COMPARE_NON_EQUAL(KEY) if (this->KEY < rhs.KEY) return true; if (this->KEY > rhs.KEY) return false;
|
||||
#define RETURN_COMPARE_NON_EQUAL_TYPED(TYPE, KEY) if (TYPE(this->KEY) < TYPE(rhs.KEY)) return true; if (TYPE(this->KEY) > TYPE(rhs.KEY)) return false;
|
||||
@@ -303,6 +322,16 @@ struct SurfaceFillParams
|
||||
RETURN_COMPARE_NON_EQUAL(symmetric_infill_y_axis);
|
||||
RETURN_COMPARE_NON_EQUAL(infill_lock_depth);
|
||||
RETURN_COMPARE_NON_EQUAL(skin_infill_depth); RETURN_COMPARE_NON_EQUAL(infill_overhang_angle);
|
||||
RETURN_COMPARE_NON_EQUAL(texture_mapping_top_surface_image);
|
||||
RETURN_COMPARE_NON_EQUAL(texture_mapping_top_surface_zone_id);
|
||||
RETURN_COMPARE_NON_EQUAL(texture_mapping_top_surface_component_id);
|
||||
RETURN_COMPARE_NON_EQUAL(texture_mapping_top_surface_stack_depth);
|
||||
RETURN_COMPARE_NON_EQUAL(texture_mapping_top_surface_fixed_coloring);
|
||||
RETURN_COMPARE_NON_EQUAL(texture_mapping_top_surface_min_width_mm);
|
||||
RETURN_COMPARE_NON_EQUAL(texture_mapping_top_surface_max_width_mm);
|
||||
RETURN_COMPARE_NON_EQUAL(texture_mapping_top_surface_same_layer_partition);
|
||||
RETURN_COMPARE_NON_EQUAL(texture_mapping_top_surface_component_index);
|
||||
RETURN_COMPARE_NON_EQUAL(texture_mapping_top_surface_component_count);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -330,7 +359,17 @@ struct SurfaceFillParams
|
||||
this->lateral_lattice_angle_2 == rhs.lateral_lattice_angle_2 &&
|
||||
this->infill_lock_depth == rhs.infill_lock_depth &&
|
||||
this->skin_infill_depth == rhs.skin_infill_depth &&
|
||||
this->infill_overhang_angle == rhs.infill_overhang_angle;
|
||||
this->infill_overhang_angle == rhs.infill_overhang_angle &&
|
||||
this->texture_mapping_top_surface_image == rhs.texture_mapping_top_surface_image &&
|
||||
this->texture_mapping_top_surface_zone_id == rhs.texture_mapping_top_surface_zone_id &&
|
||||
this->texture_mapping_top_surface_component_id == rhs.texture_mapping_top_surface_component_id &&
|
||||
this->texture_mapping_top_surface_stack_depth == rhs.texture_mapping_top_surface_stack_depth &&
|
||||
this->texture_mapping_top_surface_fixed_coloring == rhs.texture_mapping_top_surface_fixed_coloring &&
|
||||
this->texture_mapping_top_surface_min_width_mm == rhs.texture_mapping_top_surface_min_width_mm &&
|
||||
this->texture_mapping_top_surface_max_width_mm == rhs.texture_mapping_top_surface_max_width_mm &&
|
||||
this->texture_mapping_top_surface_same_layer_partition == rhs.texture_mapping_top_surface_same_layer_partition &&
|
||||
this->texture_mapping_top_surface_component_index == rhs.texture_mapping_top_surface_component_index &&
|
||||
this->texture_mapping_top_surface_component_count == rhs.texture_mapping_top_surface_component_count;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -346,6 +385,543 @@ struct SurfaceFill {
|
||||
ExPolygons no_overlap_expolygons;
|
||||
};
|
||||
|
||||
struct TopSurfaceImageStackSlice {
|
||||
unsigned int component_id = 0;
|
||||
int depth = 0;
|
||||
size_t component_index = 0;
|
||||
size_t component_count = 0;
|
||||
bool same_layer_partition = false;
|
||||
float angle_rad = float(PI / 4.0);
|
||||
ExPolygons area;
|
||||
};
|
||||
|
||||
struct TopSurfaceImageRegionPlan {
|
||||
const TextureMappingZone *zone = nullptr;
|
||||
unsigned int zone_id = 0;
|
||||
std::vector<unsigned int> components_bottom_to_top;
|
||||
std::vector<TopSurfaceImageStackSlice> slices;
|
||||
float min_width_mm = TextureMappingZone::DefaultTopSurfaceImageMinLineWidthMm;
|
||||
float max_width_mm = TextureMappingZone::DefaultTopSurfaceImageMaxLineWidthMm;
|
||||
bool fixed_coloring = true;
|
||||
bool same_layer_partition = false;
|
||||
int colored_top_layers = TextureMappingZone::DefaultTopSurfaceImageColoredTopLayers;
|
||||
};
|
||||
|
||||
static float top_surface_image_filament_luminance(const PrintConfig &config, unsigned int component_id)
|
||||
{
|
||||
ColorRGB color;
|
||||
if (component_id == 0 || component_id > config.filament_colour.values.size() ||
|
||||
!decode_color(config.filament_colour.get_at(size_t(component_id - 1)), color))
|
||||
return std::numeric_limits<float>::max();
|
||||
return 0.2126f * color.r() + 0.7152f * color.g() + 0.0722f * color.b();
|
||||
}
|
||||
|
||||
static std::vector<unsigned int> top_surface_image_components_bottom_to_top(const TextureMappingZone &zone,
|
||||
const PrintConfig &config,
|
||||
std::vector<unsigned int> components)
|
||||
{
|
||||
components.erase(std::remove_if(components.begin(), components.end(), [](unsigned int id) { return id == 0; }), components.end());
|
||||
components.erase(std::unique(components.begin(), components.end()), components.end());
|
||||
if (components.empty())
|
||||
return components;
|
||||
|
||||
bool has_complete_td = true;
|
||||
for (unsigned int component_id : components) {
|
||||
const size_t idx = size_t(component_id - 1);
|
||||
const float td = idx < zone.filament_transmission_distances_mm.size() ?
|
||||
zone.filament_transmission_distances_mm[idx] :
|
||||
0.f;
|
||||
if (!std::isfinite(td) || td <= 0.f) {
|
||||
has_complete_td = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (has_complete_td) {
|
||||
std::stable_sort(components.begin(), components.end(), [&zone](unsigned int lhs, unsigned int rhs) {
|
||||
return zone.filament_transmission_distances_mm[size_t(lhs - 1)] <
|
||||
zone.filament_transmission_distances_mm[size_t(rhs - 1)];
|
||||
});
|
||||
return components;
|
||||
}
|
||||
|
||||
auto black_it = std::min_element(components.begin(), components.end(), [&config](unsigned int lhs, unsigned int rhs) {
|
||||
return top_surface_image_filament_luminance(config, lhs) < top_surface_image_filament_luminance(config, rhs);
|
||||
});
|
||||
if (black_it != components.end() && black_it != components.begin())
|
||||
std::rotate(components.begin(), black_it, std::next(black_it));
|
||||
return components;
|
||||
}
|
||||
|
||||
static std::optional<std::array<float, 4>> top_surface_image_equal_blend_background(const PrintConfig &config,
|
||||
const std::vector<unsigned int> &component_ids)
|
||||
{
|
||||
std::vector<std::array<float, 3>> colors;
|
||||
colors.reserve(component_ids.size());
|
||||
for (unsigned int component_id : component_ids) {
|
||||
if (component_id == 0 || component_id > config.filament_colour.values.size())
|
||||
return std::nullopt;
|
||||
ColorRGB color;
|
||||
if (!decode_color(config.filament_colour.get_at(size_t(component_id - 1)), color))
|
||||
return std::nullopt;
|
||||
colors.push_back({ color.r(), color.g(), color.b() });
|
||||
}
|
||||
if (colors.empty())
|
||||
return std::nullopt;
|
||||
std::vector<float> weights(colors.size(), 1.f / float(colors.size()));
|
||||
const std::array<float, 3> mixed = mix_color_solver_components(colors, weights, ColorSolverMixModel::PigmentPainter);
|
||||
return std::array<float, 4> { mixed[0], mixed[1], mixed[2], 1.f };
|
||||
}
|
||||
|
||||
static ExPolygons top_surface_image_visible_top_mask(const Layer &layer, unsigned int zone_id)
|
||||
{
|
||||
ExPolygons mask;
|
||||
for (const LayerRegion *layerm : layer.regions()) {
|
||||
if (layerm == nullptr || unsigned(std::max(0, layerm->region().config().solid_infill_filament.value)) != zone_id)
|
||||
continue;
|
||||
for (const Surface &surface : layerm->fill_surfaces.surfaces)
|
||||
if (surface.is_top())
|
||||
mask.emplace_back(surface.expolygon);
|
||||
}
|
||||
return mask.size() > 1 ? union_ex(mask) : mask;
|
||||
}
|
||||
|
||||
static std::vector<TopSurfaceImageRegionPlan> top_surface_image_region_plans(const Layer &layer)
|
||||
{
|
||||
std::vector<TopSurfaceImageRegionPlan> plans(layer.regions().size());
|
||||
const PrintObject *object = layer.object();
|
||||
if (object == nullptr || object->print() == nullptr)
|
||||
return plans;
|
||||
|
||||
const Print *print = object->print();
|
||||
const PrintConfig &print_config = print->config();
|
||||
const TextureMappingManager &texture_mgr = print->texture_mapping_manager();
|
||||
const size_t num_physical = print_config.filament_colour.values.size();
|
||||
if (num_physical == 0)
|
||||
return plans;
|
||||
|
||||
Polygons current_layer_perimeters;
|
||||
for (const LayerRegion *layerm : layer.regions())
|
||||
if (layerm != nullptr)
|
||||
layerm->perimeters.polygons_covered_by_width(current_layer_perimeters, 0.f);
|
||||
|
||||
for (size_t region_id = 0; region_id < layer.regions().size(); ++region_id) {
|
||||
const LayerRegion *layerm = layer.regions()[region_id];
|
||||
if (layerm == nullptr)
|
||||
continue;
|
||||
const int raw_zone_id = layerm->region().config().solid_infill_filament.value;
|
||||
if (raw_zone_id <= 0)
|
||||
continue;
|
||||
const unsigned int zone_id = unsigned(raw_zone_id);
|
||||
const TextureMappingZone *zone = texture_mgr.zone_from_id(zone_id);
|
||||
if (zone == nullptr || !zone->enabled || zone->deleted || !zone->top_surface_image_printing_active())
|
||||
continue;
|
||||
|
||||
std::vector<std::string> filament_colours = print_config.filament_colour.values;
|
||||
filament_colours.resize(num_physical, "#FFFFFF");
|
||||
std::vector<unsigned int> components =
|
||||
TextureMappingManager::effective_texture_component_ids(*zone, num_physical, filament_colours);
|
||||
components.erase(std::remove_if(components.begin(), components.end(), [num_physical](unsigned int id) {
|
||||
return id == 0 || id > num_physical;
|
||||
}), components.end());
|
||||
components.erase(std::unique(components.begin(), components.end()), components.end());
|
||||
if (components.empty())
|
||||
continue;
|
||||
|
||||
TopSurfaceImageRegionPlan plan;
|
||||
plan.zone = zone;
|
||||
plan.zone_id = zone_id;
|
||||
plan.same_layer_partition =
|
||||
zone->top_surface_image_printing_method == int(TextureMappingZone::TopSurfaceImageSameLayer45Partition);
|
||||
plan.components_bottom_to_top = plan.same_layer_partition ?
|
||||
components :
|
||||
top_surface_image_components_bottom_to_top(*zone, print_config, components);
|
||||
if (plan.components_bottom_to_top.empty())
|
||||
continue;
|
||||
plan.max_width_mm = std::clamp(zone->top_surface_image_max_line_width_mm,
|
||||
TextureMappingZone::MinTopSurfaceImageLineWidthMm,
|
||||
TextureMappingZone::MaxTopSurfaceImageLineWidthMm);
|
||||
plan.min_width_mm = std::clamp(zone->top_surface_image_min_line_width_mm,
|
||||
TextureMappingZone::MinTopSurfaceImageLineWidthMm,
|
||||
plan.max_width_mm);
|
||||
plan.fixed_coloring = zone->top_surface_image_fixed_coloring_filaments;
|
||||
plan.colored_top_layers = std::clamp(zone->top_surface_image_colored_top_layers,
|
||||
TextureMappingZone::MinTopSurfaceImageColoredTopLayers,
|
||||
TextureMappingZone::MaxTopSurfaceImageColoredTopLayers);
|
||||
|
||||
const int stack_depth = plan.same_layer_partition ?
|
||||
plan.colored_top_layers :
|
||||
int(plan.components_bottom_to_top.size());
|
||||
for (int depth = 0; depth < stack_depth; ++depth) {
|
||||
const Layer *top_layer = &layer;
|
||||
for (int i = 0; i < depth && top_layer != nullptr; ++i)
|
||||
top_layer = top_layer->upper_layer;
|
||||
if (top_layer == nullptr)
|
||||
break;
|
||||
|
||||
ExPolygons area = top_surface_image_visible_top_mask(*top_layer, zone_id);
|
||||
if (area.empty())
|
||||
continue;
|
||||
if (!current_layer_perimeters.empty())
|
||||
area = diff_ex(area, current_layer_perimeters, ApplySafetyOffset::Yes);
|
||||
if (area.empty())
|
||||
continue;
|
||||
|
||||
if (plan.same_layer_partition) {
|
||||
const ExPolygons depth_area = area;
|
||||
for (size_t component_idx = 0; component_idx < plan.components_bottom_to_top.size(); ++component_idx) {
|
||||
TopSurfaceImageStackSlice slice;
|
||||
slice.component_id = plan.components_bottom_to_top[component_idx];
|
||||
slice.depth = depth;
|
||||
slice.component_index = component_idx;
|
||||
slice.component_count = plan.components_bottom_to_top.size();
|
||||
slice.same_layer_partition = true;
|
||||
slice.angle_rad = (depth & 1) ? float(-PI / 4.0) : float(PI / 4.0);
|
||||
slice.area = depth_area;
|
||||
plan.slices.emplace_back(std::move(slice));
|
||||
}
|
||||
} else {
|
||||
TopSurfaceImageStackSlice slice;
|
||||
slice.component_id = plan.components_bottom_to_top[size_t(stack_depth - 1 - depth)];
|
||||
slice.depth = depth;
|
||||
slice.component_index = size_t(stack_depth - 1 - depth);
|
||||
slice.component_count = plan.components_bottom_to_top.size();
|
||||
slice.area = std::move(area);
|
||||
plan.slices.emplace_back(std::move(slice));
|
||||
}
|
||||
}
|
||||
|
||||
if (!plan.slices.empty())
|
||||
plans[region_id] = std::move(plan);
|
||||
}
|
||||
|
||||
return plans;
|
||||
}
|
||||
|
||||
static SurfaceFill& surface_fill_for_params(std::vector<SurfaceFill> &surface_fills, const SurfaceFillParams ¶ms)
|
||||
{
|
||||
for (SurfaceFill &fill : surface_fills)
|
||||
if (fill.params == params)
|
||||
return fill;
|
||||
surface_fills.emplace_back(params);
|
||||
return surface_fills.back();
|
||||
}
|
||||
|
||||
static void append_surface_fill_expolygons(SurfaceFill &fill,
|
||||
size_t region_id,
|
||||
const Surface &surface,
|
||||
ExPolygons &&expolygons,
|
||||
const LayerRegion &layerm)
|
||||
{
|
||||
if (expolygons.empty())
|
||||
return;
|
||||
if (fill.region_id == size_t(-1)) {
|
||||
fill.region_id = region_id;
|
||||
fill.surface = surface;
|
||||
fill.surface.expolygon = ExPolygon();
|
||||
fill.expolygons = std::move(expolygons);
|
||||
fill.region_id_group.push_back(region_id);
|
||||
fill.no_overlap_expolygons = layerm.fill_no_overlap_expolygons;
|
||||
} else {
|
||||
append(fill.expolygons, std::move(expolygons));
|
||||
auto t = find(fill.region_id_group.begin(), fill.region_id_group.end(), region_id);
|
||||
if (t == fill.region_id_group.end()) {
|
||||
fill.region_id_group.push_back(region_id);
|
||||
fill.no_overlap_expolygons = union_ex(fill.no_overlap_expolygons, layerm.fill_no_overlap_expolygons);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static SurfaceFillParams top_surface_image_params_for_slice(const Layer &layer,
|
||||
const Surface &surface,
|
||||
const SurfaceFillParams &base_params,
|
||||
const TopSurfaceImageRegionPlan &plan,
|
||||
const TopSurfaceImageStackSlice &slice)
|
||||
{
|
||||
SurfaceFillParams params = base_params;
|
||||
params.extruder = slice.component_id;
|
||||
params.pattern = ipRectilinear;
|
||||
params.density = 100.f;
|
||||
params.angle = slice.angle_rad;
|
||||
params.fixed_angle = true;
|
||||
params.bridge = false;
|
||||
params.bridge_angle = 0.f;
|
||||
params.multiline = 1;
|
||||
params.anchor_length = 1000.f;
|
||||
params.anchor_length_max = 1000.f;
|
||||
params.extrusion_role = surface.is_top() ? erTopSolidInfill : erSolidInfill;
|
||||
const PrintConfig &print_config = layer.object()->print()->config();
|
||||
const float nozzle = slice.component_id > 0 && size_t(slice.component_id - 1) < print_config.nozzle_diameter.values.size() ?
|
||||
float(print_config.nozzle_diameter.get_at(size_t(slice.component_id - 1))) :
|
||||
float(print_config.nozzle_diameter.values.empty() ? 0.4 : print_config.nozzle_diameter.values.front());
|
||||
const float height = float((surface.thickness == -1) ? layer.height : surface.thickness);
|
||||
params.flow = Flow(plan.max_width_mm, height, nozzle);
|
||||
params.spacing = slice.same_layer_partition && slice.component_count > 0 ?
|
||||
(plan.min_width_mm * float(slice.component_count) + (plan.max_width_mm - plan.min_width_mm)) :
|
||||
params.flow.spacing();
|
||||
params.texture_mapping_top_surface_image = true;
|
||||
params.texture_mapping_top_surface_zone_id = plan.zone_id;
|
||||
params.texture_mapping_top_surface_component_id = slice.component_id;
|
||||
params.texture_mapping_top_surface_stack_depth = slice.depth;
|
||||
params.texture_mapping_top_surface_fixed_coloring = plan.fixed_coloring;
|
||||
params.texture_mapping_top_surface_min_width_mm = plan.min_width_mm;
|
||||
params.texture_mapping_top_surface_max_width_mm = plan.max_width_mm;
|
||||
params.texture_mapping_top_surface_same_layer_partition = slice.same_layer_partition;
|
||||
params.texture_mapping_top_surface_component_index = int(slice.component_index);
|
||||
params.texture_mapping_top_surface_component_count = int(slice.component_count);
|
||||
return params;
|
||||
}
|
||||
|
||||
static ExtrusionPaths top_surface_image_split_path(const ExtrusionPath &path,
|
||||
const TextureMappingOffsetContext &context,
|
||||
float min_width_mm,
|
||||
float max_width_mm,
|
||||
float nozzle_diameter)
|
||||
{
|
||||
ExtrusionPaths out;
|
||||
if (path.polyline.points.size() < 2)
|
||||
return out;
|
||||
const float height = path.height > 0.f ? path.height : context.layer_height_mm;
|
||||
const float sample_step_mm = std::clamp(max_width_mm * 0.5f, 0.16f, 0.40f);
|
||||
for (size_t point_idx = 1; point_idx < path.polyline.points.size(); ++point_idx) {
|
||||
const Point p0 = path.polyline.points[point_idx - 1];
|
||||
const Point p1 = path.polyline.points[point_idx];
|
||||
const double len_mm = unscale<double>(p0.distance_to(p1));
|
||||
if (!std::isfinite(len_mm) || len_mm <= EPSILON)
|
||||
continue;
|
||||
const int steps = std::max(1, int(std::ceil(len_mm / sample_step_mm)));
|
||||
for (int step = 0; step < steps; ++step) {
|
||||
const double t0 = double(step) / double(steps);
|
||||
const double t1 = double(step + 1) / double(steps);
|
||||
const Point q0 = lerp(p0, p1, t0);
|
||||
const Point q1 = lerp(p0, p1, t1);
|
||||
if (q0 == q1)
|
||||
continue;
|
||||
const Point qm = lerp(p0, p1, 0.5 * (t0 + t1));
|
||||
const std::vector<float> weights =
|
||||
sample_weight_field_components(context.weight_field,
|
||||
unscale<float>(qm.x()),
|
||||
unscale<float>(qm.y()),
|
||||
context.high_resolution_texture_sampling);
|
||||
const float coverage = context.active_component_idx < weights.size() ?
|
||||
std::clamp(weights[context.active_component_idx], 0.f, 1.f) :
|
||||
0.f;
|
||||
const float width = std::clamp(min_width_mm + coverage * (max_width_mm - min_width_mm),
|
||||
min_width_mm,
|
||||
max_width_mm);
|
||||
Polyline polyline;
|
||||
polyline.points.emplace_back(q0);
|
||||
polyline.points.emplace_back(q1);
|
||||
ExtrusionPath segment(std::move(polyline), path);
|
||||
segment.width = width;
|
||||
segment.height = height;
|
||||
segment.mm3_per_mm = Flow(width, height, nozzle_diameter).mm3_per_mm();
|
||||
out.emplace_back(std::move(segment));
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static ExtrusionEntity* top_surface_image_modulated_entity(const ExtrusionEntity &entity,
|
||||
const TextureMappingOffsetContext &context,
|
||||
float min_width_mm,
|
||||
float max_width_mm,
|
||||
float nozzle_diameter)
|
||||
{
|
||||
if (const ExtrusionPath *path = dynamic_cast<const ExtrusionPath *>(&entity)) {
|
||||
ExtrusionPaths paths = top_surface_image_split_path(*path, context, min_width_mm, max_width_mm, nozzle_diameter);
|
||||
if (paths.empty())
|
||||
return entity.clone();
|
||||
return new ExtrusionMultiPath(std::move(paths));
|
||||
}
|
||||
if (const ExtrusionMultiPath *multi_path = dynamic_cast<const ExtrusionMultiPath *>(&entity)) {
|
||||
ExtrusionPaths paths;
|
||||
for (const ExtrusionPath &path : multi_path->paths) {
|
||||
ExtrusionPaths split = top_surface_image_split_path(path, context, min_width_mm, max_width_mm, nozzle_diameter);
|
||||
append(paths, std::move(split));
|
||||
}
|
||||
if (paths.empty())
|
||||
return entity.clone();
|
||||
ExtrusionMultiPath *out = new ExtrusionMultiPath(std::move(paths));
|
||||
if (!multi_path->can_reverse())
|
||||
out->set_reverse();
|
||||
return out;
|
||||
}
|
||||
if (const ExtrusionLoop *loop = dynamic_cast<const ExtrusionLoop *>(&entity)) {
|
||||
ExtrusionPaths paths;
|
||||
for (const ExtrusionPath &path : loop->paths) {
|
||||
ExtrusionPaths split = top_surface_image_split_path(path, context, min_width_mm, max_width_mm, nozzle_diameter);
|
||||
append(paths, std::move(split));
|
||||
}
|
||||
if (paths.empty())
|
||||
return entity.clone();
|
||||
return new ExtrusionLoop(std::move(paths));
|
||||
}
|
||||
if (const ExtrusionEntityCollection *collection = dynamic_cast<const ExtrusionEntityCollection *>(&entity)) {
|
||||
ExtrusionEntityCollection *out = new ExtrusionEntityCollection(*collection);
|
||||
for (ExtrusionEntity *&child : out->entities) {
|
||||
ExtrusionEntity *replacement =
|
||||
top_surface_image_modulated_entity(*child, context, min_width_mm, max_width_mm, nozzle_diameter);
|
||||
delete child;
|
||||
child = replacement;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
return entity.clone();
|
||||
}
|
||||
|
||||
static std::vector<float> top_surface_image_same_layer_fractions(const std::optional<TextureMappingOffsetContext> &context,
|
||||
int component_count,
|
||||
float x_mm,
|
||||
float y_mm)
|
||||
{
|
||||
component_count = std::max(1, component_count);
|
||||
std::vector<float> fractions(size_t(component_count), 1.f / float(component_count));
|
||||
if (!context)
|
||||
return fractions;
|
||||
std::vector<float> weights =
|
||||
sample_weight_field_components(context->weight_field,
|
||||
x_mm,
|
||||
y_mm,
|
||||
context->high_resolution_texture_sampling);
|
||||
if (weights.size() != size_t(component_count))
|
||||
return fractions;
|
||||
fractions.assign(size_t(component_count), 0.f);
|
||||
float sum = 0.f;
|
||||
for (size_t i = 0; i < weights.size(); ++i) {
|
||||
fractions[i] = std::max(0.f, weights[i]);
|
||||
sum += fractions[i];
|
||||
}
|
||||
if (sum <= EPSILON || !std::isfinite(sum)) {
|
||||
std::fill(fractions.begin(), fractions.end(), 1.f / float(component_count));
|
||||
return fractions;
|
||||
}
|
||||
for (float &fraction : fractions)
|
||||
fraction /= sum;
|
||||
return fractions;
|
||||
}
|
||||
|
||||
static void top_surface_image_same_layer_partition_fill(ExtrusionEntityCollection &collection,
|
||||
const Surface &surface,
|
||||
const SurfaceFillParams ¶ms,
|
||||
const std::optional<TextureMappingOffsetContext> &context)
|
||||
{
|
||||
int component_count = std::max(1, params.texture_mapping_top_surface_component_count);
|
||||
int component_index = std::clamp(params.texture_mapping_top_surface_component_index, 0, component_count - 1);
|
||||
if (context && int(context->component_ids.size()) == component_count) {
|
||||
auto component_it = std::find(context->component_ids.begin(),
|
||||
context->component_ids.end(),
|
||||
params.texture_mapping_top_surface_component_id);
|
||||
if (component_it != context->component_ids.end())
|
||||
component_index = int(std::distance(context->component_ids.begin(), component_it));
|
||||
component_index = std::clamp(component_index, 0, component_count - 1);
|
||||
}
|
||||
const float min_width = std::clamp(params.texture_mapping_top_surface_min_width_mm,
|
||||
TextureMappingZone::MinTopSurfaceImageLineWidthMm,
|
||||
TextureMappingZone::MaxTopSurfaceImageLineWidthMm);
|
||||
const float max_width = std::clamp(params.texture_mapping_top_surface_max_width_mm,
|
||||
min_width,
|
||||
TextureMappingZone::MaxTopSurfaceImageLineWidthMm);
|
||||
const float pitch = min_width * float(component_count) + (max_width - min_width);
|
||||
if (pitch <= EPSILON)
|
||||
return;
|
||||
const BoundingBox bbox = get_extents(surface.expolygon);
|
||||
if (!bbox.defined)
|
||||
return;
|
||||
const double theta = params.angle;
|
||||
const double cos_t = std::cos(theta);
|
||||
const double sin_t = std::sin(theta);
|
||||
double min_u = std::numeric_limits<double>::max();
|
||||
double min_v = std::numeric_limits<double>::max();
|
||||
double max_u = -std::numeric_limits<double>::max();
|
||||
double max_v = -std::numeric_limits<double>::max();
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
const Point corner = bbox[i];
|
||||
const double x = unscale<double>(corner.x());
|
||||
const double y = unscale<double>(corner.y());
|
||||
const double u = x * cos_t + y * sin_t;
|
||||
const double v = -x * sin_t + y * cos_t;
|
||||
min_u = std::min(min_u, u);
|
||||
max_u = std::max(max_u, u);
|
||||
min_v = std::min(min_v, v);
|
||||
max_v = std::max(max_v, v);
|
||||
}
|
||||
const double sample_step = std::clamp(double(max_width), 0.32, 0.80);
|
||||
const double u_start = std::floor((min_u - pitch) / sample_step) * sample_step;
|
||||
const double u_end = std::ceil((max_u + pitch) / sample_step) * sample_step;
|
||||
const int band_start = int(std::floor((min_v - pitch) / double(pitch)));
|
||||
const int band_end = int(std::ceil((max_v + pitch) / double(pitch)));
|
||||
const ExPolygons clip { surface.expolygon };
|
||||
for (int band = band_start; band <= band_end; ++band) {
|
||||
const double band_v = double(band) * double(pitch);
|
||||
const double sample_v = band_v + double(pitch) * 0.5;
|
||||
for (double u0 = u_start; u0 < u_end - EPSILON; u0 += sample_step) {
|
||||
const double u1 = std::min(u0 + sample_step, u_end);
|
||||
const double um = 0.5 * (u0 + u1);
|
||||
const double sample_x = um * cos_t - sample_v * sin_t;
|
||||
const double sample_y = um * sin_t + sample_v * cos_t;
|
||||
const std::vector<float> fractions =
|
||||
top_surface_image_same_layer_fractions(context,
|
||||
component_count,
|
||||
float(sample_x),
|
||||
float(sample_y));
|
||||
const float available_width = std::max(0.f, pitch - min_width * float(component_count));
|
||||
double lane_offset = 0.0;
|
||||
float lane_width = min_width;
|
||||
for (int i = 0; i < component_count; ++i) {
|
||||
const float width = min_width + available_width * fractions[size_t(i)];
|
||||
if (i == component_index) {
|
||||
lane_width = width;
|
||||
break;
|
||||
}
|
||||
lane_offset += width;
|
||||
}
|
||||
lane_width = std::clamp(lane_width, min_width, max_width);
|
||||
const double v_center = band_v + lane_offset + 0.5 * double(lane_width);
|
||||
const double x0 = u0 * cos_t - v_center * sin_t;
|
||||
const double y0 = u0 * sin_t + v_center * cos_t;
|
||||
const double x1 = u1 * cos_t - v_center * sin_t;
|
||||
const double y1 = u1 * sin_t + v_center * cos_t;
|
||||
Polyline polyline;
|
||||
polyline.points.emplace_back(Point::new_scale(x0, y0));
|
||||
polyline.points.emplace_back(Point::new_scale(x1, y1));
|
||||
if (polyline.points.front() == polyline.points.back())
|
||||
continue;
|
||||
ExtrusionPath path(params.extrusion_role,
|
||||
Flow(lane_width, params.flow.height(), params.flow.nozzle_diameter()).mm3_per_mm(),
|
||||
lane_width,
|
||||
params.flow.height());
|
||||
path.polyline = std::move(polyline);
|
||||
path.intersect_expolygons(clip, &collection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void apply_top_surface_image_collection_metadata(ExtrusionEntityCollection &collection,
|
||||
const SurfaceFillParams ¶ms,
|
||||
const std::optional<TextureMappingOffsetContext> &context)
|
||||
{
|
||||
collection.texture_mapping_top_surface_image = true;
|
||||
collection.texture_mapping_top_surface_zone_id = params.texture_mapping_top_surface_zone_id;
|
||||
collection.texture_mapping_top_surface_desired_component_id = params.texture_mapping_top_surface_component_id;
|
||||
collection.texture_mapping_top_surface_stack_depth = params.texture_mapping_top_surface_stack_depth;
|
||||
collection.texture_mapping_top_surface_fixed_coloring = params.texture_mapping_top_surface_fixed_coloring;
|
||||
if (params.texture_mapping_top_surface_fixed_coloring &&
|
||||
params.texture_mapping_top_surface_component_id > 0)
|
||||
collection.texture_mapping_extruder_override = int(params.texture_mapping_top_surface_component_id - 1);
|
||||
if (!context)
|
||||
return;
|
||||
ExtrusionEntitiesPtr replacement;
|
||||
replacement.reserve(collection.entities.size());
|
||||
for (const ExtrusionEntity *entity : collection.entities)
|
||||
replacement.emplace_back(top_surface_image_modulated_entity(*entity,
|
||||
*context,
|
||||
params.texture_mapping_top_surface_min_width_mm,
|
||||
params.texture_mapping_top_surface_max_width_mm,
|
||||
params.flow.nozzle_diameter()));
|
||||
collection.clear();
|
||||
collection.entities = std::move(replacement);
|
||||
}
|
||||
|
||||
|
||||
// Detect narrow infill regions
|
||||
// Based on the anti-vibration algorithm from PrusaSlicer:
|
||||
@@ -836,6 +1412,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
|
||||
SurfaceFillParams params;
|
||||
bool has_internal_voids = false;
|
||||
const PrintObjectConfig& object_config = layer.object()->config();
|
||||
const std::vector<TopSurfaceImageRegionPlan> top_surface_plans = top_surface_image_region_plans(layer);
|
||||
|
||||
auto append_flow_param = [](std::map<Flow, ExPolygons> &flow_params, Flow flow, const ExPolygon &exp) {
|
||||
auto it = flow_params.find(flow);
|
||||
@@ -1012,23 +1589,50 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
|
||||
if (surface.surface_type != stInternalVoid) {
|
||||
const SurfaceFillParams *params = region_to_surface_params[region_id][&surface - &layerm.fill_surfaces.surfaces.front()];
|
||||
if (params != nullptr) {
|
||||
SurfaceFill &fill = surface_fills[params->idx];
|
||||
if (fill.region_id == size_t(-1)) {
|
||||
fill.region_id = region_id;
|
||||
fill.surface = surface;
|
||||
fill.expolygons.emplace_back(std::move(fill.surface.expolygon));
|
||||
//BBS
|
||||
fill.region_id_group.push_back(region_id);
|
||||
fill.no_overlap_expolygons = layerm.fill_no_overlap_expolygons;
|
||||
} else {
|
||||
fill.expolygons.emplace_back(surface.expolygon);
|
||||
//BBS
|
||||
auto t = find(fill.region_id_group.begin(), fill.region_id_group.end(), region_id);
|
||||
if (t == fill.region_id_group.end()) {
|
||||
fill.region_id_group.push_back(region_id);
|
||||
fill.no_overlap_expolygons = union_ex(fill.no_overlap_expolygons, layerm.fill_no_overlap_expolygons);
|
||||
}
|
||||
}
|
||||
ExPolygons remaining = { surface.expolygon };
|
||||
if (region_id < top_surface_plans.size() &&
|
||||
top_surface_plans[region_id].zone != nullptr &&
|
||||
(surface.is_top() || surface.surface_type == stInternalSolid) &&
|
||||
!surface.is_bridge()) {
|
||||
const TopSurfaceImageRegionPlan &plan = top_surface_plans[region_id];
|
||||
for (size_t slice_idx = 0; slice_idx < plan.slices.size();) {
|
||||
const TopSurfaceImageStackSlice &slice = plan.slices[slice_idx];
|
||||
if (remaining.empty())
|
||||
break;
|
||||
ExPolygons image_expolygons = intersection_ex(remaining, slice.area, ApplySafetyOffset::Yes);
|
||||
if (image_expolygons.empty()) {
|
||||
++slice_idx;
|
||||
continue;
|
||||
}
|
||||
ExPolygons image_clip = image_expolygons;
|
||||
if (slice.same_layer_partition) {
|
||||
size_t same_depth_end = slice_idx;
|
||||
while (same_depth_end < plan.slices.size() &&
|
||||
plan.slices[same_depth_end].same_layer_partition &&
|
||||
plan.slices[same_depth_end].depth == slice.depth)
|
||||
++same_depth_end;
|
||||
for (size_t same_idx = slice_idx; same_idx < same_depth_end; ++same_idx) {
|
||||
SurfaceFillParams image_params =
|
||||
top_surface_image_params_for_slice(layer, surface, *params, plan, plan.slices[same_idx]);
|
||||
ExPolygons component_expolygons = image_expolygons;
|
||||
SurfaceFill &image_fill = surface_fill_for_params(surface_fills, image_params);
|
||||
append_surface_fill_expolygons(image_fill, region_id, surface, std::move(component_expolygons), layerm);
|
||||
}
|
||||
slice_idx = same_depth_end;
|
||||
} else {
|
||||
SurfaceFillParams image_params =
|
||||
top_surface_image_params_for_slice(layer, surface, *params, plan, slice);
|
||||
SurfaceFill &image_fill = surface_fill_for_params(surface_fills, image_params);
|
||||
append_surface_fill_expolygons(image_fill, region_id, surface, std::move(image_expolygons), layerm);
|
||||
++slice_idx;
|
||||
}
|
||||
remaining = diff_ex(remaining, image_clip, ApplySafetyOffset::Yes);
|
||||
}
|
||||
}
|
||||
if (!remaining.empty()) {
|
||||
SurfaceFill &fill = surface_fills[params->idx];
|
||||
append_surface_fill_expolygons(fill, region_id, surface, std::move(remaining), layerm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1037,6 +1641,8 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
|
||||
Polygons all_polygons;
|
||||
for (SurfaceFill &fill : surface_fills)
|
||||
if (! fill.expolygons.empty()) {
|
||||
if (fill.params.texture_mapping_top_surface_same_layer_partition)
|
||||
continue;
|
||||
if (fill.expolygons.size() > 1 || ! all_polygons.empty()) {
|
||||
Polygons polys = to_polygons(std::move(fill.expolygons));
|
||||
// Make a union of polygons, use a safety offset, subtract the preceding polygons.
|
||||
@@ -1098,7 +1704,9 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
|
||||
region_id = region_some_infill;
|
||||
const LayerRegion& layerm = *layer.regions()[region_id];
|
||||
for (SurfaceFill &surface_fill : surface_fills)
|
||||
if (surface_fill.surface.surface_type == stInternalSolid && std::abs(layer.height - surface_fill.params.flow.height()) < EPSILON) {
|
||||
if (surface_fill.surface.surface_type == stInternalSolid &&
|
||||
!surface_fill.params.texture_mapping_top_surface_image &&
|
||||
std::abs(layer.height - surface_fill.params.flow.height()) < EPSILON) {
|
||||
internal_solid_fill = &surface_fill;
|
||||
break;
|
||||
}
|
||||
@@ -1135,7 +1743,8 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
|
||||
if (layer.object()->config().detect_narrow_internal_solid_infill) {
|
||||
size_t surface_fills_size = surface_fills.size();
|
||||
for (size_t i = 0; i < surface_fills_size; i++) {
|
||||
if (surface_fills[i].surface.surface_type != stInternalSolid)
|
||||
if (surface_fills[i].surface.surface_type != stInternalSolid ||
|
||||
surface_fills[i].params.texture_mapping_top_surface_image)
|
||||
continue;
|
||||
|
||||
ExPolygons normal_infill;
|
||||
@@ -1300,6 +1909,37 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
||||
}
|
||||
if (surface_fill.params.pattern == ipGrid)
|
||||
params.can_reverse = false;
|
||||
|
||||
std::optional<TextureMappingOffsetContext> top_surface_image_context;
|
||||
if (surface_fill.params.texture_mapping_top_surface_image) {
|
||||
const Print *print = this->object()->print();
|
||||
const TextureMappingZone *zone = print != nullptr ?
|
||||
print->texture_mapping_manager().zone_from_id(surface_fill.params.texture_mapping_top_surface_zone_id) :
|
||||
nullptr;
|
||||
if (print != nullptr && zone != nullptr) {
|
||||
const PrintConfig &print_config = print->config();
|
||||
std::vector<std::string> filament_colours = print_config.filament_colour.values;
|
||||
filament_colours.resize(print_config.filament_colour.values.size(), "#FFFFFF");
|
||||
std::vector<unsigned int> components =
|
||||
TextureMappingManager::effective_texture_component_ids(*zone,
|
||||
print_config.filament_colour.values.size(),
|
||||
filament_colours);
|
||||
const std::optional<std::array<float, 4>> background =
|
||||
top_surface_image_equal_blend_background(print_config, components);
|
||||
top_surface_image_context =
|
||||
build_texture_mapping_offset_context_for_layer(*this->object(),
|
||||
*this,
|
||||
*zone,
|
||||
surface_fill.params.texture_mapping_top_surface_zone_id,
|
||||
surface_fill.params.texture_mapping_top_surface_component_id,
|
||||
surface_fill.params.texture_mapping_top_surface_max_width_mm,
|
||||
float(this->height),
|
||||
std::nullopt,
|
||||
surface_fill.params.texture_mapping_top_surface_min_width_mm,
|
||||
background);
|
||||
}
|
||||
}
|
||||
|
||||
for (ExPolygon& expoly : surface_fill.expolygons) {
|
||||
|
||||
f->no_overlap_expolygons = intersection_ex(surface_fill.no_overlap_expolygons, ExPolygons() = {expoly}, ApplySafetyOffset::Yes);
|
||||
@@ -1328,9 +1968,30 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
||||
params.density = elefant_density * (elefant_layers - (f->layer_id - 1)) / elefant_layers;
|
||||
}
|
||||
// make fill
|
||||
f->fill_surface_extrusion(&surface_fill.surface,
|
||||
params,
|
||||
m_regions[surface_fill.region_id]->fills.entities);
|
||||
ExtrusionEntitiesPtr &fill_entities = m_regions[surface_fill.region_id]->fills.entities;
|
||||
if (surface_fill.params.texture_mapping_top_surface_same_layer_partition) {
|
||||
ExtrusionEntityCollection *collection = new ExtrusionEntityCollection();
|
||||
top_surface_image_same_layer_partition_fill(*collection,
|
||||
surface_fill.surface,
|
||||
surface_fill.params,
|
||||
top_surface_image_context);
|
||||
if (!collection->empty()) {
|
||||
apply_top_surface_image_collection_metadata(*collection, surface_fill.params, std::nullopt);
|
||||
fill_entities.push_back(collection);
|
||||
} else {
|
||||
delete collection;
|
||||
}
|
||||
} else {
|
||||
const size_t fill_entities_before = fill_entities.size();
|
||||
f->fill_surface_extrusion(&surface_fill.surface,
|
||||
params,
|
||||
fill_entities);
|
||||
if (surface_fill.params.texture_mapping_top_surface_image) {
|
||||
for (size_t i = fill_entities_before; i < fill_entities.size(); ++i)
|
||||
if (ExtrusionEntityCollection *collection = dynamic_cast<ExtrusionEntityCollection *>(fill_entities[i]))
|
||||
apply_top_surface_image_collection_metadata(*collection, surface_fill.params, top_surface_image_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1341,8 +2002,14 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
||||
for (LayerRegion *layerm : m_regions)
|
||||
for (const ExtrusionEntity *thin_fill : layerm->thin_fills.entities) {
|
||||
ExtrusionEntityCollection &collection = *(new ExtrusionEntityCollection());
|
||||
if (const auto *thin_fill_collection = dynamic_cast<const ExtrusionEntityCollection *>(thin_fill))
|
||||
if (const auto *thin_fill_collection = dynamic_cast<const ExtrusionEntityCollection *>(thin_fill)) {
|
||||
collection.texture_mapping_extruder_override = thin_fill_collection->texture_mapping_extruder_override;
|
||||
collection.texture_mapping_top_surface_image = thin_fill_collection->texture_mapping_top_surface_image;
|
||||
collection.texture_mapping_top_surface_zone_id = thin_fill_collection->texture_mapping_top_surface_zone_id;
|
||||
collection.texture_mapping_top_surface_desired_component_id = thin_fill_collection->texture_mapping_top_surface_desired_component_id;
|
||||
collection.texture_mapping_top_surface_stack_depth = thin_fill_collection->texture_mapping_top_surface_stack_depth;
|
||||
collection.texture_mapping_top_surface_fixed_coloring = thin_fill_collection->texture_mapping_top_surface_fixed_coloring;
|
||||
}
|
||||
layerm->fills.entities.push_back(&collection);
|
||||
collection.entities.push_back(thin_fill->clone());
|
||||
}
|
||||
|
||||
@@ -113,6 +113,14 @@ unsigned int LayerTools::extruder(const ExtrusionEntityCollection &extrusions, c
|
||||
(this->num_physical_filaments == 0 || unsigned(extrusions.texture_mapping_extruder_override) < this->num_physical_filaments))
|
||||
return unsigned(extrusions.texture_mapping_extruder_override);
|
||||
|
||||
if (extrusions.texture_mapping_top_surface_image &&
|
||||
!extrusions.texture_mapping_top_surface_fixed_coloring &&
|
||||
extrusions.texture_mapping_top_surface_desired_component_id > 0) {
|
||||
const unsigned int desired = extrusions.texture_mapping_top_surface_desired_component_id - 1;
|
||||
if (this->has_extruder(desired))
|
||||
return desired;
|
||||
}
|
||||
|
||||
assert(region.config().wall_filament.value > 0);
|
||||
assert(region.config().sparse_infill_filament.value > 0);
|
||||
assert(region.config().solid_infill_filament.value > 0);
|
||||
@@ -214,6 +222,19 @@ static FilamentChangeStats calc_filament_change_info_by_toolorder(const PrintCon
|
||||
|
||||
static void apply_first_layer_order(const DynamicPrintConfig* config, std::vector<unsigned int>& tool_order);
|
||||
|
||||
static void apply_top_surface_no_fixed_carry(LayerTools <, unsigned int last_extruder_id)
|
||||
{
|
||||
if (last_extruder_id == 0 || lt.extruders.empty())
|
||||
return;
|
||||
if (std::find(lt.extruders.begin(), lt.extruders.end(), last_extruder_id) != lt.extruders.end())
|
||||
return;
|
||||
for (unsigned int desired : lt.top_surface_image_no_fixed_desired_extruders)
|
||||
if (desired == last_extruder_id) {
|
||||
lt.extruders.insert(lt.extruders.begin(), desired);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ToolOrdering::handle_dontcare_extruder(const std::vector<unsigned int>& tool_order_layer0)
|
||||
{
|
||||
if(m_layer_tools.empty() || tool_order_layer0.empty())
|
||||
@@ -267,6 +288,7 @@ void ToolOrdering::handle_dontcare_extruder(const std::vector<unsigned int>& too
|
||||
break;
|
||||
}
|
||||
}
|
||||
apply_top_surface_no_fixed_carry(lt, last_extruder_id);
|
||||
last_extruder_id = lt.extruders.back();
|
||||
}
|
||||
|
||||
@@ -311,7 +333,8 @@ void ToolOrdering::handle_dontcare_extruder(unsigned int last_extruder_id)
|
||||
++ last_extruder_id;
|
||||
}
|
||||
|
||||
for (LayerTools < : m_layer_tools) {
|
||||
for (size_t layer_idx = 0; layer_idx < m_layer_tools.size(); ++layer_idx) {
|
||||
LayerTools < = m_layer_tools[layer_idx];
|
||||
if (lt.extruders.empty())
|
||||
continue;
|
||||
if (lt.extruders.size() == 1 && lt.extruders.front() == 0)
|
||||
@@ -345,6 +368,8 @@ void ToolOrdering::handle_dontcare_extruder(unsigned int last_extruder_id)
|
||||
}
|
||||
|
||||
}
|
||||
if (layer_idx > 0)
|
||||
apply_top_surface_no_fixed_carry(lt, last_extruder_id);
|
||||
last_extruder_id = lt.extruders.back();
|
||||
}
|
||||
|
||||
@@ -847,6 +872,13 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
|
||||
has_texture_override_fill = true;
|
||||
continue;
|
||||
}
|
||||
if (fill->texture_mapping_top_surface_image &&
|
||||
!fill->texture_mapping_top_surface_fixed_coloring &&
|
||||
fill->texture_mapping_top_surface_desired_component_id >= 1 &&
|
||||
(layer_tools.num_physical_filaments == 0 ||
|
||||
fill->texture_mapping_top_surface_desired_component_id <= layer_tools.num_physical_filaments))
|
||||
layer_tools.top_surface_image_no_fixed_desired_extruders.emplace_back(
|
||||
fill->texture_mapping_top_surface_desired_component_id);
|
||||
ExtrusionRole role = fill->entities.empty() ? erNone : fill->entities.front()->role();
|
||||
if (is_solid_infill(role))
|
||||
has_solid_infill = true;
|
||||
@@ -933,6 +965,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
|
||||
sort_remove_duplicates(layer.extruders);
|
||||
sort_remove_duplicates(layer.texture_mapping_extruders);
|
||||
sort_remove_duplicates(layer.texture_mapping_component_extruders);
|
||||
sort_remove_duplicates(layer.top_surface_image_no_fixed_desired_extruders);
|
||||
|
||||
// make sure that there are some tools for each object layer (e.g. tall wiping object will result in empty extruders vector)
|
||||
if (layer.extruders.empty() && layer.has_object)
|
||||
|
||||
@@ -158,6 +158,7 @@ public:
|
||||
std::vector<unsigned int> extruders;
|
||||
std::vector<unsigned int> texture_mapping_extruders;
|
||||
std::vector<unsigned int> texture_mapping_component_extruders;
|
||||
std::vector<unsigned int> top_surface_image_no_fixed_desired_extruders;
|
||||
// If per layer extruder switches are inserted by the G-code preview slider, this value contains the new (1 based) extruder, with which the whole object layer is being printed with.
|
||||
// If not overriden, it is set to 0.
|
||||
unsigned int extruder_override = 0;
|
||||
|
||||
@@ -666,6 +666,20 @@ static int modulation_mode_from_name(const std::string &name)
|
||||
return int(TextureMappingZone::ModulationLineWidth);
|
||||
}
|
||||
|
||||
static std::string top_surface_image_printing_method_name(int method)
|
||||
{
|
||||
if (method == int(TextureMappingZone::TopSurfaceImageSameLayer45Partition))
|
||||
return std::string("same_layer_45_partition");
|
||||
return std::string("same_angle_45_width");
|
||||
}
|
||||
|
||||
static int top_surface_image_printing_method_from_name(const std::string &name)
|
||||
{
|
||||
if (name == "same_layer_45_partition")
|
||||
return int(TextureMappingZone::TopSurfaceImageSameLayer45Partition);
|
||||
return int(TextureMappingZone::TopSurfaceImageSameAngle45Width);
|
||||
}
|
||||
|
||||
static std::string top_visible_recolor_aggressiveness_name(int mode)
|
||||
{
|
||||
switch (clamp_int(mode,
|
||||
@@ -1024,6 +1038,12 @@ bool TextureMappingZone::operator==(const TextureMappingZone &rhs) const
|
||||
top_visible_perimeter_recolor_aggressiveness == rhs.top_visible_perimeter_recolor_aggressiveness &&
|
||||
top_visible_perimeter_recolor_above_layers == rhs.top_visible_perimeter_recolor_above_layers &&
|
||||
top_visible_perimeter_recolor_point_sampling == rhs.top_visible_perimeter_recolor_point_sampling &&
|
||||
top_surface_image_printing_enabled == rhs.top_surface_image_printing_enabled &&
|
||||
top_surface_image_printing_method == rhs.top_surface_image_printing_method &&
|
||||
std::abs(top_surface_image_min_line_width_mm - rhs.top_surface_image_min_line_width_mm) <= eps &&
|
||||
std::abs(top_surface_image_max_line_width_mm - rhs.top_surface_image_max_line_width_mm) <= eps &&
|
||||
top_surface_image_colored_top_layers == rhs.top_surface_image_colored_top_layers &&
|
||||
top_surface_image_fixed_coloring_filaments == rhs.top_surface_image_fixed_coloring_filaments &&
|
||||
compact_offset_mode == rhs.compact_offset_mode &&
|
||||
use_legacy_fixed_color_mode == rhs.use_legacy_fixed_color_mode &&
|
||||
high_speed_image_texture_sampling == rhs.high_speed_image_texture_sampling &&
|
||||
@@ -1362,6 +1382,25 @@ std::string TextureMappingManager::serialize_entries()
|
||||
TextureMappingZone::MinTopVisiblePerimeterRecolorAboveLayers,
|
||||
TextureMappingZone::MaxTopVisiblePerimeterRecolorAboveLayers);
|
||||
texture["top_visible_perimeter_recolor_point_sampling"] = zone.top_visible_perimeter_recolor_point_sampling;
|
||||
texture["top_surface_image_printing_enabled"] = zone.top_surface_image_printing_enabled;
|
||||
texture["top_surface_image_printing_method"] =
|
||||
top_surface_image_printing_method_name(zone.top_surface_image_printing_method);
|
||||
const float top_surface_max_width =
|
||||
std::clamp(finite_or(zone.top_surface_image_max_line_width_mm,
|
||||
TextureMappingZone::DefaultTopSurfaceImageMaxLineWidthMm),
|
||||
TextureMappingZone::MinTopSurfaceImageLineWidthMm,
|
||||
TextureMappingZone::MaxTopSurfaceImageLineWidthMm);
|
||||
texture["top_surface_image_min_line_width_mm"] =
|
||||
std::clamp(finite_or(zone.top_surface_image_min_line_width_mm,
|
||||
TextureMappingZone::DefaultTopSurfaceImageMinLineWidthMm),
|
||||
TextureMappingZone::MinTopSurfaceImageLineWidthMm,
|
||||
top_surface_max_width);
|
||||
texture["top_surface_image_max_line_width_mm"] = top_surface_max_width;
|
||||
texture["top_surface_image_colored_top_layers"] =
|
||||
clamp_int(zone.top_surface_image_colored_top_layers,
|
||||
TextureMappingZone::MinTopSurfaceImageColoredTopLayers,
|
||||
TextureMappingZone::MaxTopSurfaceImageColoredTopLayers);
|
||||
texture["top_surface_image_fixed_coloring_filaments"] = zone.top_surface_image_fixed_coloring_filaments;
|
||||
texture["compact_offset_mode"] = zone.compact_offset_mode;
|
||||
texture["use_legacy_fixed_color_mode"] = zone.use_legacy_fixed_color_mode;
|
||||
texture["high_speed_image_texture_sampling"] = true;
|
||||
@@ -1560,6 +1599,33 @@ void TextureMappingManager::load_entries(const std::string &serialized,
|
||||
zone.top_visible_perimeter_recolor_point_sampling =
|
||||
texture.value("top_visible_perimeter_recolor_point_sampling",
|
||||
TextureMappingZone::DefaultTopVisiblePerimeterRecolorPointSampling);
|
||||
zone.top_surface_image_printing_enabled =
|
||||
texture.value("top_surface_image_printing_enabled",
|
||||
TextureMappingZone::DefaultTopSurfaceImagePrintingEnabled);
|
||||
zone.top_surface_image_printing_method =
|
||||
top_surface_image_printing_method_from_name(
|
||||
texture.value("top_surface_image_printing_method",
|
||||
top_surface_image_printing_method_name(TextureMappingZone::DefaultTopSurfaceImagePrintingMethod)));
|
||||
zone.top_surface_image_max_line_width_mm =
|
||||
std::clamp(finite_or(texture.value("top_surface_image_max_line_width_mm",
|
||||
TextureMappingZone::DefaultTopSurfaceImageMaxLineWidthMm),
|
||||
TextureMappingZone::DefaultTopSurfaceImageMaxLineWidthMm),
|
||||
TextureMappingZone::MinTopSurfaceImageLineWidthMm,
|
||||
TextureMappingZone::MaxTopSurfaceImageLineWidthMm);
|
||||
zone.top_surface_image_min_line_width_mm =
|
||||
std::clamp(finite_or(texture.value("top_surface_image_min_line_width_mm",
|
||||
TextureMappingZone::DefaultTopSurfaceImageMinLineWidthMm),
|
||||
TextureMappingZone::DefaultTopSurfaceImageMinLineWidthMm),
|
||||
TextureMappingZone::MinTopSurfaceImageLineWidthMm,
|
||||
zone.top_surface_image_max_line_width_mm);
|
||||
zone.top_surface_image_colored_top_layers =
|
||||
clamp_int(texture.value("top_surface_image_colored_top_layers",
|
||||
TextureMappingZone::DefaultTopSurfaceImageColoredTopLayers),
|
||||
TextureMappingZone::MinTopSurfaceImageColoredTopLayers,
|
||||
TextureMappingZone::MaxTopSurfaceImageColoredTopLayers);
|
||||
zone.top_surface_image_fixed_coloring_filaments =
|
||||
texture.value("top_surface_image_fixed_coloring_filaments",
|
||||
TextureMappingZone::DefaultTopSurfaceImageFixedColoringFilaments);
|
||||
zone.compact_offset_mode = texture.value("compact_offset_mode", TextureMappingZone::DefaultCompactOffsetMode);
|
||||
zone.use_legacy_fixed_color_mode =
|
||||
texture.value("use_legacy_fixed_color_mode", TextureMappingZone::DefaultUseLegacyFixedColorMode);
|
||||
|
||||
@@ -66,6 +66,11 @@ struct TextureMappingZone
|
||||
TopVisibleRecolorAggressive = 2
|
||||
};
|
||||
|
||||
enum TopSurfaceImagePrintingMethod : uint8_t {
|
||||
TopSurfaceImageSameAngle45Width = 0,
|
||||
TopSurfaceImageSameLayer45Partition = 1
|
||||
};
|
||||
|
||||
enum FilamentColorMode : uint8_t {
|
||||
FilamentColorAny = 0,
|
||||
FilamentColorRGB = 1,
|
||||
@@ -140,6 +145,16 @@ struct TextureMappingZone
|
||||
static constexpr int MaxTopVisiblePerimeterRecolorAboveLayers = 5;
|
||||
static constexpr int DefaultTopVisiblePerimeterRecolorAboveLayers = 2;
|
||||
static constexpr bool DefaultTopVisiblePerimeterRecolorPointSampling = true;
|
||||
static constexpr bool DefaultTopSurfaceImagePrintingEnabled = false;
|
||||
static constexpr int DefaultTopSurfaceImagePrintingMethod = int(TopSurfaceImageSameAngle45Width);
|
||||
static constexpr float MinTopSurfaceImageLineWidthMm = 0.32f;
|
||||
static constexpr float MaxTopSurfaceImageLineWidthMm = 0.80f;
|
||||
static constexpr float DefaultTopSurfaceImageMinLineWidthMm = 0.32f;
|
||||
static constexpr float DefaultTopSurfaceImageMaxLineWidthMm = 0.80f;
|
||||
static constexpr int MinTopSurfaceImageColoredTopLayers = 1;
|
||||
static constexpr int MaxTopSurfaceImageColoredTopLayers = 20;
|
||||
static constexpr int DefaultTopSurfaceImageColoredTopLayers = 3;
|
||||
static constexpr bool DefaultTopSurfaceImageFixedColoringFilaments = true;
|
||||
static constexpr bool DefaultCompactOffsetMode = true;
|
||||
static constexpr bool DefaultUseLegacyFixedColorMode = false;
|
||||
static constexpr bool DefaultHighSpeedImageTextureSampling = true;
|
||||
@@ -228,6 +243,12 @@ struct TextureMappingZone
|
||||
int top_visible_perimeter_recolor_aggressiveness = DefaultTopVisiblePerimeterRecolorAggressiveness;
|
||||
int top_visible_perimeter_recolor_above_layers = DefaultTopVisiblePerimeterRecolorAboveLayers;
|
||||
bool top_visible_perimeter_recolor_point_sampling = DefaultTopVisiblePerimeterRecolorPointSampling;
|
||||
bool top_surface_image_printing_enabled = DefaultTopSurfaceImagePrintingEnabled;
|
||||
int top_surface_image_printing_method = DefaultTopSurfaceImagePrintingMethod;
|
||||
float top_surface_image_min_line_width_mm = DefaultTopSurfaceImageMinLineWidthMm;
|
||||
float top_surface_image_max_line_width_mm = DefaultTopSurfaceImageMaxLineWidthMm;
|
||||
int top_surface_image_colored_top_layers = DefaultTopSurfaceImageColoredTopLayers;
|
||||
bool top_surface_image_fixed_coloring_filaments = DefaultTopSurfaceImageFixedColoringFilaments;
|
||||
bool compact_offset_mode = DefaultCompactOffsetMode;
|
||||
bool use_legacy_fixed_color_mode = DefaultUseLegacyFixedColorMode;
|
||||
bool high_speed_image_texture_sampling = DefaultHighSpeedImageTextureSampling;
|
||||
@@ -272,6 +293,13 @@ struct TextureMappingZone
|
||||
bool is_linear_gradient() const { return surface_pattern == int(LinearGradient); }
|
||||
bool is_radial_linear_gradient() const { return is_linear_gradient() && linear_gradient_mode == int(LinearGradientRadial); }
|
||||
bool is_surface_gradient() const { return is_2d_gradient() || is_linear_gradient(); }
|
||||
bool top_surface_image_printing_active() const
|
||||
{
|
||||
return top_surface_image_printing_enabled &&
|
||||
is_image_texture() &&
|
||||
(top_surface_image_printing_method == int(TopSurfaceImageSameAngle45Width) ||
|
||||
top_surface_image_printing_method == int(TopSurfaceImageSameLayer45Partition));
|
||||
}
|
||||
|
||||
void apply_default_modulation_mode()
|
||||
{
|
||||
@@ -309,6 +337,12 @@ struct TextureMappingZone
|
||||
top_visible_perimeter_recolor_aggressiveness = DefaultTopVisiblePerimeterRecolorAggressiveness;
|
||||
top_visible_perimeter_recolor_above_layers = DefaultTopVisiblePerimeterRecolorAboveLayers;
|
||||
top_visible_perimeter_recolor_point_sampling = DefaultTopVisiblePerimeterRecolorPointSampling;
|
||||
top_surface_image_printing_enabled = DefaultTopSurfaceImagePrintingEnabled;
|
||||
top_surface_image_printing_method = DefaultTopSurfaceImagePrintingMethod;
|
||||
top_surface_image_min_line_width_mm = DefaultTopSurfaceImageMinLineWidthMm;
|
||||
top_surface_image_max_line_width_mm = DefaultTopSurfaceImageMaxLineWidthMm;
|
||||
top_surface_image_colored_top_layers = DefaultTopSurfaceImageColoredTopLayers;
|
||||
top_surface_image_fixed_coloring_filaments = DefaultTopSurfaceImageFixedColoringFilaments;
|
||||
compact_offset_mode = DefaultCompactOffsetMode;
|
||||
use_legacy_fixed_color_mode = DefaultUseLegacyFixedColorMode;
|
||||
high_speed_image_texture_sampling = DefaultHighSpeedImageTextureSampling;
|
||||
|
||||
@@ -1510,7 +1510,8 @@ TextureMappingOffsetWeightField build_texture_mapping_offset_weight_field(
|
||||
float layer_z_mm,
|
||||
float layer_z_falloff_mm,
|
||||
bool high_resolution_texture_sampling,
|
||||
bool high_speed_image_texture_sampling)
|
||||
bool high_speed_image_texture_sampling,
|
||||
std::optional<std::array<float, 4>> image_background_rgba_override)
|
||||
{
|
||||
TextureMappingOffsetWeightField weight_field;
|
||||
if (component_colors.empty())
|
||||
@@ -1616,7 +1617,8 @@ TextureMappingOffsetWeightField build_texture_mapping_offset_weight_field(
|
||||
|
||||
const indexed_triangle_set &its = mesh_ptr->its;
|
||||
const Transform3d volume_trafo = object_trafo * volume->get_matrix();
|
||||
const std::array<float, 4> background_color = texture_mapping_background_color(*volume);
|
||||
const std::array<float, 4> background_color =
|
||||
image_background_rgba_override ? *image_background_rgba_override : texture_mapping_background_color(*volume);
|
||||
|
||||
if (!volume->texture_mapping_color_facets.empty()) {
|
||||
std::vector<ColorFacetTriangle> color_facets;
|
||||
@@ -2813,7 +2815,9 @@ std::optional<TextureMappingOffsetContext> build_texture_mapping_offset_context_
|
||||
unsigned int active_component_id_override,
|
||||
std::optional<float> base_outer_width_mm_override,
|
||||
std::optional<float> layer_height_mm_override,
|
||||
std::optional<Vec2d> plate_origin_mm_override)
|
||||
std::optional<Vec2d> plate_origin_mm_override,
|
||||
std::optional<float> min_outer_width_mm_override,
|
||||
std::optional<std::array<float, 4>> image_background_rgba_override)
|
||||
{
|
||||
const Print *print = print_object.print();
|
||||
if (print == nullptr)
|
||||
@@ -2946,10 +2950,11 @@ std::optional<TextureMappingOffsetContext> build_texture_mapping_offset_context_
|
||||
const float base_outer_width_mm = base_outer_width_mm_override ?
|
||||
std::max(0.05f, *base_outer_width_mm_override) :
|
||||
std::max(0.05f, float(print_config.texture_mapping_outer_wall_gradient_max_line_width.value));
|
||||
const float config_min_gradient_width_mm = std::clamp(
|
||||
float(print_config.texture_mapping_outer_wall_gradient_min_line_width.value),
|
||||
0.05f,
|
||||
base_outer_width_mm);
|
||||
const float config_min_gradient_width_mm = min_outer_width_mm_override ?
|
||||
std::clamp(*min_outer_width_mm_override, 0.05f, base_outer_width_mm) :
|
||||
std::clamp(float(print_config.texture_mapping_outer_wall_gradient_min_line_width.value),
|
||||
0.05f,
|
||||
base_outer_width_mm);
|
||||
const float layer_height_mm = layer_height_mm_override ?
|
||||
std::max(0.01f, *layer_height_mm_override) :
|
||||
std::max(0.01f, float(layer.height));
|
||||
@@ -3019,7 +3024,8 @@ std::optional<TextureMappingOffsetContext> build_texture_mapping_offset_context_
|
||||
float(layer.print_z),
|
||||
layer_sample_falloff_mm,
|
||||
high_resolution_texture_sampling,
|
||||
zone.high_speed_image_texture_sampling);
|
||||
zone.high_speed_image_texture_sampling,
|
||||
image_background_rgba_override);
|
||||
if (weight_field.empty())
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -103,7 +103,9 @@ std::optional<TextureMappingOffsetContext> build_texture_mapping_offset_context_
|
||||
unsigned int active_component_id_override = 0,
|
||||
std::optional<float> base_outer_width_mm_override = std::nullopt,
|
||||
std::optional<float> layer_height_mm_override = std::nullopt,
|
||||
std::optional<Vec2d> plate_origin_mm_override = std::nullopt);
|
||||
std::optional<Vec2d> plate_origin_mm_override = std::nullopt,
|
||||
std::optional<float> min_outer_width_mm_override = std::nullopt,
|
||||
std::optional<std::array<float, 4>> image_background_rgba_override = std::nullopt);
|
||||
|
||||
std::vector<float> sample_weight_field_components(const TextureMappingOffsetWeightField &weight_field,
|
||||
float x_mm,
|
||||
|
||||
@@ -1867,6 +1867,12 @@ public:
|
||||
int dithering_method,
|
||||
float dithering_resolution_mm,
|
||||
float halftone_dot_size_mm,
|
||||
bool top_surface_image_printing_enabled,
|
||||
int top_surface_image_printing_method,
|
||||
float top_surface_image_min_line_width_mm,
|
||||
float top_surface_image_max_line_width_mm,
|
||||
int top_surface_image_colored_top_layers,
|
||||
bool top_surface_image_fixed_coloring_filaments,
|
||||
const TextureMappingManager &texture_mapping_zones,
|
||||
const TextureMappingGlobalSettings &global_settings,
|
||||
const TextureMappingPrimeTowerImage &prime_tower_image,
|
||||
@@ -1892,9 +1898,10 @@ public:
|
||||
tab_choices.Add(_L("Modulation Mode"));
|
||||
tab_choices.Add(_L("Preview Options"));
|
||||
tab_choices.Add(_L("Experimental Options"));
|
||||
tab_choices.Add(_L("Top-surface coloring (experimental)"));
|
||||
tab_choices.Add(_L("Prime Tower Texture Mapping"));
|
||||
m_options_tab_choice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, tab_choices);
|
||||
m_options_tab_choice->SetSelection(std::clamp(initial_options_tab, 0, 5));
|
||||
m_options_tab_choice->SetSelection(std::clamp(initial_options_tab, 0, 6));
|
||||
tab_row->Add(m_options_tab_choice, 1, wxALIGN_CENTER_VERTICAL);
|
||||
root->Add(tab_row, 0, wxEXPAND | wxALL, gap);
|
||||
|
||||
@@ -1914,6 +1921,9 @@ public:
|
||||
auto *experimental_page = new wxPanel(m_options_book, wxID_ANY);
|
||||
auto *experimental_root = new wxBoxSizer(wxVERTICAL);
|
||||
experimental_page->SetSizer(experimental_root);
|
||||
auto *top_surface_page = new wxPanel(m_options_book, wxID_ANY);
|
||||
auto *top_surface_root = new wxBoxSizer(wxVERTICAL);
|
||||
top_surface_page->SetSizer(top_surface_root);
|
||||
auto *global_page = new wxPanel(m_options_book, wxID_ANY);
|
||||
auto *global_root = new wxBoxSizer(wxVERTICAL);
|
||||
global_page->SetSizer(global_root);
|
||||
@@ -2315,6 +2325,104 @@ public:
|
||||
update_modulation_mode_options_visibility(false);
|
||||
experimental_root->Add(experimental_box, 0, wxEXPAND | wxALL, gap);
|
||||
|
||||
auto *top_surface_box = new wxStaticBoxSizer(wxVERTICAL, top_surface_page, _L("Top-surface coloring"));
|
||||
m_top_surface_image_printing_enabled_checkbox =
|
||||
new wxCheckBox(top_surface_page, wxID_ANY, _L("Enable top-surface image coloring"));
|
||||
m_top_surface_image_printing_enabled_checkbox->SetValue(top_surface_image_printing_enabled);
|
||||
top_surface_box->Add(m_top_surface_image_printing_enabled_checkbox, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap);
|
||||
auto *top_surface_method_row = new wxBoxSizer(wxHORIZONTAL);
|
||||
top_surface_method_row->Add(new wxStaticText(top_surface_page, wxID_ANY, _L("Method")),
|
||||
0,
|
||||
wxALIGN_CENTER_VERTICAL | wxRIGHT,
|
||||
gap);
|
||||
wxArrayString top_surface_method_choices;
|
||||
top_surface_method_choices.Add(_L("45 degree width modulation"));
|
||||
top_surface_method_choices.Add(_L("Same-layer 45 partition"));
|
||||
m_top_surface_image_method_choice =
|
||||
new wxChoice(top_surface_page, wxID_ANY, wxDefaultPosition, wxDefaultSize, top_surface_method_choices);
|
||||
m_top_surface_image_method_choice->SetSelection(std::clamp(top_surface_image_printing_method,
|
||||
int(TextureMappingZone::TopSurfaceImageSameAngle45Width),
|
||||
int(TextureMappingZone::TopSurfaceImageSameLayer45Partition)));
|
||||
top_surface_method_row->Add(m_top_surface_image_method_choice, 1, wxALIGN_CENTER_VERTICAL);
|
||||
top_surface_box->Add(top_surface_method_row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap);
|
||||
auto *top_surface_width_row = new wxBoxSizer(wxHORIZONTAL);
|
||||
top_surface_width_row->Add(new wxStaticText(top_surface_page, wxID_ANY, _L("Line width")),
|
||||
0,
|
||||
wxALIGN_CENTER_VERTICAL | wxRIGHT,
|
||||
gap);
|
||||
m_top_surface_image_min_line_width_spin =
|
||||
new wxSpinCtrlDouble(top_surface_page,
|
||||
wxID_ANY,
|
||||
wxEmptyString,
|
||||
wxDefaultPosition,
|
||||
wxSize(FromDIP(84), -1),
|
||||
wxSP_ARROW_KEYS | wxALIGN_RIGHT | wxTE_PROCESS_ENTER,
|
||||
double(TextureMappingZone::MinTopSurfaceImageLineWidthMm),
|
||||
double(TextureMappingZone::MaxTopSurfaceImageLineWidthMm),
|
||||
std::clamp(double(top_surface_image_min_line_width_mm),
|
||||
double(TextureMappingZone::MinTopSurfaceImageLineWidthMm),
|
||||
double(TextureMappingZone::MaxTopSurfaceImageLineWidthMm)),
|
||||
0.01);
|
||||
m_top_surface_image_min_line_width_spin->SetDigits(2);
|
||||
top_surface_width_row->Add(m_top_surface_image_min_line_width_spin, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap / 2);
|
||||
top_surface_width_row->Add(new wxStaticText(top_surface_page, wxID_ANY, _L("to")),
|
||||
0,
|
||||
wxALIGN_CENTER_VERTICAL | wxRIGHT,
|
||||
gap / 2);
|
||||
m_top_surface_image_max_line_width_spin =
|
||||
new wxSpinCtrlDouble(top_surface_page,
|
||||
wxID_ANY,
|
||||
wxEmptyString,
|
||||
wxDefaultPosition,
|
||||
wxSize(FromDIP(84), -1),
|
||||
wxSP_ARROW_KEYS | wxALIGN_RIGHT | wxTE_PROCESS_ENTER,
|
||||
double(TextureMappingZone::MinTopSurfaceImageLineWidthMm),
|
||||
double(TextureMappingZone::MaxTopSurfaceImageLineWidthMm),
|
||||
std::clamp(double(top_surface_image_max_line_width_mm),
|
||||
double(TextureMappingZone::MinTopSurfaceImageLineWidthMm),
|
||||
double(TextureMappingZone::MaxTopSurfaceImageLineWidthMm)),
|
||||
0.01);
|
||||
m_top_surface_image_max_line_width_spin->SetDigits(2);
|
||||
top_surface_width_row->Add(m_top_surface_image_max_line_width_spin, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap / 2);
|
||||
top_surface_width_row->Add(new wxStaticText(top_surface_page, wxID_ANY, _L("mm")), 0, wxALIGN_CENTER_VERTICAL);
|
||||
top_surface_box->Add(top_surface_width_row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap);
|
||||
m_top_surface_image_colored_top_layers_panel = new wxPanel(top_surface_page, wxID_ANY);
|
||||
auto *top_surface_colored_layers_row = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_top_surface_image_colored_top_layers_panel->SetSizer(top_surface_colored_layers_row);
|
||||
top_surface_colored_layers_row->Add(new wxStaticText(m_top_surface_image_colored_top_layers_panel, wxID_ANY, _L("Colored top layers")),
|
||||
0,
|
||||
wxALIGN_CENTER_VERTICAL | wxRIGHT,
|
||||
gap);
|
||||
m_top_surface_image_colored_top_layers_spin =
|
||||
new wxSpinCtrl(m_top_surface_image_colored_top_layers_panel,
|
||||
wxID_ANY,
|
||||
wxEmptyString,
|
||||
wxDefaultPosition,
|
||||
wxSize(FromDIP(70), -1),
|
||||
wxSP_ARROW_KEYS | wxALIGN_RIGHT,
|
||||
TextureMappingZone::MinTopSurfaceImageColoredTopLayers,
|
||||
TextureMappingZone::MaxTopSurfaceImageColoredTopLayers,
|
||||
std::clamp(top_surface_image_colored_top_layers,
|
||||
TextureMappingZone::MinTopSurfaceImageColoredTopLayers,
|
||||
TextureMappingZone::MaxTopSurfaceImageColoredTopLayers));
|
||||
top_surface_colored_layers_row->Add(m_top_surface_image_colored_top_layers_spin, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap / 2);
|
||||
top_surface_colored_layers_row->Add(new wxStaticText(m_top_surface_image_colored_top_layers_panel, wxID_ANY, _L("layers")),
|
||||
0,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
top_surface_box->Add(m_top_surface_image_colored_top_layers_panel, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap);
|
||||
m_top_surface_image_fixed_coloring_filaments_checkbox =
|
||||
new wxCheckBox(top_surface_page, wxID_ANY, _L("Fixed top-surface coloring filaments"));
|
||||
m_top_surface_image_fixed_coloring_filaments_checkbox->SetValue(top_surface_image_fixed_coloring_filaments);
|
||||
top_surface_box->Add(m_top_surface_image_fixed_coloring_filaments_checkbox, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP | wxBOTTOM, gap);
|
||||
m_top_surface_image_printing_enabled_checkbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &) {
|
||||
update_top_surface_image_options_visibility(false);
|
||||
});
|
||||
m_top_surface_image_method_choice->Bind(wxEVT_CHOICE, [this](wxCommandEvent &) {
|
||||
update_top_surface_image_options_visibility(true);
|
||||
});
|
||||
top_surface_root->Add(top_surface_box, 0, wxEXPAND | wxALL, gap);
|
||||
update_top_surface_image_options_visibility(false);
|
||||
|
||||
m_prime_tower_mapping_enabled_checkbox = new wxCheckBox(global_page, wxID_ANY, _L("Enable prime tower image mapping"));
|
||||
m_prime_tower_mapping_enabled_checkbox->SetValue(m_global_settings.enabled);
|
||||
global_root->Add(m_prime_tower_mapping_enabled_checkbox, 0, wxEXPAND | wxALL, gap);
|
||||
@@ -2451,14 +2559,15 @@ public:
|
||||
m_options_book->AddPage(print_settings_page, _L("Modulation Mode"));
|
||||
m_options_book->AddPage(preview_page, _L("Preview Options"));
|
||||
m_options_book->AddPage(experimental_page, _L("Experimental Options"));
|
||||
m_options_book->AddPage(top_surface_page, _L("Top-surface coloring (experimental)"));
|
||||
m_options_book->AddPage(global_page, _L("Prime Tower Texture Mapping"));
|
||||
update_options_book_min_size();
|
||||
m_options_tab_choice->Bind(wxEVT_CHOICE, [this](wxCommandEvent &evt) {
|
||||
if (m_options_book)
|
||||
m_options_book->SetSelection(std::clamp(evt.GetSelection(), 0, 5));
|
||||
m_options_book->SetSelection(std::clamp(evt.GetSelection(), 0, 6));
|
||||
});
|
||||
if (m_options_book)
|
||||
m_options_book->SetSelection(std::clamp(initial_options_tab, 0, 5));
|
||||
m_options_book->SetSelection(std::clamp(initial_options_tab, 0, 6));
|
||||
root->Add(m_options_book, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, gap);
|
||||
if (wxSizer *buttons = CreateStdDialogButtonSizer(wxOK | wxCANCEL))
|
||||
root->Add(buttons, 0, wxEXPAND | wxALL, gap);
|
||||
@@ -2563,6 +2672,55 @@ public:
|
||||
double(TextureMappingZone::MinHalftoneDotSizeMm),
|
||||
double(TextureMappingZone::MaxHalftoneDotSizeMm)));
|
||||
}
|
||||
bool top_surface_image_printing_enabled() const
|
||||
{
|
||||
return m_top_surface_image_printing_enabled_checkbox != nullptr &&
|
||||
m_top_surface_image_printing_enabled_checkbox->GetValue();
|
||||
}
|
||||
int top_surface_image_printing_method() const
|
||||
{
|
||||
return m_top_surface_image_method_choice ?
|
||||
std::clamp(m_top_surface_image_method_choice->GetSelection(),
|
||||
int(TextureMappingZone::TopSurfaceImageSameAngle45Width),
|
||||
int(TextureMappingZone::TopSurfaceImageSameLayer45Partition)) :
|
||||
TextureMappingZone::DefaultTopSurfaceImagePrintingMethod;
|
||||
}
|
||||
float top_surface_image_min_line_width_mm() const
|
||||
{
|
||||
const double max_width = m_top_surface_image_max_line_width_spin != nullptr ?
|
||||
m_top_surface_image_max_line_width_spin->GetValue() :
|
||||
double(TextureMappingZone::DefaultTopSurfaceImageMaxLineWidthMm);
|
||||
const double value = m_top_surface_image_min_line_width_spin != nullptr ?
|
||||
m_top_surface_image_min_line_width_spin->GetValue() :
|
||||
double(TextureMappingZone::DefaultTopSurfaceImageMinLineWidthMm);
|
||||
return float(std::clamp(value,
|
||||
double(TextureMappingZone::MinTopSurfaceImageLineWidthMm),
|
||||
std::clamp(max_width,
|
||||
double(TextureMappingZone::MinTopSurfaceImageLineWidthMm),
|
||||
double(TextureMappingZone::MaxTopSurfaceImageLineWidthMm))));
|
||||
}
|
||||
float top_surface_image_max_line_width_mm() const
|
||||
{
|
||||
const double value = m_top_surface_image_max_line_width_spin != nullptr ?
|
||||
m_top_surface_image_max_line_width_spin->GetValue() :
|
||||
double(TextureMappingZone::DefaultTopSurfaceImageMaxLineWidthMm);
|
||||
return float(std::clamp(value,
|
||||
double(TextureMappingZone::MinTopSurfaceImageLineWidthMm),
|
||||
double(TextureMappingZone::MaxTopSurfaceImageLineWidthMm)));
|
||||
}
|
||||
int top_surface_image_colored_top_layers() const
|
||||
{
|
||||
return m_top_surface_image_colored_top_layers_spin ?
|
||||
std::clamp(m_top_surface_image_colored_top_layers_spin->GetValue(),
|
||||
TextureMappingZone::MinTopSurfaceImageColoredTopLayers,
|
||||
TextureMappingZone::MaxTopSurfaceImageColoredTopLayers) :
|
||||
TextureMappingZone::DefaultTopSurfaceImageColoredTopLayers;
|
||||
}
|
||||
bool top_surface_image_fixed_coloring_filaments() const
|
||||
{
|
||||
return m_top_surface_image_fixed_coloring_filaments_checkbox == nullptr ||
|
||||
m_top_surface_image_fixed_coloring_filaments_checkbox->GetValue();
|
||||
}
|
||||
bool minimum_visibility_offset_enabled() const
|
||||
{
|
||||
return m_minimum_visibility_offset_checkbox && m_minimum_visibility_offset_checkbox->GetValue();
|
||||
@@ -2638,7 +2796,7 @@ public:
|
||||
|
||||
const TextureMappingPrimeTowerImage& prime_tower_image() const { return m_prime_tower_image; }
|
||||
const TextureMappingPrimeTowerImage& prime_tower_image_back() const { return m_prime_tower_image_back; }
|
||||
int selected_options_tab() const { return std::clamp(m_options_tab_choice ? m_options_tab_choice->GetSelection() : 0, 0, 5); }
|
||||
int selected_options_tab() const { return std::clamp(m_options_tab_choice ? m_options_tab_choice->GetSelection() : 0, 0, 6); }
|
||||
bool strength_offsets_expanded() const { return m_strength_offsets_expanded; }
|
||||
|
||||
std::vector<float> component_strengths_pct() const
|
||||
@@ -2937,6 +3095,37 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void update_top_surface_image_options_visibility(bool fit_dialog)
|
||||
{
|
||||
const bool enabled =
|
||||
m_top_surface_image_printing_enabled_checkbox != nullptr &&
|
||||
m_top_surface_image_printing_enabled_checkbox->GetValue();
|
||||
if (m_top_surface_image_method_choice != nullptr)
|
||||
m_top_surface_image_method_choice->Enable(enabled);
|
||||
if (m_top_surface_image_min_line_width_spin != nullptr)
|
||||
m_top_surface_image_min_line_width_spin->Enable(enabled);
|
||||
if (m_top_surface_image_max_line_width_spin != nullptr)
|
||||
m_top_surface_image_max_line_width_spin->Enable(enabled);
|
||||
const bool same_layer =
|
||||
enabled &&
|
||||
m_top_surface_image_method_choice != nullptr &&
|
||||
m_top_surface_image_method_choice->GetSelection() == int(TextureMappingZone::TopSurfaceImageSameLayer45Partition);
|
||||
if (m_top_surface_image_colored_top_layers_panel != nullptr)
|
||||
m_top_surface_image_colored_top_layers_panel->Show(same_layer);
|
||||
if (m_top_surface_image_colored_top_layers_spin != nullptr)
|
||||
m_top_surface_image_colored_top_layers_spin->Enable(same_layer);
|
||||
if (m_top_surface_image_fixed_coloring_filaments_checkbox != nullptr)
|
||||
m_top_surface_image_fixed_coloring_filaments_checkbox->Enable(enabled);
|
||||
layout_current_options_page();
|
||||
if (!fit_dialog)
|
||||
return;
|
||||
update_options_book_min_size();
|
||||
if (GetSizer() != nullptr) {
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
}
|
||||
|
||||
wxChoice *m_options_tab_choice {nullptr};
|
||||
wxSimplebook *m_options_book {nullptr};
|
||||
wxChoice *m_texture_mapping_mode_choice {nullptr};
|
||||
@@ -2969,6 +3158,13 @@ private:
|
||||
wxSpinCtrlDouble *m_dithering_resolution_spin {nullptr};
|
||||
wxPanel *m_halftone_dot_size_panel {nullptr};
|
||||
wxSpinCtrlDouble *m_halftone_dot_size_spin {nullptr};
|
||||
wxCheckBox *m_top_surface_image_printing_enabled_checkbox {nullptr};
|
||||
wxChoice *m_top_surface_image_method_choice {nullptr};
|
||||
wxSpinCtrlDouble *m_top_surface_image_min_line_width_spin {nullptr};
|
||||
wxSpinCtrlDouble *m_top_surface_image_max_line_width_spin {nullptr};
|
||||
wxPanel *m_top_surface_image_colored_top_layers_panel {nullptr};
|
||||
wxSpinCtrl *m_top_surface_image_colored_top_layers_spin {nullptr};
|
||||
wxCheckBox *m_top_surface_image_fixed_coloring_filaments_checkbox {nullptr};
|
||||
wxCheckBox *m_use_legacy_fixed_color_mode_checkbox {nullptr};
|
||||
wxCheckBox *m_minimum_visibility_offset_checkbox {nullptr};
|
||||
wxSpinCtrl *m_minimum_visibility_offset_spin {nullptr};
|
||||
@@ -7912,6 +8108,12 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
updated.dithering_method,
|
||||
updated.dithering_resolution_mm,
|
||||
updated.halftone_dot_size_mm,
|
||||
updated.top_surface_image_printing_enabled,
|
||||
updated.top_surface_image_printing_method,
|
||||
updated.top_surface_image_min_line_width_mm,
|
||||
updated.top_surface_image_max_line_width_mm,
|
||||
updated.top_surface_image_colored_top_layers,
|
||||
updated.top_surface_image_fixed_coloring_filaments,
|
||||
bundle->texture_mapping_zones,
|
||||
bundle->texture_mapping_global_settings,
|
||||
wxGetApp().model().texture_mapping_prime_tower_image,
|
||||
@@ -7955,6 +8157,12 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
updated.dithering_method = dlg.dithering_method();
|
||||
updated.dithering_resolution_mm = dlg.dithering_resolution_mm();
|
||||
updated.halftone_dot_size_mm = dlg.halftone_dot_size_mm();
|
||||
updated.top_surface_image_printing_enabled = dlg.top_surface_image_printing_enabled();
|
||||
updated.top_surface_image_printing_method = dlg.top_surface_image_printing_method();
|
||||
updated.top_surface_image_min_line_width_mm = dlg.top_surface_image_min_line_width_mm();
|
||||
updated.top_surface_image_max_line_width_mm = dlg.top_surface_image_max_line_width_mm();
|
||||
updated.top_surface_image_colored_top_layers = dlg.top_surface_image_colored_top_layers();
|
||||
updated.top_surface_image_fixed_coloring_filaments = dlg.top_surface_image_fixed_coloring_filaments();
|
||||
if (updated.dithering_enabled)
|
||||
updated.compact_offset_mode = true;
|
||||
updated.minimum_visibility_offset_enabled = dlg.minimum_visibility_offset_enabled();
|
||||
|
||||
Reference in New Issue
Block a user