Merge remote-tracking branch 'origin/tm_sla_supports_backend' into vb_3dscene_partial_update

This commit is contained in:
bubnikv 2018-11-20 13:23:12 +01:00
commit e3b858c45f
51 changed files with 1062 additions and 594 deletions

View file

@ -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
}
}

View file

@ -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)

View file

@ -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());

View file

@ -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) {

View file

@ -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)

View file

@ -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());
}

View file

@ -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))};

View file

@ -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;
}
}
}

View file

@ -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 = {},

View file

@ -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) {

View file

@ -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.

View file

@ -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,

View file

@ -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();