Refactoring.

This commit is contained in:
Samir55 2018-07-12 02:48:13 +02:00
parent 054a52b559
commit 873558fec6
2 changed files with 319 additions and 313 deletions

View File

@ -13,7 +13,7 @@ SupportMaterial::create_circle(coordf_t radius)
PI / 3, PI / 3,
0}; 0};
for (auto pos : positions) { for (auto pos : positions) {
points.push_back(Point(radius * cos(pos), (radius * sin(pos)))); points.emplace_back(radius * cos(pos), (radius * sin(pos)));
} }
return Polygon(points); return Polygon(points);
@ -71,6 +71,110 @@ SupportMaterial::get_max_layer_height(PrintObject *object)
return ret; return ret;
} }
void
SupportMaterial::generate_toolpaths(PrintObject *object,
map<coordf_t, Polygons> overhang,
map<coordf_t, Polygons> contact,
map<int, Polygons> interface,
map<int, Polygons> base)
{
// Assig the object to the supports class.
this->object = object;
// Shape of contact area.
int contact_loops = 1;
coordf_t circle_radius = 1.5 * interface_flow->scaled_width();
coordf_t circle_distance = 3 * circle_radius;
Polygon circle = create_circle(circle_radius);
// TODO Add Slic3r debug. "Generating patterns\n"
// Prepare fillers.
auto pattern = object_config->support_material_pattern;
vector<int> angles;
angles.push_back(object_config->support_material_angle.value);
if (pattern == smpRectilinearGrid) {
pattern = smpRectilinear;
angles.push_back(angles[0] + 90);
}
else if (pattern == smpPillars) {
pattern = smpHoneycomb;
}
auto interface_angle = object_config->support_material_angle.value + 90;
auto interface_spacing = object_config->support_material_interface_spacing.value + interface_flow->spacing();
auto interface_density = interface_spacing == 0 ? 1 : interface_flow->spacing() / interface_spacing;
auto support_spacing = object_config->support_material_spacing + flow->spacing();
auto support_density = support_spacing == 0 ? 1 : flow->spacing() / support_spacing;
parallelize<size_t>(
0,
object->support_layers.size() - 1,
boost::bind(&SupportMaterial::process_layer, this, _1),
this->config->threads.value
);
}
void
SupportMaterial::generate(PrintObject *object)
{
// Determine the top surfaces of the support, defined as:
// contact = overhangs - clearance + margin
// This method is responsible for identifying what contact surfaces
// should the support material expose to the object in order to guarantee
// that it will be effective, regardless of how it's built below.
pair<map<coordf_t, Polygons>, map<coordf_t, Polygons>> contact_overhang = contact_area(object);
map<coordf_t, Polygons> &contact = contact_overhang.first;
map<coordf_t, Polygons> &overhang = contact_overhang.second;
// Determine the top surfaces of the object. We need these to determine
// the layer heights of support material and to clip support to the object
// silhouette.
map<coordf_t, Polygons> top = object_top(object, &contact);
// We now know the upper and lower boundaries for our support material object
// (@$contact_z and @$top_z), so we can generate intermediate layers.
vector<coordf_t> support_z = support_layers_z(get_keys_sorted(contact),
get_keys_sorted(top),
get_max_layer_height(object));
// If we wanted to apply some special logic to the first support layers lying on
// object's top surfaces this is the place to detect them. TODO
// Propagate contact layers downwards to generate interface layers.
map<int, Polygons> interface = generate_interface_layers(support_z, contact, top);
clip_with_object(interface, support_z, *object);
// clip_with_shape(base, shape); // TODO
// Propagate contact layers and interface layers downwards to generate
// the main support layers. TODO
// Detect what part of base support layers are "reverse interfaces" because they
// lie above object's top surfaces. TODO
// Install support layers into object.
for (int i = 0; i < support_z.size(); i++) {
object->add_support_layer(
i, // id.
(i == 0) ? support_z[0] - 0 : (support_z[i] - support_z[i - 1]), // height.
support_z[i] // print_z
);
if (i >= 1) {
object->support_layers.end()[-2]->upper_layer = object->support_layers.end()[-1];
object->support_layers.end()[-1]->lower_layer = object->support_layers.end()[-2];
}
}
// Generate the actual toolpaths and save them into each layer.
generate_toolpaths(object, overhang, contact, interface, base);
}
vector<coordf_t> vector<coordf_t>
SupportMaterial::support_layers_z(vector<coordf_t> contact_z, SupportMaterial::support_layers_z(vector<coordf_t> contact_z,
vector<coordf_t> top_z, vector<coordf_t> top_z,
@ -146,178 +250,6 @@ SupportMaterial::support_layers_z(vector<coordf_t> contact_z,
return z; return z;
} }
vector<int>
SupportMaterial::overlapping_layers(int layer_idx, const vector<coordf_t> &support_z)
{
vector<int> ret;
coordf_t z_max = support_z[layer_idx];
coordf_t z_min = layer_idx == 0 ? 0 : support_z[layer_idx - 1];
for (int i = 0; i < support_z.size(); i++) {
if (i == layer_idx) continue;
coordf_t z_max2 = support_z[i];
coordf_t z_min2 = i == 0 ? 0 : support_z[i - 1];
if (z_max > z_min2 && z_min < z_max2)
ret.push_back(i);
}
return ret;
}
void
SupportMaterial::clip_with_shape(map<int, Polygons> &support, map<int, Polygons> &shape)
{
for (auto layer : support) {
// Don't clip bottom layer with shape so that we
// can generate a continuous base flange
// also don't clip raft layers
if (layer.first == 0) continue;
else if (layer.first < object_config->raft_layers) continue;
layer.second = intersection(layer.second, shape[layer.first]);
}
}
void
SupportMaterial::clip_with_object(map<int, Polygons> &support, vector<coordf_t> support_z, PrintObject &object)
{
int i = 0;
for (auto support_layer: support) {
if (support_layer.second.empty()) {
i++;
continue;
}
coordf_t z_max = support_z[i];
coordf_t z_min = (i == 0) ? 0 : support_z[i - 1];
LayerPtrs layers;
for (auto layer : object.layers) {
if (layer->print_z > z_min && (layer->print_z - layer->height) < z_max) {
layers.push_back(layer);
}
}
// $layer->slices contains the full shape of layer, thus including
// perimeter's width. $support contains the full shape of support
// material, thus including the width of its foremost extrusion.
// We leave a gap equal to a full extrusion width. TODO ask about this line @samir
Polygons slices;
for (Layer *l : layers) {
for (auto s : l->slices.contours()) {
slices.push_back(s);
}
}
support_layer.second = diff(support_layer.second, offset(slices, flow->scaled_width()));
}
/*
$support->{$i} = diff(
$support->{$i},
offset([ map @$_, map @{$_->slices}, @layers ], +$self->flow->scaled_width),
);
*/
}
map<coordf_t, Polygons>
SupportMaterial::object_top(PrintObject *object, map<coordf_t, Polygons> *contact)
{
// find object top surfaces
// we'll use them to clip our support and detect where does it stick.
map<coordf_t, Polygons> top;
if (object_config->support_material_buildplate_only.value)
return top;
Polygons projection;
for (auto i = static_cast<int>(object->layers.size() - 1); i >= 0; i--) {
Layer *layer = object->layers[i];
SurfacesPtr m_top;
for (auto r : layer->regions)
for (auto s : r->slices.filter_by_type(stTop))
m_top.push_back(s);
if (!m_top.empty()) {
// compute projection of the contact areas above this top layer
// first add all the 'new' contact areas to the current projection
// ('new' means all the areas that are lower than the last top layer
// we considered).
// TODO Ask about this line
/*
my $min_top = min(keys %top) // max(keys %$contact);
*/
double min_top = top.begin()->first;
// Use <= instead of just < because otherwise we'd ignore any contact regions
// having the same Z of top layers.
for (auto el : *contact)
if (el.first > layer->print_z && el.first <= min_top)
for (const auto &p : el.second)
projection.push_back(p);
// Now find whether any projection falls onto this top surface.
Polygons touching = intersection(projection, p(m_top));
if (!touching.empty()) {
// Grow top surfaces so that interface and support generation are generated
// with some spacing from object - it looks we don't need the actual
// top shapes so this can be done here.
top[layer->print_z] = offset(touching, flow->scaled_width());
}
// Remove the areas that touched from the projection that will continue on
// next, lower, top surfaces.
projection = diff(projection, touching);
}
}
return top;
}
void
SupportMaterial::generate_toolpaths(PrintObject *object,
map<coordf_t, Polygons> overhang,
map<coordf_t, Polygons> contact,
map<int, Polygons> interface,
map<int, Polygons> base)
{
// Assig the object to the supports class.
this->object = object;
// Shape of contact area.
int contact_loops = 1;
coordf_t circle_radius = 1.5 * interface_flow->scaled_width();
coordf_t circle_distance = 3 * circle_radius;
Polygon circle = create_circle(circle_radius);
// TODO Add Slic3r debug. "Generating patterns\n"
// Prepare fillers.
auto pattern = object_config->support_material_pattern;
vector<int> angles;
angles.push_back(object_config->support_material_angle.value);
if (pattern == smpRectilinearGrid) {
pattern = smpRectilinear;
angles.push_back(angles[0] + 90);
}
else if (pattern == smpPillars) {
pattern = smpHoneycomb;
}
auto interface_angle = object_config->support_material_angle.value + 90;
auto interface_spacing = object_config->support_material_interface_spacing.value + interface_flow->spacing();
auto interface_density = interface_spacing == 0 ? 1 : interface_flow->spacing() / interface_spacing;
auto support_spacing = object_config->support_material_spacing + flow->spacing();
auto support_density = support_spacing == 0 ? 1 : flow->spacing() / support_spacing;
parallelize<size_t>(
0,
object->support_layers.size() - 1,
boost::bind(&SupportMaterial::process_layer, this, _1),
this->config->threads.value
);
}
pair<map<coordf_t, Polygons>, map<coordf_t, Polygons>> pair<map<coordf_t, Polygons>, map<coordf_t, Polygons>>
SupportMaterial::contact_area(PrintObject *object) SupportMaterial::contact_area(PrintObject *object)
{ {
@ -652,64 +584,106 @@ SupportMaterial::contact_area(PrintObject *object)
return make_pair(contact, overhang); return make_pair(contact, overhang);
} }
void map<coordf_t, Polygons>
SupportMaterial::generate(PrintObject *object) SupportMaterial::object_top(PrintObject *object, map<coordf_t, Polygons> *contact)
{ {
// Determine the top surfaces of the support, defined as: // find object top surfaces
// contact = overhangs - clearance + margin // we'll use them to clip our support and detect where does it stick.
// This method is responsible for identifying what contact surfaces map<coordf_t, Polygons> top;
// should the support material expose to the object in order to guarantee if (object_config->support_material_buildplate_only.value)
// that it will be effective, regardless of how it's built below. return top;
pair<map<coordf_t, Polygons>, map<coordf_t, Polygons>> contact_overhang = contact_area(object);
map<coordf_t, Polygons> &contact = contact_overhang.first;
map<coordf_t, Polygons> &overhang = contact_overhang.second;
Polygons projection;
for (auto i = static_cast<int>(object->layers.size() - 1); i >= 0; i--) {
// Determine the top surfaces of the object. We need these to determine Layer *layer = object->layers[i];
// the layer heights of support material and to clip support to the object SurfacesPtr m_top;
// silhouette.
map<coordf_t, Polygons> top = object_top(object, &contact);
// We now know the upper and lower boundaries for our support material object for (auto r : layer->regions)
// (@$contact_z and @$top_z), so we can generate intermediate layers. for (auto s : r->slices.filter_by_type(stTop))
vector<coordf_t> support_z = support_layers_z(get_keys_sorted(contact), m_top.push_back(s);
get_keys_sorted(top),
get_max_layer_height(object));
// If we wanted to apply some special logic to the first support layers lying on if (!m_top.empty()) {
// object's top surfaces this is the place to detect them. TODO // compute projection of the contact areas above this top layer
// first add all the 'new' contact areas to the current projection
// ('new' means all the areas that are lower than the last top layer
// we considered).
// TODO Ask about this line
/*
my $min_top = min(keys %top) // max(keys %$contact);
*/
double min_top = top.begin()->first;
// Use <= instead of just < because otherwise we'd ignore any contact regions
// having the same Z of top layers.
for (auto el : *contact)
if (el.first > layer->print_z && el.first <= min_top)
for (const auto &p : el.second)
projection.push_back(p);
// Propagate contact layers downwards to generate interface layers. // Now find whether any projection falls onto this top surface.
map<int, Polygons> interface = generate_interface_layers(support_z, contact, top); Polygons touching = intersection(projection, p(m_top));
clip_with_object(interface, support_z, *object); if (!touching.empty()) {
// clip_with_shape(base, shape); // TODO // Grow top surfaces so that interface and support generation are generated
// with some spacing from object - it looks we don't need the actual
// top shapes so this can be done here.
top[layer->print_z] = offset(touching, flow->scaled_width());
}
// Propagate contact layers and interface layers downwards to generate // Remove the areas that touched from the projection that will continue on
// the main support layers. TODO // next, lower, top surfaces.
projection = diff(projection, touching);
// Detect what part of base support layers are "reverse interfaces" because they
// lie above object's top surfaces. TODO
// Install support layers into object.
for (int i = 0; i < support_z.size(); i++) {
object->add_support_layer(
i, // id.
(i == 0) ? support_z[0] - 0 : (support_z[i] - support_z[i - 1]), // height.
support_z[i] // print_z
);
if (i >= 1) {
object->support_layers.end()[-2]->upper_layer = object->support_layers.end()[-1];
object->support_layers.end()[-1]->lower_layer = object->support_layers.end()[-2];
} }
} }
return top;
}
// Generate the actual toolpaths and save them into each layer. map<int, Polygons>
generate_toolpaths(object, overhang, contact, interface, base); SupportMaterial::generate_base_layers(vector<coordf_t> support_z,
map<coordf_t, Polygons> contact,
map<int, Polygons> interface,
map<coordf_t, Polygons> top)
{
// Let's now generate support layers under interface layers.
map<int, Polygons> base;
{
for (int i = static_cast<int>(support_z.size() - 1); i >= 0; i--) {
auto z = support_z[i];
auto overlapping_layers = this->overlapping_layers(i, support_z);
vector<coordf_t> overlapping_z;
for (auto el : overlapping_layers)
overlapping_z.push_back(support_z[el]);
// In case we have no interface layers, look at upper contact
// (1 interface layer means we only have contact layer, so $interface->{$i+1} is empty).
Polygons upper_contact;
if (object_config->support_material_interface_layers.value <= 1) {
append_polygons(upper_contact, contact[support_z[i + 1]]);
}
Polygons ps_1;
append_polygons(ps_1, base[i + 1]); // support regions on upper layer.
append_polygons(ps_1, interface[i + 1]); // interface regions on upper layer
append_polygons(ps_1, upper_contact); // contact regions on upper layer
Polygons ps_2;
for (auto el : overlapping_z) {
if (top.count(el) > 0)
append_polygons(ps_2, top[el]); // top slices on this layer.
if (interface.count(el) > 0)
append_polygons(ps_2, interface[el]); // interface regions on this layer.
if (contact.count(el) > 0)
append_polygons(ps_2, contact[el]); // contact regions on this layer.
}
base[i] = diff(
ps_1,
ps_2,
1
);
}
}
return base;
} }
map<int, Polygons> map<int, Polygons>
@ -764,52 +738,134 @@ SupportMaterial::generate_interface_layers(vector<coordf_t> support_z,
return interface; return interface;
} }
map<int, Polygons> void
SupportMaterial::generate_base_layers(vector<coordf_t> support_z, SupportMaterial::generate_bottom_interface_layers(const vector<coordf_t> &support_z,
map<coordf_t, Polygons> contact, map<int, Polygons> &base,
map<int, Polygons> interface, map<coordf_t, Polygons> &top,
map<coordf_t, Polygons> top) map<int, Polygons> &interface)
{ {
// Let's now generate support layers under interface layers. // If no interface layers are allowed, don't generate bottom interface layers.
map<int, Polygons> base; if (object_config->support_material_interface_layers.value == 0)
{ return;
for (int i = static_cast<int>(support_z.size() - 1); i >= 0; i--) {
auto z = support_z[i];
auto overlapping_layers = this->overlapping_layers(i, support_z);
vector<coordf_t> overlapping_z;
for (auto el : overlapping_layers)
overlapping_z.push_back(support_z[el]);
// In case we have no interface layers, look at upper contact auto area_threshold = interface_flow->scaled_spacing() * interface_flow->scaled_spacing();
// (1 interface layer means we only have contact layer, so $interface->{$i+1} is empty).
Polygons upper_contact; // Loop through object's top surfaces. TODO CHeck if the keys are sorted.
if (object_config->support_material_interface_layers.value <= 1) { for (auto &top_el : top) {
append_polygons(upper_contact, contact[support_z[i + 1]]); // Keep a count of the interface layers we generated for this top surface.
int interface_layers = 0;
// Loop through support layers until we find the one(s) right above the top
// surface.
for (int layer_id = 0; layer_id < support_z.size(); layer_id++) {
auto z = support_z[layer_id];
if (!z > top_el.first) // next unless $z > $top_z;
continue;
if (base.count(layer_id) > 0) {
// Get the support material area that should be considered interface.
auto interface_area = intersection(
base[layer_id],
top_el.second
);
// Discard too small areas.
Polygons new_interface_area;
for (auto p : interface_area) {
if (abs(p.area()) >= area_threshold)
new_interface_area.push_back(p);
}
interface_area = new_interface_area;
// Subtract new interface area from base.
base[layer_id] = diff(
base[layer_id],
interface_area
);
// Add the new interface area to interface.
append_polygons(interface[layer_id], interface_area);
} }
Polygons ps_1; interface_layers++;
append_polygons(ps_1, base[i + 1]); // support regions on upper layer. if (interface_layers == object_config->support_material_interface_layers.value)
append_polygons(ps_1, interface[i + 1]); // interface regions on upper layer layer_id = static_cast<int>(support_z.size());
append_polygons(ps_1, upper_contact); // contact regions on upper layer
Polygons ps_2;
for (auto el : overlapping_z) {
if (top.count(el) > 0)
append_polygons(ps_2, top[el]); // top slices on this layer.
if (interface.count(el) > 0)
append_polygons(ps_2, interface[el]); // interface regions on this layer.
if (contact.count(el) > 0)
append_polygons(ps_2, contact[el]); // contact regions on this layer.
}
base[i] = diff(
ps_1,
ps_2,
1
);
} }
} }
return base; }
vector<int>
SupportMaterial::overlapping_layers(int layer_idx, const vector<coordf_t> &support_z)
{
vector<int> ret;
coordf_t z_max = support_z[layer_idx];
coordf_t z_min = layer_idx == 0 ? 0 : support_z[layer_idx - 1];
for (int i = 0; i < support_z.size(); i++) {
if (i == layer_idx) continue;
coordf_t z_max2 = support_z[i];
coordf_t z_min2 = i == 0 ? 0 : support_z[i - 1];
if (z_max > z_min2 && z_min < z_max2)
ret.push_back(i);
}
return ret;
}
void
SupportMaterial::clip_with_shape(map<int, Polygons> &support, map<int, Polygons> &shape)
{
for (auto layer : support) {
// Don't clip bottom layer with shape so that we
// can generate a continuous base flange
// also don't clip raft layers
if (layer.first == 0) continue;
else if (layer.first < object_config->raft_layers) continue;
layer.second = intersection(layer.second, shape[layer.first]);
}
}
void
SupportMaterial::clip_with_object(map<int, Polygons> &support, vector<coordf_t> support_z, PrintObject &object)
{
int i = 0;
for (auto support_layer: support) {
if (support_layer.second.empty()) {
i++;
continue;
}
coordf_t z_max = support_z[i];
coordf_t z_min = (i == 0) ? 0 : support_z[i - 1];
LayerPtrs layers;
for (auto layer : object.layers) {
if (layer->print_z > z_min && (layer->print_z - layer->height) < z_max) {
layers.push_back(layer);
}
}
// $layer->slices contains the full shape of layer, thus including
// perimeter's width. $support contains the full shape of support
// material, thus including the width of its foremost extrusion.
// We leave a gap equal to a full extrusion width. TODO ask about this line @samir
Polygons slices;
for (Layer *l : layers) {
for (auto s : l->slices.contours()) {
slices.push_back(s);
}
}
support_layer.second = diff(support_layer.second, offset(slices, flow->scaled_width()));
}
/*
$support->{$i} = diff(
$support->{$i},
offset([ map @$_, map @{$_->slices}, @layers ], +$self->flow->scaled_width),
);
*/
} }
} }

