Ensure bed shape is in correct orientation (#9350)

Fix #9345

This also fixes deltamaker's plate logo rendering:
![image](https://github.com/user-attachments/assets/517c9b3c-8eee-4081-a2bc-5913fe35328b)

And fix bed rendering issue for custom shaped bed without model:
![image](https://github.com/user-attachments/assets/9643413e-9b1c-4e74-afe8-edf2306e7021)


Also fix rendering of exclusion area that are defined in clockwise:
![image](https://github.com/user-attachments/assets/0949c1c3-6304-4ece-85c7-f3162249bf90)
This commit is contained in:
SoftFever 2025-05-01 17:28:10 +08:00 committed by GitHub
commit a4f35e0291
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 42 additions and 28 deletions

View file

@ -3081,7 +3081,7 @@ int CLI::run(int argc, char **argv)
else { else {
partplate_list.reset_size(old_printable_width, old_printable_depth, old_printable_height, false); partplate_list.reset_size(old_printable_width, old_printable_depth, old_printable_height, false);
} }
partplate_list.set_shapes(current_printable_area, current_exclude_area, bed_texture, height_to_lid, height_to_rod); partplate_list.set_shapes(make_counter_clockwise(current_printable_area), current_exclude_area, bed_texture, height_to_lid, height_to_rod);
//plate_stride = partplate_list.plate_stride_x(); //plate_stride = partplate_list.plate_stride_x();
} }

View file

@ -14,6 +14,7 @@ BuildVolume::BuildVolume(const std::vector<Vec2d> &printable_area, const double
assert(printable_height >= 0); assert(printable_height >= 0);
m_polygon = Polygon::new_scale(printable_area); m_polygon = Polygon::new_scale(printable_area);
assert(m_polygon.is_counter_clockwise());
// Calcuate various metrics of the input polygon. // Calcuate various metrics of the input polygon.
m_convex_hull = Geometry::convex_hull(m_polygon.points); m_convex_hull = Geometry::convex_hull(m_polygon.points);

View file

@ -1410,4 +1410,14 @@ ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<s
return output; return output;
} }
Pointfs make_counter_clockwise(const Pointfs& pointfs)
{
Pointfs ps = pointfs;
if (Polygon::new_scale(pointfs).is_clockwise()) {
std::reverse(ps.begin(), ps.end());
}
return ps;
}
} }

View file

@ -661,6 +661,8 @@ Polygons variable_offset_outer(const ExPolygon &expoly, const std::vector<std::
ExPolygons variable_offset_outer_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.); ExPolygons variable_offset_outer_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.);
ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.); ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.);
Pointfs make_counter_clockwise(const Pointfs& pointfs);
} // namespace Slic3r } // namespace Slic3r
#endif // slic3r_ClipperUtils_hpp_ #endif // slic3r_ClipperUtils_hpp_

View file

@ -831,7 +831,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
const ConfigOptionPoints* printable_area = config.option<ConfigOptionPoints>("printable_area"); const ConfigOptionPoints* printable_area = config.option<ConfigOptionPoints>("printable_area");
if (printable_area != nullptr) if (printable_area != nullptr)
m_result.printable_area = printable_area->values; m_result.printable_area = make_counter_clockwise(printable_area->values);
//BBS: add bed_exclude_area //BBS: add bed_exclude_area
const ConfigOptionPoints* bed_exclude_area = config.option<ConfigOptionPoints>("bed_exclude_area"); const ConfigOptionPoints* bed_exclude_area = config.option<ConfigOptionPoints>("bed_exclude_area");

View file

