ENH: CLI: add support for colored obj
jira: no-jira Change-Id: If9e698d60b71e8835a3ae46c75e9c8c2878556a7 (cherry picked from commit a2b2ec9cb80e3bafabd07a377aff9e11188be346)
This commit is contained in:
parent
b97d44dae4
commit
201d3b18cc
|
@ -68,6 +68,7 @@ using namespace nlohmann;
|
|||
|
||||
#include "libslic3r/Orient.hpp"
|
||||
#include "libslic3r/PNGReadWrite.hpp"
|
||||
#include "libslic3r/ObjColorUtils.hpp"
|
||||
|
||||
#include "BambuStudio.hpp"
|
||||
//BBS: add exception handler for win32
|
||||
|
@ -81,6 +82,7 @@ using namespace nlohmann;
|
|||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/Camera.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/GuiColor.hpp"
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#ifdef __WXGTK__
|
||||
|
@ -777,17 +779,74 @@ void merge_or_add_object(assemble_plate_info_t& assemble_plate_info, Model &mode
|
|||
}
|
||||
}
|
||||
|
||||
bool convert_obj_cluster_colors(std::vector<Slic3r::RGBA>& input_colors, std::vector<RGBA>& all_colours, int max_filament_count, std::vector<unsigned char>& output_filament_ids)
|
||||
{
|
||||
using namespace Slic3r::GUI;
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("%1%:%2%, got original input obj colors %3%")%__FUNCTION__ %__LINE__ %input_colors.size();
|
||||
if (input_colors.size() > 0) {
|
||||
std::vector<Slic3r::RGBA> cluster_colors;
|
||||
std::vector<int> cluster_labels;
|
||||
char cluster_number = -1;
|
||||
|
||||
obj_color_deal_algo(input_colors, cluster_colors, cluster_labels, cluster_number);
|
||||
std::vector<int> cluster_color_maps;
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("%1%:%2%, after obj_color_deal_algo, cluster_colors size %3%, all_colours size %4%, max_filament_count=%5%")%__FUNCTION__ %__LINE__%cluster_colors.size() %all_colours.size() %max_filament_count;
|
||||
|
||||
cluster_color_maps.resize(cluster_colors.size(), 1);
|
||||
|
||||
int init_size = all_colours.size();
|
||||
|
||||
for (size_t i = 0; i < cluster_colors.size(); i++) {
|
||||
if ((init_size + i + 1) <= max_filament_count) {
|
||||
all_colours.push_back(cluster_colors[i]);
|
||||
cluster_color_maps[i] = all_colours.size();
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("%1%:%2%, cluster color index %3% RGBA {%4%,%5%,%6%,%7%} directly inserted, id %8%")
|
||||
%__FUNCTION__ %__LINE__%(i+1) %cluster_colors[i][0] %cluster_colors[i][1] %cluster_colors[i][2] %cluster_colors[i][3] %cluster_color_maps[i] ;
|
||||
}
|
||||
else {
|
||||
std::vector<ColorDistValue> color_dists;
|
||||
color_dists.resize(max_filament_count);
|
||||
for (size_t j = 0; j < max_filament_count; j++) {
|
||||
color_dists[j].distance = calc_color_distance(cluster_colors[i], all_colours[j]);
|
||||
color_dists[j].id = j + 1;
|
||||
}
|
||||
std::sort(color_dists.begin(), color_dists.end(), [](ColorDistValue &a, ColorDistValue &b) { return a.distance < b.distance; });
|
||||
cluster_color_maps[i] = color_dists[0].id;
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("%1%:%2%, cluster color index %3% RGBA {%4%,%5%,%6%,%7%} directly inserted, id %8%")
|
||||
%__FUNCTION__ %__LINE__%(i+1) %cluster_colors[i][0] %cluster_colors[i][1] %cluster_colors[i][2] %cluster_colors[i][3] %cluster_color_maps[i] ;
|
||||
}
|
||||
}
|
||||
|
||||
//3.generate filament_ids
|
||||
auto input_colors_size = input_colors.size();
|
||||
output_filament_ids.resize(input_colors_size);
|
||||
for (size_t i = 0; i < input_colors_size; i++) {
|
||||
int label = cluster_labels[i];
|
||||
output_filament_ids[i] = cluster_color_maps[label];
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("%1%:%2%, all_colours size changes to %3%")%__FUNCTION__ %__LINE__%all_colours.size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#define DIR_SEPARATOR '\\'
|
||||
#else
|
||||
#define DIR_SEPARATOR '/'
|
||||
#endif
|
||||
static int construct_assemble_list(std::vector<assemble_plate_info_t> &assemble_plate_info_list, Model &model, PlateDataPtrs &plate_list)
|
||||
static int construct_assemble_list(std::vector<assemble_plate_info_t> &assemble_plate_info_list, Model &model, PlateDataPtrs &plate_list, std::vector<RGBA>& all_colours)
|
||||
{
|
||||
int ret = 0;
|
||||
int plate_count = assemble_plate_info_list.size();
|
||||
ConfigSubstitutionContext config_substitutions(ForwardCompatibilitySubstitutionRule::Enable);
|
||||
Model temp_model;
|
||||
const int max_filament_count = size_t(EnforcerBlockerType::ExtruderMax);
|
||||
|
||||
plate_list.resize(plate_count);
|
||||
for (int index = 0; index < plate_count; index++)
|
||||
|
@ -821,7 +880,10 @@ static int construct_assemble_list(std::vector<assemble_plate_info_t> &assemble_
|
|||
{
|
||||
assemble_object_info_t& assemble_object = assemble_plate_info.assemble_obj_list[obj_index];
|
||||
std::string object_name;
|
||||
std::string object_1_name;
|
||||
ModelObject* object = nullptr;
|
||||
TriangleMesh mesh;
|
||||
bool skip_filament = false;
|
||||
|
||||
boost::filesystem::path object_path(assemble_object.path);
|
||||
if (!fs::exists(object_path)) {
|
||||
|
@ -843,7 +905,13 @@ static int construct_assemble_list(std::vector<assemble_plate_info_t> &assemble_
|
|||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": found no mesh data from stl file %1%, plate index %2%, object index %3%") % assemble_object.path % (index + 1) % (obj_index + 1);
|
||||
return CLI_DATA_FILE_ERROR;
|
||||
}
|
||||
object_name.erase(object_name.end() - 3, object_name.end());
|
||||
object_name.erase(object_name.end() - 4, object_name.end());
|
||||
object_1_name = object_name + "_1";
|
||||
object = temp_model.add_object(object_1_name.c_str(), path_str, std::move(mesh));
|
||||
if (!object) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": add_object %1% for stl failed, plate index %2%, object index %3%") % object_1_name % (index + 1) % (obj_index + 1);
|
||||
return CLI_DATA_FILE_ERROR;
|
||||
}
|
||||
}
|
||||
else if (boost::algorithm::iends_with(assemble_object.path, ".obj"))
|
||||
{
|
||||
|
@ -854,20 +922,61 @@ static int construct_assemble_list(std::vector<assemble_plate_info_t> &assemble_
|
|||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": failed to read a valid mesh from obj file %1%, plate index %2%, object index %3%, error %4%") % assemble_object.path % (index + 1) % (obj_index + 1) % message;
|
||||
return CLI_DATA_FILE_ERROR;
|
||||
}
|
||||
object_name.erase(object_name.end() - 3, object_name.end());
|
||||
object_name.erase(object_name.end() - 4, object_name.end());
|
||||
object_1_name = object_name + "_1";
|
||||
//process colors
|
||||
Model obj_temp_model;
|
||||
ModelObject* temp_object = obj_temp_model.add_object(object_1_name.c_str(), path_str, std::move(mesh));
|
||||
if (!temp_object) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": add_object %1% for obj failed, plate index %2%, object index %3%") % object_1_name % (index + 1) % (obj_index + 1);
|
||||
return CLI_DATA_FILE_ERROR;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> output_filament_ids;
|
||||
if (obj_info.vertex_colors.size() > 0) {
|
||||
convert_obj_cluster_colors(obj_info.vertex_colors, all_colours, max_filament_count, output_filament_ids);
|
||||
if (output_filament_ids.size() > 0) {
|
||||
unsigned char first_extruder_id = output_filament_ids.front();
|
||||
result = Model::obj_import_vertex_color_deal(output_filament_ids, first_extruder_id, & obj_temp_model);
|
||||
}
|
||||
skip_filament = true;
|
||||
} else if (obj_info.face_colors.size() > 0 && obj_info.has_uv_png == false) { // mtl file
|
||||
convert_obj_cluster_colors(obj_info.face_colors, all_colours, max_filament_count, output_filament_ids);
|
||||
if (output_filament_ids.size() > 0) {
|
||||
unsigned char first_extruder_id = output_filament_ids.front();
|
||||
result = Model::obj_import_face_color_deal(output_filament_ids, first_extruder_id, & obj_temp_model);
|
||||
}
|
||||
skip_filament = true;
|
||||
}
|
||||
if (!result) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": failed to convert colors for %1%, plate index %2%, object index %3%, error %4%") % assemble_object.path % (index + 1) % (obj_index + 1) % message;
|
||||
return CLI_DATA_FILE_ERROR;
|
||||
}
|
||||
object = temp_model.add_object(*temp_object);
|
||||
if (!object) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": add_object %1% for stl failed, plate index %2%, object index %3%") % object_1_name % (index + 1) % (obj_index + 1);
|
||||
return CLI_DATA_FILE_ERROR;
|
||||
}
|
||||
obj_temp_model.clear_objects();
|
||||
obj_temp_model.clear_materials();
|
||||
}
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": unsupported file %1%, plate index %2%, object index %3%") % assemble_object.path % (index + 1) % (obj_index + 1);
|
||||
return CLI_INVALID_PARAMS;
|
||||
}
|
||||
|
||||
std::string object_1_name = object_name + "_1";
|
||||
ModelObject* object = temp_model.add_object(object_1_name.c_str(), path_str, std::move(mesh));
|
||||
if (!object) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": add_object %1% failed, plate index %2%, object index %3%") % object_1_name % (index + 1) % (obj_index + 1);
|
||||
return CLI_DATA_FILE_ERROR;
|
||||
}
|
||||
if (!skip_filament) {
|
||||
object->config.set_key_value("extruder", new ConfigOptionInt(assemble_object.filaments[0]));
|
||||
used_filaments.emplace(assemble_object.filaments[0]);
|
||||
}
|
||||
else {
|
||||
assemble_object.filaments[0] = 0;
|
||||
for (const ModelVolume* mv : object->volumes) {
|
||||
std::vector<int> volume_extruders = mv->get_extruders();
|
||||
used_filaments.insert(volume_extruders.begin(), volume_extruders.end());
|
||||
}
|
||||
}
|
||||
|
||||
if (!assemble_object.print_params.empty())
|
||||
{
|
||||
for (auto param_iter = assemble_object.print_params.begin(); param_iter != assemble_object.print_params.end(); param_iter++)
|
||||
|
@ -903,7 +1012,7 @@ static int construct_assemble_list(std::vector<assemble_plate_info_t> &assemble_
|
|||
|
||||
object->translate(assemble_object.pos_x[0], assemble_object.pos_y[0], assemble_object.pos_z[0]);
|
||||
merge_or_add_object(assemble_plate_info, model, assemble_object.assemble_index[0], merged_objects, object);
|
||||
used_filaments.emplace(assemble_object.filaments[0]);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": object %1%, name %2%, pos_x %3% pos_y %4%, pos_z %5%, filament %6%, assemble_index %7%")
|
||||
%obj_index %object->name %assemble_object.pos_x[0] %assemble_object.pos_y[0] %assemble_object.pos_z[0] %assemble_object.filaments[0] %assemble_object.assemble_index[0];
|
||||
|
||||
|
@ -922,8 +1031,14 @@ static int construct_assemble_list(std::vector<assemble_plate_info_t> &assemble_
|
|||
array_index = copy_index;
|
||||
else
|
||||
array_index = 0;
|
||||
|
||||
if (!skip_filament) {
|
||||
copy_obj->config.set_key_value("extruder", new ConfigOptionInt(assemble_object.filaments[array_index]));
|
||||
used_filaments.emplace(assemble_object.filaments[array_index]);
|
||||
}
|
||||
else {
|
||||
assemble_object.filaments[array_index] = 0;
|
||||
}
|
||||
|
||||
if (copy_index < assemble_object.assemble_index.size())
|
||||
array_index = copy_index;
|
||||
|
@ -1373,6 +1488,7 @@ int CLI::run(int argc, char **argv)
|
|||
}*/
|
||||
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;
|
||||
std::vector<RGBA> input_obj_colours;
|
||||
if (!load_assemble_list.empty() && ((m_input_files.size() > 0) || (m_transforms.size() > 0)))
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("load_assemble_list should not be used with input model files to load and should not be sued with transforms");
|
||||
|
@ -1638,7 +1754,7 @@ int CLI::run(int argc, char **argv)
|
|||
}
|
||||
|
||||
try {
|
||||
ret = construct_assemble_list(assemble_plate_info_list, model, plate_data_src);
|
||||
ret = construct_assemble_list(assemble_plate_info_list, model, plate_data_src, input_obj_colours);
|
||||
if (ret) {
|
||||
record_exit_reson(outfile_dir, ret, 0, cli_errors[ret], sliced_info);
|
||||
flush_and_exit(ret);
|
||||
|
@ -1956,6 +2072,60 @@ int CLI::run(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
//add logic for obj auto colors
|
||||
if (input_obj_colours.size() > 0) {
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("%1%:%2%, got input obj colors %3%")%__FUNCTION__ %__LINE__ %input_obj_colours.size();
|
||||
int input_color_count = input_obj_colours.size();
|
||||
if (load_filament_count == 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("filament config not loaded when loading colored obj");
|
||||
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info);
|
||||
flush_and_exit(CLI_INVALID_PARAMS);
|
||||
}
|
||||
|
||||
//check filament_color from extra config
|
||||
ConfigOptionStrings *selected_filament_colors_option = m_extra_config.option<ConfigOptionStrings>("filament_colour");
|
||||
if (selected_filament_colors_option) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("filament_colour should not be set when loading colored obj");
|
||||
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info);
|
||||
flush_and_exit(CLI_INVALID_PARAMS);
|
||||
}
|
||||
if (load_filament_count < input_color_count) {
|
||||
int delta = input_color_count - load_filament_count;
|
||||
for (int index = 0; index < delta; index++) {
|
||||
load_filaments_id.push_back(load_filaments_id[0]);
|
||||
load_filaments_name.push_back(load_filaments_name[0]);
|
||||
load_filaments_config.push_back(load_filaments_config[0]);
|
||||
load_filaments_index.push_back(index+1+load_filament_count);
|
||||
load_filaments_inherit.push_back(load_filaments_inherit[0]);
|
||||
}
|
||||
load_filament_count = input_color_count;
|
||||
}
|
||||
|
||||
selected_filament_colors_option = m_extra_config.option<ConfigOptionStrings>("filament_colour", true);
|
||||
std::vector<std::string>& filament_colors = selected_filament_colors_option->values;
|
||||
filament_colors.resize(input_color_count);
|
||||
for (int index = 0; index < input_color_count; index++)
|
||||
{
|
||||
std::string color_string;
|
||||
int color[4];
|
||||
color[0] = std::clamp((int) (input_obj_colours[index][0] * 255.f), 0, 255);
|
||||
color[1] = std::clamp((int) (input_obj_colours[index][1] * 255.f), 0, 255);
|
||||
color[2] = std::clamp((int) (input_obj_colours[index][2] * 255.f), 0, 255);
|
||||
color[3] = std::clamp((int) (input_obj_colours[index][3] * 255.f), 0, 255);
|
||||
|
||||
std::stringstream stream;
|
||||
stream << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << color[0];
|
||||
stream << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << color[1];
|
||||
stream << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << color[2];
|
||||
stream << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << color[3];
|
||||
std::string result(stream.str());
|
||||
|
||||
filament_colors[index] = "#" + result;
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("%1%:%2%, index %3%, argb {%4%,%5%,%6%,%7%} to string %8%")%__FUNCTION__ %__LINE__ %(index+1) %color[0] %color[1] %color[2] %color[3] %filament_colors[index];
|
||||
}
|
||||
}
|
||||
|
||||
if (filament_count == 0)
|
||||
filament_count = load_filament_count;
|
||||
|
||||
|
@ -2123,13 +2293,13 @@ int CLI::run(int argc, char **argv)
|
|||
{
|
||||
if (uptodate_filaments.size() > 0)
|
||||
{
|
||||
if (uptodate_filaments.size() != filament_count)
|
||||
if (uptodate_filaments.size() != (size_t)filament_count)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("uptodate_filaments size %1% not equal to filament_count %2% ")%uptodate_filaments.size() %filament_count;
|
||||
record_exit_reson(outfile_dir, CLI_INVALID_PARAMS, 0, cli_errors[CLI_INVALID_PARAMS], sliced_info);
|
||||
flush_and_exit(CLI_INVALID_PARAMS);
|
||||
}
|
||||
for (unsigned int index = 0; index < filament_count; index ++)
|
||||
for (int index = 0; index < filament_count; index ++)
|
||||
{
|
||||
std::string file = uptodate_filaments[index];
|
||||
DynamicPrintConfig config;
|
||||
|
|
|
@ -29,4 +29,14 @@ float calc_color_distance(wxColour c1, wxColour c2)
|
|||
|
||||
return DeltaE76(lab[0][0], lab[0][1], lab[0][2], lab[1][0], lab[1][1], lab[1][2]);
|
||||
}
|
||||
|
||||
float calc_color_distance(RGBA c1, RGBA c2)
|
||||
{
|
||||
float lab[2][3];
|
||||
RGB2Lab(c1[0], c1[1], c1[2], &lab[0][0], &lab[0][1], &lab[0][2]);
|
||||
RGB2Lab(c2[0], c2[1], c2[2], &lab[1][0], &lab[1][1], &lab[1][2]);
|
||||
|
||||
return DeltaE76(lab[0][0], lab[0][1], lab[0][2], lab[1][0], lab[1][1], lab[1][2]);
|
||||
}
|
||||
|
||||
} }
|
||||
|
|
|
@ -3,10 +3,18 @@
|
|||
#include <wx/colour.h>
|
||||
#include "libslic3r/Color.hpp"
|
||||
#include "slic3r/Utils/ColorSpaceConvert.hpp"
|
||||
|
||||
struct ColorDistValue
|
||||
{
|
||||
int id;
|
||||
float distance;
|
||||
};
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
wxColour convert_to_wxColour(const RGBA &color);
|
||||
RGBA convert_to_rgba(const wxColour &color);
|
||||
float calc_color_distance(wxColour c1, wxColour c2);
|
||||
float calc_color_distance(RGBA c1, RGBA c2);
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
|
|
|
@ -12,11 +12,7 @@
|
|||
class Button;
|
||||
class Label;
|
||||
class ComboBox;
|
||||
struct ColorDistValue
|
||||
{
|
||||
int id;
|
||||
float distance;
|
||||
};
|
||||
|
||||
class ObjColorPanel : public wxPanel
|
||||
{
|
||||
public:
|
||||
|
|
Loading…
Reference in New Issue