View File

@ -50,63 +50,13 @@ public:
object(nullptr) object(nullptr)
{} {}
void generate_pillars_shape(vector<coordf_t, Polygons> contact, vector<coordf_t> support_z)
{}
void generate_bottom_interface_layers(const vector<coordf_t> &support_z, void generate_bottom_interface_layers(const vector<coordf_t> &support_z,
map<int, Polygons> &base, map<int, Polygons> &base,
map<coordf_t, Polygons> &top, map<coordf_t, Polygons> &top,
map<int, Polygons> &interface) map<int, Polygons> &interface);
{
// If no interface layers are allowed, don't generate bottom interface layers.
if (object_config->support_material_interface_layers.value == 0)
return;
auto area_threshold = interface_flow->scaled_spacing() * interface_flow->scaled_spacing();
// Loop through object's top surfaces. TODO CHeck if the keys are sorted.
for (auto &top_el : top) {
// Keep a count of the interface layers we generated for this top surface.
int interface_layers = 0;
// Loop through support layers until we find the one(s) right above the top
// surface.
for (int layer_id = 0; layer_id < support_z.size(); layer_id++) {
auto z = support_z[layer_id];
if (!z > top_el.first) // next unless $z > $top_z;
continue;
if (base.count(layer_id) > 0) {
// Get the support material area that should be considered interface.
auto interface_area = intersection(
base[layer_id],
top_el.second
);
// Discard too small areas.
Polygons new_interface_area;
for (auto p : interface_area) {
if (abs(p.area()) >= area_threshold)
new_interface_area.push_back(p);
}
interface_area = new_interface_area;
// Subtract new interface area from base.
base[layer_id] = diff(
base[layer_id],
interface_area
);
// Add the new interface area to interface.
append_polygons(interface[layer_id], interface_area);
}
interface_layers++;
if (interface_layers == object_config->support_material_interface_layers.value)
layer_id = support_z.size();
}
}
}
void generate_pillars_shape()
{}
map<int, Polygons> generate_base_layers(vector<coordf_t> support_z, map<int, Polygons> generate_base_layers(vector<coordf_t> support_z,
map<coordf_t, Polygons> contact, map<coordf_t, Polygons> contact,