@ -8117,15 +8117,15 @@ Points get_bed_shape(const DynamicPrintConfig &config)
return {}; return {};
} }
return to_points(bed_shape_opt->values); return to_points(make_counter_clockwise(bed_shape_opt->values));
} }
Points get_bed_shape(const PrintConfig &cfg) Points get_bed_shape(const PrintConfig &cfg)
{ {
return to_points(cfg.printable_area.values); return to_points(make_counter_clockwise(cfg.printable_area.values));
} }
Points get_bed_shape(const SLAPrinterConfig &cfg) { return to_points(cfg.printable_area.values); } Points get_bed_shape(const SLAPrinterConfig &cfg) { return to_points(make_counter_clockwise(cfg.printable_area.values)); }
Polygon get_bed_shape_with_excluded_area(const PrintConfig& cfg) Polygon get_bed_shape_with_excluded_area(const PrintConfig& cfg)
{ {

View file

@ -432,7 +432,7 @@ std::tuple<Bed3D::Type, std::string, std::string> Bed3D::detect_type(const Point
while (curr != nullptr) { while (curr != nullptr) {
if (curr->config.has("printable_area")) { if (curr->config.has("printable_area")) {
std::string texture_filename, model_filename; std::string texture_filename, model_filename;
if (shape == dynamic_cast<const ConfigOptionPoints*>(curr->config.option("printable_area"))->values) { if (shape == make_counter_clockwise(dynamic_cast<const ConfigOptionPoints*>(curr->config.option("printable_area"))->values)) {
if (curr->is_system) if (curr->is_system)
model_filename = PresetUtils::system_printer_bed_model(*curr); model_filename = PresetUtils::system_printer_bed_model(*curr);
else { else {

View file

@ -20,9 +20,9 @@
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
BedShape::BedShape(const ConfigOptionPoints& points) BedShape::BedShape(const Pointfs& points)
{ {
m_build_volume = { points.values, 0. }; m_build_volume = { points, 0. };
} }
static std::string get_option_label(BedShape::Parameter param) static std::string get_option_label(BedShape::Parameter param)
@ -130,7 +130,7 @@ void BedShape::apply_optgroup_values(ConfigOptionsGroupShp optgroup)
} }
} }
void BedShapeDialog::build_dialog(const ConfigOptionPoints& default_pt, const ConfigOptionString& custom_texture, const ConfigOptionString& custom_model) void BedShapeDialog::build_dialog(const Pointfs& default_pt, const ConfigOptionString& custom_texture, const ConfigOptionString& custom_model)
{ {
SetFont(wxGetApp().normal_font()); SetFont(wxGetApp().normal_font());
@ -172,10 +172,10 @@ void BedShapeDialog::on_dpi_changed(const wxRect &suggested_rect)
const std::string BedShapePanel::NONE = "None"; const std::string BedShapePanel::NONE = "None";
const std::string BedShapePanel::EMPTY_STRING = ""; const std::string BedShapePanel::EMPTY_STRING = "";
void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const std::string& custom_texture, const std::string& custom_model) void BedShapePanel::build_panel(const Pointfs& default_pt, const std::string& custom_texture, const std::string& custom_model)
{ {
wxGetApp().UpdateDarkUI(this); wxGetApp().UpdateDarkUI(this);
m_shape = default_pt.values; m_shape = make_counter_clockwise(default_pt);
m_custom_texture = custom_texture.empty() ? NONE : custom_texture; m_custom_texture = custom_texture.empty() ? NONE : custom_texture;
m_custom_model = custom_model.empty() ? NONE : custom_model; m_custom_model = custom_model.empty() ? NONE : custom_model;
@ -240,7 +240,7 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const std:
SetSizerAndFit(top_sizer); SetSizerAndFit(top_sizer);
set_shape(default_pt); set_shape(m_shape);
update_preview(); update_preview();
} }
@ -454,7 +454,7 @@ wxPanel* BedShapePanel::init_model_panel()
// Deduce the bed shape type(rect, circle, custom) // Deduce the bed shape type(rect, circle, custom)
// This routine shall be smart enough if the user messes up // This routine shall be smart enough if the user messes up
// with the list of points in the ini file directly. // with the list of points in the ini file directly.
void BedShapePanel::set_shape(const ConfigOptionPoints& points) void BedShapePanel::set_shape(const Pointfs& points)
{ {
BedShape shape(points); BedShape shape(points);
@ -463,7 +463,7 @@ void BedShapePanel::set_shape(const ConfigOptionPoints& points)
// Copy the polygon to the canvas, make a copy of the array, if custom shape is selected // Copy the polygon to the canvas, make a copy of the array, if custom shape is selected
if (shape.is_custom()) if (shape.is_custom())
m_loaded_shape = points.values; m_loaded_shape = points;
update_shape(); update_shape();
@ -580,6 +580,7 @@ void BedShapePanel::load_stl()
} }
auto polygon = expolygons[0].contour; auto polygon = expolygons[0].contour;
polygon.make_counter_clockwise();
std::vector<Vec2d> points; std::vector<Vec2d> points;
for (auto pt : polygon.points) for (auto pt : polygon.points)
points.push_back(unscale(pt)); points.push_back(unscale(pt));

View file

@ -34,7 +34,7 @@ struct BedShape
Diameter Diameter
}; };
BedShape(const ConfigOptionPoints& points); BedShape(const Pointfs& points);
bool is_custom() { return m_build_volume.type() == BuildVolume_Type::Convex || m_build_volume.type() == BuildVolume_Type::Custom; } bool is_custom() { return m_build_volume.type() == BuildVolume_Type::Convex || m_build_volume.type() == BuildVolume_Type::Custom; }
@ -56,18 +56,18 @@ class BedShapePanel : public wxPanel
static const std::string EMPTY_STRING; static const std::string EMPTY_STRING;
Bed_2D* m_canvas; Bed_2D* m_canvas;
std::vector<Vec2d> m_shape; Pointfs m_shape;
std::vector<Vec2d> m_loaded_shape; Pointfs m_loaded_shape;
std::string m_custom_texture; std::string m_custom_texture;
std::string m_custom_model; std::string m_custom_model;
public: public:
BedShapePanel(wxWindow* parent) : wxPanel(parent, wxID_ANY), m_custom_texture(NONE), m_custom_model(NONE) {} BedShapePanel(wxWindow* parent) : wxPanel(parent, wxID_ANY), m_custom_texture(NONE), m_custom_model(NONE) {}
void build_panel(const ConfigOptionPoints& default_pt, const std::string& custom_texture, const std::string& custom_model); void build_panel(const Pointfs& default_pt, const std::string& custom_texture, const std::string& custom_model);
// Returns the resulting bed shape polygon. This value will be stored to the ini file. // Returns the resulting bed shape polygon. This value will be stored to the ini file.
const std::vector<Vec2d>& get_shape() const { return m_shape; } const Pointfs& get_shape() const { return m_shape; }
const std::string& get_custom_texture() const { return (m_custom_texture != NONE) ? m_custom_texture : EMPTY_STRING; } const std::string& get_custom_texture() const { return (m_custom_texture != NONE) ? m_custom_texture : EMPTY_STRING; }
const std::string& get_custom_model() const { return (m_custom_model != NONE) ? m_custom_model : EMPTY_STRING; } const std::string& get_custom_model() const { return (m_custom_model != NONE) ? m_custom_model : EMPTY_STRING; }
@ -76,7 +76,7 @@ private:
void activate_options_page(ConfigOptionsGroupShp options_group); void activate_options_page(ConfigOptionsGroupShp options_group);
wxPanel* init_texture_panel(); wxPanel* init_texture_panel();
wxPanel* init_model_panel(); wxPanel* init_model_panel();
void set_shape(const ConfigOptionPoints& points); void set_shape(const Pointfs& points);
void update_preview(); void update_preview();
void update_shape(); void update_shape();
void load_stl(); void load_stl();
@ -96,9 +96,9 @@ public:
BedShapeDialog(wxWindow* parent) : DPIDialog(parent, wxID_ANY, _(L("Bed Shape")), BedShapeDialog(wxWindow* parent) : DPIDialog(parent, wxID_ANY, _(L("Bed Shape")),
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) {} wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) {}
void build_dialog(const ConfigOptionPoints& default_pt, const ConfigOptionString& custom_texture, const ConfigOptionString& custom_model); void build_dialog(const Pointfs& default_pt, const ConfigOptionString& custom_texture, const ConfigOptionString& custom_model);
const std::vector<Vec2d>& get_shape() const { return m_panel->get_shape(); } const Pointfs& get_shape() const { return m_panel->get_shape(); }
const std::string& get_custom_texture() const { return m_panel->get_custom_texture(); } const std::string& get_custom_texture() const { return m_panel->get_custom_texture(); }
const std::string& get_custom_model() const { return m_panel->get_custom_model(); } const std::string& get_custom_model() const { return m_panel->get_custom_model(); }

View file

@ -1278,7 +1278,7 @@ PageBedShape::PageBedShape(ConfigWizard* parent)
{ {
append_text(_L("Set the shape of your printer's bed.")); append_text(_L("Set the shape of your printer's bed."));
shape_panel->build_panel(*wizard_p()->custom_config->option<ConfigOptionPoints>("printable_area"), shape_panel->build_panel(wizard_p()->custom_config->option<ConfigOptionPoints>("printable_area")->values,
*wizard_p()->custom_config->option<ConfigOptionString>("bed_custom_texture"), *wizard_p()->custom_config->option<ConfigOptionString>("bed_custom_texture"),
*wizard_p()->custom_config->option<ConfigOptionString>("bed_custom_model")); *wizard_p()->custom_config->option<ConfigOptionString>("bed_custom_model"));

View file

@ -2627,12 +2627,13 @@ void PartPlate::generate_exclude_polygon(ExPolygon &exclude_polygon)
exclude_polygon.contour.append({ scale_(p(0)), scale_(p(1)) }); exclude_polygon.contour.append({ scale_(p(0)), scale_(p(1)) });
} }
} }
exclude_polygon.contour.make_counter_clockwise();
} }
bool PartPlate::set_shape(const Pointfs& shape, const Pointfs& exclude_areas, Vec2d position, float height_to_lid, float height_to_rod) bool PartPlate::set_shape(const Pointfs& shape, const Pointfs& exclude_areas, Vec2d position, float height_to_lid, float height_to_rod)
{ {
Pointfs new_shape, new_exclude_areas; Pointfs new_shape, new_exclude_areas;
m_raw_shape = shape;
for (const Vec2d& p : shape) { for (const Vec2d& p : shape) {
new_shape.push_back(Vec2d(p.x() + position.x(), p.y() + position.y())); new_shape.push_back(Vec2d(p.x() + position.x(), p.y() + position.y()));
} }

View file

@ -117,7 +117,6 @@ private:
friend class PartPlateList; friend class PartPlateList;
Pointfs m_raw_shape;
Pointfs m_shape; Pointfs m_shape;
Pointfs m_exclude_area; Pointfs m_exclude_area;
BoundingBoxf3 m_bounding_box; BoundingBoxf3 m_bounding_box;

View file

@ -13397,7 +13397,7 @@ void Plater::set_bed_shape() const
//BBS: add bed exclude area //BBS: add bed exclude area
void Plater::set_bed_shape(const Pointfs& shape, const Pointfs& exclude_area, const double printable_height, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom) const void Plater::set_bed_shape(const Pointfs& shape, const Pointfs& exclude_area, const double printable_height, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom) const
{ {
p->set_bed_shape(shape, exclude_area, printable_height, custom_texture, custom_model, force_as_custom); p->set_bed_shape(make_counter_clockwise(shape), exclude_area, printable_height, custom_texture, custom_model, force_as_custom);
} }
void Plater::force_filament_colors_update() void Plater::force_filament_colors_update()

View file

@ -6060,7 +6060,7 @@ wxSizer* TabPrinter::create_bed_shape_widget(wxWindow* parent)
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) { btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) {
bool is_configed_by_BBL = PresetUtils::system_printer_bed_model(m_preset_bundle->printers.get_edited_preset()).size() > 0; bool is_configed_by_BBL = PresetUtils::system_printer_bed_model(m_preset_bundle->printers.get_edited_preset()).size() > 0;
BedShapeDialog dlg(this); BedShapeDialog dlg(this);
dlg.build_dialog(*m_config->option<ConfigOptionPoints>("printable_area"), dlg.build_dialog(m_config->option<ConfigOptionPoints>("printable_area")->values,
*m_config->option<ConfigOptionString>("bed_custom_texture"), *m_config->option<ConfigOptionString>("bed_custom_texture"),
*m_config->option<ConfigOptionString>("bed_custom_model")); *m_config->option<ConfigOptionString>("bed_custom_model"));
if (dlg.ShowModal() == wxID_OK) { if (dlg.ShowModal() == wxID_OK) {

View file

@ -990,7 +990,7 @@ bool CalibUtils::get_pa_k_n_value_by_cali_idx(const MachineObject *obj, int cali
bool CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &full_config, const Calib_Params &params, wxString &error_message) bool CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &full_config, const Calib_Params &params, wxString &error_message)
{ {
Pointfs bedfs = full_config.opt<ConfigOptionPoints>("printable_area")->values; Pointfs bedfs = make_counter_clockwise(full_config.opt<ConfigOptionPoints>("printable_area")->values);
double print_height = full_config.opt_float("printable_height"); double print_height = full_config.opt_float("printable_height");
double current_width = bedfs[2].x() - bedfs[0].x(); double current_width = bedfs[2].x() - bedfs[0].x();
double current_depth = bedfs[2].y() - bedfs[0].y(); double current_depth = bedfs[2].y() - bedfs[0].y();