mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 12:25:57 +08:00
Create method for infill above bridges identification
This commit is contained in:
parent
8e7e26289d
commit
fc7ab914a1
@ -245,6 +245,8 @@ set(SLIC3R_SOURCES
|
|||||||
Geometry/VoronoiUtils.hpp
|
Geometry/VoronoiUtils.hpp
|
||||||
Geometry/VoronoiUtils.cpp
|
Geometry/VoronoiUtils.cpp
|
||||||
Geometry/VoronoiVisualUtils.hpp
|
Geometry/VoronoiVisualUtils.hpp
|
||||||
|
InfillAboveBridges.hpp
|
||||||
|
InfillAboveBridges.cpp
|
||||||
JumpPointSearch.cpp
|
JumpPointSearch.cpp
|
||||||
JumpPointSearch.hpp
|
JumpPointSearch.hpp
|
||||||
KDTreeIndirect.hpp
|
KDTreeIndirect.hpp
|
||||||
|
@ -31,6 +31,7 @@ enum class ExtrusionRoleModifier : uint16_t {
|
|||||||
Solid,
|
Solid,
|
||||||
Ironing,
|
Ironing,
|
||||||
Bridge,
|
Bridge,
|
||||||
|
OverBridge,
|
||||||
// 3) Special types
|
// 3) Special types
|
||||||
// Indicator that the extrusion role was mixed from multiple differing extrusion roles,
|
// Indicator that the extrusion role was mixed from multiple differing extrusion roles,
|
||||||
// for example from Support and SupportInterface.
|
// for example from Support and SupportInterface.
|
||||||
@ -62,6 +63,7 @@ struct ExtrusionRole : public ExtrusionRoleModifiers
|
|||||||
static constexpr const ExtrusionRoleModifiers SolidInfill{ ExtrusionRoleModifier::Infill | ExtrusionRoleModifier::Solid };
|
static constexpr const ExtrusionRoleModifiers SolidInfill{ ExtrusionRoleModifier::Infill | ExtrusionRoleModifier::Solid };
|
||||||
// Top solid infill (visible).
|
// Top solid infill (visible).
|
||||||
//FIXME why there is no bottom solid infill type?
|
//FIXME why there is no bottom solid infill type?
|
||||||
|
static constexpr const ExtrusionRoleModifiers InfillOverBridge{ ExtrusionRoleModifier::Infill | ExtrusionRoleModifier::Solid | ExtrusionRoleModifier::OverBridge };
|
||||||
static constexpr const ExtrusionRoleModifiers TopSolidInfill{ ExtrusionRoleModifier::Infill | ExtrusionRoleModifier::Solid | ExtrusionRoleModifier::External };
|
static constexpr const ExtrusionRoleModifiers TopSolidInfill{ ExtrusionRoleModifier::Infill | ExtrusionRoleModifier::Solid | ExtrusionRoleModifier::External };
|
||||||
// Ironing infill at the top surfaces.
|
// Ironing infill at the top surfaces.
|
||||||
static constexpr const ExtrusionRoleModifiers Ironing{ ExtrusionRoleModifier::Infill | ExtrusionRoleModifier::Solid | ExtrusionRoleModifier::Ironing | ExtrusionRoleModifier::External };
|
static constexpr const ExtrusionRoleModifiers Ironing{ ExtrusionRoleModifier::Infill | ExtrusionRoleModifier::Solid | ExtrusionRoleModifier::Ironing | ExtrusionRoleModifier::External };
|
||||||
|
@ -183,15 +183,24 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
|||||||
} else if (params.density <= 0)
|
} else if (params.density <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
params.extrusion_role =
|
if (is_bridge) {
|
||||||
is_bridge ?
|
params.extrusion_role = ExtrusionRole::BridgeInfill;
|
||||||
ExtrusionRole::BridgeInfill :
|
} else {
|
||||||
(surface.is_solid() ?
|
if (surface.is_solid()) {
|
||||||
(surface.is_top() ? ExtrusionRole::TopSolidInfill : ExtrusionRole::SolidInfill) :
|
if (surface.is_top()) {
|
||||||
ExtrusionRole::InternalInfill);
|
params.extrusion_role = ExtrusionRole::TopSolidInfill;
|
||||||
|
} else if (surface.surface_type == stSolidOverBridge) {
|
||||||
|
params.extrusion_role = ExtrusionRole::InfillOverBridge;
|
||||||
|
} else {
|
||||||
|
params.extrusion_role = ExtrusionRole::SolidInfill;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
params.extrusion_role = ExtrusionRole::InternalInfill;
|
||||||
|
}
|
||||||
|
}
|
||||||
params.bridge_angle = float(surface.bridge_angle);
|
params.bridge_angle = float(surface.bridge_angle);
|
||||||
params.angle = float(Geometry::deg2rad(region_config.fill_angle.value));
|
params.angle = float(Geometry::deg2rad(region_config.fill_angle.value));
|
||||||
|
|
||||||
// Calculate the actual flow we'll be using for this infill.
|
// Calculate the actual flow we'll be using for this infill.
|
||||||
params.bridge = is_bridge || Fill::use_bridge_flow(params.pattern);
|
params.bridge = is_bridge || Fill::use_bridge_flow(params.pattern);
|
||||||
params.flow = params.bridge ?
|
params.flow = params.bridge ?
|
||||||
@ -342,7 +351,9 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
|||||||
// Use ipEnsuring pattern for all internal Solids.
|
// Use ipEnsuring pattern for all internal Solids.
|
||||||
{
|
{
|
||||||
for (size_t surface_fill_id = 0; surface_fill_id < surface_fills.size(); ++surface_fill_id)
|
for (size_t surface_fill_id = 0; surface_fill_id < surface_fills.size(); ++surface_fill_id)
|
||||||
if (SurfaceFill &fill = surface_fills[surface_fill_id]; fill.surface.surface_type == stInternalSolid) {
|
if (SurfaceFill &fill = surface_fills[surface_fill_id];
|
||||||
|
fill.surface.surface_type == stInternalSolid
|
||||||
|
|| fill.surface.surface_type == stSolidOverBridge) {
|
||||||
fill.params.pattern = ipEnsuring;
|
fill.params.pattern = ipEnsuring;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3387,6 +3387,8 @@ std::string GCodeGenerator::_extrude(
|
|||||||
speed = m_config.get_abs_value("infill_speed");
|
speed = m_config.get_abs_value("infill_speed");
|
||||||
} else if (path_attr.role == ExtrusionRole::SolidInfill) {
|
} else if (path_attr.role == ExtrusionRole::SolidInfill) {
|
||||||
speed = m_config.get_abs_value("solid_infill_speed");
|
speed = m_config.get_abs_value("solid_infill_speed");
|
||||||
|
} else if (path_attr.role == ExtrusionRole::InfillOverBridge) {
|
||||||
|
speed = 10;
|
||||||
} else if (path_attr.role == ExtrusionRole::TopSolidInfill) {
|
} else if (path_attr.role == ExtrusionRole::TopSolidInfill) {
|
||||||
speed = m_config.get_abs_value("top_solid_infill_speed");
|
speed = m_config.get_abs_value("top_solid_infill_speed");
|
||||||
} else if (path_attr.role == ExtrusionRole::Ironing) {
|
} else if (path_attr.role == ExtrusionRole::Ironing) {
|
||||||
|
36
src/libslic3r/InfillAboveBridges.cpp
Normal file
36
src/libslic3r/InfillAboveBridges.cpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include <tcbspan/span.hpp>
|
||||||
|
#include "libslic3r/InfillAboveBridges.hpp"
|
||||||
|
#include "libslic3r/ClipperUtils.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r::PrepareInfill {
|
||||||
|
void mark_as_infill_above_bridge(const ExPolygons &marker, const SurfaceRefsByRegion &layer) {
|
||||||
|
for (const SurfaceCollectionRef ®ion : layer) {
|
||||||
|
const ExPolygons intersection{intersection_ex(region.get().filter_by_type(stInternalSolid), marker, ApplySafetyOffset::No)};
|
||||||
|
if (intersection.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const ExPolygons clipped{diff_ex(region.get().filter_by_type(stInternalSolid), marker, ApplySafetyOffset::Yes)};
|
||||||
|
region.get().remove_type(stInternalSolid);
|
||||||
|
region.get().append(clipped, stInternalSolid);
|
||||||
|
region.get().append(intersection, stSolidOverBridge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void separate_infill_above_bridges(const SurfaceRefs &surfaces) {
|
||||||
|
if (surfaces.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SurfaceRefsByRegion *previous_layer{&surfaces.front()};
|
||||||
|
for (const SurfaceRefsByRegion &layer : tcb::span{surfaces}.subspan(1)) {
|
||||||
|
ExPolygons bridges;
|
||||||
|
for (const SurfaceCollectionRef ®ion : *previous_layer) {
|
||||||
|
for (const Surface *bridge : region.get().filter_by_type(stBottomBridge)) {
|
||||||
|
bridges.push_back(bridge->expolygon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mark_as_infill_above_bridge(bridges, layer);
|
||||||
|
previous_layer = &layer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/libslic3r/InfillAboveBridges.hpp
Normal file
16
src/libslic3r/InfillAboveBridges.hpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef slic3r_InfillAboveBridges_hpp_
|
||||||
|
#define slic3r_InfillAboveBridges_hpp_
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include "libslic3r/SurfaceCollection.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r::PrepareInfill {
|
||||||
|
using SurfaceCollectionRef = std::reference_wrapper<SurfaceCollection>;
|
||||||
|
using SurfaceRefsByRegion = std::vector<SurfaceCollectionRef>;
|
||||||
|
using SurfaceRefs = std::vector<SurfaceRefsByRegion>;
|
||||||
|
|
||||||
|
void separate_infill_above_bridges(const SurfaceRefs &surfaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // slic3r_InfillAboveBridges_hpp_
|
@ -64,6 +64,7 @@
|
|||||||
#include "libslic3r/TriangleSelector.hpp"
|
#include "libslic3r/TriangleSelector.hpp"
|
||||||
#include "tcbspan/span.hpp"
|
#include "tcbspan/span.hpp"
|
||||||
#include "libslic3r/Point.hpp"
|
#include "libslic3r/Point.hpp"
|
||||||
|
#include "libslic3r/InfillAboveBridges.hpp"
|
||||||
|
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
|
|
||||||
@ -412,6 +413,19 @@ void PrintObject::prepare_infill()
|
|||||||
} // for each layer
|
} // for each layer
|
||||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||||
|
|
||||||
|
|
||||||
|
PrepareInfill::SurfaceRefs surfaces;
|
||||||
|
for (const Layer *layer : m_layers) {
|
||||||
|
surfaces.emplace_back();
|
||||||
|
for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
|
||||||
|
LayerRegion *layerm = layer->m_regions[region_id];
|
||||||
|
if (!layerm->fill_surfaces().empty()) {
|
||||||
|
surfaces.back().push_back(std::ref(layerm->m_fill_surfaces));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrepareInfill::separate_infill_above_bridges(surfaces);
|
||||||
|
|
||||||
this->set_done(posPrepareInfill);
|
this->set_done(posPrepareInfill);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,6 +53,7 @@ const char* surface_type_to_color_name(const SurfaceType surface_type)
|
|||||||
case stInternalSolid: return "rgb(255,0,255)"; // magenta
|
case stInternalSolid: return "rgb(255,0,255)"; // magenta
|
||||||
case stInternalBridge: return "rgb(0,255,255)";
|
case stInternalBridge: return "rgb(0,255,255)";
|
||||||
case stInternalVoid: return "rgb(128,128,128)";
|
case stInternalVoid: return "rgb(128,128,128)";
|
||||||
|
case stSolidOverBridge: return "rgb(255,128,0)"; // orange
|
||||||
case stPerimeter: return "rgb(128,0,0)"; // maroon
|
case stPerimeter: return "rgb(128,0,0)"; // maroon
|
||||||
default: return "rgb(64,64,64)";
|
default: return "rgb(64,64,64)";
|
||||||
};
|
};
|
||||||
@ -89,6 +90,8 @@ void export_surface_type_legend_to_svg(SVG &svg, const Point &pos)
|
|||||||
svg.draw_legend(Point(pos_x, pos_y), "internal bridge", surface_type_to_color_name(stInternalBridge));
|
svg.draw_legend(Point(pos_x, pos_y), "internal bridge", surface_type_to_color_name(stInternalBridge));
|
||||||
pos_x += step_x;
|
pos_x += step_x;
|
||||||
svg.draw_legend(Point(pos_x, pos_y), "internal void" , surface_type_to_color_name(stInternalVoid));
|
svg.draw_legend(Point(pos_x, pos_y), "internal void" , surface_type_to_color_name(stInternalVoid));
|
||||||
|
pos_x += step_x;
|
||||||
|
svg.draw_legend(Point(pos_x, pos_y), "over bridge" , surface_type_to_color_name(stSolidOverBridge));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool export_to_svg(const char *path, const Surfaces &surfaces, const float transparency)
|
bool export_to_svg(const char *path, const Surfaces &surfaces, const float transparency)
|
||||||
|
@ -44,6 +44,8 @@ enum SurfaceType {
|
|||||||
stInternalVoid,
|
stInternalVoid,
|
||||||
// Inner/outer perimeters.
|
// Inner/outer perimeters.
|
||||||
stPerimeter,
|
stPerimeter,
|
||||||
|
// InternalSolid that is directly above stBottomBridge.
|
||||||
|
stSolidOverBridge,
|
||||||
// Number of SurfaceType enums.
|
// Number of SurfaceType enums.
|
||||||
stCount,
|
stCount,
|
||||||
};
|
};
|
||||||
@ -111,7 +113,12 @@ public:
|
|||||||
bool is_bridge() const { return this->surface_type == stBottomBridge || this->surface_type == stInternalBridge; }
|
bool is_bridge() const { return this->surface_type == stBottomBridge || this->surface_type == stInternalBridge; }
|
||||||
bool is_external() const { return this->is_top() || this->is_bottom(); }
|
bool is_external() const { return this->is_top() || this->is_bottom(); }
|
||||||
bool is_internal() const { return ! this->is_external(); }
|
bool is_internal() const { return ! this->is_external(); }
|
||||||
bool is_solid() const { return this->is_external() || this->surface_type == stInternalSolid || this->surface_type == stInternalBridge; }
|
bool is_solid() const {
|
||||||
|
return this->is_external()
|
||||||
|
|| this->surface_type == stInternalSolid
|
||||||
|
|| this->surface_type == stSolidOverBridge
|
||||||
|
|| this->surface_type == stInternalBridge;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Surface> Surfaces;
|
typedef std::vector<Surface> Surfaces;
|
||||||
|
@ -14,6 +14,7 @@ add_executable(${_TEST_NAME}_tests
|
|||||||
test_gaps.cpp
|
test_gaps.cpp
|
||||||
test_gcode.cpp
|
test_gcode.cpp
|
||||||
test_gcode_travels.cpp
|
test_gcode_travels.cpp
|
||||||
|
test_infill_above_bridges.cpp
|
||||||
test_seam_perimeters.cpp
|
test_seam_perimeters.cpp
|
||||||
test_seam_shells.cpp
|
test_seam_shells.cpp
|
||||||
test_seam_geometry.cpp
|
test_seam_geometry.cpp
|
||||||
|
81
tests/fff_print/test_infill_above_bridges.cpp
Normal file
81
tests/fff_print/test_infill_above_bridges.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#include <catch2/catch.hpp>
|
||||||
|
#include <libslic3r/InfillAboveBridges.hpp>
|
||||||
|
|
||||||
|
using namespace Slic3r;
|
||||||
|
|
||||||
|
const ExPolygon square{
|
||||||
|
Point::new_scale(0, 0),
|
||||||
|
Point::new_scale(10, 0),
|
||||||
|
Point::new_scale(10, 10),
|
||||||
|
Point::new_scale(0, 10)
|
||||||
|
};
|
||||||
|
|
||||||
|
ExPolygon translate(const ExPolygon &polygon, const Point &offset) {
|
||||||
|
ExPolygons result{polygon};
|
||||||
|
translate(result, offset);
|
||||||
|
return result.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool debug_files{false};
|
||||||
|
|
||||||
|
void draw_surfaces(const PrepareInfill::SurfaceRefsByRegion &surfaces, std::string_view file_name) {
|
||||||
|
using PrepareInfill::SurfaceCollectionRef;
|
||||||
|
|
||||||
|
SurfaceCollection to_display;
|
||||||
|
for (const SurfaceCollectionRef &surface_collection : surfaces) {
|
||||||
|
to_display.append(surface_collection.get());
|
||||||
|
}
|
||||||
|
to_display.export_to_svg(file_name.data(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Separate infill above bridges", "[PrepareInfill]") {
|
||||||
|
ExPolygons layer_0_region_0_bridge{
|
||||||
|
square
|
||||||
|
};
|
||||||
|
ExPolygons layer_0_region_0_internal{
|
||||||
|
translate(square, Point::new_scale(10, 0))
|
||||||
|
};
|
||||||
|
ExPolygons layer_0_region_1_internal{
|
||||||
|
translate(square, Point::new_scale(0, 10))
|
||||||
|
};
|
||||||
|
ExPolygons layer_0_region_1_bridge{
|
||||||
|
translate(square, Point::new_scale(10, 10))
|
||||||
|
};
|
||||||
|
SurfaceCollection layer_0_region_0;
|
||||||
|
layer_0_region_0.append(layer_0_region_0_bridge, stBottomBridge);
|
||||||
|
layer_0_region_0.append(layer_0_region_0_internal, stInternal);
|
||||||
|
SurfaceCollection layer_0_region_1;
|
||||||
|
layer_0_region_1.append(layer_0_region_1_bridge, stBottomBridge);
|
||||||
|
layer_0_region_1.append(layer_0_region_1_internal, stInternal);
|
||||||
|
|
||||||
|
PrepareInfill::SurfaceRefsByRegion layer_0{layer_0_region_0, layer_0_region_1};
|
||||||
|
|
||||||
|
ExPolygons layer_1_region_0_solid{
|
||||||
|
translate(square, Point::new_scale(5, 5))
|
||||||
|
};
|
||||||
|
SurfaceCollection layer_1_region_0;
|
||||||
|
layer_1_region_0.append(layer_1_region_0_solid, stInternalSolid);
|
||||||
|
PrepareInfill::SurfaceRefsByRegion layer_1{layer_1_region_0};
|
||||||
|
|
||||||
|
if constexpr (debug_files) {
|
||||||
|
draw_surfaces(layer_0, "layer_0.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
PrepareInfill::separate_infill_above_bridges({layer_0, layer_1});
|
||||||
|
|
||||||
|
if constexpr (debug_files) {
|
||||||
|
draw_surfaces(layer_1, "layer_1.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
const Surfaces &result{layer_1.front().get().surfaces};
|
||||||
|
REQUIRE(result.size() == 4);
|
||||||
|
const double expected_area{scale_(5.0) * scale_(5.0)};
|
||||||
|
CHECK(result[0].expolygon.contour.area() == Approx(expected_area));
|
||||||
|
CHECK(result[0].surface_type == stInternalSolid);
|
||||||
|
CHECK(result[1].expolygon.contour.area() == Approx(expected_area));
|
||||||
|
CHECK(result[1].surface_type == stInternalSolid);
|
||||||
|
CHECK(result[2].expolygon.contour.area() == Approx(expected_area));
|
||||||
|
CHECK(result[2].surface_type == stSolidOverBridge);
|
||||||
|
CHECK(result[3].expolygon.contour.area() == Approx(expected_area));
|
||||||
|
CHECK(result[3].surface_type == stSolidOverBridge);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user