mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-27 10:41:15 -06:00
Merge remote-tracking branch 'origin/tm_sla_supports_backend' into vb_3dscene_partial_update
This commit is contained in:
commit
e3b858c45f
51 changed files with 1062 additions and 594 deletions
|
|
@ -1858,7 +1858,7 @@ namespace Slic3r {
|
|||
if (volume == nullptr)
|
||||
continue;
|
||||
|
||||
VolumeToOffsetsMap::iterator volume_it = volumes_offsets.insert(VolumeToOffsetsMap::value_type(volume, Offsets(vertices_count))).first;
|
||||
volumes_offsets.insert(VolumeToOffsetsMap::value_type(volume, Offsets(vertices_count))).first;
|
||||
|
||||
if (!volume->mesh.repaired)
|
||||
volume->mesh.repair();
|
||||
|
|
@ -1875,12 +1875,23 @@ namespace Slic3r {
|
|||
|
||||
vertices_count += stl.stats.shared_vertices;
|
||||
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
Transform3d matrix = volume->get_matrix();
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
|
||||
for (int i = 0; i < stl.stats.shared_vertices; ++i)
|
||||
{
|
||||
stream << " <" << VERTEX_TAG << " ";
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
Vec3d v = matrix * stl.v_shared[i].cast<double>();
|
||||
stream << "x=\"" << v(0) << "\" ";
|
||||
stream << "y=\"" << v(1) << "\" ";
|
||||
stream << "z=\"" << v(2) << "\" />\n";
|
||||
#else
|
||||
stream << "x=\"" << stl.v_shared[i](0) << "\" ";
|
||||
stream << "y=\"" << stl.v_shared[i](1) << "\" ";
|
||||
stream << "z=\"" << stl.v_shared[i](2) << "\" />\n";
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1663,8 +1663,9 @@ void GCode::append_full_config(const Print& print, std::string& str)
|
|||
}
|
||||
const DynamicConfig &full_config = print.placeholder_parser().config();
|
||||
for (const char *key : {
|
||||
"print_settings_id", "filament_settings_id", "sla_material_settings_id", "printer_settings_id",
|
||||
"printer_model", "printer_variant", "default_print_profile", "default_filament_profile", "default_sla_material_profile",
|
||||
"print_settings_id", "filament_settings_id", "sla_print_settings_id", "sla_material_settings_id", "printer_settings_id",
|
||||
"printer_model", "printer_variant",
|
||||
"default_print_profile", "default_filament_profile", "default_sla_print_profile", "default_sla_material_profile",
|
||||
"compatible_printers_condition_cummulative", "inherits_cummulative" }) {
|
||||
const ConfigOption *opt = full_config.option(key);
|
||||
if (opt != nullptr)
|
||||
|
|
|
|||
|
|
@ -951,25 +951,54 @@ bool ModelObject::needed_repair() const
|
|||
return false;
|
||||
}
|
||||
|
||||
void ModelObject::cut(coordf_t z, Model* model) const
|
||||
template<class T> static void cut_reset_transform(T *thing) {
|
||||
const Vec3d offset = thing->get_offset();
|
||||
thing->set_transformation(Geometry::Transformation());
|
||||
thing->set_offset(offset);
|
||||
}
|
||||
|
||||
ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z)
|
||||
{
|
||||
// clone this one to duplicate instances, materials etc.
|
||||
ModelObject* upper = model->add_object(*this);
|
||||
ModelObject* lower = model->add_object(*this);
|
||||
// Clone the object to duplicate instances, materials etc.
|
||||
ModelObject* upper = ModelObject::new_clone(*this);
|
||||
ModelObject* lower = ModelObject::new_clone(*this);
|
||||
upper->set_model(nullptr);
|
||||
lower->set_model(nullptr);
|
||||
upper->sla_support_points.clear();
|
||||
lower->sla_support_points.clear();
|
||||
upper->clear_volumes();
|
||||
lower->clear_volumes();
|
||||
upper->input_file = "";
|
||||
lower->input_file = "";
|
||||
|
||||
for (ModelVolume *volume : this->volumes) {
|
||||
|
||||
const auto instance_matrix = instances[instance]->get_matrix(true);
|
||||
|
||||
// Because transformations are going to be applied to meshes directly,
|
||||
// we reset transformation of all instances and volumes,
|
||||
// _except_ for translation, which is preserved in the transformation matrix
|
||||
// and not applied to the mesh transform.
|
||||
// TODO: Do the same for Z-rotation as well?
|
||||
|
||||
// Convert z from relative to bb's base to object coordinates
|
||||
// FIXME: doesn't work well for rotated objects
|
||||
const auto bb = instance_bounding_box(instance, true);
|
||||
z -= bb.min(2);
|
||||
|
||||
for (auto *instance : upper->instances) { cut_reset_transform(instance); }
|
||||
for (auto *instance : lower->instances) { cut_reset_transform(instance); }
|
||||
|
||||
for (ModelVolume *volume : volumes) {
|
||||
if (! volume->is_model_part()) {
|
||||
// don't cut modifiers
|
||||
upper->add_volume(*volume);
|
||||
lower->add_volume(*volume);
|
||||
} else {
|
||||
TriangleMesh upper_mesh, lower_mesh;
|
||||
|
||||
// Transform the mesh by the object transformation matrix
|
||||
volume->mesh.transform(instance_matrix * volume->get_matrix(true));
|
||||
cut_reset_transform(volume);
|
||||
|
||||
TriangleMeshSlicer tms(&volume->mesh);
|
||||
tms.cut(z, &upper_mesh, &lower_mesh);
|
||||
|
||||
|
|
@ -977,7 +1006,7 @@ void ModelObject::cut(coordf_t z, Model* model) const
|
|||
lower_mesh.repair();
|
||||
upper_mesh.reset_repair_stats();
|
||||
lower_mesh.reset_repair_stats();
|
||||
|
||||
|
||||
if (upper_mesh.facets_count() > 0) {
|
||||
ModelVolume* vol = upper->add_volume(upper_mesh);
|
||||
vol->name = volume->name;
|
||||
|
|
@ -992,6 +1021,15 @@ void ModelObject::cut(coordf_t z, Model* model) const
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
upper->invalidate_bounding_box();
|
||||
lower->invalidate_bounding_box();
|
||||
|
||||
ModelObjectPtrs res;
|
||||
if (upper->volumes.size() > 0) { res.push_back(upper); }
|
||||
if (lower->volumes.size() > 0) { res.push_back(lower); }
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void ModelObject::split(ModelObjectPtrs* new_objects)
|
||||
|
|
@ -1011,7 +1049,8 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
|
|||
|
||||
mesh->repair();
|
||||
|
||||
ModelObject* new_object = m_model->add_object();
|
||||
// XXX: this seems to be the only real usage of m_model, maybe refactor this so that it's not needed?
|
||||
ModelObject* new_object = m_model->add_object();
|
||||
new_object->name = this->name;
|
||||
new_object->config = this->config;
|
||||
new_object->instances.reserve(this->instances.size());
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ public:
|
|||
size_t materials_count() const;
|
||||
size_t facets_count() const;
|
||||
bool needed_repair() const;
|
||||
void cut(coordf_t z, Model* model) const;
|
||||
ModelObjectPtrs cut(size_t instance, coordf_t z);
|
||||
void split(ModelObjectPtrs* new_objects);
|
||||
void repair();
|
||||
|
||||
|
|
@ -607,7 +607,7 @@ public:
|
|||
bool delete_object(ModelID id);
|
||||
bool delete_object(ModelObject* object);
|
||||
void clear_objects();
|
||||
|
||||
|
||||
ModelMaterial* add_material(t_model_material_id material_id);
|
||||
ModelMaterial* add_material(t_model_material_id material_id, const ModelMaterial &other);
|
||||
ModelMaterial* get_material(t_model_material_id material_id) {
|
||||
|
|
|
|||
|
|
@ -2434,6 +2434,128 @@ void PrintConfigDef::init_sla_params()
|
|||
|
||||
def = this->add("sla_material_settings_id", coString);
|
||||
def->default_value = new ConfigOptionString("");
|
||||
|
||||
|
||||
def = this->add("default_sla_print_profile", coString);
|
||||
def->label = L("Default SLA material profile");
|
||||
def->tooltip = L("Default print profile associated with the current printer profile. "
|
||||
"On selection of the current printer profile, this print profile will be activated.");
|
||||
def->default_value = new ConfigOptionString();
|
||||
|
||||
def = this->add("sla_print_settings_id", coString);
|
||||
def->default_value = new ConfigOptionString("");
|
||||
|
||||
def = this->add("support_head_front_radius", coFloat);
|
||||
def->label = L("Support head front radius");
|
||||
def->tooltip = L("Radius of the pointing side of the head");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(0.2);
|
||||
|
||||
def = this->add("support_head_penetration", coFloat);
|
||||
def->label = L("Support head penetration");
|
||||
def->tooltip = L("How much the pinhead has to penetrate the model surface");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(0.2);
|
||||
|
||||
def = this->add("support_head_back_radius", coFloat);
|
||||
def->label = L("Support head back radius");
|
||||
def->tooltip = L("Radius of the back side of the 3d arrow");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(0.5);
|
||||
|
||||
def = this->add("support_head_width", coFloat);
|
||||
def->label = L("Support head width");
|
||||
def->tooltip = L("Width from the back sphere center to the front sphere center");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(1.0);
|
||||
|
||||
def = this->add("support_pillar_radius", coFloat);
|
||||
def->label = L("Support pillar radius");
|
||||
def->tooltip = L("Radius in mm of the support pillars");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(0.8);
|
||||
|
||||
def = this->add("support_base_radius", coFloat);
|
||||
def->label = L("Support base radius");
|
||||
def->tooltip = L("Radius in mm of the pillar base");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(2.0);
|
||||
|
||||
def = this->add("support_base_height", coFloat);
|
||||
def->label = L("Support base height");
|
||||
def->tooltip = L("The height of the pillar base cone");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(1.0);
|
||||
|
||||
def = this->add("support_critical_angle", coFloat);
|
||||
def->label = L("Critical angle");
|
||||
def->tooltip = L("The default angle for connecting support sticks and junctions.");
|
||||
def->sidetext = L("°");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(45);
|
||||
|
||||
def = this->add("support_max_bridge_length", coFloat);
|
||||
def->label = L("Max bridge length");
|
||||
def->tooltip = L("The max length of a bridge");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(15.0);
|
||||
|
||||
def = this->add("support_object_elevation", coFloat);
|
||||
def->label = L("Object elevation");
|
||||
def->tooltip = L("How much the supports should lift up the supported object.");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(5.0);
|
||||
|
||||
def = this->add("pad_wall_thickness", coFloat);
|
||||
def->label = L("Pad wall thickness");
|
||||
def->tooltip = L("");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(2.0);
|
||||
|
||||
def = this->add("pad_wall_height", coFloat);
|
||||
def->label = L("Pad wall height");
|
||||
def->tooltip = L("");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(5.0);
|
||||
|
||||
def = this->add("pad_max_merge_distance", coFloat);
|
||||
def->label = L("Max merge distance");
|
||||
def->tooltip = L("");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(50.0);
|
||||
|
||||
def = this->add("pad_edge_radius", coFloat);
|
||||
def->label = L("Pad edge radius");
|
||||
def->tooltip = L("");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(1.0);
|
||||
}
|
||||
|
||||
void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ enum PrinterTechnology
|
|||
};
|
||||
|
||||
enum GCodeFlavor {
|
||||
gcfRepRap, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlin, gcfSailfish, gcfMach3, gcfMachinekit,
|
||||
gcfRepRap, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlin, gcfSailfish, gcfMach3, gcfMachinekit,
|
||||
gcfSmoothie, gcfNoExtrusion,
|
||||
};
|
||||
|
||||
|
|
@ -167,7 +167,7 @@ private:
|
|||
// This definition is constant.
|
||||
extern const PrintConfigDef print_config_def;
|
||||
|
||||
// Slic3r dynamic configuration, used to override the configuration
|
||||
// Slic3r dynamic configuration, used to override the configuration
|
||||
// per object, per modification volume or per printing material.
|
||||
// The dynamic configuration is also used to store user modifications of the print global parameters,
|
||||
// so the modified configuration values may be diffed against the active configuration
|
||||
|
|
@ -274,12 +274,12 @@ protected:
|
|||
m_defaults = defaults;
|
||||
m_keys.clear();
|
||||
m_keys.reserve(m_map_name_to_offset.size());
|
||||
for (const auto &kvp : defs->options) {
|
||||
// Find the option given the option name kvp.first by an offset from (char*)m_defaults.
|
||||
ConfigOption *opt = this->optptr(kvp.first, m_defaults);
|
||||
if (opt == nullptr)
|
||||
// This option is not defined by the ConfigBase of type T.
|
||||
continue;
|
||||
for (const auto &kvp : defs->options) {
|
||||
// Find the option given the option name kvp.first by an offset from (char*)m_defaults.
|
||||
ConfigOption *opt = this->optptr(kvp.first, m_defaults);
|
||||
if (opt == nullptr)
|
||||
// This option is not defined by the ConfigBase of type T.
|
||||
continue;
|
||||
m_keys.emplace_back(kvp.first);
|
||||
const ConfigOptionDef *def = defs->get(kvp.first);
|
||||
assert(def != nullptr);
|
||||
|
|
@ -463,7 +463,7 @@ public:
|
|||
ConfigOptionInt top_solid_layers;
|
||||
ConfigOptionFloatOrPercent top_solid_infill_speed;
|
||||
ConfigOptionBool wipe_into_infill;
|
||||
|
||||
|
||||
protected:
|
||||
void initialize(StaticCacheBase &cache, const char *base_ptr)
|
||||
{
|
||||
|
|
@ -768,7 +768,7 @@ public:
|
|||
ConfigOptionInt pixel_height;
|
||||
ConfigOptionFloat exp_time;
|
||||
ConfigOptionFloat exp_time_first;
|
||||
|
||||
|
||||
protected:
|
||||
PrintConfig(int) : GCodeConfig(1) {}
|
||||
void initialize(StaticCacheBase &cache, const char *base_ptr)
|
||||
|
|
@ -859,7 +859,7 @@ public:
|
|||
ConfigOptionString printhost_cafile;
|
||||
ConfigOptionString serial_port;
|
||||
ConfigOptionInt serial_speed;
|
||||
|
||||
|
||||
protected:
|
||||
void initialize(StaticCacheBase &cache, const char *base_ptr)
|
||||
{
|
||||
|
|
@ -873,14 +873,14 @@ protected:
|
|||
};
|
||||
|
||||
// This object is mapped to Perl as Slic3r::Config::Full.
|
||||
class FullPrintConfig :
|
||||
public PrintObjectConfig,
|
||||
class FullPrintConfig :
|
||||
public PrintObjectConfig,
|
||||
public PrintRegionConfig,
|
||||
public PrintConfig,
|
||||
public HostConfig
|
||||
{
|
||||
STATIC_PRINT_CONFIG_CACHE_DERIVED(FullPrintConfig)
|
||||
FullPrintConfig() : PrintObjectConfig(0), PrintRegionConfig(0), PrintConfig(0), HostConfig(0) { initialize_cache(); *this = s_cache_FullPrintConfig.defaults(); }
|
||||
FullPrintConfig() : PrintObjectConfig(0), PrintRegionConfig(0), PrintConfig(0), HostConfig(0) { initialize_cache(); *this = s_cache_FullPrintConfig.defaults(); }
|
||||
|
||||
public:
|
||||
// Validate the FullPrintConfig. Returns an empty string on success, otherwise an error message is returned.
|
||||
|
|
@ -908,16 +908,17 @@ public:
|
|||
ConfigOptionFloat support_head_front_radius /*= 0.2*/;
|
||||
|
||||
// How much the pinhead has to penetrate the model surface
|
||||
ConfigOptionFloat support_head_penetraiton /*= 0.2*/;
|
||||
ConfigOptionFloat support_head_penetration /*= 0.2*/;
|
||||
|
||||
// Radius of the back side of the 3d arrow.
|
||||
// Radius of the back side of the 3d arrow. TODO: consider renaming this
|
||||
// to actual pillar radius, because that's what it boils down to.
|
||||
ConfigOptionFloat support_head_back_radius /*= 0.5*/;
|
||||
|
||||
// Width in mm from the back sphere center to the front sphere center.
|
||||
ConfigOptionFloat support_head_width /*= 1.0*/;
|
||||
|
||||
// Radius in mm of the support pillars.
|
||||
// TODO: This parameter is invalid. The pillar radius will be dynamic in
|
||||
// TODO: This parameter is questionable. The pillar radius will be dynamic in
|
||||
// nature. Merged pillars will have an increased thickness. This parameter
|
||||
// may serve as the maximum radius, or maybe an increase when two are merged
|
||||
// The default radius will be derived from head_back_radius_mm
|
||||
|
|
@ -930,16 +931,16 @@ public:
|
|||
ConfigOptionFloat support_base_height /*= 1.0*/;
|
||||
|
||||
// The default angle for connecting support sticks and junctions.
|
||||
ConfigOptionFloat support_critical_angle /*= M_PI/4*/;
|
||||
ConfigOptionFloat support_critical_angle /*= 45*/;
|
||||
|
||||
// The max length of a bridge in mm
|
||||
ConfigOptionFloat support_max_bridge_length /*= 15.0*/;
|
||||
|
||||
// The elevation in Z direction upwards. This is the space between the pad
|
||||
// and the model object's bounding box bottom.
|
||||
ConfigOptionFloat support_object_elevation;
|
||||
// and the model object's bounding box bottom. Units in mm.
|
||||
ConfigOptionFloat support_object_elevation /*= 5.0*/;
|
||||
|
||||
// Now for the base pool (plate) ///////////////////////////////////////////
|
||||
// Now for the base pool (pad) /////////////////////////////////////////////
|
||||
|
||||
ConfigOptionFloat pad_wall_thickness /*= 2*/;
|
||||
ConfigOptionFloat pad_wall_height /*= 5*/;
|
||||
|
|
@ -951,7 +952,7 @@ protected:
|
|||
{
|
||||
OPT_PTR(layer_height);
|
||||
OPT_PTR(support_head_front_radius);
|
||||
OPT_PTR(support_head_penetraiton);
|
||||
OPT_PTR(support_head_penetration);
|
||||
OPT_PTR(support_head_back_radius);
|
||||
OPT_PTR(support_head_width);
|
||||
OPT_PTR(support_pillar_radius);
|
||||
|
|
@ -959,6 +960,7 @@ protected:
|
|||
OPT_PTR(support_base_height);
|
||||
OPT_PTR(support_critical_angle);
|
||||
OPT_PTR(support_max_bridge_length);
|
||||
OPT_PTR(support_object_elevation);
|
||||
OPT_PTR(pad_wall_thickness);
|
||||
OPT_PTR(pad_wall_height);
|
||||
OPT_PTR(pad_max_merge_distance);
|
||||
|
|
@ -1068,7 +1070,7 @@ public:
|
|||
ConfigOptionFloat scale;
|
||||
// ConfigOptionPoint3 scale_to_fit;
|
||||
ConfigOptionBool slice;
|
||||
|
||||
|
||||
CLIConfig() : ConfigBase(), StaticConfig()
|
||||
{
|
||||
this->set_defaults();
|
||||
|
|
@ -1076,7 +1078,7 @@ public:
|
|||
|
||||
// Overrides ConfigBase::def(). Static configuration definition. Any value stored into this ConfigBase shall have its definition here.
|
||||
const ConfigDef* def() const override { return &cli_config_def; }
|
||||
t_config_option_keys keys() const override { return cli_config_def.keys(); }
|
||||
t_config_option_keys keys() const override { return cli_config_def.keys(); }
|
||||
|
||||
ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) override
|
||||
{
|
||||
|
|
@ -1118,7 +1120,7 @@ private:
|
|||
class PrintAndCLIConfigDef : public ConfigDef
|
||||
{
|
||||
public:
|
||||
PrintAndCLIConfigDef() {
|
||||
PrintAndCLIConfigDef() {
|
||||
this->options.insert(print_config_def.options.begin(), print_config_def.options.end());
|
||||
this->options.insert(cli_config_def.options.begin(), cli_config_def.options.end());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -424,12 +424,6 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
|
|||
TriangleMesh m = mesh;
|
||||
TriangleMeshSlicer slicer(&m);
|
||||
|
||||
// TriangleMesh upper, lower;
|
||||
// slicer.cut(h, &upper, &lower);
|
||||
|
||||
// TODO: this might be slow (in fact it was)
|
||||
// output = lower.horizontal_projection();
|
||||
|
||||
auto bb = mesh.bounding_box();
|
||||
float gnd = float(bb.min(Z));
|
||||
std::vector<float> heights = {float(bb.min(Z))};
|
||||
|
|
|
|||
|
|
@ -213,6 +213,7 @@ struct Head {
|
|||
double r_back_mm = 1;
|
||||
double r_pin_mm = 0.5;
|
||||
double width_mm = 2;
|
||||
double penetration_mm = 0.5;
|
||||
|
||||
// For identification purposes. This will be used as the index into the
|
||||
// container holding the head structures. See SLASupportTree::Impl
|
||||
|
|
@ -224,11 +225,13 @@ struct Head {
|
|||
Head(double r_big_mm,
|
||||
double r_small_mm,
|
||||
double length_mm,
|
||||
double penetration,
|
||||
Vec3d direction = {0, 0, -1}, // direction (normal to the dull end )
|
||||
Vec3d offset = {0, 0, 0}, // displacement
|
||||
const size_t circlesteps = 45):
|
||||
steps(circlesteps), dir(direction), tr(offset),
|
||||
r_back_mm(r_big_mm), r_pin_mm(r_small_mm), width_mm(length_mm)
|
||||
r_back_mm(r_big_mm), r_pin_mm(r_small_mm), width_mm(length_mm),
|
||||
penetration_mm(penetration)
|
||||
{
|
||||
|
||||
// We create two spheres which will be connected with a robe that fits
|
||||
|
|
@ -281,7 +284,7 @@ struct Head {
|
|||
|
||||
// To simplify further processing, we translate the mesh so that the
|
||||
// last vertex of the pointing sphere (the pinpoint) will be at (0,0,0)
|
||||
for(auto& p : mesh.points) { z(p) -= (h + 0.5 * r_small_mm); }
|
||||
for(auto& p : mesh.points) z(p) -= (h + r_small_mm - penetration_mm);
|
||||
}
|
||||
|
||||
void transform()
|
||||
|
|
@ -298,11 +301,11 @@ struct Head {
|
|||
}
|
||||
|
||||
double fullwidth() const {
|
||||
return 1.5 * r_pin_mm + width_mm + 2*r_back_mm;
|
||||
return 2 * r_pin_mm + width_mm + 2*r_back_mm - penetration_mm;
|
||||
}
|
||||
|
||||
Vec3d junction_point() const {
|
||||
return tr + ( 1.5 * r_pin_mm + width_mm + r_back_mm)*dir;
|
||||
return tr + ( 2 * r_pin_mm + width_mm + r_back_mm - penetration_mm)*dir;
|
||||
}
|
||||
|
||||
double request_pillar_radius(double radius) const {
|
||||
|
|
@ -507,7 +510,9 @@ struct Pad {
|
|||
Pad(const TriangleMesh& object_support_mesh,
|
||||
const ExPolygons& baseplate,
|
||||
double ground_level,
|
||||
const PoolConfig& cfg) : zlevel(ground_level + cfg.min_wall_height_mm/2)
|
||||
const PoolConfig& pcfg) :
|
||||
cfg(pcfg),
|
||||
zlevel(ground_level + cfg.min_wall_height_mm/2)
|
||||
{
|
||||
ExPolygons basep;
|
||||
base_plate(object_support_mesh, basep,
|
||||
|
|
@ -538,19 +543,6 @@ EigenMesh3D to_eigenmesh(const Contour3D& cntr) {
|
|||
return emesh;
|
||||
}
|
||||
|
||||
void create_head(TriangleMesh& out, double r1_mm, double r2_mm, double width_mm)
|
||||
{
|
||||
Head head(r1_mm, r2_mm, width_mm, {0, std::sqrt(0.5), -std::sqrt(0.5)},
|
||||
{0, 0, 30});
|
||||
out.merge(mesh(head.mesh));
|
||||
|
||||
Pillar cst(head, {0, 0, 0});
|
||||
cst.add_base();
|
||||
|
||||
out.merge(mesh(cst.mesh));
|
||||
out.merge(mesh(cst.base));
|
||||
}
|
||||
|
||||
// The minimum distance for two support points to remain valid.
|
||||
static const double /*constexpr*/ D_SP = 0.1;
|
||||
|
||||
|
|
@ -593,21 +585,6 @@ EigenMesh3D to_eigenmesh(const ModelObject& modelobj) {
|
|||
return to_eigenmesh(modelobj.raw_mesh());
|
||||
}
|
||||
|
||||
EigenMesh3D to_eigenmesh(const Model& model) {
|
||||
TriangleMesh combined_mesh;
|
||||
|
||||
for(ModelObject *o : model.objects) {
|
||||
TriangleMesh tmp = o->raw_mesh();
|
||||
for(ModelInstance * inst: o->instances) {
|
||||
TriangleMesh ttmp(tmp);
|
||||
inst->transform_mesh(&ttmp);
|
||||
combined_mesh.merge(ttmp);
|
||||
}
|
||||
}
|
||||
|
||||
return to_eigenmesh(combined_mesh);
|
||||
}
|
||||
|
||||
PointSet to_point_set(const std::vector<Vec3d> &v)
|
||||
{
|
||||
PointSet ret(v.size(), 3);
|
||||
|
|
@ -619,43 +596,6 @@ Vec3d model_coord(const ModelInstance& object, const Vec3f& mesh_coord) {
|
|||
return object.transform_vector(mesh_coord.cast<double>());
|
||||
}
|
||||
|
||||
PointSet support_points(const Model& model) {
|
||||
size_t sum = 0;
|
||||
for(auto *o : model.objects)
|
||||
sum += o->instances.size() * o->sla_support_points.size();
|
||||
|
||||
PointSet ret(sum, 3);
|
||||
|
||||
for(ModelObject *o : model.objects)
|
||||
for(ModelInstance *inst : o->instances) {
|
||||
int i = 0;
|
||||
for(Vec3f& msource : o->sla_support_points) {
|
||||
ret.row(i++) = model_coord(*inst, msource);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PointSet support_points(const ModelObject& modelobject)
|
||||
{
|
||||
PointSet ret(modelobject.sla_support_points.size(), 3);
|
||||
auto rot = modelobject.instances.front()->get_rotation();
|
||||
// auto scaling = modelobject.instances.front()->get_scaling_factor();
|
||||
|
||||
// Transform3d tr;
|
||||
// tr.rotate(Eigen::AngleAxisd(rot(X), Vec3d::UnitX()) *
|
||||
// Eigen::AngleAxisd(rot(Y), Vec3d::UnitY()));
|
||||
|
||||
long i = 0;
|
||||
for(const Vec3f& msource : modelobject.sla_support_points) {
|
||||
Vec3d&& p = msource.cast<double>();
|
||||
// p = tr * p;
|
||||
ret.row(i++) = p;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
double ray_mesh_intersect(const Vec3d& s,
|
||||
const Vec3d& dir,
|
||||
const EigenMesh3D& m);
|
||||
|
|
@ -1154,6 +1094,7 @@ bool SLASupportTree::generate(const PointSet &points,
|
|||
cfg.head_back_radius_mm,
|
||||
cfg.head_front_radius_mm,
|
||||
cfg.head_width_mm,
|
||||
cfg.head_penetration_mm,
|
||||
nmls.row(i), // dir
|
||||
head_pos.row(i) // displacement
|
||||
);
|
||||
|
|
@ -1521,6 +1462,7 @@ bool SLASupportTree::generate(const PointSet &points,
|
|||
Head base_head(cfg.head_back_radius_mm,
|
||||
cfg.head_front_radius_mm,
|
||||
cfg.head_width_mm,
|
||||
cfg.head_penetration_mm,
|
||||
{0.0, 0.0, 1.0},
|
||||
{headend(X), headend(Y), headend(Z) - gh});
|
||||
|
||||
|
|
@ -1719,10 +1661,10 @@ const TriangleMesh &SLASupportTree::add_pad(const SliceLayer& baseplate,
|
|||
TriangleMesh mm;
|
||||
merged_mesh(mm);
|
||||
PoolConfig pcfg;
|
||||
// pcfg.min_wall_thickness_mm = min_wall_thickness_mm;
|
||||
// pcfg.min_wall_height_mm = min_wall_height_mm;
|
||||
// pcfg.max_merge_distance_mm = max_merge_distance_mm;
|
||||
// pcfg.edge_radius_mm = edge_radius_mm;
|
||||
pcfg.min_wall_thickness_mm = min_wall_thickness_mm;
|
||||
pcfg.min_wall_height_mm = min_wall_height_mm;
|
||||
pcfg.max_merge_distance_mm = max_merge_distance_mm;
|
||||
pcfg.edge_radius_mm = edge_radius_mm;
|
||||
return m_impl->create_pad(mm, baseplate, pcfg).tmesh;
|
||||
}
|
||||
|
||||
|
|
@ -1735,15 +1677,7 @@ double SLASupportTree::get_elevation() const
|
|||
{
|
||||
double ph = m_impl->pad().empty()? 0 :
|
||||
m_impl->pad().cfg.min_wall_height_mm/2.0;
|
||||
return -m_impl->ground_level + ph;
|
||||
}
|
||||
|
||||
SLASupportTree::SLASupportTree(const Model& model,
|
||||
const SupportConfig& cfg,
|
||||
const Controller& ctl):
|
||||
m_impl(new Impl()), m_ctl(ctl)
|
||||
{
|
||||
generate(support_points(model), to_eigenmesh(model), cfg, ctl);
|
||||
return m_elevation + ph;
|
||||
}
|
||||
|
||||
SLASupportTree::SLASupportTree(const PointSet &points,
|
||||
|
|
@ -1752,6 +1686,7 @@ SLASupportTree::SLASupportTree(const PointSet &points,
|
|||
const Controller &ctl):
|
||||
m_impl(new Impl()), m_ctl(ctl)
|
||||
{
|
||||
m_elevation = cfg.object_elevation_mm;
|
||||
m_impl->ground_level = emesh.ground_level - cfg.object_elevation_mm;
|
||||
generate(points, emesh, cfg, ctl);
|
||||
}
|
||||
|
|
@ -1767,66 +1702,5 @@ SLASupportTree &SLASupportTree::operator=(const SLASupportTree &c)
|
|||
|
||||
SLASupportTree::~SLASupportTree() {}
|
||||
|
||||
void add_sla_supports(Model &model,
|
||||
const SupportConfig &cfg,
|
||||
const Controller &ctl)
|
||||
{
|
||||
Benchmark bench;
|
||||
|
||||
bench.start();
|
||||
SLASupportTree _stree(model, cfg, ctl);
|
||||
bench.stop();
|
||||
|
||||
std::cout << "Support tree creation time: " << bench.getElapsedSec()
|
||||
<< " seconds" << std::endl;
|
||||
|
||||
bench.start();
|
||||
ModelObject* o = model.add_object();
|
||||
o->add_instance();
|
||||
|
||||
TriangleMesh streemsh;
|
||||
_stree.merged_mesh(streemsh);
|
||||
o->add_volume(streemsh);
|
||||
|
||||
bench.stop();
|
||||
std::cout << "support tree added to model in: " << bench.getElapsedSec()
|
||||
<< " seconds" << std::endl;
|
||||
|
||||
// TODO this would roughly be the code for the base pool
|
||||
ExPolygons plate;
|
||||
auto modelmesh = model.mesh();
|
||||
TriangleMesh poolmesh;
|
||||
sla::PoolConfig poolcfg;
|
||||
poolcfg.min_wall_height_mm = 1;
|
||||
poolcfg.edge_radius_mm = 0.1;
|
||||
poolcfg.min_wall_thickness_mm = 0.8;
|
||||
|
||||
bench.start();
|
||||
sla::base_plate(modelmesh, plate);
|
||||
bench.stop();
|
||||
|
||||
std::cout << "Base plate calculation time: " << bench.getElapsedSec()
|
||||
<< " seconds." << std::endl;
|
||||
|
||||
bench.start();
|
||||
sla::create_base_pool(plate, poolmesh, poolcfg);
|
||||
bench.stop();
|
||||
|
||||
std::cout << "Pool generation completed in " << bench.getElapsedSec()
|
||||
<< " second." << std::endl;
|
||||
|
||||
bench.start();
|
||||
poolmesh.translate(.0f, .0f, float(poolcfg.min_wall_height_mm / 2));
|
||||
o->add_volume(poolmesh);
|
||||
bench.stop();
|
||||
|
||||
// TODO: will cause incorrect placement of the model;
|
||||
// o->translate({0, 0, poolcfg.min_wall_height_mm / 2});
|
||||
|
||||
std::cout << "Added pool to model in " << bench.getElapsedSec()
|
||||
<< " seconds." << std::endl;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ struct SupportConfig {
|
|||
double head_front_radius_mm = 0.2;
|
||||
|
||||
// How much the pinhead has to penetrate the model surface
|
||||
double head_penetraiton = 0.2;
|
||||
double head_penetration_mm = 0.5;
|
||||
|
||||
// Radius of the back side of the 3d arrow.
|
||||
double head_back_radius_mm = 0.5;
|
||||
|
|
@ -90,34 +90,17 @@ struct EigenMesh3D {
|
|||
Eigen::MatrixXd V;
|
||||
Eigen::MatrixXi F;
|
||||
double ground_level = 0;
|
||||
|
||||
// igl crashes with the following data types:
|
||||
// Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::DontAlign> V;
|
||||
// Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::DontAlign> F;
|
||||
};
|
||||
|
||||
//using PointSet = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::DontAlign>; //Eigen::MatrixXd;
|
||||
using PointSet = Eigen::MatrixXd;
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* TODO: May not be needed: */
|
||||
/* ************************************************************************** */
|
||||
|
||||
void create_head(TriangleMesh&, double r1_mm, double r2_mm, double width_mm);
|
||||
|
||||
/// Add support volumes to the model directly
|
||||
void add_sla_supports(Model& model, const SupportConfig& cfg = {},
|
||||
const Controller& ctl = {});
|
||||
|
||||
EigenMesh3D to_eigenmesh(const TriangleMesh& m);
|
||||
PointSet to_point_set(const std::vector<Vec3d>&);
|
||||
|
||||
|
||||
// obsolete, not used anymore
|
||||
EigenMesh3D to_eigenmesh(const Model& model);
|
||||
// needed for find best rotation
|
||||
EigenMesh3D to_eigenmesh(const ModelObject& model);
|
||||
PointSet support_points(const ModelObject& modelobject);
|
||||
PointSet support_points(const Model& model);
|
||||
|
||||
// Simple conversion of 'vector of points' to an Eigen matrix
|
||||
PointSet to_point_set(const std::vector<Vec3d>&);
|
||||
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
|
@ -135,6 +118,9 @@ class SLASupportTree {
|
|||
std::unique_ptr<Impl> m_impl;
|
||||
Controller m_ctl;
|
||||
|
||||
// the only value from config that is also needed after construction
|
||||
double m_elevation = 0;
|
||||
|
||||
Impl& get() { return *m_impl; }
|
||||
const Impl& get() const { return *m_impl; }
|
||||
|
||||
|
|
@ -149,11 +135,6 @@ class SLASupportTree {
|
|||
const Controller& ctl = {});
|
||||
public:
|
||||
|
||||
// Constructors will throw if the stop condition becomes true.
|
||||
SLASupportTree(const Model& model,
|
||||
const SupportConfig& cfg = {},
|
||||
const Controller& ctl = {});
|
||||
|
||||
SLASupportTree(const PointSet& pts,
|
||||
const EigenMesh3D& em,
|
||||
const SupportConfig& cfg = {},
|
||||
|
|
|
|||
|
|
@ -85,7 +85,8 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model,
|
|||
// Temporary: just to have to correct layer height for the rasterization
|
||||
DynamicPrintConfig config(config_in);
|
||||
config.normalize();
|
||||
auto lh = config.opt<ConfigOptionFloat>("layer_height");
|
||||
m_material_config.initial_layer_height.set(
|
||||
config.opt<ConfigOptionFloat>("initial_layer_height"));
|
||||
|
||||
// Temporary quick fix, just invalidate everything.
|
||||
{
|
||||
|
|
@ -102,7 +103,10 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model,
|
|||
// Generate new SLAPrintObjects.
|
||||
for (ModelObject *model_object : m_model.objects) {
|
||||
auto po = new SLAPrintObject(this, model_object);
|
||||
po->m_config.layer_height.set(lh);
|
||||
|
||||
// po->m_config.layer_height.set(lh);
|
||||
po->m_config.apply(config, true);
|
||||
|
||||
m_objects.emplace_back(po);
|
||||
for (ModelInstance *oinst : model_object->instances) {
|
||||
Point tr = Point::new_scale(oinst->get_offset()(X),
|
||||
|
|
@ -126,6 +130,8 @@ void SLAPrint::process()
|
|||
// shortcut to initial layer height
|
||||
auto ilh = float(m_material_config.initial_layer_height.getFloat());
|
||||
|
||||
std::cout << "Initial layer height: " << m_material_config.initial_layer_height.getFloat() << std::endl;
|
||||
|
||||
// Slicing the model object. This method is oversimplified and needs to
|
||||
// be compared with the fff slicing algorithm for verification
|
||||
auto slice_model = [this, ilh](SLAPrintObject& po) {
|
||||
|
|
@ -137,8 +143,12 @@ void SLAPrint::process()
|
|||
|
||||
auto H = bb3d.max(Z) - bb3d.min(Z);
|
||||
auto gnd = float(bb3d.min(Z));
|
||||
|
||||
double elevation = po.m_config.support_object_elevation.getFloat();
|
||||
float ih = elevation > 0 ? lh : ilh;
|
||||
|
||||
std::vector<float> heights = {gnd};
|
||||
for(float h = gnd + ilh; h < gnd + H; h += lh) heights.emplace_back(h);
|
||||
for(float h = gnd + ih; h < gnd + H; h += lh) heights.emplace_back(h);
|
||||
|
||||
auto& layers = po.m_model_slices;
|
||||
slicer.slice(heights, &layers, [this](){
|
||||
|
|
@ -169,7 +179,17 @@ void SLAPrint::process()
|
|||
auto& emesh = po.m_supportdata->emesh;
|
||||
auto& pts = po.m_supportdata->support_points; // nowhere filled yet
|
||||
try {
|
||||
SupportConfig scfg; // TODO fill or replace with po.m_config
|
||||
sla::SupportConfig scfg;
|
||||
SLAPrintObjectConfig& c = po.m_config;
|
||||
|
||||
scfg.head_front_radius_mm = c.support_head_front_radius.getFloat();
|
||||
scfg.head_back_radius_mm = c.support_head_back_radius.getFloat();
|
||||
scfg.head_penetration_mm = c.support_head_penetration.getFloat();
|
||||
scfg.head_width_mm = c.support_head_width.getFloat();
|
||||
scfg.object_elevation_mm = c.support_object_elevation.getFloat();
|
||||
scfg.tilt = c.support_critical_angle.getFloat() * PI / 180.0 ;
|
||||
scfg.max_bridge_length_mm = c.support_max_bridge_length.getFloat();
|
||||
scfg.pillar_radius_mm = c.support_pillar_radius.getFloat();
|
||||
|
||||
sla::Controller ctl;
|
||||
ctl.statuscb = [this](unsigned st, const std::string& msg) {
|
||||
|
|
@ -207,9 +227,8 @@ void SLAPrint::process()
|
|||
double elevation = po.m_config.support_object_elevation.getFloat();
|
||||
|
||||
sla::ExPolygons bp;
|
||||
if(elevation < h/2)
|
||||
sla::base_plate(po.transformed_mesh(), bp,
|
||||
float(h/2), float(lh));
|
||||
if(elevation < h/2) sla::base_plate(po.transformed_mesh(), bp,
|
||||
float(h/2), float(lh));
|
||||
|
||||
po.m_supportdata->support_tree_ptr->add_pad(bp, wt, h, md, er);
|
||||
}
|
||||
|
|
@ -237,43 +256,59 @@ void SLAPrint::process()
|
|||
lref(std::cref(lyr)), copies(std::cref(cp)) {}
|
||||
};
|
||||
|
||||
using LevelID = long long;
|
||||
using LayerRefs = std::vector<LayerRef>;
|
||||
|
||||
// layers according to quantized height levels
|
||||
std::map<long long, LayerRefs> levels;
|
||||
std::map<LevelID, LayerRefs> levels;
|
||||
|
||||
auto sinitlh = LevelID(scale_(ilh));
|
||||
|
||||
// For all print objects, go through its initial layers and place them
|
||||
// into the layers hash
|
||||
for(SLAPrintObject *o : m_objects) {
|
||||
|
||||
double gndlvl = o->transformed_mesh().bounding_box().min(Z);
|
||||
double elevation = o->m_config.support_object_elevation.getFloat();
|
||||
|
||||
double lh = o->m_config.layer_height.getFloat();
|
||||
|
||||
// TODO: this juust misses the support layers with a slight offset...
|
||||
double ih = elevation > 0 ? lh : ilh;
|
||||
|
||||
auto sgl = LevelID(scale_(gndlvl));
|
||||
auto slh = LevelID(scale_(lh)); // scaled layer height
|
||||
auto sih = LevelID(scale_(ih));
|
||||
|
||||
SlicedModel & oslices = o->m_model_slices;
|
||||
for(int i = 0; i < oslices.size(); ++i) {
|
||||
int a = i == 0 ? 0 : 1;
|
||||
int b = i == 0 ? 0 : i - 1;
|
||||
|
||||
double h = gndlvl + ilh * a + b * lh;
|
||||
long long lyridx = static_cast<long long>(scale_(h));
|
||||
auto& lyrs = levels[lyridx]; // this initializes a new record
|
||||
LevelID h = sgl + sih * a + b * slh;
|
||||
|
||||
std::cout << "Model layer level: " << h << std::endl;
|
||||
|
||||
auto& lyrs = levels[h]; // this initializes a new record
|
||||
lyrs.emplace_back(oslices[i], o->m_instances);
|
||||
}
|
||||
|
||||
if(o->m_supportdata) { // deal with the support slices if present
|
||||
auto& sslices = o->m_supportdata->support_slices;
|
||||
double el = o->m_config.support_object_elevation.getFloat();
|
||||
//TODO: remove next line:
|
||||
el = SupportConfig().object_elevation_mm;
|
||||
|
||||
// Supports start below the ground level.
|
||||
// Counting the pad height as well
|
||||
double el = o->get_elevation();
|
||||
auto sel = LevelID(scale_(el));
|
||||
|
||||
for(int i = 0; i < sslices.size(); ++i) {
|
||||
int a = i == 0 ? 0 : 1;
|
||||
int b = i == 0 ? 0 : i - 1;
|
||||
|
||||
double h = gndlvl - el + ilh * a + b * lh;
|
||||
LevelID h = sgl - sel + sinitlh * a + b * slh;
|
||||
std::cout << "Support layer level: " << h << std::endl;
|
||||
|
||||
long long lyridx = static_cast<long long>(scale_(h));
|
||||
auto& lyrs = levels[lyridx];
|
||||
auto& lyrs = levels[h];
|
||||
lyrs.emplace_back(sslices[i], o->m_instances);
|
||||
}
|
||||
}
|
||||
|
|
@ -437,6 +472,26 @@ SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object):
|
|||
|
||||
SLAPrintObject::~SLAPrintObject() {}
|
||||
|
||||
double SLAPrintObject::get_elevation() const {
|
||||
return m_supportdata && m_supportdata->support_tree_ptr?
|
||||
m_supportdata->support_tree_ptr->get_elevation() :
|
||||
0;
|
||||
}
|
||||
|
||||
//const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
|
||||
//{
|
||||
// // I don't want to return a copy but the points may not exist, so ...
|
||||
// static const std::vector<ExPolygons> dummy_empty;
|
||||
|
||||
// if(!m_supportdata) return dummy_empty;
|
||||
// return m_supportdata->support_slices;
|
||||
//}
|
||||
|
||||
//const std::vector<ExPolygons> &SLAPrintObject::get_model_slices() const
|
||||
//{
|
||||
// return m_model_slices;
|
||||
//}
|
||||
|
||||
bool SLAPrintObject::has_mesh(SLAPrintObjectStep step) const
|
||||
{
|
||||
switch (step) {
|
||||
|
|
|
|||
|
|
@ -63,6 +63,15 @@ public:
|
|||
|
||||
std::vector<Vec3d> transformed_support_points() const;
|
||||
|
||||
// Get the needed Z elevation for the model geometry if supports should be
|
||||
// displayed. This Z offset should also be applied to the support
|
||||
// geometries. Note that this is not the same as the value stored in config
|
||||
// as the pad height also needs to be considered.
|
||||
double get_elevation() const;
|
||||
|
||||
// const std::vector<ExPolygons>& get_support_slices() const;
|
||||
// const std::vector<ExPolygons>& get_model_slices() const;
|
||||
|
||||
// I refuse to grantee copying (Tamas)
|
||||
SLAPrintObject(const SLAPrintObject&) = delete;
|
||||
SLAPrintObject& operator=(const SLAPrintObject&) = delete;
|
||||
|
|
@ -84,6 +93,7 @@ protected:
|
|||
bool invalidate_step(SLAPrintObjectStep step);
|
||||
|
||||
private:
|
||||
|
||||
// Object specific configuration, pulled from the configuration layer.
|
||||
SLAPrintObjectConfig m_config;
|
||||
// Translation in Z + Rotation by Y and Z + Scaling / Mirroring.
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ namespace PerlUtils {
|
|||
extern std::string path_to_parent_path(const char *src);
|
||||
};
|
||||
|
||||
std::string string_printf(const char *format, ...);
|
||||
|
||||
// Timestamp formatted for header_slic3r_generated().
|
||||
extern std::string timestamp_str();
|
||||
// Standard "generated by Slic3r version xxx timestamp xxx" header string,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <locale>
|
||||
#include <ctime>
|
||||
#include <cstdarg>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
|
|
@ -297,6 +299,25 @@ namespace PerlUtils {
|
|||
std::string path_to_parent_path(const char *src) { return boost::filesystem::path(src).parent_path().string(); }
|
||||
};
|
||||
|
||||
|
||||
std::string string_printf(const char *format, ...)
|
||||
{
|
||||
va_list args1;
|
||||
va_start(args1, format);
|
||||
va_list args2;
|
||||
va_copy(args2, args1);
|
||||
|
||||
size_t needed_size = ::vsnprintf(nullptr, 0, format, args1) + 1;
|
||||
va_end(args1);
|
||||
|
||||
std::string res(needed_size, '\0');
|
||||
::vsnprintf(&res.front(), res.size(), format, args2);
|
||||
va_end(args2);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
std::string timestamp_str()
|
||||
{
|
||||
const auto now = boost::posix_time::second_clock::local_time();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue