NEW: add some cli options to support more function

1. Option "assemble" assembles multiple input meshes into a single object.
2. Option "load_filament_ids" sets filament ids for each loaded object.
3. Option "clone_objects" add multiple copies for each loaded object

Jira: STUDIO-4848

Change-Id: I707b48767a7c978118490398da440f0fb54351fa
(cherry picked from commit 8ddb456375be1abc6a0f692096068d8eda89b0eb)
This commit is contained in:
Arthur 2023-10-11 14:37:02 +08:00 committed by Lane.Wei
parent 0964b5bb0a
commit 95430ee68d
4 changed files with 206 additions and 38 deletions

View file

@ -97,6 +97,7 @@ using namespace Slic3r;
std::string message;
}error_message;*/
#define MAX_CLONEABLE_SIZE 512
std::map<int, std::string> cli_errors = {
{CLI_SUCCESS, "Success."},
@ -743,6 +744,43 @@ int CLI::run(int argc, char **argv)
if (custom_gcode_option)
custom_gcode_file = custom_gcode_option->value;
bool allow_multicolor_oneplate = m_config.option<ConfigOptionBool>("allow_multicolor_oneplate", true)->value;
const std::vector<int> loaded_filament_ids = m_config.option<ConfigOptionInts>("load_filament_ids", true)->values;
const std::vector<int> clone_objects = m_config.option<ConfigOptionInts>("clone_objects", true)->values;
//when load objects from stl/obj, the total used filaments set
std::set<int> used_filament_set;
BOOST_LOG_TRIVIAL(info) << boost::format("allow_multicolor_oneplate %1%, loaded_filament_ids size %2%, clone_objects size %3%")%allow_multicolor_oneplate %loaded_filament_ids.size() %clone_objects.size();
if (clone_objects.size() > 0)
{
if (clone_objects.size() != m_input_files.size())
{
BOOST_LOG_TRIVIAL(error) << boost::format("clone_objects size %1% should be the same with input files size %2%")%clone_objects.size() %m_input_files.size();
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info);
flush_and_exit(CLI_INVALID_PARAMS);
}
else if (load_filaments.size() == 0)
{
BOOST_LOG_TRIVIAL(error) << boost::format("clone_objects should be used with load_filaments together");
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info);
flush_and_exit(CLI_INVALID_PARAMS);
}
}
if (loaded_filament_ids.size() > 0)
{
if (loaded_filament_ids.size() != m_input_files.size())
{
BOOST_LOG_TRIVIAL(error) << boost::format("loaded_filament_ids size %1% should be the same with input files size %2%")%loaded_filament_ids.size() %m_input_files.size();
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info);
flush_and_exit(CLI_INVALID_PARAMS);
}
else if (load_filaments.size() == 0)
{
BOOST_LOG_TRIVIAL(error) << boost::format("loaded_filament_ids should be used with load_filaments together");
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info);
flush_and_exit(CLI_INVALID_PARAMS);
}
}
/*for (const std::string& file : m_input_files)
if (is_gcode_file(file) && boost::filesystem::exists(file)) {
start_as_gcodeviewer = true;
@ -750,6 +788,7 @@ int CLI::run(int argc, char **argv)
break;
}*/
BOOST_LOG_TRIVIAL(info) << boost::format("plate_to_slice=%1%, normative_check=%2%, use_first_fila_as_default=%3%")%plate_to_slice %normative_check %use_first_fila_as_default;
unsigned int input_index = 0;
//if (!start_as_gcodeviewer) {
for (const std::string& file : m_input_files) {
if (!boost::filesystem::exists(file)) {
@ -770,11 +809,18 @@ int CLI::run(int argc, char **argv)
is_bbl_3mf = false;
LoadStrategy strategy;
if (boost::algorithm::iends_with(file, ".3mf") && first_file) {
if ((clone_objects.size() > 0) || (loaded_filament_ids.size() > 0))
{
BOOST_LOG_TRIVIAL(error) << boost::format("can not load 3mf when set loaded_filament_ids or clone_objects");
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info);
flush_and_exit(CLI_INVALID_PARAMS);
}
strategy = LoadStrategy::LoadModel | LoadStrategy::LoadConfig|LoadStrategy::AddDefaultInstances | LoadStrategy::LoadAuxiliary;
//load_aux = true;
}
else
else {
strategy = LoadStrategy::LoadModel | LoadStrategy::AddDefaultInstances;
}
// BBS: adjust whebackup
//LoadStrategy strategy = LoadStrategy::LoadModel | LoadStrategy::LoadConfig|LoadStrategy::AddDefaultInstances;
//if (load_aux) strategy = strategy | LoadStrategy::LoadAuxiliary;
@ -789,11 +835,11 @@ int CLI::run(int argc, char **argv)
}
BOOST_LOG_TRIVIAL(info) << boost::format("the first file is a 3mf, version %1%, got plate count %2%") %file_version.to_string() %plate_data_src.size();
need_arrange = false;
for (ModelObject* o : model.objects)
/*for (ModelObject* o : model.objects)
{
orients_requirement.insert(std::pair<size_t, bool>(o->id().id, false));
BOOST_LOG_TRIVIAL(info) << "object "<<o->name <<", id :" << o->id().id << ", from bbl 3mf\n";
}
}*/
Semver old_version(1, 5, 9), old_version2(1, 5, 9);
if ((file_version < old_version) && !config.empty()) {
@ -896,9 +942,56 @@ int CLI::run(int argc, char **argv)
else
{
need_arrange = true;
int object_extruder_id = 0, clone_count = 1;
if (loaded_filament_ids.size() > input_index) {
if (loaded_filament_ids[input_index] > 0) {
if (loaded_filament_ids[input_index] > load_filaments.size()) {
BOOST_LOG_TRIVIAL(error) << boost::format("invalid filament id %1% at index %2%, max %3%")%loaded_filament_ids[input_index] % (input_index + 1) %load_filaments.size();
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info);
flush_and_exit(CLI_INVALID_PARAMS);
}
object_extruder_id = loaded_filament_ids[input_index];
used_filament_set.emplace(object_extruder_id);
}
}
if (clone_objects.size() > input_index) {
if (clone_objects[input_index] > 0) {
if (clone_objects[input_index] > MAX_CLONEABLE_SIZE) {
BOOST_LOG_TRIVIAL(error) << boost::format("invalid clone count %1% at index %2%, max %3%")%clone_objects[input_index] % (input_index + 1) %MAX_CLONEABLE_SIZE;
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info);
flush_and_exit(CLI_INVALID_PARAMS);
}
clone_count = clone_objects[input_index];
}
}
//clone objects process
if (clone_count > 1)
{
unsigned int object_count = model.objects.size();
for (unsigned int obj_index = 0; obj_index < object_count; obj_index++)
{
ModelObject* object = model.objects[obj_index];
for (unsigned int clone_index = 1; clone_index < clone_count; clone_index++)
{
ModelObject* newObj = model.add_object(*object);
newObj->name = object->name +"_"+ std::to_string(clone_index+1);
}
object->name = object->name +"_"+ std::to_string(1);
}
}
for (ModelObject* o : model.objects)
{
orients_requirement.insert(std::pair<size_t, bool>(o->id().id, true));
if (object_extruder_id != 0) {
o->config.set_key_value("extruder", new ConfigOptionInt(object_extruder_id));
}
//default not orient for all, if need to orient use the action
//orients_requirement.insert(std::pair<size_t, bool>(o->id().id, false));
BOOST_LOG_TRIVIAL(info) << "object "<<o->name <<", id :" << o->id().id << ", from stl or other 3mf\n";
o->ensure_on_bed();
}
@ -923,6 +1016,7 @@ int CLI::run(int argc, char **argv)
// config is applied to m_print_config before the current m_config values.
config += std::move(m_print_config);
m_print_config = std::move(config);
input_index++;
}
catch (std::exception& e) {
boost::nowide::cerr << file << ": " << e.what() << std::endl;
@ -1994,8 +2088,8 @@ int CLI::run(int argc, char **argv)
{
ModelObject* new_object = m.add_object(*o);
//BOOST_LOG_TRIVIAL(info) << "object "<<o->name <<", id :" << o->id().id << "\n";
orients_requirement.emplace(new_object->id().id, orients_requirement[o->id().id]);
orients_requirement.erase(o->id().id);
//orients_requirement.emplace(new_object->id().id, orients_requirement[o->id().id]);
//orients_requirement.erase(o->id().id);
}
m.add_default_instances();
m_models.clear();
@ -2199,22 +2293,27 @@ int CLI::run(int argc, char **argv)
for (auto const &opt_key : m_transforms) {
BOOST_LOG_TRIVIAL(info) << "process transform " << opt_key << "\n";
if (opt_key == "merge") {
//BBS: always merge, do nothing here
/*Model m;
if (opt_key == "assemble") {
if (clone_objects.size() > 0) {
BOOST_LOG_TRIVIAL(error) << "Invalid params: can not set assemble and clone_objects together." << std::endl;
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info);
flush_and_exit(CLI_INVALID_PARAMS);
}
Model m;
ModelObject* new_object = m.add_object();
new_object->name = _u8L("Assembly");
new_object->add_instance();
int idx = 0;
for (auto& model : m_models)
for (ModelObject* o : model.objects)
m.add_object(*o);
// Rearrange instances unless --dont-arrange is supplied
if (!m_config.opt_bool("dont_arrange")) {
m.add_default_instances();
if (this->has_print_action())
arrange_objects(m, bed, arrange_cfg);
else
arrange_objects(m, InfiniteBed{}, arrange_cfg);
for (ModelObject* o : model.objects) {
for (auto volume : o->volumes) {
ModelVolume* new_volume = new_object->add_volume(*volume);
// set extruder id
new_volume->config.set_key_value("extruder", new ConfigOptionInt(o->config.extruder()));
}
}
m_models.clear();
m_models.emplace_back(std::move(m));*/
m_models.emplace_back(std::move(m));
}
else if (opt_key == "repetitions") {
int repetitions_count = m_config.option<ConfigOptionInt>("repetitions")->value;
@ -2257,7 +2356,7 @@ int CLI::run(int argc, char **argv)
if (orient_option == 0)
{
orients_requirement.clear();
//orients_requirement.clear();
for (auto& model : m_models)
for (ModelObject* o : model.objects)
{
@ -2268,7 +2367,7 @@ int CLI::run(int argc, char **argv)
else if (orient_option == 1)
{
//force orient
orients_requirement.clear();
//orients_requirement.clear();
for (auto& model : m_models)
for (ModelObject* o : model.objects)
{
@ -2675,6 +2774,48 @@ int CLI::run(int argc, char **argv)
//add the virtual object into unselect list if has
partplate_list.preprocess_exclude_areas(unselected);
if (used_filament_set.size() > 0)
{
//prepare the wipe tower
int plate_count = partplate_list.get_plate_count();
int extruder_size = used_filament_set.size();
auto printer_structure_opt = m_print_config.option<ConfigOptionEnum<PrinterStructure>>("printer_structure");
// set the default position, the same with print config(left top)
float x = WIPE_TOWER_DEFAULT_X_POS;
float y = WIPE_TOWER_DEFAULT_Y_POS;
if (printer_structure_opt && printer_structure_opt->value == PrinterStructure::psI3) {
x = I3_WIPE_TOWER_DEFAULT_X_POS;
y = I3_WIPE_TOWER_DEFAULT_Y_POS;
}
ConfigOptionFloat wt_x_opt(x);
ConfigOptionFloat wt_y_opt(y);
//create the options using default if neccessary
ConfigOptionFloats* wipe_x_option = m_print_config.option<ConfigOptionFloats>("wipe_tower_x", true);
ConfigOptionFloats* wipe_y_option = m_print_config.option<ConfigOptionFloats>("wipe_tower_y", true);
ConfigOptionFloat* width_option = m_print_config.option<ConfigOptionFloat>("prime_tower_width", true);
ConfigOptionFloat* rotation_angle_option = m_print_config.option<ConfigOptionFloat>("wipe_tower_rotation_angle", true);
ConfigOptionFloat* volume_option = m_print_config.option<ConfigOptionFloat>("prime_volume", true);
BOOST_LOG_TRIVIAL(info) << boost::format("prime_tower_width %1% wipe_tower_rotation_angle %2% prime_volume %3%")%width_option->value %rotation_angle_option->value %volume_option->value ;
for (int bedid = 0; bedid < MAX_PLATE_COUNT; bedid++) {
int plate_index_valid = std::min(bedid, plate_count - 1);
if (bedid < plate_count) {
wipe_x_option->set_at(&wt_x_opt, plate_index_valid, 0);
wipe_y_option->set_at(&wt_y_opt, plate_index_valid, 0);
}
ArrangePolygon wipe_tower_ap = partplate_list.get_plate(plate_index_valid)->estimate_wipe_tower_polygon(m_print_config, plate_index_valid, extruder_size, true);
wipe_tower_ap.bed_idx = bedid;
unselected.emplace_back(wipe_tower_ap);
}
}
}
else {
//only arrange current plate
@ -2798,7 +2939,7 @@ int CLI::run(int argc, char **argv)
//Step-2:prepare the arrange params
arrange_cfg.allow_rotations = true;
arrange_cfg.allow_multi_materials_on_same_plate = true;
arrange_cfg.allow_multi_materials_on_same_plate = allow_multicolor_oneplate;
arrange_cfg.avoid_extrusion_cali_region = false;
arrange_cfg.clearance_height_to_rod = height_to_rod;
arrange_cfg.clearance_height_to_lid = height_to_lid;
@ -2824,7 +2965,7 @@ int CLI::run(int argc, char **argv)
{
BOOST_LOG_TRIVIAL(debug) << "arrange bedpts:" << beds[0].transpose() << ", " << beds[1].transpose() << ", " << beds[2].transpose() << ", " << beds[3].transpose();
BOOST_LOG_TRIVIAL(warning)<< "Arrange full params: "<< arrange_cfg.to_json();
BOOST_LOG_TRIVIAL(info)<< "Arrange full params: "<< arrange_cfg.to_json();
BOOST_LOG_TRIVIAL(info) << boost::format("arrange: items selected before arranging: %1%")%selected.size();
for (auto item : selected)
BOOST_LOG_TRIVIAL(trace) << item.name << ", extruder: " << item.extrude_ids.back() << ", bed: " << item.bed_idx

View file

@ -5308,12 +5308,13 @@ CLITransformConfigDef::CLITransformConfigDef()
/*def = this->add("duplicate_grid", coPoint);
def->label = L("Duplicate by grid");
def->tooltip = L("Multiply copies by creating a grid.");
def->tooltip = L("Multiply copies by creating a grid.");*/
def = this->add("assemble", coBool);
def->label = L("Assemble");
def->tooltip = L("Arrange the supplied models in a plate and merge them in a single model in order to perform actions once.");
def->cli = "merge|m";*/
//def->cli = "merge|m";
def->set_default_value(new ConfigOptionBool(false));
def = this->add("convert_unit", coBool);
def->label = L("Convert Unit");
@ -5406,6 +5407,12 @@ CLIMiscConfigDef::CLIMiscConfigDef()
def->cli_params = "\"3,5,10,77\"";
def->set_default_value(new ConfigOptionInts());
def = this->add("clone_objects", coInts);
def->label = L("Clone Objects");
def->tooltip = L("Clone objects in the load list");
def->cli_params = "\"1,3,1,10\"";
def->set_default_value(new ConfigOptionInts());
def = this->add("uptodate_settings", coStrings);
def->label = L("load uptodate process/machine settings when using uptodate");
def->tooltip = L("load uptodate process/machine settings from the specified file when using uptodate");
@ -5454,6 +5461,17 @@ CLIMiscConfigDef::CLIMiscConfigDef()
def->tooltip = L("Load custom gcode from json");
def->cli_params = "custom_gcode_toolchange.json";
def->set_default_value(new ConfigOptionString());
def = this->add("load_filament_ids", coInts);
def->label = L("Load filament ids");
def->tooltip = L("Load filament ids for each object");
def->cli_params = "\"1,2,3,1\"";
def->set_default_value(new ConfigOptionInts());
def = this->add("allow_multicolor_oneplate", coBool);
def->label = L("Allow multiple color on one plate");
def->tooltip = L("If enabled, the arrange will allow multiple color on one plate ");
def->set_default_value(new ConfigOptionBool(true));
}
const CLIActionsConfigDef cli_actions_config_def;

View file

@ -59,11 +59,11 @@ static const int PARTPLATE_TEXT_OFFSET_X2 = 1;
static const int PARTPLATE_TEXT_OFFSET_Y = 1;
static const int PARTPLATE_PLATENAME_OFFSET_Y = 10;
static const float WIPE_TOWER_DEFAULT_X_POS = 165.;
static const float WIPE_TOWER_DEFAULT_Y_POS = 250.; // Max y
const float WIPE_TOWER_DEFAULT_X_POS = 165.;
const float WIPE_TOWER_DEFAULT_Y_POS = 250.; // Max y
static const float I3_WIPE_TOWER_DEFAULT_X_POS = 0.;
static const float I3_WIPE_TOWER_DEFAULT_Y_POS = 250.; // Max y
const float I3_WIPE_TOWER_DEFAULT_X_POS = 0.;
const float I3_WIPE_TOWER_DEFAULT_Y_POS = 250.; // Max y
std::array<unsigned char, 4> PlateTextureForeground = {0x0, 0xae, 0x42, 0xff};
@ -1627,7 +1627,7 @@ std::vector<int> PartPlate::get_used_extruders()
return used_extruders;
}
Vec3d PartPlate::estimate_wipe_tower_size(const DynamicPrintConfig & config, const double w, const double wipe_volume, int plate_extruder_size) const
Vec3d PartPlate::estimate_wipe_tower_size(const DynamicPrintConfig & config, const double w, const double wipe_volume, int plate_extruder_size, bool use_global_objects) const
{
Vec3d wipe_tower_size;
@ -1650,7 +1650,7 @@ Vec3d PartPlate::estimate_wipe_tower_size(const DynamicPrintConfig & config, con
return wipe_tower_size;
for (int obj_idx = 0; obj_idx < m_model->objects.size(); obj_idx++) {
if (!contain_instance_totally(obj_idx, 0))
if (!use_global_objects && !contain_instance_totally(obj_idx, 0))
continue;
BoundingBoxf3 bbox = m_model->objects[obj_idx]->bounding_box();
@ -1701,14 +1701,14 @@ Vec3d PartPlate::estimate_wipe_tower_size(const DynamicPrintConfig & config, con
return wipe_tower_size;
}
arrangement::ArrangePolygon PartPlate::estimate_wipe_tower_polygon(const DynamicPrintConfig& config, int plate_index, int plate_extruder_size) const
arrangement::ArrangePolygon PartPlate::estimate_wipe_tower_polygon(const DynamicPrintConfig& config, int plate_index, 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;
Vec3d wipe_tower_size = estimate_wipe_tower_size(config, w, v, plate_extruder_size);
Vec3d wipe_tower_size = estimate_wipe_tower_size(config, w, v, plate_extruder_size, use_global_objects);
int plate_width=m_width, plate_depth=m_depth;
float depth = wipe_tower_size(1);
float margin = WIPE_TOWER_MARGIN, wp_brim_width = 0.f;

View file

@ -47,6 +47,15 @@ inline int compute_colum_count(int count)
return cols;
}
extern const float WIPE_TOWER_DEFAULT_X_POS;
extern const float WIPE_TOWER_DEFAULT_Y_POS; // Max y
extern const float I3_WIPE_TOWER_DEFAULT_X_POS;
extern const float I3_WIPE_TOWER_DEFAULT_Y_POS; // Max y
namespace Slic3r {
class Model;
@ -293,8 +302,8 @@ public:
ModelInstance* get_instance(int obj_id, int instance_id);
Vec3d get_origin() { return m_origin; }
Vec3d estimate_wipe_tower_size(const DynamicPrintConfig & config, const double w, const double wipe_volume, int plate_extruder_size = 0) const;
arrangement::ArrangePolygon estimate_wipe_tower_polygon(const DynamicPrintConfig & config, int plate_index, int plate_extruder_size = 0) const;
Vec3d estimate_wipe_tower_size(const DynamicPrintConfig & config, const double w, const double wipe_volume, int plate_extruder_size = 0, bool use_global_objects = false) const;
arrangement::ArrangePolygon estimate_wipe_tower_polygon(const DynamicPrintConfig & config, int plate_index, int plate_extruder_size = 0, bool use_global_objects = false) const;
std::vector<int> get_extruders(bool conside_custom_gcode = false) const;
std::vector<int> get_extruders_under_cli(bool conside_custom_gcode, DynamicPrintConfig& full_config) const;
std::vector<int> get_extruders_without_support(bool conside_custom_gcode = false) const;