ENH: dual_extruder: add logic to process extruder_printable_area

JIRA: STUDIO-7498
Change-Id: I1cf53db93acf41b06cb1b9569a0679487c9f1e41
(cherry picked from commit e5be69dedd1ba6dc289a14b89598c9a6101dacb3)
This commit is contained in:
lane.wei 2024-08-30 21:13:16 +08:00 committed by Noisyfox
parent e433e49e2f
commit f702ad9fd2
20 changed files with 339 additions and 76 deletions

View file

@ -9,7 +9,7 @@
namespace Slic3r {
BuildVolume::BuildVolume(const std::vector<Vec2d> &printable_area, const double printable_height) : m_bed_shape(printable_area), m_max_print_height(printable_height)
BuildVolume::BuildVolume(const std::vector<Vec2d> &printable_area, const double printable_height, const std::vector<std::vector<Vec2d>> &extruder_areas) : m_bed_shape(printable_area), m_max_print_height(printable_height), m_extruder_shapes(extruder_areas)
{
assert(printable_height >= 0);
@ -77,6 +77,69 @@ BuildVolume::BuildVolume(const std::vector<Vec2d> &printable_area, const double
m_top_bottom_convex_hull_decomposition_bed = convex_decomposition(m_convex_hull, BedEpsilon);
}
if (m_extruder_shapes.size() > 0)
{
for (unsigned int index = 0; index < m_extruder_shapes.size(); index++)
{
std::vector<Vec2d>& extruder_shape = m_extruder_shapes[index];
BuildExtruderVolume extruder_volume;
if (extruder_shape == printable_area) {
extruder_volume.same_with_bed = true;
extruder_volume.type = m_type;
extruder_volume.bbox = m_bbox;
extruder_volume.bboxf = m_bboxf;
extruder_volume.circle = m_circle;
}
else {
Polygon poly = Polygon::new_scale(extruder_shape);
double poly_area = poly.area();
extruder_volume.bbox = get_extents(poly);
BoundingBoxf temp_bboxf = get_extents(extruder_shape);
extruder_volume.bboxf = BoundingBoxf3{ to_3d(temp_bboxf.min, 0.), to_3d(temp_bboxf.max, printable_height) };
if (extruder_shape.size() >= 4 && std::abs((poly_area - double(extruder_volume.bbox.size().x()) * double(extruder_volume.bbox.size().y()))) < sqr(SCALED_EPSILON))
{
extruder_volume.type = Type::Rectangle;
extruder_volume.circle.center = 0.5 * (extruder_volume.bbox.min.cast<double>() + extruder_volume.bbox.max.cast<double>());
extruder_volume.circle.radius = 0.5 * extruder_volume.bbox.size().cast<double>().norm();
}
else if (extruder_shape.size() > 3) {
extruder_volume.circle = Geometry::circle_ransac(extruder_shape);
bool is_circle = true;
Vec2d prev = extruder_shape.back();
for (const Vec2d &p : extruder_shape) {
if (// Polygon vertices must lie very close the circle.
std::abs((p - extruder_volume.circle.center).norm() - extruder_volume.circle.radius) > 0.005 ||
// Midpoints of polygon edges must not undercat more than 3mm. This corresponds to 72 edges per circle generated by BedShapePanel::update_shape().
extruder_volume.circle.radius - (0.5 * (prev + p) -extruder_volume.circle.center).norm() > 3.) {
is_circle = false;
break;
}
prev = p;
}
if (is_circle) {
extruder_volume.type = Type::Circle;
extruder_volume.circle.center = scaled<double>(extruder_volume.circle.center);
extruder_volume.circle.radius = scaled<double>(extruder_volume.circle.radius);
}
}
if (m_type == Type::Invalid) {
//not supported currently, use the same as bed
extruder_volume.same_with_bed = true;
extruder_volume.type = m_type;
extruder_volume.bbox = m_bbox;
extruder_volume.bboxf = m_bboxf;
extruder_volume.circle = m_circle;
}
m_extruder_volumes.push_back(std::move(extruder_volume));
}
}
}
BOOST_LOG_TRIVIAL(debug) << "BuildVolume printable_area clasified as: " << this->type_name();
}
@ -197,7 +260,7 @@ BuildVolume::ObjectState object_state_templ(const indexed_triangle_set &its, con
bool outside = false;
static constexpr const auto world_min_z = float(-BuildVolume::SceneEpsilon);
if (may_be_below_bed)
if (may_be_below_bed)
{
// Slower test, needs to clip the object edges with the print bed plane.
// 1) Allocate transformed vertices with their position with respect to print bed surface.
@ -260,7 +323,7 @@ BuildVolume::ObjectState object_state_templ(const indexed_triangle_set &its, con
}
}
}
else
else
{
// Much simpler and faster code, not clipping the object with the print bed.
assert(! may_be_below_bed);
@ -297,14 +360,14 @@ BuildVolume::ObjectState BuildVolume::object_state(const indexed_triangle_set& i
case BuildVolume_Type::Circle:
{
Geometry::Circlef circle { unscaled<float>(m_circle.center), unscaled<float>(m_circle.radius + SceneEpsilon) };
return m_max_print_height == 0.0 ?
return m_max_print_height == 0.0 ?
object_state_templ(its, trafo, may_be_below_bed, true, [circle](const Vec3f& pt) { return circle.contains(to_2d(pt)); }) :
object_state_templ(its, trafo, may_be_below_bed, true, [circle, z = m_max_print_height + SceneEpsilon](const Vec3f &pt) { return pt.z() < z && circle.contains(to_2d(pt)); });
}
case BuildVolume_Type::Convex:
//FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently.
case BuildVolume_Type::Custom:
return m_max_print_height == 0.0 ?
return m_max_print_height == 0.0 ?
object_state_templ(its, trafo, may_be_below_bed, m_type == BuildVolume_Type::Convex, [this](const Vec3f &pt) { return Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_scene, to_2d(pt).cast<double>()); }) :
object_state_templ(its, trafo, may_be_below_bed, m_type == BuildVolume_Type::Convex, [this, z = m_max_print_height + SceneEpsilon](const Vec3f &pt) { return pt.z() < z && Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_scene, to_2d(pt).cast<double>()); });
case BuildVolume_Type::Invalid:
@ -322,10 +385,100 @@ BuildVolume::ObjectState BuildVolume::volume_state_bbox(const BoundingBoxf3& vol
if (ignore_bottom)
build_volume.min.z() = -std::numeric_limits<double>::max();
return build_volume.max.z() <= - SceneEpsilon ? ObjectState::Below :
build_volume.contains(volume_bbox) ? ObjectState::Inside :
build_volume.contains(volume_bbox) ? ObjectState::Inside :
build_volume.intersects(volume_bbox) ? ObjectState::Colliding : ObjectState::Outside;
}
const BuildVolume::BuildExtruderVolume& BuildVolume::get_extruder_area_volume(int index) const
{
assert(index >= 0 && index < m_extruder_volumes.size());
return m_extruder_volumes[index];
}
BuildVolume::ObjectState BuildVolume::check_object_state_with_extruder_area(const indexed_triangle_set &its, const Transform3f &trafo, int index) const
{
const BuildExtruderVolume& extruder_volume = get_extruder_area_volume(index);
ObjectState return_state = ObjectState::Inside;
if (!extruder_volume.same_with_bed) {
switch (extruder_volume.type) {
case Type::Rectangle:
{
BoundingBox3Base<Vec3d> build_volume = extruder_volume.bboxf.inflated(SceneEpsilon);
if (m_max_print_height == 0.0)
build_volume.max.z() = std::numeric_limits<double>::max();
BoundingBox3Base<Vec3f> build_volumef(build_volume.min.cast<float>(), build_volume.max.cast<float>());
return_state = object_state_templ(its, trafo, false, [build_volumef](const Vec3f &pt) { return build_volumef.contains(pt); });
break;
}
case Type::Circle:
{
Geometry::Circlef circle { unscaled<float>(extruder_volume.circle.center), unscaled<float>(extruder_volume.circle.radius + SceneEpsilon) };
return_state = (m_max_print_height == 0.0) ?
object_state_templ(its, trafo, false, [circle](const Vec3f &pt) { return circle.contains(to_2d(pt)); }) :
object_state_templ(its, trafo, false, [circle, z = m_max_print_height + SceneEpsilon](const Vec3f &pt) { return pt.z() < z && circle.contains(to_2d(pt)); });
break;
}
case Type::Invalid:
default:
break;
}
}
if (return_state != ObjectState::Inside)
return_state = ObjectState::Limited;
return return_state;
}
BuildVolume::ObjectState BuildVolume::check_object_state_with_extruder_areas(const indexed_triangle_set &its, const Transform3f &trafo, std::vector<bool>& inside_extruders) const
{
ObjectState result = ObjectState::Inside;
int extruder_area_count = get_extruder_area_count();
inside_extruders.resize(extruder_area_count, true);
for (int index = 0; index < extruder_area_count; index++)
{
ObjectState state = check_object_state_with_extruder_area(its, trafo, index);
if (state == ObjectState::Limited) {
inside_extruders[index] = false;
result = ObjectState::Limited;
}
}
return result;
}
BuildVolume::ObjectState BuildVolume::check_volume_bbox_state_with_extruder_area(const BoundingBoxf3& volume_bbox, int index) const
{
const BuildExtruderVolume& extruder_volume = get_extruder_area_volume(index);
if (extruder_volume.same_with_bed || extruder_volume.bboxf.contains(volume_bbox))
return ObjectState::Inside;
else
return ObjectState::Limited;
}
BuildVolume::ObjectState BuildVolume::check_volume_bbox_state_with_extruder_areas(const BoundingBoxf3& volume_bbox, std::vector<bool>& inside_extruders) const
{
ObjectState result = ObjectState::Inside;
int extruder_area_count = get_extruder_area_count();
inside_extruders.resize(extruder_area_count, true);
for (int index = 0; index < extruder_area_count; index++)
{
ObjectState state = check_volume_bbox_state_with_extruder_area(volume_bbox, index);
if (state == ObjectState::Limited) {
inside_extruders[index] = false;
result = ObjectState::Limited;
}
}
return result;
}
bool BuildVolume::all_paths_inside(const GCodeProcessorResult& paths, const BoundingBoxf3& paths_bbox, bool ignore_bottom) const
{
auto move_valid = [](const GCodeProcessorResult::MoveVertex &move) {
@ -348,7 +501,7 @@ bool BuildVolume::all_paths_inside(const GCodeProcessorResult& paths, const Boun
const Vec2f c = unscaled<float>(m_circle.center);
const float r = unscaled<double>(m_circle.radius) + epsilon;
const float r2 = sqr(r);
return m_max_print_height == 0.0 ?
return m_max_print_height == 0.0 ?
std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, c, r2](const GCodeProcessorResult::MoveVertex &move)
{ return ! move_valid(move) || (to_2d(move.position) - c).squaredNorm() <= r2; }) :
std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, c, r2, z = m_max_print_height + epsilon](const GCodeProcessorResult::MoveVertex& move)
@ -358,7 +511,7 @@ bool BuildVolume::all_paths_inside(const GCodeProcessorResult& paths, const Boun
//FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently.
case BuildVolume_Type::Custom:
return m_max_print_height == 0.0 ?
std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, this](const GCodeProcessorResult::MoveVertex &move)
std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, this](const GCodeProcessorResult::MoveVertex &move)
{ return ! move_valid(move) || Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_bed, to_2d(move.position).cast<double>()); }) :
std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, this, z = m_max_print_height + epsilon](const GCodeProcessorResult::MoveVertex &move)
{ return ! move_valid(move) || (Geometry::inside_convex_polygon(m_top_bottom_convex_hull_decomposition_bed, to_2d(move.position).cast<double>()) && move.position.z() <= z); });