2014-08-03 17:28:40 +00:00
|
|
|
#include "Print.hpp"
|
|
|
|
#include "BoundingBox.hpp"
|
2014-11-09 11:25:59 +00:00
|
|
|
#include "Geometry.hpp"
|
2014-08-03 17:28:40 +00:00
|
|
|
|
|
|
|
namespace Slic3r {
|
|
|
|
|
|
|
|
PrintObject::PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox)
|
|
|
|
: _print(print),
|
|
|
|
_model_object(model_object),
|
|
|
|
typed_slices(false)
|
|
|
|
{
|
|
|
|
region_volumes.resize(this->_print->regions.size());
|
|
|
|
|
|
|
|
// Compute the translation to be applied to our meshes so that we work with smaller coordinates
|
|
|
|
{
|
|
|
|
// Translate meshes so that our toolpath generation algorithms work with smaller
|
|
|
|
// XY coordinates; this translation is an optimization and not strictly required.
|
|
|
|
// A cloned mesh will be aligned to 0 before slicing in _slice_region() since we
|
|
|
|
// don't assume it's already aligned and we don't alter the original position in model.
|
|
|
|
// We store the XY translation so that we can place copies correctly in the output G-code
|
|
|
|
// (copies are expressed in G-code coordinates and this translation is not publicly exposed).
|
|
|
|
this->_copies_shift = Point(
|
|
|
|
scale_(modobj_bbox.min.x), scale_(modobj_bbox.min.y));
|
|
|
|
|
|
|
|
// Scale the object size and store it
|
|
|
|
Pointf3 size = modobj_bbox.size();
|
|
|
|
this->size = Point3(scale_(size.x), scale_(size.y), scale_(size.z));
|
|
|
|
}
|
2014-11-12 22:28:42 +00:00
|
|
|
|
|
|
|
this->reload_model_instances();
|
|
|
|
this->layer_height_ranges = model_object->layer_height_ranges;
|
2014-08-03 17:28:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PrintObject::~PrintObject()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Print*
|
|
|
|
PrintObject::print()
|
|
|
|
{
|
|
|
|
return this->_print;
|
|
|
|
}
|
|
|
|
|
|
|
|
ModelObject*
|
|
|
|
PrintObject::model_object()
|
|
|
|
{
|
|
|
|
return this->_model_object;
|
|
|
|
}
|
|
|
|
|
2014-11-09 11:25:59 +00:00
|
|
|
Points
|
|
|
|
PrintObject::copies() const
|
|
|
|
{
|
|
|
|
return this->_copies;
|
|
|
|
}
|
|
|
|
|
2014-11-12 23:34:56 +00:00
|
|
|
bool
|
|
|
|
PrintObject::add_copy(const Pointf &point)
|
|
|
|
{
|
|
|
|
Points points = this->_copies;
|
|
|
|
points.push_back(Point::new_scale(point.x, point.y));
|
|
|
|
return this->set_copies(points);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
PrintObject::delete_last_copy()
|
|
|
|
{
|
|
|
|
Points points = this->_copies;
|
|
|
|
points.pop_back();
|
|
|
|
return this->set_copies(points);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
PrintObject::delete_all_copies()
|
|
|
|
{
|
|
|
|
Points points;
|
|
|
|
return this->set_copies(points);
|
|
|
|
}
|
|
|
|
|
2014-11-12 22:28:42 +00:00
|
|
|
bool
|
2014-11-09 11:25:59 +00:00
|
|
|
PrintObject::set_copies(const Points &points)
|
|
|
|
{
|
|
|
|
this->_copies = points;
|
|
|
|
|
|
|
|
// order copies with a nearest neighbor search and translate them by _copies_shift
|
|
|
|
this->_shifted_copies.clear();
|
|
|
|
this->_shifted_copies.reserve(points.size());
|
|
|
|
|
|
|
|
// order copies with a nearest-neighbor search
|
|
|
|
std::vector<Points::size_type> ordered_copies;
|
|
|
|
Slic3r::Geometry::chained_path(points, ordered_copies);
|
|
|
|
|
|
|
|
for (std::vector<Points::size_type>::const_iterator it = ordered_copies.begin(); it != ordered_copies.end(); ++it) {
|
|
|
|
Point copy = points[*it];
|
|
|
|
copy.translate(this->_copies_shift);
|
|
|
|
this->_shifted_copies.push_back(copy);
|
|
|
|
}
|
|
|
|
|
2014-11-12 22:28:42 +00:00
|
|
|
bool invalidated = false;
|
|
|
|
if (this->_print->invalidate_step(psSkirt)) invalidated = true;
|
|
|
|
if (this->_print->invalidate_step(psBrim)) invalidated = true;
|
|
|
|
return invalidated;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
PrintObject::reload_model_instances()
|
|
|
|
{
|
|
|
|
Points copies;
|
|
|
|
for (ModelInstancePtrs::const_iterator i = this->_model_object->instances.begin(); i != this->_model_object->instances.end(); ++i) {
|
|
|
|
copies.push_back(Point::new_scale((*i)->offset.x, (*i)->offset.y));
|
|
|
|
}
|
|
|
|
return this->set_copies(copies);
|
2014-11-09 11:25:59 +00:00
|
|
|
}
|
|
|
|
|
2014-11-30 20:58:41 +00:00
|
|
|
void
|
|
|
|
PrintObject::bounding_box(BoundingBox* bb) const
|
|
|
|
{
|
|
|
|
// since the object is aligned to origin, bounding box coincides with size
|
|
|
|
Points pp;
|
|
|
|
pp.push_back(Point(0,0));
|
|
|
|
pp.push_back(this->size);
|
|
|
|
*bb = BoundingBox(pp);
|
|
|
|
}
|
|
|
|
|
2014-08-03 17:28:40 +00:00
|
|
|
void
|
|
|
|
PrintObject::add_region_volume(int region_id, int volume_id)
|
|
|
|
{
|
|
|
|
if (region_id >= region_volumes.size()) {
|
|
|
|
region_volumes.resize(region_id + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
region_volumes[region_id].push_back(volume_id);
|
|
|
|
}
|
|
|
|
|
2014-11-30 21:01:46 +00:00
|
|
|
/* This is the *total* layer count (including support layers)
|
|
|
|
this value is not supposed to be compared with Layer::id
|
|
|
|
since they have different semantics */
|
2014-08-03 17:28:40 +00:00
|
|
|
size_t
|
2014-11-30 21:01:46 +00:00
|
|
|
PrintObject::total_layer_count() const
|
|
|
|
{
|
|
|
|
return this->layer_count() + this->support_layer_count();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
|
|
|
PrintObject::layer_count() const
|
2014-08-03 17:28:40 +00:00
|
|
|
{
|
|
|
|
return this->layers.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
PrintObject::clear_layers()
|
|
|
|
{
|
|
|
|
for (int i = this->layers.size()-1; i >= 0; --i)
|
|
|
|
this->delete_layer(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
Layer*
|
|
|
|
PrintObject::get_layer(int idx)
|
|
|
|
{
|
|
|
|
return this->layers.at(idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
Layer*
|
|
|
|
PrintObject::add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z)
|
|
|
|
{
|
|
|
|
Layer* layer = new Layer(id, this, height, print_z, slice_z);
|
|
|
|
layers.push_back(layer);
|
|
|
|
return layer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
PrintObject::delete_layer(int idx)
|
|
|
|
{
|
|
|
|
LayerPtrs::iterator i = this->layers.begin() + idx;
|
|
|
|
delete *i;
|
|
|
|
this->layers.erase(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
2014-11-30 21:01:46 +00:00
|
|
|
PrintObject::support_layer_count() const
|
2014-08-03 17:28:40 +00:00
|
|
|
{
|
|
|
|
return this->support_layers.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
PrintObject::clear_support_layers()
|
|
|
|
{
|
|
|
|
for (int i = this->support_layers.size()-1; i >= 0; --i)
|
|
|
|
this->delete_support_layer(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
SupportLayer*
|
|
|
|
PrintObject::get_support_layer(int idx)
|
|
|
|
{
|
|
|
|
return this->support_layers.at(idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
SupportLayer*
|
|
|
|
PrintObject::add_support_layer(int id, coordf_t height, coordf_t print_z,
|
|
|
|
coordf_t slice_z)
|
|
|
|
{
|
|
|
|
SupportLayer* layer = new SupportLayer(id, this, height, print_z, slice_z);
|
|
|
|
support_layers.push_back(layer);
|
|
|
|
return layer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
PrintObject::delete_support_layer(int idx)
|
|
|
|
{
|
|
|
|
SupportLayerPtrs::iterator i = this->support_layers.begin() + idx;
|
|
|
|
delete *i;
|
|
|
|
this->support_layers.erase(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
PrintObject::invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys)
|
|
|
|
{
|
|
|
|
std::set<PrintObjectStep> steps;
|
|
|
|
|
|
|
|
// this method only accepts PrintObjectConfig and PrintRegionConfig option keys
|
|
|
|
for (std::vector<t_config_option_key>::const_iterator opt_key = opt_keys.begin(); opt_key != opt_keys.end(); ++opt_key) {
|
|
|
|
if (*opt_key == "perimeters"
|
|
|
|
|| *opt_key == "extra_perimeters"
|
|
|
|
|| *opt_key == "gap_fill_speed"
|
|
|
|
|| *opt_key == "overhangs"
|
2014-11-30 19:38:42 +00:00
|
|
|
|| *opt_key == "first_layer_extrusion_width"
|
2014-08-03 17:28:40 +00:00
|
|
|
|| *opt_key == "perimeter_extrusion_width"
|
|
|
|
|| *opt_key == "thin_walls"
|
|
|
|
|| *opt_key == "external_perimeters_first") {
|
|
|
|
steps.insert(posPerimeters);
|
|
|
|
} else if (*opt_key == "resolution"
|
|
|
|
|| *opt_key == "layer_height"
|
|
|
|
|| *opt_key == "first_layer_height"
|
|
|
|
|| *opt_key == "xy_size_compensation"
|
|
|
|
|| *opt_key == "raft_layers") {
|
|
|
|
steps.insert(posSlice);
|
|
|
|
} else if (*opt_key == "support_material"
|
|
|
|
|| *opt_key == "support_material_angle"
|
|
|
|
|| *opt_key == "support_material_extruder"
|
|
|
|
|| *opt_key == "support_material_extrusion_width"
|
|
|
|
|| *opt_key == "support_material_interface_layers"
|
|
|
|
|| *opt_key == "support_material_interface_extruder"
|
|
|
|
|| *opt_key == "support_material_interface_spacing"
|
|
|
|
|| *opt_key == "support_material_interface_speed"
|
|
|
|
|| *opt_key == "support_material_pattern"
|
|
|
|
|| *opt_key == "support_material_spacing"
|
|
|
|
|| *opt_key == "support_material_threshold"
|
2014-11-30 19:38:42 +00:00
|
|
|
|| *opt_key == "dont_support_bridges"
|
|
|
|
|| *opt_key == "first_layer_extrusion_width") {
|
2014-08-03 17:28:40 +00:00
|
|
|
steps.insert(posSupportMaterial);
|
|
|
|
} else if (*opt_key == "interface_shells"
|
|
|
|
|| *opt_key == "infill_only_where_needed"
|
2014-12-08 20:23:42 +00:00
|
|
|
|| *opt_key == "infill_every_layers"
|
|
|
|
|| *opt_key == "solid_infill_every_layers"
|
2014-08-03 17:28:40 +00:00
|
|
|
|| *opt_key == "bottom_solid_layers"
|
|
|
|
|| *opt_key == "top_solid_layers"
|
2014-11-06 23:53:15 +00:00
|
|
|
|| *opt_key == "solid_infill_below_area"
|
2014-08-03 17:28:40 +00:00
|
|
|
|| *opt_key == "infill_extruder"
|
|
|
|
|| *opt_key == "infill_extrusion_width") {
|
|
|
|
steps.insert(posPrepareInfill);
|
2014-11-26 23:38:05 +00:00
|
|
|
} else if (*opt_key == "external_fill_pattern"
|
|
|
|
|| *opt_key == "fill_angle"
|
2014-08-03 17:28:40 +00:00
|
|
|
|| *opt_key == "fill_pattern"
|
2014-11-30 19:38:42 +00:00
|
|
|
|| *opt_key == "top_infill_extrusion_width"
|
|
|
|
|| *opt_key == "first_layer_extrusion_width") {
|
2014-08-03 17:28:40 +00:00
|
|
|
steps.insert(posInfill);
|
|
|
|
} else if (*opt_key == "fill_density"
|
|
|
|
|| *opt_key == "solid_infill_extrusion_width") {
|
|
|
|
steps.insert(posPerimeters);
|
|
|
|
steps.insert(posPrepareInfill);
|
|
|
|
} else if (*opt_key == "external_perimeter_extrusion_width"
|
|
|
|
|| *opt_key == "perimeter_extruder") {
|
|
|
|
steps.insert(posPerimeters);
|
|
|
|
steps.insert(posSupportMaterial);
|
|
|
|
} else if (*opt_key == "bridge_flow_ratio") {
|
|
|
|
steps.insert(posPerimeters);
|
|
|
|
steps.insert(posInfill);
|
|
|
|
} else if (*opt_key == "seam_position"
|
|
|
|
|| *opt_key == "support_material_speed"
|
|
|
|
|| *opt_key == "bridge_speed"
|
|
|
|
|| *opt_key == "external_perimeter_speed"
|
|
|
|
|| *opt_key == "infill_speed"
|
|
|
|
|| *opt_key == "perimeter_speed"
|
|
|
|
|| *opt_key == "small_perimeter_speed"
|
|
|
|
|| *opt_key == "solid_infill_speed"
|
|
|
|
|| *opt_key == "top_solid_infill_speed") {
|
|
|
|
// these options only affect G-code export, so nothing to invalidate
|
|
|
|
} else {
|
|
|
|
// for legacy, if we can't handle this option let's invalidate all steps
|
|
|
|
return this->invalidate_all_steps();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool invalidated = false;
|
|
|
|
for (std::set<PrintObjectStep>::const_iterator step = steps.begin(); step != steps.end(); ++step) {
|
|
|
|
if (this->invalidate_step(*step)) invalidated = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return invalidated;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
PrintObject::invalidate_step(PrintObjectStep step)
|
|
|
|
{
|
|
|
|
bool invalidated = this->state.invalidate(step);
|
|
|
|
|
|
|
|
// propagate to dependent steps
|
|
|
|
if (step == posPerimeters) {
|
|
|
|
this->invalidate_step(posPrepareInfill);
|
|
|
|
this->_print->invalidate_step(psSkirt);
|
|
|
|
this->_print->invalidate_step(psBrim);
|
|
|
|
} else if (step == posPrepareInfill) {
|
|
|
|
this->invalidate_step(posInfill);
|
|
|
|
} else if (step == posInfill) {
|
|
|
|
this->_print->invalidate_step(psSkirt);
|
|
|
|
this->_print->invalidate_step(psBrim);
|
|
|
|
} else if (step == posSlice) {
|
|
|
|
this->invalidate_step(posPerimeters);
|
|
|
|
this->invalidate_step(posSupportMaterial);
|
2014-08-07 23:37:39 +00:00
|
|
|
} else if (step == posSupportMaterial) {
|
|
|
|
this->_print->invalidate_step(psSkirt);
|
|
|
|
this->_print->invalidate_step(psBrim);
|
2014-08-03 17:28:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return invalidated;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
PrintObject::invalidate_all_steps()
|
|
|
|
{
|
|
|
|
// make a copy because when invalidating steps the iterators are not working anymore
|
|
|
|
std::set<PrintObjectStep> steps = this->state.started;
|
|
|
|
|
|
|
|
bool invalidated = false;
|
|
|
|
for (std::set<PrintObjectStep>::const_iterator step = steps.begin(); step != steps.end(); ++step) {
|
|
|
|
if (this->invalidate_step(*step)) invalidated = true;
|
|
|
|
}
|
|
|
|
return invalidated;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef SLIC3RXS
|
|
|
|
REGISTER_CLASS(PrintObject, "Print::Object");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|