Some Refactoring.

This commit is contained in:
Samir55 2018-07-11 07:27:45 +02:00
parent 5a2e71283d
commit 50acce9f54
2 changed files with 502 additions and 411 deletions

View File

@ -2,6 +2,22 @@
namespace Slic3r
{
Polygon
SupportMaterial::create_circle(coordf_t radius)
{
Points points;
coordf_t positions[] = {5 * PI / 3,
4 * PI / 3,
PI,
2 * PI / 3,
PI / 3,
0};
for (auto pos : positions) {
points.push_back(Point(radius * cos(pos), (radius * sin(pos))));
}
return Polygon(points);
}
Polygons
SupportMaterial::p(SurfacesPtr &surfaces)
@ -16,6 +32,14 @@ SupportMaterial::p(SurfacesPtr &surfaces)
return ret;
}
void
SupportMaterial::append_polygons(Polygons &dst, Polygons &src)
{
for (const auto polygon : src) {
dst.push_back(polygon);
}
}
coordf_t
SupportMaterial::contact_distance(coordf_t layer_height, coordf_t nozzle_diameter)
{
@ -231,4 +255,382 @@ SupportMaterial::object_top(PrintObject *object, map<coordf_t, Polygons> *contac
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>>
SupportMaterial::contact_area(PrintObject *object)
{
PrintObjectConfig conf = this->object_config;
// If user specified a custom angle threshold, convert it to radians.
float threshold_rad;
cout << conf.support_material_threshold << endl;
if (conf.support_material_threshold > 0) {
threshold_rad = static_cast<float>(Geometry::deg2rad(
conf.support_material_threshold.value + 1)); // +1 makes the threshold inclusive
// TODO @Samir55 add debug statetments.
}
// Build support on a build plate only? If so, then collect top surfaces into $buildplate_only_top_surfaces
// and subtract buildplate_only_top_surfaces from the contact surfaces, so
// there is no contact surface supported by a top surface.
bool buildplate_only =
(conf.support_material || conf.support_material_enforce_layers)
&& conf.support_material_buildplate_only;
Polygons buildplate_only_top_surfaces;
// Determine contact areas.
map<coordf_t, Polygons> contact;
map<coordf_t, Polygons> overhang; // This stores the actual overhang supported by each contact layer
for (int layer_id = 0; layer_id < object->layers.size(); layer_id++) {
// Note $layer_id might != $layer->id when raft_layers > 0
// so $layer_id == 0 means first object layer
// and $layer->id == 0 means first print layer (including raft).
// If no raft, and we're at layer 0, skip to layer 1
if (conf.raft_layers == 0 && layer_id == 0)
continue;
// With or without raft, if we're above layer 1, we need to quit
// support generation if supports are disabled, or if we're at a high
// enough layer that enforce-supports no longer applies.
if (layer_id > 0
&& !conf.support_material
&& (layer_id >= conf.support_material_enforce_layers))
// If we are only going to generate raft just check
// the 'overhangs' of the first object layer.
break;
Layer *layer = object->get_layer(layer_id);
if (conf.support_material_max_layers
&& layer_id > conf.support_material_max_layers)
break;
if (buildplate_only) {
// Collect the top surfaces up to this layer and merge them. TODO @Ask about this line.
Polygons projection_new;
for (auto const &region : layer->regions) {
SurfacesPtr top_surfaces = region->slices.filter_by_type(stTop);
for (auto polygon : p(top_surfaces)) {
projection_new.push_back(polygon);
}
}
if (!projection_new.empty()) {
// Merge the new top surfaces with the preceding top surfaces.
// Apply the safety offset to the newly added polygons, so they will connect
// with the polygons collected before,
// but don't apply the safety offset during the union operation as it would
// inflate the polygons over and over.
Polygons polygons = offset(projection_new, scale_(0.01));
append_polygons(buildplate_only_top_surfaces, polygons);
buildplate_only_top_surfaces = union_(buildplate_only_top_surfaces, 0);
}
}
// Detect overhangs and contact areas needed to support them.
Polygons m_overhang, m_contact;
if (layer_id == 0) {
// this is the first object layer, so we're here just to get the object
// footprint for the raft.
// we only consider contours and discard holes to get a more continuous raft.
for (auto const &contour : layer->slices.contours()) {
auto contour_clone = contour;
m_overhang.push_back(contour_clone);
}
Polygons polygons = offset(m_overhang, scale_(+SUPPORT_MATERIAL_MARGIN));
append_polygons(m_contact, polygons);
}
else {
Layer *lower_layer = object->get_layer(layer_id - 1);
for (auto layerm : layer->regions) {
float fw = layerm->flow(frExternalPerimeter).scaled_width();
Polygons difference;
// If a threshold angle was specified, use a different logic for detecting overhangs.
if ((conf.support_material && threshold_rad > 0)
|| layer_id <= conf.support_material_enforce_layers
|| (conf.raft_layers > 0 && layer_id
== 0)) { // TODO ASK @Samir why layer_id ==0 check , layer_id will never equal to zero
float d = 0;
float layer_threshold_rad = threshold_rad;
if (layer_id <= conf.support_material_enforce_layers) {
// Use ~45 deg number for enforced supports if we are in auto.
layer_threshold_rad = static_cast<float>(Geometry::deg2rad(89));
}
if (layer_threshold_rad > 0) {
d = scale_(lower_layer->height
* ((cos(layer_threshold_rad)) / (sin(layer_threshold_rad))));
}
// TODO Check.
difference = diff(
Polygons(layerm->slices),
offset(lower_layer->slices, +d)
);
// only enforce spacing from the object ($fw/2) if the threshold angle
// is not too high: in that case, $d will be very small (as we need to catch
// very short overhangs), and such contact area would be eaten by the
// enforced spacing, resulting in high threshold angles to be almost ignored
if (d > fw / 2) {
difference = diff(
offset(difference, d - fw / 2),
lower_layer->slices);
}
}
else {
difference = diff(
Polygons(layerm->slices),
offset(lower_layer->slices,
static_cast<const float>(+conf.get_abs_value("support_material_threshold", fw)))
);
// Collapse very tiny spots.
difference = offset2(difference, -fw / 10, +fw / 10);
// $diff now contains the ring or stripe comprised between the boundary of
// lower slices and the centerline of the last perimeter in this overhanging layer.
// Void $diff means that there's no upper perimeter whose centerline is
// outside the lower slice boundary, thus no overhang
}
if (conf.dont_support_bridges) {
// Compute the area of bridging perimeters.
Polygons bridged_perimeters;
{
auto bridge_flow = layerm->flow(FlowRole::frPerimeter, 1);
// Get the lower layer's slices and grow them by half the nozzle diameter
// because we will consider the upper perimeters supported even if half nozzle
// falls outside the lower slices.
Polygons lower_grown_slices;
{
coordf_t nozzle_diameter = this->config->nozzle_diameter
.get_at(static_cast<size_t>(layerm->region()->config.perimeter_extruder - 1));
lower_grown_slices = offset(
lower_layer->slices,
scale_(nozzle_diameter / 2)
);
}
// Get all perimeters as polylines.
// TODO: split_at_first_point() (called by as_polyline() for ExtrusionLoops)
// could split a bridge mid-way.
Polylines overhang_perimeters;
overhang_perimeters.push_back(layerm->perimeters.flatten().as_polyline());
// Only consider the overhang parts of such perimeters,
// overhangs being those parts not supported by
// workaround for Clipper bug, see Slic3r::Polygon::clip_as_polyline()
overhang_perimeters[0].translate(1, 0);
overhang_perimeters = diff_pl(overhang_perimeters, lower_grown_slices);
// Only consider straight overhangs.
Polylines new_overhangs_perimeters_polylines;
for (auto p : overhang_perimeters)
if (p.is_straight())
new_overhangs_perimeters_polylines.push_back(p);
overhang_perimeters = new_overhangs_perimeters_polylines;
new_overhangs_perimeters_polylines = Polylines();
// Only consider overhangs having endpoints inside layer's slices
for (auto &p : overhang_perimeters) {
p.extend_start(fw);
p.extend_end(fw);
}
for (auto p : overhang_perimeters) {
if (layer->slices.contains_b(p.first_point())
&& layer->slices.contains_b(p.last_point())) {
new_overhangs_perimeters_polylines.push_back(p);
}
}
overhang_perimeters = new_overhangs_perimeters_polylines;
new_overhangs_perimeters_polylines = Polylines();
// Convert bridging polylines into polygons by inflating them with their thickness.
{
// For bridges we can't assume width is larger than spacing because they
// are positioned according to non-bridging perimeters spacing.
coordf_t widths[] = {bridge_flow.scaled_width(),
bridge_flow.scaled_spacing(),
fw,
layerm->flow(FlowRole::frPerimeter).scaled_width()};
coordf_t w = *max_element(widths, widths + 4);
// Also apply safety offset to ensure no gaps are left in between.
// TODO CHeck this.
for (auto &p : overhang_perimeters) {
Polygons ps = union_(offset(p, w / 2 + 10));
for (auto ps_el : ps)
bridged_perimeters.push_back(ps_el);
}
}
}
if (1) {
// Remove the entire bridges and only support the unsupported edges.
ExPolygons bridges;
for (auto surface : layerm->fill_surfaces.filter_by_type(stBottomBridge)) {
if (surface->bridge_angle != -1) {
bridges.push_back(surface->expolygon);
}
}
ExPolygons ps;
for (auto p : bridged_perimeters)
ps.push_back(ExPolygon(p));
for (auto p : bridges)
ps.push_back(p);
// TODO ASK about this.
difference = diff(
difference,
to_polygons(ps),
true
);
// TODO Ask about this.
auto p_intersections = intersection(offset(layerm->unsupported_bridge_edges.polylines,
+scale_(SUPPORT_MATERIAL_MARGIN)),
to_polygons(bridges));
for (auto p: p_intersections) {
difference.push_back(p);
}
}
else {
// just remove bridged areas.
difference = diff(
difference,
layerm->bridged,
1
);
}
} // if ($conf->dont_support_bridges)
if (buildplate_only) {
// Don't support overhangs above the top surfaces.
// This step is done before the contact surface is calcuated by growing the overhang region.
difference = diff(difference, buildplate_only_top_surfaces);
}
if (difference.empty()) continue;
// NOTE: this is not the full overhang as it misses the outermost half of the perimeter width!
append_polygons(m_overhang, difference);
// Let's define the required contact area by using a max gap of half the upper
// extrusion width and extending the area according to the configured margin.
// We increment the area in steps because we don't want our support to overflow
// on the other side of the object (if it's very thin).
{
Polygons slices_margin = offset(lower_layer->slices, +fw / 2);
if (buildplate_only) {
// Trim the inflated contact surfaces by the top surfaces as well.
append_polygons(slices_margin, buildplate_only_top_surfaces);
slices_margin = union_(slices_margin);
}
// TODO Ask how to port this.
/*
for ($fw/2, map {scale MARGIN_STEP} 1..(MARGIN / MARGIN_STEP)) {
$diff = diff(
offset($diff, $_),
$slices_margin,
);
}
*/
}
append_polygons(m_contact, difference);
}
}
if (contact.empty())
continue;
// Now apply the contact areas to the layer were they need to be made.
{
// Get the average nozzle diameter used on this layer.
vector<double> nozzle_diameters;
for (auto region : layer->regions) {
nozzle_diameters.push_back(config->nozzle_diameter.get_at(static_cast<size_t>(
region->region()->config
.perimeter_extruder - 1)));
nozzle_diameters.push_back(config->nozzle_diameter.get_at(static_cast<size_t>(
region->region()->config
.infill_extruder - 1)));
nozzle_diameters.push_back(config->nozzle_diameter.get_at(static_cast<size_t>(
region->region()->config
.solid_infill_extruder - 1)));
}
int nozzle_diameters_count = static_cast<int>(nozzle_diameters.size() > 0 ? nozzle_diameters.size() : 1);
auto nozzle_diameter =
accumulate(nozzle_diameters.begin(), nozzle_diameters.end(), 0.0) / nozzle_diameters_count;
coordf_t contact_z = layer->print_z - contact_distance(layer->height, nozzle_diameter);
// Ignore this contact area if it's too low.
if (contact_z < conf.first_layer_height - EPSILON)
continue;
contact[contact_z] = m_contact;
overhang[contact_z] = m_overhang;
}
}
return make_pair(contact, overhang);
}
}

View File

@ -49,7 +49,8 @@ public:
object_config(print_object_config),
flow(flow),
first_layer_flow(first_layer_flow),
interface_flow(interface_flow)
interface_flow(interface_flow),
object(nullptr)
{}
void generate()
@ -64,364 +65,16 @@ public:
void generate_base_layers()
{}
void generate_toolpaths()
{}
void generate_pillars_shape()
{}
pair<Polygons, Polygons> contact_area(PrintObject *object)
{
PrintObjectConfig conf = this->object_config;
pair<map<coordf_t, Polygons>, map<coordf_t, Polygons>> contact_area(PrintObject *object);
// If user specified a custom angle threshold, convert it to radians.
float threshold_rad;
cout << conf.support_material_threshold << endl;
if (conf.support_material_threshold > 0) {
threshold_rad = static_cast<float>(Geometry::deg2rad(
conf.support_material_threshold.value + 1)); // +1 makes the threshold inclusive
// TODO @Samir55 add debug statetments.
}
// Build support on a build plate only? If so, then collect top surfaces into $buildplate_only_top_surfaces
// and subtract buildplate_only_top_surfaces from the contact surfaces, so
// there is no contact surface supported by a top surface.
bool buildplate_only =
(conf.support_material || conf.support_material_enforce_layers)
&& conf.support_material_buildplate_only;
Surfaces buildplate_only_top_surfaces;
// Determine contact areas.
Polygons contact;
Polygons overhang; // This stores the actual overhang supported by each contact layer
for (int layer_id = 0; layer_id < object->layers.size(); layer_id++) {
// Note $layer_id might != $layer->id when raft_layers > 0
// so $layer_id == 0 means first object layer
// and $layer->id == 0 means first print layer (including raft).
// If no raft, and we're at layer 0, skip to layer 1
if (conf.raft_layers == 0 && layer_id == 0)
continue;
// With or without raft, if we're above layer 1, we need to quit
// support generation if supports are disabled, or if we're at a high
// enough layer that enforce-supports no longer applies.
if (layer_id > 0
&& !conf.support_material
&& (layer_id >= conf.support_material_enforce_layers))
// If we are only going to generate raft just check
// the 'overhangs' of the first object layer.
break;
auto layer = object->get_layer(layer_id);
if (conf.support_material_max_layers
&& layer_id > conf.support_material_max_layers)
break;
ExPolygons buildplate_only_top_surfaces_polygons;
if (buildplate_only) {
// Collect the top surfaces up to this layer and merge them. TODO @Ask about this line.
SurfacesPtr projection_new;
for (auto const &region : layer->regions) {
SurfacesPtr top_surfaces = region->slices.filter_by_type(stTop);
for (auto top_surface : top_surfaces) {
projection_new.push_back(top_surface);
}
}
if (!projection_new.empty()) {
// Merge the new top surfaces with the preceding top surfaces.
// Apply the safety offset to the newly added polygons, so they will connect
// with the polygons collected before,
// but don't apply the safety offset during the union operation as it would
// inflate the polygons over and over.
for (Surface *surface : projection_new) {
Surfaces s = offset(*surface, scale_(0.01));
for (auto el : s)
buildplate_only_top_surfaces.push_back(el);
}
// TODO @Ask about this
buildplate_only_top_surfaces_polygons = union_ex(buildplate_only_top_surfaces, 0);
}
}
// Detect overhangs and contact areas needed to support them.
if (layer_id == 0) {
// this is the first object layer, so we're here just to get the object
// footprint for the raft.
// we only consider contours and discard holes to get a more continuous raft.
for (auto const &contour : layer->slices.contours()) {
auto contour_clone = contour;
overhang.push_back(contour_clone);
}
Polygons ps = offset(overhang, scale_(+SUPPORT_MATERIAL_MARGIN));
for (auto p : ps)
contact.push_back(p);
}
else {
Layer *lower_layer = object->get_layer(layer_id - 1);
for (auto layerm : layer->regions) {
float fw = layerm->flow(frExternalPerimeter).scaled_width();
Polygons difference;
// If a threshold angle was specified, use a different logic for detecting overhangs.
if ((conf.support_material && threshold_rad > 0)
|| layer_id <= conf.support_material_enforce_layers
|| (conf.raft_layers > 0 && layer_id == 0)) {
float d = 0;
float layer_threshold_rad = threshold_rad;
if (layer_id <= conf.support_material_enforce_layers) {
// Use ~45 deg number for enforced supports if we are in auto.
layer_threshold_rad = Geometry::deg2rad(89);
}
if (layer_threshold_rad > 0) {
d = scale_(lower_layer->height
* ((cos(layer_threshold_rad)) / (sin(layer_threshold_rad))));
}
// TODO Ask about this.
difference = diff(
layerm->slices,
offset(lower_layer->slices, +d)
);
// only enforce spacing from the object ($fw/2) if the threshold angle
// is not too high: in that case, $d will be very small (as we need to catch
// very short overhangs), and such contact area would be eaten by the
// enforced spacing, resulting in high threshold angles to be almost ignored
if (d > fw / 2) {
difference = diff(
offset(difference, d - fw / 2),
lower_layer->slices);
}
}
else {
difference = diff(
layerm->slices,
offset(lower_layer->slices,
static_cast<const float>(+conf.get_abs_value("support_material_threshols", fw)))
);
// Collapse very tiny spots.
difference = offset2(difference, -fw / 10, +fw / 10);
// $diff now contains the ring or stripe comprised between the boundary of
// lower slices and the centerline of the last perimeter in this overhanging layer.
// Void $diff means that there's no upper perimeter whose centerline is
// outside the lower slice boundary, thus no overhang
}
if (conf.dont_support_bridges) {
// Compute the area of bridging perimeters.
Polygons bridged_perimeters;
{
auto bridge_flow = layerm->flow(FlowRole::frPerimeter, 1);
// Get the lower layer's slices and grow them by half the nozzle diameter
// because we will consider the upper perimeters supported even if half nozzle
// falls outside the lower slices.
Polygons lower_grown_slices;
{
coordf_t nozzle_diameter = this->config->nozzle_diameter
.get_at(layerm->region()->config.perimeter_extruder - 1);
lower_grown_slices = offset(
lower_layer->slices,
scale_(nozzle_diameter / 2)
);
}
// Get all perimeters as polylines.
// TODO: split_at_first_point() (called by as_polyline() for ExtrusionLoops)
// could split a bridge mid-way.
Polyline overhang_perimeters_polyline = layerm->perimeters.flatten().as_polyline();
Polylines overhang_perimeters_polylines;
// Only consider the overhang parts of such perimeters,
// overhangs being those parts not supported by
// workaround for Clipper bug, see Slic3r::Polygon::clip_as_polyline()
// ASk About htis.
overhang_perimeters_polyline.translate(1, 0);
Polylines ps = diff_pl(overhang_perimeters_polyline, lower_grown_slices);
for (const auto &p : ps) {
overhang_perimeters_polylines.push_back(p);
}
// Only consider straight overhangs.
Polylines new_overhangs_perimeters_polylines;
for (auto p : overhang_perimeters_polylines) {
if (p.is_straight())
new_overhangs_perimeters_polylines.push_back(p);
}
overhang_perimeters_polylines = new_overhangs_perimeters_polylines;
new_overhangs_perimeters_polylines = Polylines();
// Only consider overhangs having endpoints inside layer's slices
for (auto &p : overhang_perimeters_polylines) {
p.extend_start(fw);
p.extend_end(fw);
}
for (auto p : overhang_perimeters_polylines) {
if (layer->slices.contains_b(p.first_point())
&& layer->slices.contains_b(p.last_point())) {
new_overhangs_perimeters_polylines.push_back(p);
}
}
overhang_perimeters_polylines = new_overhangs_perimeters_polylines;
new_overhangs_perimeters_polylines = Polylines();
// Convert bridging polylines into polygons by inflating them with their thickness.
{
// For bridges we can't assume width is larger than spacing because they
// are positioned according to non-bridging perimeters spacing.
coordf_t widths[] = {bridge_flow.scaled_width(),
bridge_flow.scaled_spacing(),
fw,
layerm->flow(FlowRole::frPerimeter).scaled_width()};
coordf_t w = *max_element(widths, widths + 4);
// Also apply safety offset to ensure no gaps are left in between.
for (auto &p : overhang_perimeters_polylines) {
Polygons ps = union_(offset(p, w / 2 + 10));
for (auto ps_el : ps)
bridged_perimeters.push_back(ps_el);
}
}
}
if (1) {
// Remove the entire bridges and only support the unsupported edges.
ExPolygons bridges;
for (auto surface : layerm->fill_surfaces.filter_by_type(stBottomBridge)) {
if (surface->bridge_angle != -1) {
bridges.push_back(surface->expolygon);
}
}
ExPolygons ps;
for (auto p : bridged_perimeters)
ps.push_back(ExPolygon(p));
for (auto p : bridges)
ps.push_back(p);
// TODO ASK about this.
difference = diff(
difference,
to_polygons(ps),
true
);
// TODO Ask about this.
auto p_intersections = intersection(offset(layerm->unsupported_bridge_edges.polylines,
+scale_(SUPPORT_MATERIAL_MARGIN)),
to_polygons(bridges));
for (auto p: p_intersections) {
difference.push_back(p);
}
}
else {
// just remove bridged areas.
difference = diff(
difference,
layerm->bridged,
1
);
}
} // if ($conf->dont_support_bridges)
if (buildplate_only) {
// Don't support overhangs above the top surfaces.
// This step is done before the contact surface is calcuated by growing the overhang region.
// TODO Ask about this.
difference = diff(difference, to_polygons(buildplate_only_top_surfaces_polygons));
}
if (difference.empty()) continue;
// NOTE: this is not the full overhang as it misses the outermost half of the perimeter width!
for (auto p : difference) {
overhang.push_back(p);
}
// Let's define the required contact area by using a max gap of half the upper
// extrusion width and extending the area according to the configured margin.
// We increment the area in steps because we don't want our support to overflow
// on the other side of the object (if it's very thin).
{
auto slices_margin = offset(lower_layer->slices, +fw / 2);
if (buildplate_only) {
// TODO Ask about this.
// Trim the inflated contact surfaces by the top surfaces as well.
for (auto s_p : to_polygons(buildplate_only_top_surfaces)) {
slices_margin.push_back(s_p);
}
slices_margin = union_(slices_margin);
}
// TODO Ask how to port this.
/*
for ($fw/2, map {scale MARGIN_STEP} 1..(MARGIN / MARGIN_STEP)) {
$diff = diff(
offset($diff, $_),
$slices_margin,
);
}
*/
}
for (auto p : difference)
contact.push_back(p);
}
}
if (contact.empty())
continue;
// Now apply the contact areas to the layer were they need to be made.
{
// Get the average nozzle diameter used on this layer.
vector<double> nozzle_diameters;
for (auto region : layer->regions) {
nozzle_diameters.push_back(config->nozzle_diameter.get_at(static_cast<size_t>(
region->region()->config
.perimeter_extruder - 1)));
nozzle_diameters.push_back(config->nozzle_diameter.get_at(static_cast<size_t>(
region->region()->config
.infill_extruder - 1)));
nozzle_diameters.push_back(config->nozzle_diameter.get_at(static_cast<size_t>(
region->region()->config
.solid_infill_extruder - 1)));
}
auto nozzle_diameter =
accumulate(nozzle_diameters.begin(), nozzle_diameters.end(), 0.0) / nozzle_diameters.size();
auto contact_z = layer->print_z - contact_distance(layer->height, nozzle_diameter);
// Ignore this contact area if it's too low.
if (contact_z < conf.first_layer_height - EPSILON)
continue;
// TODO ASK how to port this.
/*
$contact{$contact_z} = [ @contact ];
$overhang{$contact_z} = [ @overhang ];
require "Slic3r/SVG.pm";
Slic3r::SVG::output("out\\contact_" . $contact_z . ".svg",
green_expolygons => union_ex($buildplate_only_top_surfaces),
blue_expolygons => union_ex(\@contact),
red_expolygons => union_ex(\@overhang),
);
*/
}
}
return make_pair(contact, overhang);
}
void generate_toolpaths(PrintObject *object,
map<coordf_t, Polygons> overhang,
map<coordf_t, Polygons> contact,
map<int, Polygons> interface,
map<int, Polygons> base);
// Is this expolygons or polygons?
map<coordf_t, Polygons> object_top(PrintObject *object, map<coordf_t, Polygons> *contact);
@ -441,48 +94,84 @@ public:
coordf_t contact_distance(coordf_t layer_height, coordf_t nozzle_diameter);
Polygons p(SurfacesPtr &surfaces);
Polygon create_circle(coordf_t radius);
void append_polygons(Polygons &dst, Polygons &src);
void process_layer(int layer_id)
{
SupportLayer *layer = this->object->support_layers[layer_id];
coordf_t z = layer->print_z;
// We redefine flows locally by applyinh this layer's height.
auto _flow = *flow;
auto _interface_flow = *interface_flow;
_flow.height = static_cast<float>(layer->height);
_interface_flow.height = static_cast<float>(layer->height);
Polygons overhang = this->overhang.count(z) > 0 ? this->overhang[z] : Polygons();
Polygons contact = this->contact.count(z) > 0 ? this->contact[z] : Polygons();
Polygons interface = interface[layer_id];
Polygons base = base[layer_id];
// TODO add the equivalent debug code.
// Islands.
// layer->support_islands.append()
}
private:
// Used during generate_toolpaths function.
PrintObject *object;
map<coordf_t, Polygons> overhang;
map<coordf_t, Polygons> contact;
map<int, Polygons> interface;
map<int, Polygons> base;
};
//// TO Be converted to catch.
//class SupportMaterialTests
//{
//public:
// bool test_1()
// {
// // Create a mesh & modelObject.
// TriangleMesh mesh = TriangleMesh::make_cube(20, 20, 20);
//
// // Create modelObject.
// Model model = Model();
// ModelObject *object = model.add_object();
// object->add_volume(mesh);
// model.add_default_instances();
//
// // Align to origin.
// model.align_instances_to_origin();
//
// // Create Print.
// Print print = Print();
//
// // Configure the printObjectConfig.
// print.default_object_config.set_deserialize("support_material", "1");
// print.default_object_config.set_deserialize("layer_height", "0.2");
// print.config.set_deserialize("first_layer_height", "0.3");
//
// vector<float> contact_z;
// vector<float> top_z;
// contact_z.push_back(1.9);
// top_z.push_back(1.9);
//
// // Add the modelObject.
// print.add_model_object(model.objects[0]);
//
// // Create new supports.
// SupportMaterial support = SupportMaterial(&print.config, &print.objects.front()->config);
//
// vector<coordf_t>
// support_z = support.support_layers_z(contact_z, top_z, print.default_object_config.layer_height);
//
// To Be converted to catch.
class SupportMaterialTests
{
public:
bool test_1()
{
// Create a mesh & modelObject.
TriangleMesh mesh = TriangleMesh::make_cube(20, 20, 20);
// Create modelObject.
Model model = Model();
ModelObject *object = model.add_object();
object->add_volume(mesh);
model.add_default_instances();
// Align to origin.
model.align_instances_to_origin();
// Create Print.
Print print = Print();
// Configure the printObjectConfig.
print.default_object_config.set_deserialize("support_material", "1");
print.default_object_config.set_deserialize("layer_height", "0.2");
print.config.set_deserialize("first_layer_height", "0.3");
vector<float> contact_z;
vector<float> top_z;
contact_z.push_back(1.9);
top_z.push_back(1.9);
// Add the modelObject.
print.add_model_object(model.objects[0]);
// Create new supports.
SupportMaterial support = SupportMaterial(&print.config, &print.objects.front()->config);
vector<coordf_t>
support_z = support.support_layers_z(contact_z, top_z, print.default_object_config.layer_height);
// bool
// is_1 = (support_z[0] == print.default_object_config.first_layer_height); // 'first layer height is honored'.
//
@ -515,22 +204,22 @@ public:
// wrong_top_spacing = 1;
// }
// bool is_4 = !wrong_top_spacing; // 'layers above top surfaces are spaced correctly'
//
// /* Test Also with this
// $config->set('first_layer_height', 0.4);
// $test->();
//
// $config->set('layer_height', $config->nozzle_diameter->[0]);
// $test->();
// */
// }
//
// bool test_2()
// {
//
// }
//
//};
/* Test Also with this
$config->set('first_layer_height', 0.4);
$test->();
$config->set('layer_height', $config->nozzle_diameter->[0]);
$test->();
*/
}
bool test_2()
{
}
};
}