ENH: add vertical support enforcer
Previously painting support enforces on vertical faces doesn't work, as projecting the facets downwards will give empty polygons. Now we use a different mechanism to enable vertical paint-on enforces, by directly adding contact nodes. Note: this feature only works with tree support as only tree support has contact nodes. jira: none Change-Id: Id171b1665566d142a6427285baccb40c0aa00949 (cherry picked from commit 9c882f61eb37350a4486df58de48f0ae489f2d15)
This commit is contained in:
parent
65cfb9ad13
commit
68625a6e60
|
@ -1363,7 +1363,7 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
|
|||
if (!zs.empty() && is_volume_sinking(painted, volume_trafo)) {
|
||||
std::vector<float> zs_sinking = {0.f};
|
||||
Slic3r::append(zs_sinking, zs);
|
||||
slice_mesh_slabs(painted, zs_sinking, volume_trafo, max_top_layers > 0 ? &top : nullptr, max_bottom_layers > 0 ? &bottom : nullptr, throw_on_cancel_callback);
|
||||
slice_mesh_slabs(painted, zs_sinking, volume_trafo, max_top_layers > 0 ? &top : nullptr, max_bottom_layers > 0 ? &bottom : nullptr, nullptr, throw_on_cancel_callback);
|
||||
|
||||
if (top.size() > 0)
|
||||
top.erase(top.begin());
|
||||
|
@ -1377,7 +1377,7 @@ static inline std::vector<std::vector<ExPolygons>> mmu_segmentation_top_and_bott
|
|||
bottom[0] = union_(bottom[0], bottom_slice);
|
||||
}
|
||||
} else
|
||||
slice_mesh_slabs(painted, zs, volume_trafo, max_top_layers > 0 ? &top : nullptr, max_bottom_layers > 0 ? &bottom : nullptr, throw_on_cancel_callback);
|
||||
slice_mesh_slabs(painted, zs, volume_trafo, max_top_layers > 0 ? &top : nullptr, max_bottom_layers > 0 ? &bottom : nullptr, nullptr, throw_on_cancel_callback);
|
||||
auto merge = [](std::vector<Polygons> &&src, std::vector<Polygons> &dst) {
|
||||
auto it_src = find_if(src.begin(), src.end(), [](const Polygons &p){ return ! p.empty(); });
|
||||
if (it_src != src.end()) {
|
||||
|
|
|
@ -429,7 +429,7 @@ public:
|
|||
std::vector<Polygons> slice_support_enforcers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_ENFORCER); }
|
||||
|
||||
// Helpers to project custom facets on slices
|
||||
void project_and_append_custom_facets(bool seam, EnforcerBlockerType type, std::vector<Polygons>& expolys) const;
|
||||
void project_and_append_custom_facets(bool seam, EnforcerBlockerType type, std::vector<Polygons>& expolys, std::vector<std::pair<Vec3f,Vec3f>>* vertical_points=nullptr) const;
|
||||
|
||||
//BBS
|
||||
BoundingBox get_first_layer_bbox(float& area, float& layer_height, std::string& name);
|
||||
|
|
|
@ -3820,7 +3820,7 @@ static void project_triangles_to_slabs(ConstLayerPtrsAdaptor layers, const index
|
|||
}
|
||||
|
||||
void PrintObject::project_and_append_custom_facets(
|
||||
bool seam, EnforcerBlockerType type, std::vector<Polygons>& out) const
|
||||
bool seam, EnforcerBlockerType type, std::vector<Polygons>& out, std::vector<std::pair<Vec3f, Vec3f>>* vertical_points) const
|
||||
{
|
||||
for (const ModelVolume* mv : this->model_object()->volumes)
|
||||
if (mv->is_model_part()) {
|
||||
|
@ -3835,7 +3835,7 @@ void PrintObject::project_and_append_custom_facets(
|
|||
else {
|
||||
std::vector<Polygons> projected;
|
||||
// Support blockers or enforcers. Project downward facing painted areas upwards to their respective slicing plane.
|
||||
slice_mesh_slabs(custom_facets, zs_from_layers(this->layers()), this->trafo_centered() * mv->get_matrix(), nullptr, &projected, [](){});
|
||||
slice_mesh_slabs(custom_facets, zs_from_layers(this->layers()), this->trafo_centered() * mv->get_matrix(), nullptr, &projected, vertical_points, [](){});
|
||||
// Merge these projections with the output, layer by layer.
|
||||
assert(! projected.empty());
|
||||
assert(out.empty() || out.size() == projected.size());
|
||||
|
|
|
@ -976,7 +976,8 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/)
|
|||
|
||||
auto enforcers = m_object->slice_support_enforcers();
|
||||
auto blockers = m_object->slice_support_blockers();
|
||||
m_object->project_and_append_custom_facets(false, EnforcerBlockerType::ENFORCER, enforcers);
|
||||
m_vertical_enforcer_points.clear();
|
||||
m_object->project_and_append_custom_facets(false, EnforcerBlockerType::ENFORCER, enforcers, &m_vertical_enforcer_points);
|
||||
m_object->project_and_append_custom_facets(false, EnforcerBlockerType::BLOCKER, blockers);
|
||||
|
||||
if (is_auto(stype) && config_remove_small_overhangs) {
|
||||
|
@ -2890,12 +2891,17 @@ void TreeSupport::drop_nodes()
|
|||
movement = move_to_neighbor_center; // otherwise move to neighbor center first
|
||||
}
|
||||
|
||||
if (vsize2_with_unscale(movement) > get_max_move_dist(&node,2))
|
||||
movement = normal(movement, scale_(get_max_move_dist(&node)));
|
||||
if (node.is_sharp_tail && node.dist_mm_to_top < 3) {
|
||||
movement = normal(node.skin_direction, scale_(get_max_move_dist(&node)));
|
||||
}
|
||||
else if (dist2_to_outer > 0)
|
||||
movement = normal(direction_to_outer, scale_(get_max_move_dist(&node)));
|
||||
else
|
||||
movement = normal(move_to_neighbor_center, scale_(get_max_move_dist(&node)));
|
||||
|
||||
next_layer_vertex += movement;
|
||||
|
||||
if (group_index == 0) {
|
||||
if (group_index == 0 && 0) {
|
||||
// Avoid collisions.
|
||||
const coordf_t max_move_between_samples = get_max_move_dist(&node, 1) + radius_sample_resolution + EPSILON; // 100 micron extra for rounding errors.
|
||||
bool is_outside = move_out_expolys(avoidance_next, next_layer_vertex, radius_sample_resolution + EPSILON, max_move_between_samples);
|
||||
|
@ -3363,6 +3369,21 @@ void TreeSupport::generate_contact_points()
|
|||
|
||||
tbb::spin_mutex mtx;
|
||||
|
||||
// add vertical enforcer points
|
||||
std::vector<float> zs = zs_from_layers(m_object->layers());
|
||||
std::vector<std::vector<std::pair<Point,Point>>> vertical_enforcer_points_by_layers(m_object->layer_count());
|
||||
for (auto& pt_and_normal : m_vertical_enforcer_points) {
|
||||
auto pt = pt_and_normal.first;
|
||||
auto normal = pt_and_normal.second; // normal seems useless
|
||||
auto iter = std::lower_bound(zs.begin(), zs.end(), pt.z());
|
||||
if (iter != zs.end()) {
|
||||
size_t layer_nr = iter - zs.begin();
|
||||
if (layer_nr > 0 && layer_nr < contact_nodes.size()) {
|
||||
vertical_enforcer_points_by_layers[layer_nr].push_back({ to_2d(pt).cast<coord_t>(),scaled(to_2d(normal)) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nonempty_layers = 0;
|
||||
tbb::concurrent_vector<Slic3r::Vec3f> all_nodes;
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(1, m_object->layers().size()), [&](const tbb::blocked_range<size_t>& range) {
|
||||
|
@ -3371,7 +3392,6 @@ void TreeSupport::generate_contact_points()
|
|||
break;
|
||||
Layer* layer = m_object->get_layer(layer_nr);
|
||||
auto& curr_nodes = contact_nodes[layer_nr-1];
|
||||
if (layer->loverhangs.empty()) continue;
|
||||
|
||||
std::unordered_set<Point, PointHash> already_inserted;
|
||||
auto bottom_z = m_object->get_layer(layer_nr)->bottom_z();
|
||||
|
@ -3472,6 +3492,13 @@ void TreeSupport::generate_contact_points()
|
|||
}
|
||||
}
|
||||
}
|
||||
for (auto& pt_and_normal : vertical_enforcer_points_by_layers[layer_nr]) {
|
||||
is_sharp_tail = true;// fake it as sharp tail point so the contact distance will be 0
|
||||
auto vertical_enforcer_point= pt_and_normal.first;
|
||||
auto node=insert_point(vertical_enforcer_point, ExPolygon(), false);
|
||||
if (node)
|
||||
node->skin_direction = pt_and_normal.second;
|
||||
}
|
||||
if (!curr_nodes.empty()) nonempty_layers++;
|
||||
for (auto node : curr_nodes) { all_nodes.emplace_back(node->position(0), node->position(1), scale_(node->print_z)); }
|
||||
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
|
||||
|
@ -3480,6 +3507,9 @@ void TreeSupport::generate_contact_points()
|
|||
#endif
|
||||
}}
|
||||
); // end tbb::parallel_for
|
||||
|
||||
|
||||
|
||||
int nNodes = all_nodes.size();
|
||||
avg_node_per_layer = nodes_angle = 0;
|
||||
if (nNodes > 0) {
|
||||
|
|
|
@ -260,7 +260,7 @@ private:
|
|||
coordf_t radius;
|
||||
size_t layer_nr;
|
||||
int recursions;
|
||||
|
||||
|
||||
};
|
||||
struct RadiusLayerPairEquality {
|
||||
constexpr bool operator()(const RadiusLayerPair& _Left, const RadiusLayerPair& _Right) const {
|
||||
|
@ -334,7 +334,7 @@ public:
|
|||
* generally considered OK as the functions are still logically const
|
||||
* (ie there is no difference in behaviour for the user betweeen
|
||||
* calculating the values each time vs caching the results).
|
||||
*
|
||||
*
|
||||
* coconut: previously stl::unordered_map is used which seems problematic with tbb::parallel_for.
|
||||
* So we change to tbb::concurrent_unordered_map
|
||||
*/
|
||||
|
@ -414,6 +414,8 @@ public:
|
|||
|
||||
enum OverhangType { Detected = 0, Enforced, SharpTail };
|
||||
std::map<const ExPolygon*, OverhangType> overhang_types;
|
||||
std::vector<std::pair<Vec3f, Vec3f>> m_vertical_enforcer_points;
|
||||
|
||||
private:
|
||||
/*!
|
||||
* \brief Generator for model collision, avoidance and internal guide volumes
|
||||
|
@ -433,7 +435,6 @@ private:
|
|||
size_t m_highest_overhang_layer = 0;
|
||||
std::vector<std::vector<MinimumSpanningTree>> m_spanning_trees;
|
||||
std::vector< std::unordered_map<Line, bool, LineHash>> m_mst_line_x_layer_contour_caches;
|
||||
|
||||
float DO_NOT_MOVER_UNDER_MM = 0.0;
|
||||
coordf_t base_radius = 0.0;
|
||||
const coordf_t MAX_BRANCH_RADIUS = 10.0;
|
||||
|
@ -484,7 +485,7 @@ private:
|
|||
|
||||
/*! BBS: MusangKing: maximum layer height
|
||||
* \brief Optimize the generation of tree support by pre-planning the layer_heights
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
std::vector<LayerHeightData> plan_layer_heights();
|
||||
|
|
|
@ -4178,6 +4178,22 @@ static void generate_support_areas(Print &print, TreeSupport* tree_support, cons
|
|||
append(overhangs[i + num_raft_layers], polys);
|
||||
}
|
||||
}
|
||||
// add vertical enforcer points
|
||||
std::vector<float> zs = zs_from_layers(print_object.layers());
|
||||
Polygon base_circle = make_circle(scale_(0.5), SUPPORT_TREE_CIRCLE_RESOLUTION);
|
||||
for (auto &pt_and_normal :tree_support->m_vertical_enforcer_points) {
|
||||
auto pt = pt_and_normal.first;
|
||||
auto normal = pt_and_normal.second; // normal seems useless
|
||||
auto iter = std::lower_bound(zs.begin(), zs.end(), pt.z());
|
||||
if (iter != zs.end()) {
|
||||
size_t layer_nr = iter - zs.begin();
|
||||
if (layer_nr > 0 && layer_nr < print_object.layer_count()) {
|
||||
Polygon circle = base_circle;
|
||||
circle.translate(to_2d(pt).cast<coord_t>());
|
||||
overhangs[layer_nr + num_raft_layers].emplace_back(std::move(circle));
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
std::vector<Polygons> overhangs = generate_overhangs(config, *print.get_object(processing.second.front()), throw_on_cancel);
|
||||
#endif
|
||||
|
|
|
@ -957,7 +957,6 @@ inline std::pair<SlabLines, SlabLines> slice_slabs_make_lines(
|
|||
}
|
||||
slice_facet_with_slabs<true>(vertices, indices, face_idx, neighbors, edge_ids, num_edges, zs, lines_top, lines_mutex_top);
|
||||
}
|
||||
// BBS: add vertical faces option
|
||||
if (bottom && (fo == FaceOrientation::Down || fo == FaceOrientation::Degenerate)) {
|
||||
Vec3i neighbors = face_neighbors[face_idx];
|
||||
// Reset neighborship of this triangle in case the other triangle is oriented backwards from this one.
|
||||
|
@ -2063,6 +2062,7 @@ void slice_mesh_slabs(
|
|||
const Transform3d &trafo,
|
||||
std::vector<Polygons> *out_top,
|
||||
std::vector<Polygons> *out_bottom,
|
||||
std::vector<std::pair<Vec3f, Vec3f>> *vertical_points,
|
||||
std::function<void()> throw_on_cancel)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << "slice_mesh_slabs to polygons";
|
||||
|
@ -2133,6 +2133,11 @@ void slice_mesh_slabs(
|
|||
// Is the triangle vertical or degenerate?
|
||||
assert(d == 0);
|
||||
fo = fa == fb || fa == fc || fb == fc ? FaceOrientation::Degenerate : FaceOrientation::Vertical;
|
||||
if(vertical_points && fo==FaceOrientation::Vertical)
|
||||
{
|
||||
Vec3f normal = (fb - fa).cross(fc - fa).normalized();
|
||||
vertical_points->push_back({ (fa + fb + fc) / 3,normal });
|
||||
}
|
||||
}
|
||||
face_orientation[&tri - mesh.indices.data()] = fo;
|
||||
}
|
||||
|
@ -2297,7 +2302,7 @@ void project_mesh(
|
|||
{
|
||||
std::vector<Polygons> top, bottom;
|
||||
std::vector<float> zs { -1e10, 1e10 };
|
||||
slice_mesh_slabs(mesh, zs, trafo, out_top ? &top : nullptr, out_bottom ? &bottom : nullptr, throw_on_cancel);
|
||||
slice_mesh_slabs(mesh, zs, trafo, out_top ? &top : nullptr, out_bottom ? &bottom : nullptr, nullptr, throw_on_cancel);
|
||||
if (out_top)
|
||||
*out_top = std::move(top.front());
|
||||
if (out_bottom)
|
||||
|
@ -2311,7 +2316,7 @@ Polygons project_mesh(
|
|||
{
|
||||
std::vector<Polygons> top, bottom;
|
||||
std::vector<float> zs { -1e10, 1e10 };
|
||||
slice_mesh_slabs(mesh, zs, trafo, &top, &bottom, throw_on_cancel);
|
||||
slice_mesh_slabs(mesh, zs, trafo, &top, &bottom, nullptr, throw_on_cancel);
|
||||
return union_(top.front(), bottom.back());
|
||||
}
|
||||
|
||||
|
|
|
@ -107,6 +107,7 @@ void slice_mesh_slabs(
|
|||
const Transform3d &trafo,
|
||||
std::vector<Polygons> *out_top,
|
||||
std::vector<Polygons> *out_bottom,
|
||||
std::vector<std::pair<Vec3f, Vec3f>> *vertical_points,
|
||||
std::function<void()> throw_on_cancel);
|
||||
|
||||
// Project mesh upwards pointing surfaces / downwards pointing surfaces into 2D polygons.
|
||||
|
|
Loading…
Reference in New Issue