mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-20 07:22:35 +00:00
Merge branch 'main' into feat/plugin-lifecycle-evts
This commit is contained in:
+176
-162
@@ -1,5 +1,6 @@
|
||||
#include <cstddef>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
@@ -16,10 +17,12 @@
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/GCode/WipeTowerEstimate.hpp"
|
||||
#include "libslic3r/ClipperUtils.hpp"
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
@@ -158,7 +161,7 @@ PartPlate::PartPlate()
|
||||
init();
|
||||
}
|
||||
|
||||
PartPlate::PartPlate(PartPlateList *partplate_list, Vec3d origin, int width, int depth, int height, Plater* platerObj, Model* modelObj, bool printable, PrinterTechnology tech)
|
||||
PartPlate::PartPlate(PartPlateList *partplate_list, Vec3d origin, int width, int depth, double height, Plater* platerObj, Model* modelObj, bool printable, PrinterTechnology tech)
|
||||
:m_partplate_list(partplate_list), m_plater(platerObj), m_model(modelObj), printer_technology(tech), m_origin(origin), m_width(width), m_depth(depth), m_height(height), m_printable(printable)
|
||||
{
|
||||
init();
|
||||
@@ -1051,7 +1054,13 @@ void PartPlate::render_grid(bool bottom) {
|
||||
|
||||
void PartPlate::render_height_limit(PartPlate::HeightLimitMode mode)
|
||||
{
|
||||
if (m_print && m_print->config().print_sequence == PrintSequence::ByObject && mode != HEIGHT_LIMIT_NONE)
|
||||
// Orca: a prime tower compacted by "No sparse layers" drags the nozzle back down to the plate on
|
||||
// every toolchange, so the rod and the lid limit how tall a neighbouring object may be exactly as
|
||||
// they do in sequential printing. The reference lines are just as useful there.
|
||||
const bool relevant_for_print_mode = m_print && (m_print->config().print_sequence == PrintSequence::ByObject ||
|
||||
(m_print->config().print_sequence == PrintSequence::ByLayer &&
|
||||
wipe_tower_sparse_layers_skipped(m_print->config()) && m_print->has_wipe_tower()));
|
||||
if (relevant_for_print_mode && mode != HEIGHT_LIMIT_NONE)
|
||||
{
|
||||
// draw lower limit
|
||||
// ORCA: OpenGL Core Profile
|
||||
@@ -1111,7 +1120,7 @@ void PartPlate::show_tooltip(const std::string tooltip)
|
||||
{
|
||||
const auto scale = m_plater->get_current_canvas3D()->get_scale();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {6 * scale, 3 * scale});
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, {3 * scale});
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 3 * scale);
|
||||
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND);
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, {0, 0, 0, 0});
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.00f, 1.00f, 1.00f, 1.00f));
|
||||
@@ -1532,8 +1541,23 @@ std::vector<int> PartPlate::get_extruders(bool conside_custom_gcode) const
|
||||
if (check_objects_empty_and_gcode3mf(plate_extruders)) {
|
||||
return plate_extruders;
|
||||
}
|
||||
// if 3mf file
|
||||
const DynamicPrintConfig& glb_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
return get_extruders(conside_custom_gcode, wxGetApp().preset_bundle->prints.get_edited_preset().config, wxGetApp().preset_bundle->project_config);
|
||||
}
|
||||
|
||||
// The plate's filaments, with the global keys read from the given configs rather than the
|
||||
// application's presets: the wipe tower estimate is also called under the CLI, which has no
|
||||
// application object. get_extruders(bool) passes the edited presets; a full config serves both.
|
||||
std::vector<int> PartPlate::get_extruders(bool conside_custom_gcode, const DynamicPrintConfig& glb_config, const DynamicPrintConfig& project_config) const
|
||||
{
|
||||
std::vector<int> plate_extruders;
|
||||
// A plate from a sliced .gcode.3mf holds no objects, so report the filaments the G-code
|
||||
// used. check_objects_empty_and_gcode3mf does this for get_extruders(bool), but reaches
|
||||
// the plater, which the CLI has none of; slice_filaments_info is only filled for such a plate.
|
||||
if (m_model->objects.empty()) {
|
||||
for (const FilamentInfo &info : slice_filaments_info)
|
||||
plate_extruders.push_back(info.id + 1);
|
||||
return plate_extruders;
|
||||
}
|
||||
int glb_support_intf_extr = glb_config.opt_int("support_interface_filament");
|
||||
int glb_support_extr = glb_config.opt_int("support_filament");
|
||||
int glb_outer_wall_extr = glb_config.opt_int("outer_wall_filament_id");
|
||||
@@ -1550,7 +1574,9 @@ std::vector<int> PartPlate::get_extruders(bool conside_custom_gcode) const
|
||||
glb_support |= glb_config.opt_int("raft_layers") > 0;
|
||||
|
||||
for (int obj_idx = 0; obj_idx < m_model->objects.size(); obj_idx++) {
|
||||
if (!contain_instance_totally(obj_idx, 0))
|
||||
// Any instance on the plate counts, as PrintApply does: after an arrange, instance 0
|
||||
// can sit on a different plate.
|
||||
if (!contain_any_instance_totally(obj_idx))
|
||||
continue;
|
||||
|
||||
ModelObject* mo = m_model->objects[obj_idx];
|
||||
@@ -1663,7 +1689,7 @@ std::vector<int> PartPlate::get_extruders(bool conside_custom_gcode) const
|
||||
if (conside_custom_gcode) {
|
||||
//BBS
|
||||
int nums_extruders = 0;
|
||||
if (const ConfigOptionStrings *color_option = dynamic_cast<const ConfigOptionStrings *>(wxGetApp().preset_bundle->project_config.option("filament_colour"))) {
|
||||
if (const ConfigOptionStrings *color_option = dynamic_cast<const ConfigOptionStrings *>(project_config.option("filament_colour"))) {
|
||||
nums_extruders = color_option->values.size();
|
||||
if (m_model->plates_custom_gcodes.find(m_plate_index) != m_model->plates_custom_gcodes.end()) {
|
||||
for (auto item : m_model->plates_custom_gcodes.at(m_plate_index).gcodes) {
|
||||
@@ -1682,9 +1708,8 @@ std::vector<int> PartPlate::get_extruders(bool conside_custom_gcode) const
|
||||
// is never loaded into a tray, so callers (AMS mapping, filament checks) must see the
|
||||
// physical filaments it resolves to instead.
|
||||
{
|
||||
auto& project_config = wxGetApp().preset_bundle->project_config;
|
||||
auto* is_mixed_opt = project_config.option<ConfigOptionBools>("filament_is_mixed");
|
||||
auto* comp_strs_opt = project_config.option<ConfigOptionStrings>("filament_mixed_components");
|
||||
const auto* is_mixed_opt = project_config.option<ConfigOptionBools>("filament_is_mixed");
|
||||
const auto* comp_strs_opt = project_config.option<ConfigOptionStrings>("filament_mixed_components");
|
||||
if (is_mixed_opt && comp_strs_opt && has_any_mixed_filament(is_mixed_opt->values)) {
|
||||
std::vector<unsigned int> ext_0based;
|
||||
for (int e : plate_extruders)
|
||||
@@ -1699,7 +1724,7 @@ std::vector<int> PartPlate::get_extruders(bool conside_custom_gcode) const
|
||||
return plate_extruders;
|
||||
}
|
||||
|
||||
std::vector<int> PartPlate::get_extruders_under_cli(bool conside_custom_gcode, DynamicPrintConfig& full_config) const
|
||||
std::vector<int> PartPlate::get_extruders_under_cli(bool conside_custom_gcode, DynamicPrintConfig& full_config, bool expand_mixed_slots) const
|
||||
{
|
||||
std::vector<int> plate_extruders;
|
||||
|
||||
@@ -1758,26 +1783,25 @@ std::vector<int> PartPlate::get_extruders_under_cli(bool conside_custom_gcode, D
|
||||
else
|
||||
obj_support = glb_support;
|
||||
|
||||
if (!obj_support)
|
||||
continue;
|
||||
if (obj_support) {
|
||||
int obj_support_intf_extr = 0;
|
||||
const ConfigOption* support_intf_extr_opt = object->config.option("support_interface_filament");
|
||||
if (support_intf_extr_opt != nullptr)
|
||||
obj_support_intf_extr = support_intf_extr_opt->getInt();
|
||||
if (obj_support_intf_extr != 0)
|
||||
plate_extruders.push_back(obj_support_intf_extr);
|
||||
else if (glb_support_intf_extr != 0)
|
||||
plate_extruders.push_back(glb_support_intf_extr);
|
||||
|
||||
int obj_support_intf_extr = 0;
|
||||
const ConfigOption* support_intf_extr_opt = object->config.option("support_interface_filament");
|
||||
if (support_intf_extr_opt != nullptr)
|
||||
obj_support_intf_extr = support_intf_extr_opt->getInt();
|
||||
if (obj_support_intf_extr != 0)
|
||||
plate_extruders.push_back(obj_support_intf_extr);
|
||||
else if (glb_support_intf_extr != 0)
|
||||
plate_extruders.push_back(glb_support_intf_extr);
|
||||
|
||||
int obj_support_extr = 0;
|
||||
const ConfigOption* support_extr_opt = object->config.option("support_filament");
|
||||
if (support_extr_opt != nullptr)
|
||||
obj_support_extr = support_extr_opt->getInt();
|
||||
if (obj_support_extr != 0)
|
||||
plate_extruders.push_back(obj_support_extr);
|
||||
else if (glb_support_extr != 0)
|
||||
plate_extruders.push_back(glb_support_extr);
|
||||
int obj_support_extr = 0;
|
||||
const ConfigOption* support_extr_opt = object->config.option("support_filament");
|
||||
if (support_extr_opt != nullptr)
|
||||
obj_support_extr = support_extr_opt->getInt();
|
||||
if (obj_support_extr != 0)
|
||||
plate_extruders.push_back(obj_support_extr);
|
||||
else if (glb_support_extr != 0)
|
||||
plate_extruders.push_back(glb_support_extr);
|
||||
}
|
||||
|
||||
int obj_outer_wall_extr = 0;
|
||||
if (const ConfigOption* wall_opt = object->config.option("outer_wall_filament_id"); wall_opt != nullptr)
|
||||
@@ -1861,7 +1885,7 @@ std::vector<int> PartPlate::get_extruders_under_cli(bool conside_custom_gcode, D
|
||||
// Expand mixed filament slots to their physical components. A mixed slot is virtual and
|
||||
// is never loaded into a tray, so callers (AMS mapping, filament checks) must see the
|
||||
// physical filaments it resolves to instead.
|
||||
{
|
||||
if (expand_mixed_slots) {
|
||||
auto* is_mixed_opt = full_config.option<ConfigOptionBools>("filament_is_mixed");
|
||||
auto* comp_strs_opt = full_config.option<ConfigOptionStrings>("filament_mixed_components");
|
||||
if (is_mixed_opt && comp_strs_opt && has_any_mixed_filament(is_mixed_opt->values)) {
|
||||
@@ -1901,7 +1925,7 @@ std::vector<int> PartPlate::get_extruders_without_support(bool conside_custom_gc
|
||||
const DynamicPrintConfig& glb_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
|
||||
for (int obj_idx = 0; obj_idx < m_model->objects.size(); obj_idx++) {
|
||||
if (!contain_instance_totally(obj_idx, 0))
|
||||
if (!contain_any_instance_totally(obj_idx))
|
||||
continue;
|
||||
|
||||
ModelObject* mo = m_model->objects[obj_idx];
|
||||
@@ -2072,7 +2096,7 @@ bool PartPlate::check_single_extruder_mixed_filament_risk(const DynamicPrintConf
|
||||
"which may significantly increase waste and the risk of nozzle / waste-chute clogging.");
|
||||
|
||||
for (int obj_idx = 0; obj_idx < (int)m_model->objects.size(); ++obj_idx) {
|
||||
if (!contain_instance_totally(obj_idx, 0))
|
||||
if (!contain_any_instance_totally(obj_idx))
|
||||
continue;
|
||||
ModelObject *mo = m_model->objects[obj_idx];
|
||||
int obj_ext = mo->config.has("extruder") ? mo->config.extruder() : 1;
|
||||
@@ -2291,7 +2315,7 @@ bool PartPlate::check_compatible_of_nozzle_and_filament(const DynamicPrintConfig
|
||||
return wipe_tower_size;
|
||||
|
||||
for (int obj_idx = 0; obj_idx < m_model->objects.size(); obj_idx++) {
|
||||
if (!use_global_objects && !contain_instance_totally(obj_idx, 0))
|
||||
if (!use_global_objects && !contain_any_instance_totally(obj_idx))
|
||||
continue;
|
||||
|
||||
BoundingBoxf3 bbox = m_model->objects[obj_idx]->bounding_box();
|
||||
@@ -2313,113 +2337,97 @@ bool PartPlate::check_compatible_of_nozzle_and_filament(const DynamicPrintConfig
|
||||
return wipe_tower_size;
|
||||
}*/
|
||||
|
||||
Vec3d PartPlate::estimate_wipe_tower_size(const DynamicPrintConfig & config, const double w, const double wipe_volume, int extruder_count, int plate_extruder_size, bool use_global_objects, bool enable_wrapping_detection) const
|
||||
WipeTowerFootprint PartPlate::estimate_wipe_tower_footprint(const DynamicPrintConfig &config, int plate_extruder_size, bool use_global_objects) const
|
||||
{
|
||||
Vec3d wipe_tower_size;
|
||||
double layer_height = 0.08f; // hard code layer height
|
||||
double max_height = 0.f;
|
||||
wipe_tower_size.setZero();
|
||||
// The CLI calls this too, so the plate's filaments are derived from the passed config:
|
||||
// get_extruders(bool) reads the same keys off wxGetApp()'s presets, which the CLI has none of.
|
||||
// An explicit count is a floor: init-time and arrange estimates size an empty plate for that
|
||||
// many generic filaments, the lowest ids not already on the plate.
|
||||
std::vector<int> plate_extruders = get_extruders(true, config, config);
|
||||
for (int id = 1; int(plate_extruders.size()) < plate_extruder_size; ++id)
|
||||
if (std::find(plate_extruders.begin(), plate_extruders.end(), id) == plate_extruders.end())
|
||||
plate_extruders.push_back(id);
|
||||
// The wipe tower filament joins the tool ordering even when unused (Print::extruders), so
|
||||
// validation counts it - but only where there is a tower to join, which is the
|
||||
// has_wipe_tower() half of that guard.
|
||||
const ConfigOption *wipe_tower_filament_opt = config.option("wipe_tower_filament");
|
||||
const ConfigOption *enable_prime_tower_opt = config.option("enable_prime_tower");
|
||||
const int wipe_tower_filament = wipe_tower_filament_opt != nullptr ? wipe_tower_filament_opt->getInt() : 0;
|
||||
if (enable_prime_tower_opt != nullptr && enable_prime_tower_opt->getBool() && plate_extruders.size() > 1 && wipe_tower_filament > 0 &&
|
||||
std::find(plate_extruders.begin(), plate_extruders.end(), wipe_tower_filament) == plate_extruders.end())
|
||||
plate_extruders.push_back(wipe_tower_filament);
|
||||
if (plate_extruders.empty())
|
||||
return WipeTowerFootprint();
|
||||
|
||||
const ConfigOption* layer_height_opt = config.option("layer_height");
|
||||
if (layer_height_opt)
|
||||
layer_height = layer_height_opt->getFloat();
|
||||
|
||||
// empty plate
|
||||
if (plate_extruder_size == 0)
|
||||
{
|
||||
std::vector<int> plate_extruders = get_extruders(true);
|
||||
plate_extruder_size = plate_extruders.size();
|
||||
}
|
||||
if (plate_extruder_size == 0)
|
||||
return wipe_tower_size;
|
||||
|
||||
for (int obj_idx = 0; obj_idx < m_model->objects.size(); obj_idx++) {
|
||||
if (!use_global_objects && !contain_instance_totally(obj_idx, 0))
|
||||
// Tallest object on this plate and the thinnest layer it is sliced at, resolved per object
|
||||
// as PrintObject resolves them (override, else preset) and over this plate's objects only -
|
||||
// seeding from the global value, or folding in an off-plate override, diverges from Print.
|
||||
const ConfigOption *layer_height_opt = config.option("layer_height");
|
||||
const double global_layer_height = layer_height_opt != nullptr ? layer_height_opt->getFloat() : 0.08;
|
||||
double max_height = 0.;
|
||||
double layer_height = std::numeric_limits<double>::max();
|
||||
for (int obj_idx = 0; obj_idx < int(m_model->objects.size()); ++obj_idx) {
|
||||
const ModelObject *object = m_model->objects[obj_idx];
|
||||
if (!use_global_objects && !contain_any_instance_totally(obj_idx))
|
||||
continue;
|
||||
|
||||
BoundingBoxf3 bbox = m_model->objects[obj_idx]->bounding_box_exact();
|
||||
max_height = std::max(bbox.size().z(), max_height);
|
||||
}
|
||||
wipe_tower_size(2) = max_height;
|
||||
//const DynamicPrintConfig &dconfig = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
auto timelapse_type = config.option<ConfigOptionEnum<TimelapseType>>("timelapse_type");
|
||||
bool need_wipe_tower = (timelapse_type ? (timelapse_type->value == TimelapseType::tlSmooth) : false) | enable_wrapping_detection;
|
||||
double extra_spacing = config.option("prime_tower_infill_gap")->getFloat() / 100.;
|
||||
const ConfigOptionEnum<WipeTowerWallType>* use_rib_wall_opt = config.option<ConfigOptionEnum<WipeTowerWallType>>("wipe_tower_wall_type");
|
||||
bool use_rib_wall = use_rib_wall_opt ? use_rib_wall_opt->value == WipeTowerWallType::wtwRib: false;
|
||||
double rib_width = config.option("wipe_tower_rib_width")->getFloat();
|
||||
double depth;
|
||||
double filament_change_volume=0.;
|
||||
{
|
||||
std::vector<double> filament_change_lengths;
|
||||
auto filament_change_lengths_opt = m_print->config().option<ConfigOptionFloats>("filament_change_length");
|
||||
if (filament_change_lengths_opt) filament_change_lengths = filament_change_lengths_opt->values;
|
||||
double length = filament_change_lengths.empty() ? 0 : *std::max_element(filament_change_lengths.begin(), filament_change_lengths.end());
|
||||
double diameter = 1.75;
|
||||
std::vector<double> diameters;
|
||||
auto filament_diameter_opt = m_print->config().option<ConfigOptionFloats>("filament_diameter");
|
||||
if (filament_diameter_opt) diameters = filament_diameter_opt->values;
|
||||
diameter = diameters.empty() ? diameter : *std::max_element(diameters.begin(), diameters.end());
|
||||
filament_change_volume = length * PI * diameter * diameter / 4.;
|
||||
}
|
||||
double volume = wipe_volume * (extruder_count == 2 ? plate_extruder_size : (plate_extruder_size - 1));
|
||||
if (extruder_count == 2) volume += filament_change_volume * (int) (plate_extruder_size / 2);
|
||||
// Read from the passed plate config — m_print may not have been applied yet
|
||||
// (fresh plates, CLI), in which case its PrintConfig still holds defaults.
|
||||
const auto *purge_opt = config.option<ConfigOptionBool>("purge_in_prime_tower");
|
||||
const auto *semm_opt = config.option<ConfigOptionBool>("single_extruder_multi_material");
|
||||
const bool semm_flush = purge_opt && purge_opt->value && semm_opt && semm_opt->value;
|
||||
if (semm_flush) volume = WipeTower2::estimate_semm_flush_volume(config, plate_extruder_size);
|
||||
if (use_rib_wall) {
|
||||
depth = std::sqrt(volume / layer_height * extra_spacing);
|
||||
if (need_wipe_tower || plate_extruder_size > 1) {
|
||||
float min_wipe_tower_depth = WipeTower::get_limit_depth_by_height(max_height);
|
||||
double volume_depth = depth;
|
||||
depth = std::max((double) min_wipe_tower_depth, depth);
|
||||
rib_width = std::min(rib_width, depth / 2);
|
||||
depth = rib_width / std::sqrt(2) + std::max(depth + m_print->config().wipe_tower_extra_rib_length.value, volume_depth);
|
||||
wipe_tower_size(0) = wipe_tower_size(1) = depth;
|
||||
// Per instance, to match PrintObject::size(); the union over instances differs once
|
||||
// they are rotated apart. The cached convex hull has the mesh's z extent and is cheap
|
||||
// enough for every scene reload.
|
||||
for (int inst_idx = 0; inst_idx < int(object->instances.size()); ++inst_idx) {
|
||||
if (!use_global_objects && !contain_instance_totally(obj_idx, inst_idx))
|
||||
continue;
|
||||
max_height = std::max(max_height, object->instance_convex_hull_bounding_box(inst_idx, true).size().z());
|
||||
}
|
||||
const ConfigOption *object_layer_height = object->config.option("layer_height");
|
||||
layer_height = std::min(layer_height, object_layer_height != nullptr ? object_layer_height->getFloat() : global_layer_height);
|
||||
}
|
||||
else {
|
||||
depth = volume / (layer_height * w);
|
||||
// The flush volumes already hold the spacing between wipes.
|
||||
if (!semm_flush) depth *= extra_spacing;
|
||||
if (need_wipe_tower || depth > EPSILON) {
|
||||
float min_wipe_tower_depth = WipeTower::get_limit_depth_by_height(max_height);
|
||||
depth = std::max((double)min_wipe_tower_depth, depth);
|
||||
}
|
||||
wipe_tower_size(0) = w;
|
||||
wipe_tower_size(1) = depth;
|
||||
}
|
||||
if (layer_height == std::numeric_limits<double>::max())
|
||||
layer_height = global_layer_height;
|
||||
|
||||
return wipe_tower_size;
|
||||
std::vector<unsigned int> filament_ids;
|
||||
for (int id : plate_extruders)
|
||||
if (id > 0)
|
||||
filament_ids.push_back(static_cast<unsigned int>(id - 1));
|
||||
return Slic3r::estimate_wipe_tower_footprint(config, resolve_wipe_tower_type(config), filament_ids, layer_height, max_height);
|
||||
}
|
||||
|
||||
arrangement::ArrangePolygon PartPlate::estimate_wipe_tower_polygon(const DynamicPrintConfig& config, int plate_index, Vec3d& wt_pos, Vec3d& wt_size, int extruder_count, int plate_extruder_size, bool use_global_objects) const
|
||||
arrangement::ArrangePolygon PartPlate::estimate_wipe_tower_polygon(const DynamicPrintConfig& config, int plate_index, Vec3d& wt_pos, Vec3d& wt_size, int plate_extruder_size, bool use_global_objects) const
|
||||
{
|
||||
float x = dynamic_cast<const ConfigOptionFloats*>(config.option("wipe_tower_x"))->get_at(plate_index);
|
||||
float y = dynamic_cast<const ConfigOptionFloats*>(config.option("wipe_tower_y"))->get_at(plate_index);
|
||||
float w = dynamic_cast<const ConfigOptionFloat*>(config.option("prime_tower_width"))->value;
|
||||
//float a = dynamic_cast<const ConfigOptionFloat*>(config.option("wipe_tower_rotation_angle"))->value;
|
||||
float v = dynamic_cast<const ConfigOptionFloat*>(config.option("prime_volume"))->value;
|
||||
float tower_brim_width = dynamic_cast<const ConfigOptionFloat*>(config.option("prime_tower_brim_width"))->value;
|
||||
const ConfigOptionBool * wrapping_opt = dynamic_cast<const ConfigOptionBool *>(config.option("enable_wrapping_detection"));
|
||||
bool enable_wrapping = (wrapping_opt != nullptr) && wrapping_opt->value;
|
||||
wt_size = estimate_wipe_tower_size(config, w, v, extruder_count, plate_extruder_size, use_global_objects, enable_wrapping);
|
||||
const WipeTowerFootprint footprint = estimate_wipe_tower_footprint(config, plate_extruder_size, use_global_objects);
|
||||
wt_size = Vec3d(footprint.width, footprint.depth, footprint.height);
|
||||
int plate_width=m_width, plate_depth=m_depth;
|
||||
w = wt_size(0); // effective width; differs from prime_tower_width when the rib wall squares the tower
|
||||
float w = wt_size(0); // effective width; differs from prime_tower_width when the rib wall squares the tower
|
||||
float depth = wt_size(1);
|
||||
float margin = WIPE_TOWER_MARGIN + tower_brim_width, wp_brim_width = 0.f;
|
||||
const ConfigOption* wipe_tower_brim_width_opt = config.option("prime_tower_brim_width");
|
||||
if (wipe_tower_brim_width_opt) {
|
||||
wp_brim_width = wipe_tower_brim_width_opt->getFloat();
|
||||
if (wp_brim_width < 0) wp_brim_width = WipeTower::get_auto_brim_by_height((float) wt_size.z());
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("arrange wipe_tower: wp_brim_width %1%") % wp_brim_width;
|
||||
}
|
||||
|
||||
x = std::clamp(x, margin, (float)plate_width - w - margin - wp_brim_width);
|
||||
y = std::clamp(y, margin, (float)plate_depth - depth - margin - wp_brim_width);
|
||||
// Resolved brim, not the raw option: "Auto" (-1) would yield a margin of 0 and let the
|
||||
// clamp put the brim off the bed. Matches set_default_wipe_tower_pos_for_plate.
|
||||
float wp_brim_width = float(footprint.brim_width);
|
||||
// A Type2 stabilization cone bulges past the body box like a brim does - fold its worst-axis
|
||||
// bulge into the same margin.
|
||||
const BoundingBox outline = get_extents(estimate_wipe_tower_first_layer_outline(config, resolve_wipe_tower_type(config), w, depth, wt_size.z()));
|
||||
wp_brim_width += float(std::max({0., unscaled(outline.max.x()) - w, unscaled(outline.max.y()) - depth, -unscaled(outline.min.x()), -unscaled(outline.min.y())}));
|
||||
// A position valid by WIPE_TOWER_MARGIN is the user's choice and stays untouched; an
|
||||
// invalid one is re-placed with the comfort margin (falling back to the validity bounds
|
||||
// on cramped plates). std::clamp is UB if lo > hi, so keep every hi >= lo.
|
||||
const float margin = WIPE_TOWER_MARGIN + wp_brim_width;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("arrange wipe_tower: wp_brim_width %1%") % wp_brim_width;
|
||||
const float x_hi = std::max(margin, (float) plate_width - w - margin);
|
||||
const float y_hi = std::max(margin, (float) plate_depth - depth - margin);
|
||||
const float margin_c = (float) WIPE_TOWER_AUTO_MARGIN + wp_brim_width;
|
||||
float x_lo_c = margin_c, x_hi_c = (float) plate_width - w - margin_c;
|
||||
if (x_lo_c > x_hi_c) { x_lo_c = margin; x_hi_c = x_hi; }
|
||||
float y_lo_c = margin_c, y_hi_c = (float) plate_depth - depth - margin_c;
|
||||
if (y_lo_c > y_hi_c) { y_lo_c = margin; y_hi_c = y_hi; }
|
||||
// Drag clamps reach this limit through the volume's bounding box (post-slice: the real
|
||||
// mesh, a couple of mm inside this reserved estimate), so a drop can land slightly out
|
||||
// of bounds — snap it onto the bound; only far-out positions get the comfort re-place.
|
||||
const float tol = 5.f;
|
||||
if (x < margin - tol || x > x_hi + tol) x = std::clamp(x, x_lo_c, x_hi_c);
|
||||
else x = std::clamp(x, margin, x_hi);
|
||||
if (y < margin - tol || y > y_hi + tol) y = std::clamp(y, y_lo_c, y_hi_c);
|
||||
else y = std::clamp(y, margin, y_hi);
|
||||
wt_pos(0) = x;
|
||||
wt_pos(1) = y;
|
||||
wt_pos(2) = 0.f;
|
||||
@@ -2474,7 +2482,7 @@ void PartPlate::clear(bool clear_sliced_result)
|
||||
|
||||
/* size and position related functions*/
|
||||
//set position and size
|
||||
void PartPlate::set_pos_and_size(Vec3d& origin, int width, int depth, int height, bool with_instance_move, bool do_clear)
|
||||
void PartPlate::set_pos_and_size(Vec3d& origin, int width, int depth, double height, bool with_instance_move, bool do_clear)
|
||||
{
|
||||
bool size_changed = false; //size changed means the machine changed
|
||||
bool pos_changed = false;
|
||||
@@ -2766,6 +2774,20 @@ bool PartPlate::contain_instance_totally(int obj_id, int instance_id) const
|
||||
return result;
|
||||
}
|
||||
|
||||
//judge whether any of the object's instances is totally included in plate or not
|
||||
bool PartPlate::contain_any_instance_totally(int obj_id) const
|
||||
{
|
||||
if (obj_id < 0 || obj_id >= int(m_model->objects.size()))
|
||||
return false;
|
||||
|
||||
const ModelObject *object = m_model->objects[obj_id];
|
||||
for (int instance_id = 0; instance_id < int(object->instances.size()); ++instance_id)
|
||||
if (contain_instance_totally(obj_id, instance_id))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//check whether instance is outside the plate or not
|
||||
bool PartPlate::check_outside(int obj_id, int instance_id, BoundingBoxf3* bounding_box)
|
||||
{
|
||||
@@ -2782,10 +2804,10 @@ bool PartPlate::check_outside(int obj_id, int instance_id, BoundingBoxf3* boundi
|
||||
|
||||
if (instance_box.min.z() < SINKING_Z_THRESHOLD) {
|
||||
// Orca: For sinking object, we use a more expensive algorithm so part below build plate won't be considered
|
||||
// m_plater is null in CLI mode.
|
||||
if (m_plater && plate_box.intersects(instance_box)) {
|
||||
// m_height mirrors the printer's printable height and is set in CLI mode too, unlike m_plater.
|
||||
if (plate_box.intersects(instance_box)) {
|
||||
// TODO: FIXME: this does not take exclusion area into account
|
||||
const BuildVolume build_volume(get_shape(), m_plater->build_volume().printable_height(), m_extruder_areas, m_extruder_heights);
|
||||
const BuildVolume build_volume(get_shape(), m_height, m_extruder_areas, m_extruder_heights);
|
||||
const auto state = instance->calc_print_volume_state(build_volume);
|
||||
outside = state == ModelInstancePVS_Partly_Outside;
|
||||
}
|
||||
@@ -3495,7 +3517,7 @@ bool PartPlate::intersects(const BoundingBoxf3& bb) const
|
||||
return print_volume.intersects(bb);
|
||||
}
|
||||
|
||||
void PartPlate::render(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_body, bool force_background_color, HeightLimitMode mode, int hover_id, bool render_cali, bool show_grid)
|
||||
void PartPlate::render(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_body, bool force_background_color, HeightLimitMode mode, int hover_id, bool render_cali, bool show_grid, bool hide_chrome)
|
||||
{
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
@@ -3546,16 +3568,18 @@ void PartPlate::render(const Transform3d& view_matrix, const Transform3d& projec
|
||||
if (wxGetApp().show_plate_gridlines() && show_grid)
|
||||
render_grid(bottom);
|
||||
|
||||
if (!bottom && m_selected && !force_background_color) {
|
||||
if (!hide_chrome && !bottom && m_selected && !force_background_color) {
|
||||
if (m_partplate_list)
|
||||
render_logo(bottom, m_partplate_list->render_cali_logo && render_cali);
|
||||
else
|
||||
render_logo(bottom);
|
||||
}
|
||||
|
||||
render_icons(bottom, only_body, hover_id);
|
||||
if (!force_background_color) {
|
||||
render_only_numbers(bottom);
|
||||
if (!hide_chrome) {
|
||||
render_icons(bottom, only_body, hover_id);
|
||||
if (!force_background_color) {
|
||||
render_only_numbers(bottom);
|
||||
}
|
||||
}
|
||||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
@@ -4109,7 +4133,7 @@ void PartPlate::on_filament_deleted(int filament_count, int filament_id)
|
||||
|
||||
|
||||
/* PartPlate List related functions*/
|
||||
PartPlateList::PartPlateList(int width, int depth, int height, Plater* platerObj, Model* modelObj, PrinterTechnology tech)
|
||||
PartPlateList::PartPlateList(int width, int depth, double height, Plater* platerObj, Model* modelObj, PrinterTechnology tech)
|
||||
:m_plate_width(width), m_plate_depth(depth), m_plate_height(height), m_plater(platerObj), m_model(modelObj), printer_technology(tech),
|
||||
unprintable_plate(this, Vec3d(0.0 + width * (1. + LOGICAL_PART_PLATE_GAP), 0.0, 0.0), width, depth, height, platerObj, modelObj, false, tech)
|
||||
{
|
||||
@@ -4499,26 +4523,16 @@ void PartPlateList::set_default_wipe_tower_pos_for_plate(int plate_idx, bool ini
|
||||
f_volume_maps = wxGetApp().preset_bundle->get_default_nozzle_volume_types_for_filaments(filament_maps);
|
||||
}
|
||||
DynamicPrintConfig full_config = wxGetApp().preset_bundle->full_config(false, filament_maps, f_volume_maps);
|
||||
float w = dynamic_cast<const ConfigOptionFloat *>(full_config.option("prime_tower_width"))->value;
|
||||
float v = dynamic_cast<const ConfigOptionFloat *>(full_config.option("prime_volume"))->value;
|
||||
bool enable_wrapping = false;
|
||||
const ConfigOptionBool *wrapping_opt = dynamic_cast<const ConfigOptionBool *>(full_config.option("enable_wrapping_detection"));
|
||||
if (wrapping_opt) enable_wrapping = wrapping_opt->value;
|
||||
int nozzle_nums = wxGetApp().preset_bundle->get_printer_extruder_count();
|
||||
Vec3d wipe_tower_size = part_plate->estimate_wipe_tower_size(full_config, w, v, nozzle_nums, init_pos ? 2 : 0, false, enable_wrapping);
|
||||
WipeTowerFootprint footprint = part_plate->estimate_wipe_tower_footprint(full_config, init_pos ? 2 : 0);
|
||||
|
||||
if (!init_pos && (is_approx(wipe_tower_size(0), 0.0) || is_approx(wipe_tower_size(1), 0.0))) {
|
||||
wipe_tower_size = part_plate->estimate_wipe_tower_size(full_config, w, v, nozzle_nums, 2, false, enable_wrapping);
|
||||
if (!init_pos && (is_approx(footprint.width, 0.0) || is_approx(footprint.depth, 0.0))) {
|
||||
footprint = part_plate->estimate_wipe_tower_footprint(full_config, 2);
|
||||
}
|
||||
Vec3d wipe_tower_size(footprint.width, footprint.depth, footprint.height);
|
||||
|
||||
// Compute brim-aware margin: brim extends outward from tower position
|
||||
float brim_width = 0.f;
|
||||
const ConfigOptionFloat *brim_opt = full_config.option<ConfigOptionFloat>("prime_tower_brim_width");
|
||||
if (brim_opt) {
|
||||
brim_width = brim_opt->value;
|
||||
if (brim_width < 0) brim_width = WipeTower::get_auto_brim_by_height((float) wipe_tower_size.z());
|
||||
}
|
||||
const float margin = WIPE_TOWER_MARGIN + brim_width;
|
||||
// Brim-aware margin: the brim extends outward from the tower position.
|
||||
const float brim_width = float(footprint.brim_width);
|
||||
const float margin = WIPE_TOWER_AUTO_MARGIN + brim_width;
|
||||
|
||||
// clamp wipe tower position within plate boundaries
|
||||
{
|
||||
@@ -4554,7 +4568,7 @@ void PartPlateList::set_default_wipe_tower_pos_for_plate(int plate_idx, bool ini
|
||||
}
|
||||
|
||||
//this may be happened after machine changed
|
||||
void PartPlateList::reset_size(int width, int depth, int height, bool reload_objects, bool update_shapes)
|
||||
void PartPlateList::reset_size(int width, int depth, double height, bool reload_objects, bool update_shapes)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(":before size: plate_width %1%, plate_depth %2%, plate_height %3%") % m_plate_width % m_plate_depth % m_plate_height;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(":after size: plate_width %1%, plate_depth %2%, plate_height %3%") % width % depth % height;
|
||||
@@ -5983,7 +5997,7 @@ void PartPlateList::postprocess_arrange_polygon(arrangement::ArrangePolygon& arr
|
||||
|
||||
/*rendering related functions*/
|
||||
//render
|
||||
void PartPlateList::render(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_current, bool only_body, int hover_id, bool render_cali, bool show_grid)
|
||||
void PartPlateList::render(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_current, bool only_body, int hover_id, bool render_cali, bool show_grid, bool hide_chrome)
|
||||
{
|
||||
const std::lock_guard<std::mutex> local_lock(m_plates_mutex);
|
||||
std::vector<PartPlate*>::iterator it = m_plate_list.begin();
|
||||
@@ -6008,15 +6022,15 @@ void PartPlateList::render(const Transform3d& view_matrix, const Transform3d& pr
|
||||
if (current_index == m_current_plate) {
|
||||
PartPlate::HeightLimitMode height_mode = (only_current)?PartPlate::HEIGHT_LIMIT_NONE:m_height_limit_mode;
|
||||
if (plate_hover_index == current_index)
|
||||
(*it)->render(view_matrix, projection_matrix, bottom, only_body, false, height_mode, plate_hover_action, render_cali, show_grid);
|
||||
(*it)->render(view_matrix, projection_matrix, bottom, only_body, false, height_mode, plate_hover_action, render_cali, show_grid, hide_chrome);
|
||||
else
|
||||
(*it)->render(view_matrix, projection_matrix, bottom, only_body, false, height_mode, -1, render_cali, show_grid);
|
||||
(*it)->render(view_matrix, projection_matrix, bottom, only_body, false, height_mode, -1, render_cali, show_grid, hide_chrome);
|
||||
}
|
||||
else {
|
||||
if (plate_hover_index == current_index)
|
||||
(*it)->render(view_matrix, projection_matrix, bottom, only_body, false, PartPlate::HEIGHT_LIMIT_NONE, plate_hover_action, render_cali, show_grid);
|
||||
(*it)->render(view_matrix, projection_matrix, bottom, only_body, false, PartPlate::HEIGHT_LIMIT_NONE, plate_hover_action, render_cali, show_grid, hide_chrome);
|
||||
else
|
||||
(*it)->render(view_matrix, projection_matrix, bottom, only_body, false, PartPlate::HEIGHT_LIMIT_NONE, -1, render_cali, show_grid);
|
||||
(*it)->render(view_matrix, projection_matrix, bottom, only_body, false, PartPlate::HEIGHT_LIMIT_NONE, -1, render_cali, show_grid, hide_chrome);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6503,7 +6517,7 @@ int PartPlateList::store_to_3mf_structure(PlateDataPtrs& plate_data_list, bool w
|
||||
plate_data_item->filament_change_sequence = m_plate_list[i]->m_gcode_result->filament_change_sequence;
|
||||
plate_data_item->nozzle_change_sequence = m_plate_list[i]->m_gcode_result->nozzle_change_sequence;
|
||||
plate_data_item->optimal_assignment = m_plate_list[i]->m_gcode_result->optimal_assignment;
|
||||
plate_data_item->first_layer_time = std::to_string(m_plate_list[i]->cali_bboxes_data.first_layer_time);
|
||||
plate_data_item->first_layer_time = std::to_string(m_plate_list[i]->get_slice_result()->initial_layer_time);
|
||||
Print *print = nullptr;
|
||||
m_plate_list[i]->get_print((PrintBase **) &print, nullptr, nullptr);
|
||||
if (print) {
|
||||
@@ -6732,7 +6746,7 @@ int PartPlateList::load_gcode_files()
|
||||
//BoundingBoxf3 print_volume = m_plate_list[i]->get_bounding_box(false);
|
||||
//print_volume.max(2) = this->m_plate_height;
|
||||
//print_volume.min(2) = -1e10;
|
||||
m_model->update_print_volume_state({m_plate_list[i]->get_shape(), (double)this->m_plate_height, m_plate_list[i]->get_extruder_areas(), m_plate_list[i]->get_extruder_heights() });
|
||||
m_model->update_print_volume_state({m_plate_list[i]->get_shape(), this->m_plate_height, m_plate_list[i]->get_extruder_areas(), m_plate_list[i]->get_extruder_heights() });
|
||||
|
||||
if (!m_plate_list[i]->load_gcode_from_file(m_plate_list[i]->m_gcode_path_from_3mf))
|
||||
ret ++;
|
||||
|
||||
Reference in New Issue
Block a user