mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-14 15:25:55 +08:00
Porting process_layer function and start testing.
This commit is contained in:
parent
4d1e4eb252
commit
76c686b2ca
@ -2,6 +2,14 @@
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
|
||||
PolylineCollection _fill_surface(Fill *fill, Surface *surface)
|
||||
{
|
||||
PolylineCollection ps;
|
||||
ps.polylines = fill->fill_surface(*surface);
|
||||
return ps;
|
||||
}
|
||||
|
||||
void
|
||||
SupportMaterial::generate_toolpaths(PrintObject *object,
|
||||
map<coordf_t, Polygons> overhang,
|
||||
@ -13,35 +21,35 @@ SupportMaterial::generate_toolpaths(PrintObject *object,
|
||||
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);
|
||||
toolpaths_params params;
|
||||
params.contact_loops = 1;
|
||||
params.circle_radius = 1.5 * interface_flow->scaled_width();
|
||||
params.circle_distance = 3 * params.circle_radius;
|
||||
params.circle = create_circle(params.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);
|
||||
params.pattern = object_config->support_material_pattern.value;
|
||||
params.angles.push_back(object_config->support_material_angle.value);
|
||||
|
||||
if (pattern == smpRectilinearGrid) {
|
||||
pattern = smpRectilinear;
|
||||
angles.push_back(angles[0] + 90);
|
||||
if (params.pattern == smpRectilinearGrid) {
|
||||
params.pattern = smpRectilinear;
|
||||
params.angles.push_back(params.angles[0] + 90);
|
||||
}
|
||||
else if (pattern == smpPillars) {
|
||||
pattern = smpHoneycomb;
|
||||
else if (params.pattern == smpPillars) {
|
||||
params.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;
|
||||
params.interface_angle = object_config->support_material_angle.value + 90;
|
||||
params.interface_spacing = object_config->support_material_interface_spacing.value + interface_flow->spacing();
|
||||
params.interface_density = params.interface_spacing == 0 ? 1 : interface_flow->spacing() / params.interface_spacing;
|
||||
params.support_spacing = object_config->support_material_spacing.value + flow->spacing();
|
||||
params.support_density = params.support_spacing == 0 ? 1 : flow->spacing() / params.support_spacing;
|
||||
|
||||
parallelize<size_t>(
|
||||
0,
|
||||
object->support_layers.size() - 1,
|
||||
boost::bind(&SupportMaterial::process_layer, this, _1),
|
||||
boost::bind(&SupportMaterial::process_layer, this, _1, params),
|
||||
this->config->threads.value
|
||||
);
|
||||
}
|
||||
@ -571,8 +579,8 @@ SupportMaterial::object_top(PrintObject *object, map<coordf_t, Polygons> *contac
|
||||
|
||||
void
|
||||
SupportMaterial::generate_pillars_shape(const map<coordf_t, Polygons> &contact,
|
||||
const vector<coordf_t> &support_z,
|
||||
map<int, Polygons> &shape)
|
||||
const vector<coordf_t> &support_z,
|
||||
map<int, Polygons> &shape)
|
||||
{
|
||||
// This prevents supplying an empty point set to BoundingBox constructor.
|
||||
if (contact.empty()) return;
|
||||
@ -758,9 +766,9 @@ SupportMaterial::generate_interface_layers(vector<coordf_t> support_z,
|
||||
|
||||
void
|
||||
SupportMaterial::generate_bottom_interface_layers(const vector<coordf_t> &support_z,
|
||||
map<int, Polygons> &base,
|
||||
map<coordf_t, Polygons> &top,
|
||||
map<int, Polygons> &interface)
|
||||
map<int, Polygons> &base,
|
||||
map<coordf_t, Polygons> &top,
|
||||
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)
|
||||
@ -898,6 +906,283 @@ SupportMaterial::clip_with_object(map<int, Polygons> &support, vector<coordf_t>
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
SupportMaterial::process_layer(int layer_id, toolpaths_params params)
|
||||
{
|
||||
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 = this->interface.count(layer_id) > 0 ? this->interface[layer_id] : Polygons();
|
||||
Polygons base = this->base.count(layer_id) > 0 ? this->base[layer_id] : Polygons();
|
||||
|
||||
// Islands.
|
||||
{
|
||||
Polygons ps;
|
||||
append_to(ps, base);
|
||||
append_to(ps, contact);
|
||||
append_to(ps, interface);
|
||||
layer->support_islands.append(union_ex(ps));
|
||||
}
|
||||
|
||||
// Contact.
|
||||
Polygons contact_infill;
|
||||
if (object_config->support_material_interface_layers.value == 0) {
|
||||
// If no interface layers were requested we treat the contact layer
|
||||
// exactly as a generic base layer.
|
||||
append_to(base, contact);
|
||||
}
|
||||
else if (!contact.empty() && params.contact_loops > 0) { // Generate the outermost loop.
|
||||
// Find the centerline of the external loop (or any other kind of extrusions should the loop be skipped).
|
||||
contact = offset(contact, -_interface_flow.scaled_width() / 2);
|
||||
|
||||
Polygons loops0;
|
||||
{
|
||||
// Find centerline of the external loop of the contours.
|
||||
auto external_loops = contact;
|
||||
|
||||
// Only consider the loops facing the overhang.
|
||||
{
|
||||
auto overhang_with_margin = offset(overhang, +_interface_flow.scaled_width() / 2);
|
||||
{
|
||||
Polygons ps;
|
||||
for (auto p : external_loops) {
|
||||
if (!intersection_pl(
|
||||
p.split_at_first_point(),
|
||||
overhang_with_margin).empty()
|
||||
)
|
||||
ps.push_back(p);
|
||||
}
|
||||
external_loops = ps;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply a pattern to the loop.
|
||||
Points positions;
|
||||
for (auto p : external_loops)
|
||||
append_to(positions, Polygon(p).equally_spaced_points(params.circle_distance));
|
||||
Polygons circles;
|
||||
for (auto pos : positions) {
|
||||
circles.push_back(params.circle);
|
||||
circles.back().translate(pos.x, pos.y);
|
||||
}
|
||||
loops0 = diff(
|
||||
external_loops,
|
||||
circles
|
||||
);
|
||||
}
|
||||
|
||||
// TODO Revise the loop range.
|
||||
// Make more loops.
|
||||
auto loops = loops0;
|
||||
for (int i = 2; i <= params.contact_loops; i++) {
|
||||
auto d = (i - 1) * _interface_flow.scaled_spacing();
|
||||
append_to(loops,
|
||||
offset2(loops0,
|
||||
-d - 0.5 * _interface_flow.scaled_spacing(),
|
||||
+0.5 * _interface_flow.scaled_spacing()));
|
||||
}
|
||||
|
||||
// Clip such loops to the side oriented towards the object.
|
||||
Polylines ps;
|
||||
for (auto p : loops)
|
||||
ps.push_back(p.split_at_first_point());
|
||||
|
||||
auto new_loops = intersection_pl(
|
||||
ps,
|
||||
offset(overhang, scale_(SUPPORT_MATERIAL_MARGIN))
|
||||
);
|
||||
|
||||
// Add the contact infill area to the interface area
|
||||
// note that growing loops by $circle_radius ensures no tiny
|
||||
// extrusions are left inside the circles; however it creates
|
||||
// a very large gap between loops and contact_infill, so maybe another
|
||||
// solution should be found to achieve both goals.
|
||||
{
|
||||
Polygons ps;
|
||||
for (auto pl : new_loops)
|
||||
append_to(ps, offset(pl, params.circle_radius * 1.1));
|
||||
|
||||
contact_infill = diff(
|
||||
contact,
|
||||
ps
|
||||
);
|
||||
}
|
||||
|
||||
// Transform loops into ExtrusionPath objects.
|
||||
auto mm3_per_mm = _interface_flow.mm3_per_mm();
|
||||
ExtrusionPaths loops_extrusion_paths;
|
||||
for (auto l : new_loops) {
|
||||
ExtrusionPath extrusion_path(erSupportMaterialInterface);
|
||||
extrusion_path.polyline = l;
|
||||
extrusion_path.mm3_per_mm = mm3_per_mm;
|
||||
extrusion_path.width = _interface_flow.width;
|
||||
extrusion_path.height = layer->height;
|
||||
loops_extrusion_paths.push_back(extrusion_path);
|
||||
}
|
||||
|
||||
layer->support_interface_fills.append(loops_extrusion_paths);
|
||||
}
|
||||
|
||||
// Allocate the fillers exclusively in the worker threads! Don't allocate them at the main thread,
|
||||
// as Perl copies the C++ pointers by default, so then the C++ objects are shared between threads!
|
||||
map<string, Fill *> fillers;
|
||||
fillers["interface"] = Fill::new_from_type("rectilinear");
|
||||
fillers["support"] = Fill::new_from_type(InfillPattern(params.pattern)); // FIXME @Samir55
|
||||
|
||||
BoundingBox bounding_box = object->bounding_box();
|
||||
fillers["interface"]->bounding_box = bounding_box;
|
||||
fillers["support"]->bounding_box = bounding_box;
|
||||
|
||||
// Interface and contact infill.
|
||||
if (!interface.empty() || !contact_infill.empty()) {
|
||||
// Make interface layers alternate angles by 90 degrees.
|
||||
double alternate_angle = params.interface_angle + (90 * ((layer_id + 1) % 2));
|
||||
fillers["interface"]->angle = static_cast<float>(Geometry::deg2rad(alternate_angle));
|
||||
fillers["interface"]->min_spacing = _interface_flow.spacing();
|
||||
|
||||
// Find centerline of the external loop.
|
||||
interface = offset2(interface, +SCALED_EPSILON, -(SCALED_EPSILON + _interface_flow.scaled_width() / 2));
|
||||
|
||||
// Join regions by offsetting them to ensure they're merged.
|
||||
{
|
||||
Polygons ps;
|
||||
append_to(ps, interface);
|
||||
append_to(ps, contact_infill);
|
||||
interface = offset(ps, SCALED_EPSILON);
|
||||
}
|
||||
|
||||
// turn base support into interface when it's contained in our holes
|
||||
// (this way we get wider interface anchoring).
|
||||
{
|
||||
Polygons ps = interface;
|
||||
interface = Polygons();
|
||||
for (auto p: ps) {
|
||||
if (p.is_clockwise()) {
|
||||
Polygon p2 = p;
|
||||
p2.make_counter_clockwise();
|
||||
if (diff(Polygons({p2}), base, 1).empty())
|
||||
continue;
|
||||
interface.push_back(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
base = diff(base, interface);
|
||||
|
||||
ExtrusionPaths paths;
|
||||
ExPolygons expolygons = union_ex(interface);
|
||||
for (auto expolygon : expolygons) {
|
||||
Surface surface(stInternal, expolygon);
|
||||
fillers["interface"]->density = params.interface_density;
|
||||
fillers["interface"]->complete = true;
|
||||
// TODO What layer height come from FIXME. or Polyline collection
|
||||
Polylines ps = fillers["interface"]->fill_surface(surface);
|
||||
|
||||
auto mm3_per_mm = _interface_flow.mm3_per_mm();
|
||||
|
||||
for (auto p : ps) {
|
||||
ExtrusionPath extrusion_path(erSupportMaterialInterface);
|
||||
extrusion_path.polyline = p;
|
||||
extrusion_path.mm3_per_mm = mm3_per_mm;
|
||||
extrusion_path.width = _interface_flow.width;
|
||||
extrusion_path.height = layer->height;
|
||||
paths.push_back(extrusion_path);
|
||||
}
|
||||
}
|
||||
|
||||
layer->support_interface_fills.append(paths);
|
||||
}
|
||||
|
||||
// Support or flange
|
||||
if (!base.empty()) {
|
||||
Fill *filler = fillers["support"];
|
||||
filler->angle = static_cast<float>(Geometry::deg2rad(params.angles[layer_id % int(params.angles.size())]));
|
||||
|
||||
// We don't use $base_flow->spacing because we need a constant spacing
|
||||
// value that guarantees that all layers are correctly aligned.
|
||||
filler->min_spacing = flow->spacing();
|
||||
|
||||
auto density = params.support_density;
|
||||
Flow *base_flow = &_flow;
|
||||
|
||||
// Find centerline of the external loop/extrusions.
|
||||
Polygons to_infill = offset2(base, +SCALED_EPSILON, -(SCALED_EPSILON + _flow.scaled_width() / 2));
|
||||
ExPolygons new_to_infill;
|
||||
|
||||
ExtrusionPaths paths;
|
||||
|
||||
// Base flange.
|
||||
if (layer_id == 0) {
|
||||
filler = fillers["interface"];
|
||||
filler->angle = static_cast<float>(Geometry::deg2rad(object_config->support_material_angle.value + 90));
|
||||
density = 0.5;
|
||||
base_flow = first_layer_flow;
|
||||
|
||||
// Use the proper spacing for first layer as we don't need to align
|
||||
// its pattern to the other layers.
|
||||
filler->min_spacing = base_flow->spacing();
|
||||
|
||||
// Subtract brim so that it goes around the object fully (and support gets its own brim).
|
||||
if (config->brim_width.value > 0) {
|
||||
float d = +scale_(config->brim_width.value * 2);
|
||||
|
||||
new_to_infill = diff_ex(
|
||||
to_infill,
|
||||
offset(to_polygons(object->get_layer(0)->slices), d)
|
||||
);
|
||||
}
|
||||
else {
|
||||
new_to_infill = union_ex(to_infill);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Draw a perimeter all around support infill.
|
||||
// TODO: use brim ordering algorithm.
|
||||
auto mm3_per_mm = _flow.mm3_per_mm();
|
||||
for (auto p : to_infill) {
|
||||
ExtrusionPath extrusionPath(erSupportMaterial);
|
||||
extrusionPath.polyline = p.split_at_first_point();
|
||||
extrusionPath.mm3_per_mm = mm3_per_mm;
|
||||
extrusionPath.width = _flow.width;
|
||||
extrusionPath.height = layer->height;
|
||||
|
||||
paths.push_back(extrusionPath);
|
||||
}
|
||||
|
||||
// TODO: use offset2_ex()
|
||||
new_to_infill = offset_ex(to_infill, -_flow.scaled_spacing());
|
||||
}
|
||||
|
||||
auto mm3_per_mm = base_flow->mm3_per_mm();
|
||||
for (const auto &expolygon : new_to_infill) {
|
||||
Surface surface(stInternal, expolygon);
|
||||
filler->density = static_cast<float>(density);
|
||||
filler->complete = true;
|
||||
// TODO What layer height come from FIXME. or Polyline collection
|
||||
Polylines ps = filler->fill_surface(surface);
|
||||
|
||||
for (auto pl : ps) {
|
||||
ExtrusionPath extrusionPath(erSupportMaterial);
|
||||
extrusionPath.polyline = pl;
|
||||
extrusionPath.mm3_per_mm = mm3_per_mm;
|
||||
extrusionPath.width = base_flow->width;
|
||||
extrusionPath.height = static_cast<float>(layer->height);
|
||||
|
||||
paths.push_back(extrusionPath);
|
||||
}
|
||||
}
|
||||
|
||||
layer->support_fills.append(paths);
|
||||
}
|
||||
}
|
||||
|
||||
Polygons
|
||||
SupportMaterial::p(SurfacesPtr &surfaces)
|
||||
{
|
||||
|
@ -12,9 +12,9 @@
|
||||
#include "Geometry.hpp"
|
||||
#include "Print.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "SupportMaterial.hpp"
|
||||
#include "ExPolygon.hpp"
|
||||
#include "SVG.hpp"
|
||||
#include <libslic3r/Fill/Fill.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -28,6 +28,35 @@ constexpr coordf_t PILLAR_SIZE = 2.5;
|
||||
|
||||
constexpr coordf_t PILLAR_SPACING = 10;
|
||||
|
||||
struct toolpaths_params
|
||||
{
|
||||
int contact_loops;
|
||||
coordf_t circle_radius;
|
||||
coordf_t circle_distance;
|
||||
Polygon circle;
|
||||
SupportMaterialPattern pattern;
|
||||
vector<int> angles;
|
||||
double interface_angle;
|
||||
double interface_spacing;
|
||||
float interface_density;
|
||||
double support_spacing;
|
||||
double support_density;
|
||||
|
||||
toolpaths_params(int contact_loops = 0,
|
||||
coordf_t circle_radius = 0,
|
||||
coordf_t circle_distance = 0,
|
||||
const Polygon &circle = Polygon(),
|
||||
const SupportMaterialPattern &pattern = SupportMaterialPattern(),
|
||||
const vector<int> &angles = vector<int>())
|
||||
: contact_loops(contact_loops),
|
||||
circle_radius(circle_radius),
|
||||
circle_distance(circle_distance),
|
||||
circle(circle),
|
||||
pattern(pattern),
|
||||
angles(angles)
|
||||
{}
|
||||
};
|
||||
|
||||
class SupportMaterial
|
||||
{
|
||||
public:
|
||||
@ -50,29 +79,6 @@ public:
|
||||
object(nullptr)
|
||||
{}
|
||||
|
||||
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()
|
||||
|
||||
}
|
||||
|
||||
void generate_toolpaths(PrintObject *object,
|
||||
map<coordf_t, Polygons> overhang,
|
||||
map<coordf_t, Polygons> contact,
|
||||
@ -120,6 +126,8 @@ public:
|
||||
// leaving a thin gap between object and support in the XY plane.
|
||||
void clip_with_object(map<int, Polygons> &support, vector<coordf_t> support_z, PrintObject &object);
|
||||
|
||||
void process_layer(int layer_id, toolpaths_params params);
|
||||
|
||||
private:
|
||||
coordf_t get_max_layer_height(PrintObject *object);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user