Files
OrcaSlicer/src/libslic3r/ContourZ.cpp

233 lines
7.0 KiB
C++

#include "Exception.hpp"
#include "ExtrusionEntity.hpp"
#include "ExtrusionEntityCollection.hpp"
#include "Layer.hpp"
#include "Point.hpp"
#include "Print.hpp"
#include "SLA/IndexedMesh.hpp"
#include "libslic3r.h"
#include <cfloat>
#include <cmath>
#include <initializer_list>
#include <string>
namespace Slic3r {
static void contour_extrusion_entity(LayerRegion *region, const sla::IndexedMesh &mesh, ExtrusionEntity *extr);
static double follow_slope_down(double angle_rad, double dist)
{
return -dist * std::sin(angle_rad);
}
static double slope_from_normal(const Eigen::Vector3d& normal)
{
// Ensure the normal is normalized
Eigen::Vector3d n = normal.normalized();
// Compute angle between normal and z-axis
double angle_rad = std::acos(std::abs(n.z())); // angle between normal and vertical
return angle_rad;
}
static bool contour_extrusion_path(LayerRegion *region, const sla::IndexedMesh &mesh, ExtrusionPath &path)
{
if (region->region().config().zaa_region_disable) {
return false;
}
if (path.role() != erTopSolidInfill && path.role() != erIroning && path.role() != erExternalPerimeter && path.role() != erPerimeter) {
return false;
}
Layer *layer = region->layer();
coordf_t mesh_z = layer->print_z + mesh.ground_level();
coordf_t min_z = layer->object()->config().zaa_min_z;
const Points3 &points = path.polyline.points;
double resolution_mm = 0.1;
coordf_t height = layer->height;
double minimize_perimeter_height_angle = region->region().config().zaa_minimize_perimeter_height;
Pointf3s contoured_points;
bool was_contoured = false;
for (Points3::const_iterator it = points.begin(); it != points.end()-1; ++it) {
Vec2d p1d(unscale_(it->x()), unscale_(it->y()));
Vec2d p2d(unscale_((it+1)->x()), unscale_((it+1)->y()));
Linef line(p1d, p2d);
double length_mm = line.length();
int num_segments = int(std::ceil(length_mm / resolution_mm));
Vec2d delta = line.vector();
if (num_segments == 0) {
continue;
}
for (int i = 0; i < num_segments + 1; i++) {
Vec2d p = p1d + delta * i / num_segments;
coordf_t x = p.x();
coordf_t y = p.y();
sla::IndexedMesh::hit_result hit_up = mesh.query_ray_hit({x, y, mesh_z}, {0.0, 0.0, 1.0});
sla::IndexedMesh::hit_result hit_down = mesh.query_ray_hit({x, y, mesh_z}, {0.0, 0.0, -1.0});
double up = hit_up.distance();
double down = hit_down.distance();
double d = up < down ? up : -down;
const Vec3d &normal = (up < down ? hit_up : hit_down).normal();
double max_up = min_z;
double min_down = -(height - min_z);
double half_width = path.width / 2.0;
if (path.role() == erIroning) {
max_up = height;
min_down = -(height + 0.1);
}
double slope_rad = slope_from_normal(normal);
double slope_degrees = slope_rad * 180.0 / M_PI;
if (d > min_down && minimize_perimeter_height_angle > 0 && minimize_perimeter_height_angle < slope_degrees && path.role() == erExternalPerimeter) {
double adjustment = follow_slope_down(slope_rad, half_width);
if (adjustment > 0) {
throw RuntimeError("ContourZ: got positive adjustment");
}
d += adjustment;
if (d < min_down) {
d = min_down;
}
}
if (d > max_up + 0.03 || d < min_down) {
d = 0;
} else {
if (d > max_up) {
d = max_up;
}
}
if (path.role() == erExternalPerimeter && d > 0) {
// do not increase height of external perimeters as this may create an appearance of a seam
d = 0;
}
if (std::abs(d) > EPSILON) {
was_contoured = true;
}
Vec3d new_point = {p.x(), p.y(), d};
if (contoured_points.size() >= 2) {
double dist = Linef3::distance_to_infinite_squared(new_point, contoured_points[contoured_points.size() - 2],
contoured_points[contoured_points.size() - 1]);
if (dist < EPSILON * EPSILON) {
contoured_points[contoured_points.size() - 1] = new_point;
continue;
}
}
contoured_points.push_back(new_point);
}
}
if (!was_contoured) {
return false;
}
Polyline3 polyline;
for (const Vec3d &point : contoured_points) {
polyline.append(Point3(scale_(point.x()), scale_(point.y()), scale_(point.z())));
}
path.polyline = std::move(polyline);
path.z_contoured = true;
return true;
}
static void contour_extrusion_multipath(LayerRegion *region, const sla::IndexedMesh &mesh, ExtrusionMultiPath &multipath)
{
for (ExtrusionPath &path : multipath.paths) {
contour_extrusion_path(region, mesh, path);
}
}
static void contour_extrusion_loop(LayerRegion *region, const sla::IndexedMesh &mesh, ExtrusionLoop &loop)
{
for (ExtrusionPath &path : loop.paths) {
contour_extrusion_path(region, mesh, path);
}
}
static void contour_extrusion_entitiy_collection(LayerRegion *region, const sla::IndexedMesh &mesh, ExtrusionEntityCollection &collection)
{
for (ExtrusionEntity *entity : collection.entities) {
contour_extrusion_entity(region, mesh, entity);
}
}
static void contour_extrusion_entity(LayerRegion *region, const sla::IndexedMesh &mesh, ExtrusionEntity *extr)
{
const ExtrusionPathSloped *sloped = dynamic_cast<const ExtrusionPathSloped*>(extr);
if (sloped != nullptr) {
throw RuntimeError("ExtrusionPathSloped not implemented");
return;
}
ExtrusionMultiPath *multipath = dynamic_cast<ExtrusionMultiPath*>(extr);
if (multipath != nullptr) {
contour_extrusion_multipath(region, mesh, *multipath);
return;
}
ExtrusionPath *path = dynamic_cast<ExtrusionPath*>(extr);
if (path != nullptr) {
contour_extrusion_path(region, mesh, *path);
return;
}
ExtrusionLoop *loop = dynamic_cast<ExtrusionLoop*>(extr);
if (loop != nullptr) {
contour_extrusion_loop(region, mesh, *loop);
return;
}
const ExtrusionLoopSloped *loop_sloped = dynamic_cast<const ExtrusionLoopSloped*>(extr);
if (loop_sloped != nullptr) {
throw RuntimeError("ExtrusionLoopSloped not implemented");
return;
}
ExtrusionEntityCollection *collection = dynamic_cast<ExtrusionEntityCollection*>(extr);
if (collection != nullptr) {
contour_extrusion_entitiy_collection(region, mesh, *collection);
return;
}
throw RuntimeError("ContourZ: ExtrusionEntity type not implemented: " + std::string(typeid(*extr).name()));
return;
}
static void handle_extrusion_collection(LayerRegion *region, const sla::IndexedMesh &mesh, ExtrusionEntityCollection &collection, std::initializer_list<ExtrusionRole> roles) {
for (ExtrusionEntity* extr : collection.entities) {
if (!contains(roles, extr->role())) {
continue;
}
contour_extrusion_entity(region, mesh, extr);
}
}
void Layer::make_contour_z(const sla::IndexedMesh &mesh)
{
for (LayerRegion *region : this->regions()) {
handle_extrusion_collection(region, mesh, region->fills, {erTopSolidInfill, erIroning, erExternalPerimeter, erMixed});
handle_extrusion_collection(region, mesh, region->perimeters, {erExternalPerimeter, erMixed});
}
}
} // namespace Slic3r