Try to avoid object overlap when snapping prime tower position. Sort boundary skin paths internally to avoid excessive travel moves
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
#include "../PNGReadWrite.hpp"
|
||||
#include "../Print.hpp"
|
||||
#include "../PrintConfig.hpp"
|
||||
#include "../ShortestPath.hpp"
|
||||
#include "../SVG.hpp"
|
||||
#include "../Surface.hpp"
|
||||
#include "../TextureMapping.hpp"
|
||||
@@ -8498,6 +8499,14 @@ static void top_surface_image_filter_short_boundary_skin_entities(ExtrusionEntit
|
||||
collection.entities = std::move(kept);
|
||||
}
|
||||
|
||||
static void top_surface_image_reorder_boundary_skin_entities(ExtrusionEntityCollection &collection)
|
||||
{
|
||||
if (collection.entities.size() < 2)
|
||||
return;
|
||||
const Point start_near = collection.entities.front()->first_point();
|
||||
reorder_extrusion_entities(collection.entities, chain_extrusion_entities(collection.entities, &start_near));
|
||||
}
|
||||
|
||||
static ExPolygons top_surface_image_boundary_skin_leftover(const Surface &surface,
|
||||
const ExtrusionEntityCollection &collection)
|
||||
{
|
||||
@@ -8771,6 +8780,7 @@ static std::unique_ptr<ExtrusionEntityCollection> top_surface_image_boundary_ski
|
||||
variable ? max_flow : output_flow,
|
||||
collection->entities);
|
||||
top_surface_image_filter_short_boundary_skin_entities(*collection, min_length_mm);
|
||||
top_surface_image_reorder_boundary_skin_entities(*collection);
|
||||
} else {
|
||||
for (const ThickPolyline &thick_polyline : thick_polylines) {
|
||||
check_canceled(throw_if_canceled);
|
||||
@@ -8785,6 +8795,7 @@ static std::unique_ptr<ExtrusionEntityCollection> top_surface_image_boundary_ski
|
||||
path->polyline = std::move(polyline);
|
||||
collection->entities.emplace_back(path);
|
||||
}
|
||||
top_surface_image_reorder_boundary_skin_entities(*collection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -244,6 +244,7 @@ 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;
|
||||
static constexpr float WIPE_TOWER_OBJECT_CLEARANCE = 10.f;
|
||||
#define PRINTER_THUMBNAIL_SIZE (wxSize(40, 40)) // ORCA
|
||||
#define PRINTER_PANEL_SIZE ( wxSize(70, 60)) // ORCA
|
||||
#define PRINTER_PANEL_RADIUS (6) // ORCA
|
||||
@@ -382,6 +383,111 @@ namespace {
|
||||
|
||||
static void clamp_wipe_tower_positions_for_slicing(PartPlateList &partplate_list, PresetBundle &preset_bundle)
|
||||
{
|
||||
struct Rectf {
|
||||
float min_x;
|
||||
float min_y;
|
||||
float max_x;
|
||||
float max_y;
|
||||
};
|
||||
|
||||
auto rects_overlap = [](const Rectf &lhs, const Rectf &rhs) {
|
||||
return lhs.min_x < rhs.max_x && lhs.max_x > rhs.min_x && lhs.min_y < rhs.max_y && lhs.max_y > rhs.min_y;
|
||||
};
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
auto collect_object_rects = [](PartPlate *part_plate, float clearance) {
|
||||
std::vector<Rectf> rects;
|
||||
Model &model = wxGetApp().model();
|
||||
const Vec3d plate_origin = part_plate->get_origin();
|
||||
for (int obj_id = 0; obj_id < int(model.objects.size()); ++obj_id) {
|
||||
ModelObject *object = model.objects[obj_id];
|
||||
if (object == nullptr)
|
||||
continue;
|
||||
for (int instance_id = 0; instance_id < int(object->instances.size()); ++instance_id) {
|
||||
if (!part_plate->contain_instance_totally(obj_id, instance_id))
|
||||
continue;
|
||||
const BoundingBoxf3 bbox = object->instance_bounding_box(size_t(instance_id));
|
||||
if (!bbox.defined)
|
||||
continue;
|
||||
rects.push_back({
|
||||
float(bbox.min(0) - plate_origin(0) - clearance),
|
||||
float(bbox.min(1) - plate_origin(1) - clearance),
|
||||
float(bbox.max(0) - plate_origin(0) + clearance),
|
||||
float(bbox.max(1) - plate_origin(1) + clearance)
|
||||
});
|
||||
}
|
||||
}
|
||||
return rects;
|
||||
};
|
||||
|
||||
auto choose_safe_position = [&](float desired_x,
|
||||
float desired_y,
|
||||
double width,
|
||||
double depth,
|
||||
coordf_t min_x,
|
||||
coordf_t max_x,
|
||||
coordf_t min_y,
|
||||
coordf_t max_y,
|
||||
float margin,
|
||||
const std::vector<Rectf> &object_rects) {
|
||||
const float axis_min_x = float(min_x) + margin;
|
||||
const float axis_max_x = float(max_x) - margin - float(width);
|
||||
const float axis_min_y = float(min_y) + margin;
|
||||
const float axis_max_y = float(max_y) - margin - float(depth);
|
||||
const float fallback_x = clamp_axis(desired_x, min_x, max_x, width, margin);
|
||||
const float fallback_y = clamp_axis(desired_y, min_y, max_y, depth, margin);
|
||||
if (axis_max_x < axis_min_x || axis_max_y < axis_min_y)
|
||||
return Vec2f(fallback_x, fallback_y);
|
||||
|
||||
std::vector<float> x_candidates = { fallback_x, axis_min_x, axis_max_x };
|
||||
std::vector<float> y_candidates = { fallback_y, axis_min_y, axis_max_y };
|
||||
for (const Rectf &rect : object_rects) {
|
||||
x_candidates.emplace_back(rect.min_x - float(width));
|
||||
x_candidates.emplace_back(rect.max_x);
|
||||
y_candidates.emplace_back(rect.min_y - float(depth));
|
||||
y_candidates.emplace_back(rect.max_y);
|
||||
}
|
||||
|
||||
auto normalize_candidates = [](std::vector<float> &values, float min_value, float max_value) {
|
||||
for (float &value : values)
|
||||
value = std::clamp(value, min_value, max_value);
|
||||
std::sort(values.begin(), values.end());
|
||||
values.erase(std::unique(values.begin(), values.end(), [](float lhs, float rhs) { return std::abs(lhs - rhs) <= EPSILON; }), values.end());
|
||||
};
|
||||
normalize_candidates(x_candidates, axis_min_x, axis_max_x);
|
||||
normalize_candidates(y_candidates, axis_min_y, axis_max_y);
|
||||
|
||||
Vec2f best(fallback_x, fallback_y);
|
||||
float best_score = std::numeric_limits<float>::max();
|
||||
for (const float x : x_candidates) {
|
||||
for (const float y : y_candidates) {
|
||||
const Rectf tower_rect { x, y, x + float(width), y + float(depth) };
|
||||
bool overlaps = false;
|
||||
for (const Rectf &object_rect : object_rects) {
|
||||
if (rects_overlap(tower_rect, object_rect)) {
|
||||
overlaps = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (overlaps)
|
||||
continue;
|
||||
const float dx = x - desired_x;
|
||||
const float dy = y - desired_y;
|
||||
const float score = dx * dx + dy * dy;
|
||||
if (score < best_score) {
|
||||
best_score = score;
|
||||
best = Vec2f(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
return best;
|
||||
};
|
||||
|
||||
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);
|
||||
@@ -451,14 +557,19 @@ static void clamp_wipe_tower_positions_for_slicing(PartPlateList &partplate_list
|
||||
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));
|
||||
const std::vector<Rectf> object_rects = collect_object_rects(part_plate, brim_width + WIPE_TOWER_OBJECT_CLEARANCE);
|
||||
const Vec2f safe_pos = choose_safe_position(wipe_tower_x->get_at(plate_id),
|
||||
wipe_tower_y->get_at(plate_id),
|
||||
wipe_tower_size(0),
|
||||
wipe_tower_size(1),
|
||||
min_x,
|
||||
max_x,
|
||||
min_y,
|
||||
max_y,
|
||||
margin,
|
||||
object_rects);
|
||||
ConfigOptionFloat x_opt(safe_pos.x());
|
||||
ConfigOptionFloat y_opt(safe_pos.y());
|
||||
wipe_tower_x->set_at(&x_opt, plate_id, 0);
|
||||
wipe_tower_y->set_at(&y_opt, plate_id, 0);
|
||||
}
|
||||
@@ -2999,7 +3110,7 @@ public:
|
||||
};
|
||||
add_contoning_flat_infill_choice(_L("Default (Boundary Skin variable width)"),
|
||||
int(TextureMappingZone::ContoningFlatSurfaceInfillDefault));
|
||||
add_contoning_flat_infill_choice(_L("Rectilinear"),
|
||||
add_contoning_flat_infill_choice(_L("Rectilinear - not recommended"),
|
||||
int(TextureMappingZone::ContoningFlatSurfaceInfillRectilinear));
|
||||
if (TextureMappingZone::ShowExperimentalTopSurfaceContoningOptions) {
|
||||
add_contoning_flat_infill_choice(_L("Concentric"),
|
||||
|
||||
Reference in New Issue
Block a user