mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-13 18:55:53 +08:00
Beta version of the algorithm
Implemented long unsupported segments detection, which considers also curvature Implemented detection of curved segments at the edge of the previous layer - danger of warping/curling
This commit is contained in:
parent
adf39805bc
commit
706cd63e61
@ -275,6 +275,8 @@ set(SLIC3R_SOURCES
|
|||||||
TriangleSelector.hpp
|
TriangleSelector.hpp
|
||||||
TriangleSetSampling.cpp
|
TriangleSetSampling.cpp
|
||||||
TriangleSetSampling.hpp
|
TriangleSetSampling.hpp
|
||||||
|
TriangleSelectorWrapper.cpp
|
||||||
|
TriangleSelectorWrapper.hpp
|
||||||
MTUtils.hpp
|
MTUtils.hpp
|
||||||
Zipper.hpp
|
Zipper.hpp
|
||||||
Zipper.cpp
|
Zipper.cpp
|
||||||
|
@ -402,12 +402,38 @@ void PrintObject::find_supportable_issues()
|
|||||||
BOOST_LOG_TRIVIAL(debug)
|
BOOST_LOG_TRIVIAL(debug)
|
||||||
<< "Searching supportable issues - start";
|
<< "Searching supportable issues - start";
|
||||||
//TODO status number?
|
//TODO status number?
|
||||||
m_print->set_status(70, L("Searching supportable issues"));
|
m_print->set_status(75, L("Searching supportable issues"));
|
||||||
|
|
||||||
if (this->has_support()) {
|
|
||||||
|
|
||||||
|
if (!this->m_config.support_material) {
|
||||||
|
std::vector<size_t> problematic_layers = SupportableIssues::quick_search(this);
|
||||||
|
if (!problematic_layers.empty()){
|
||||||
|
//TODO report problems
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
SupportableIssues::quick_search(this);
|
SupportableIssues::Issues issues = SupportableIssues::full_search(this);
|
||||||
|
if (!issues.supports_nedded.empty()) {
|
||||||
|
auto obj_transform = this->trafo_centered();
|
||||||
|
for (ModelVolume *model_volume : this->model_object()->volumes) {
|
||||||
|
if (model_volume->type() == ModelVolumeType::MODEL_PART) {
|
||||||
|
Transform3d model_transformation = model_volume->get_matrix();
|
||||||
|
Transform3d inv_transform = (obj_transform * model_transformation).inverse();
|
||||||
|
TriangleSelectorWrapper selector { model_volume->mesh() };
|
||||||
|
|
||||||
|
for (const Vec3f &support_point : issues.supports_nedded) {
|
||||||
|
selector.enforce_spot(Vec3f(inv_transform.cast<float>() * support_point), 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
model_volume->supported_facets.set(selector.selector);
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
indexed_triangle_set copy = model_volume->mesh().its;
|
||||||
|
its_transform(copy, obj_transform * model_transformation);
|
||||||
|
its_write_obj(copy,
|
||||||
|
debug_out_path(("model" + std::to_string(model_volume->id().id) + ".obj").c_str()).c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_print->throw_if_canceled();
|
m_print->throw_if_canceled();
|
||||||
@ -417,6 +443,7 @@ void PrintObject::find_supportable_issues()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PrintObject::generate_support_material()
|
void PrintObject::generate_support_material()
|
||||||
{
|
{
|
||||||
if (this->set_started(posSupportMaterial)) {
|
if (this->set_started(posSupportMaterial)) {
|
||||||
|
@ -4,18 +4,31 @@
|
|||||||
#include "tbb/blocked_range.h"
|
#include "tbb/blocked_range.h"
|
||||||
#include "tbb/parallel_reduce.h"
|
#include "tbb/parallel_reduce.h"
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include "libslic3r/Layer.hpp"
|
#include "libslic3r/Layer.hpp"
|
||||||
#include "libslic3r/EdgeGrid.hpp"
|
#include "libslic3r/EdgeGrid.hpp"
|
||||||
#include "libslic3r/ClipperUtils.hpp"
|
#include "libslic3r/ClipperUtils.hpp"
|
||||||
|
|
||||||
|
#define DEBUG_FILES
|
||||||
|
|
||||||
|
#ifdef DEBUG_FILES
|
||||||
|
#include <boost/nowide/cstdio.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
namespace SupportableIssues {
|
namespace SupportableIssues {
|
||||||
|
|
||||||
struct Params {
|
void Issues::add(const Issues &layer_issues) {
|
||||||
float bridge_distance = 5.0f;
|
supports_nedded.insert(supports_nedded.end(),
|
||||||
float printable_protrusion_distance = 1.0f;
|
layer_issues.supports_nedded.begin(), layer_issues.supports_nedded.end());
|
||||||
};
|
curling_up.insert(curling_up.end(), layer_issues.curling_up.begin(),
|
||||||
|
layer_issues.curling_up.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Issues::empty() const {
|
||||||
|
return supports_nedded.empty() && curling_up.empty();
|
||||||
|
}
|
||||||
|
|
||||||
namespace Impl {
|
namespace Impl {
|
||||||
|
|
||||||
@ -34,62 +47,218 @@ struct EdgeGridWrapper {
|
|||||||
}
|
}
|
||||||
EdgeGrid::Grid grid;
|
EdgeGrid::Grid grid;
|
||||||
ExPolygons ex_polys;
|
ExPolygons ex_polys;
|
||||||
}
|
};
|
||||||
;
|
|
||||||
|
|
||||||
EdgeGridWrapper compute_layer_merged_edge_grid(const Layer *layer) {
|
#ifdef DEBUG_FILES
|
||||||
static const float eps = float(scale_(layer->object()->config().slice_closing_radius.value));
|
void debug_export(Issues issues, std::string file_name) {
|
||||||
// merge with offset
|
Slic3r::CNumericLocalesSetter locales_setter;
|
||||||
ExPolygons merged = layer->merged(eps);
|
|
||||||
// ofsset back
|
|
||||||
ExPolygons layer_outline = offset_ex(merged, -eps);
|
|
||||||
|
|
||||||
float min_region_flow_width { };
|
{
|
||||||
for (const auto *region : layer->regions()) {
|
FILE *fp = boost::nowide::fopen(debug_out_path((file_name + "_supports.obj").c_str()).c_str(), "w");
|
||||||
min_region_flow_width = std::max(min_region_flow_width, region->flow(FlowRole::frExternalPerimeter).width());
|
if (fp == nullptr) {
|
||||||
}
|
BOOST_LOG_TRIVIAL(error)
|
||||||
std::cout << "min_region_flow_width: " << min_region_flow_width << std::endl;
|
<< "Debug files: Couldn't open " << file_name << " for writing";
|
||||||
return EdgeGridWrapper(scale_(min_region_flow_width), layer_outline);
|
|
||||||
}
|
|
||||||
|
|
||||||
void check_extrusion_entity_stability(const ExtrusionEntity *entity, const EdgeGridWrapper &supported_grid,
|
|
||||||
const Params ¶ms) {
|
|
||||||
if (entity->is_collection()){
|
|
||||||
for (const auto* e: static_cast<ExtrusionEntityCollection>(entity).entities){
|
|
||||||
check_extrusion_entity_stability(e, supported_grid, params);
|
|
||||||
}
|
|
||||||
} else { //single extrusion path, with possible varying parameters
|
|
||||||
entity->as_polyline().points;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void check_layer_stability(const PrintObject *po, size_t layer_idx, const Params ¶ms) {
|
|
||||||
if (layer_idx == 0) {
|
|
||||||
// first layer is usually ok
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const Layer *layer = po->get_layer(layer_idx);
|
|
||||||
const Layer *prev_layer = layer->lower_layer;
|
|
||||||
EdgeGridWrapper supported_grid = compute_layer_merged_edge_grid(prev_layer);
|
|
||||||
|
|
||||||
|
for (size_t i = 0; i < issues.supports_nedded.size(); ++i) {
|
||||||
|
fprintf(fp, "v %f %f %f %f %f %f\n",
|
||||||
|
issues.supports_nedded[i](0), issues.supports_nedded[i](1), issues.supports_nedded[i](2),
|
||||||
|
1.0, 0.0, 0.0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
FILE *fp = boost::nowide::fopen(debug_out_path((file_name + "_curling.obj").c_str()).c_str(), "w");
|
||||||
|
if (fp == nullptr) {
|
||||||
|
BOOST_LOG_TRIVIAL(error)
|
||||||
|
<< "Debug files: Couldn't open " << file_name << " for writing";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < issues.curling_up.size(); ++i) {
|
||||||
|
fprintf(fp, "v %f %f %f %f %f %f\n",
|
||||||
|
issues.curling_up[i](0), issues.curling_up[i](1), issues.curling_up[i](2),
|
||||||
|
0.0, 1.0, 0.0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EdgeGridWrapper compute_layer_edge_grid(const Layer *layer) {
|
||||||
|
float min_region_flow_width { 1.0f };
|
||||||
|
for (const auto *region : layer->regions()) {
|
||||||
|
min_region_flow_width = std::min(min_region_flow_width, region->flow(FlowRole::frExternalPerimeter).width());
|
||||||
|
}
|
||||||
|
ExPolygons ex_polygons;
|
||||||
for (const LayerRegion *layer_region : layer->regions()) {
|
for (const LayerRegion *layer_region : layer->regions()) {
|
||||||
coordf_t flow_width = coordf_t(
|
|
||||||
scale_(layer_region->flow(FlowRole::frExternalPerimeter).width()));
|
|
||||||
for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) {
|
for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) {
|
||||||
for (const ExtrusionEntity *perimeter : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
|
for (const ExtrusionEntity *perimeter : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
|
||||||
if (perimeter->role() == ExtrusionRole::erExternalPerimeter) {
|
if (perimeter->role() == ExtrusionRole::erExternalPerimeter) {
|
||||||
check_extrusion_entity_stability(perimeter, supported_grid, params);
|
ex_polygons.push_back(ExPolygon { perimeter->as_polyline().points });
|
||||||
} // ex_perimeter
|
} // ex_perimeter
|
||||||
} // perimeter
|
} // perimeter
|
||||||
} // ex_entity
|
} // ex_entity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return EdgeGridWrapper(scale_(min_region_flow_width), ex_polygons);
|
||||||
|
}
|
||||||
|
|
||||||
|
Issues check_extrusion_entity_stability(const ExtrusionEntity *entity, size_t layer_idx,
|
||||||
|
float slice_z,
|
||||||
|
coordf_t flow_width,
|
||||||
|
const EdgeGridWrapper &supported_grid,
|
||||||
|
const Params ¶ms) {
|
||||||
|
|
||||||
|
Issues issues { };
|
||||||
|
if (entity->is_collection()) {
|
||||||
|
for (const auto *e : static_cast<const ExtrusionEntityCollection*>(entity)->entities) {
|
||||||
|
issues.add(check_extrusion_entity_stability(e, layer_idx, slice_z, flow_width, supported_grid, params));
|
||||||
|
}
|
||||||
|
} else { //single extrusion path, with possible varying parameters
|
||||||
|
Points points = entity->as_polyline().points;
|
||||||
|
float unsupported_distance = params.bridge_distance + 1.0f;
|
||||||
|
float curvature = 0;
|
||||||
|
float max_curvature = 0;
|
||||||
|
Vec2f tmp = unscale(points[0]).cast<float>();
|
||||||
|
Vec3f prev_point = Vec3f(tmp.x(), tmp.y(), slice_z);
|
||||||
|
|
||||||
|
for (size_t point_index = 0; point_index < points.size(); ++point_index) {
|
||||||
|
std::cout << "index: " << point_index << " dist: " << unsupported_distance << " curvature: "
|
||||||
|
<< curvature << " max curvature: " << max_curvature << std::endl;
|
||||||
|
|
||||||
|
Vec2f tmp = unscale(points[point_index]).cast<float>();
|
||||||
|
Vec3f u_point = Vec3f(tmp.x(), tmp.y(), slice_z);
|
||||||
|
|
||||||
|
coordf_t dist_from_prev_layer { 0 };
|
||||||
|
if (!supported_grid.grid.signed_distance(points[point_index], flow_width, dist_from_prev_layer)) {
|
||||||
|
issues.supports_nedded.push_back(u_point);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr float limit_overlap_factor = 0.5;
|
||||||
|
|
||||||
|
if (dist_from_prev_layer > flow_width) { //unsupported
|
||||||
|
std::cout << "index: " << point_index << " unsupported " << std::endl;
|
||||||
|
unsupported_distance += (u_point - prev_point).norm();
|
||||||
|
} else {
|
||||||
|
std::cout << "index: " << point_index << " grounded " << std::endl;
|
||||||
|
unsupported_distance = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "index: " << point_index << " dfromprev: " << dist_from_prev_layer << std::endl;
|
||||||
|
|
||||||
|
if (dist_from_prev_layer > flow_width * limit_overlap_factor && point_index < points.size() - 1) {
|
||||||
|
const Vec2f v1 = (u_point - prev_point).head<2>();
|
||||||
|
const Vec2f v2 = unscale(points[point_index + 1]).cast<float>() - u_point.head<2>();
|
||||||
|
float dot = v1(0) * v2(0) + v1(1) * v2(1);
|
||||||
|
float cross = v1(0) * v2(1) - v1(1) * v2(0);
|
||||||
|
float angle = float(atan2(float(cross), float(dot)));
|
||||||
|
|
||||||
|
std::cout << "index: " << point_index << " angle: " << angle << std::endl;
|
||||||
|
|
||||||
|
curvature += angle;
|
||||||
|
max_curvature = std::max(abs(curvature), max_curvature);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(dist_from_prev_layer > flow_width * limit_overlap_factor)) {
|
||||||
|
std::cout << "index: " << point_index << " reset curvature" << std::endl;
|
||||||
|
max_curvature = 0;
|
||||||
|
curvature = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unsupported_distance > params.bridge_distance / (1 + int(max_curvature * 9 / PI))) {
|
||||||
|
issues.supports_nedded.push_back(u_point);
|
||||||
|
unsupported_distance = 0;
|
||||||
|
curvature = 0;
|
||||||
|
max_curvature = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_curvature / (PI * unsupported_distance) > params.limit_curvature) {
|
||||||
|
issues.curling_up.push_back(u_point);
|
||||||
|
curvature = 0;
|
||||||
|
max_curvature = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_point = u_point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return issues;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO needs revision
|
||||||
|
coordf_t get_flow_width(const LayerRegion *region, ExtrusionRole role) {
|
||||||
|
switch (role) {
|
||||||
|
case ExtrusionRole::erBridgeInfill:
|
||||||
|
return region->flow(FlowRole::frExternalPerimeter).scaled_width();
|
||||||
|
case ExtrusionRole::erExternalPerimeter:
|
||||||
|
return region->flow(FlowRole::frExternalPerimeter).scaled_width();
|
||||||
|
case ExtrusionRole::erGapFill:
|
||||||
|
return region->flow(FlowRole::frInfill).scaled_width();
|
||||||
|
case ExtrusionRole::erPerimeter:
|
||||||
|
return region->flow(FlowRole::frPerimeter).scaled_width();
|
||||||
|
case ExtrusionRole::erSolidInfill:
|
||||||
|
return region->flow(FlowRole::frSolidInfill).scaled_width();
|
||||||
|
default:
|
||||||
|
return region->flow(FlowRole::frExternalPerimeter).scaled_width();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Issues check_layer_stability(const PrintObject *po, size_t layer_idx, bool full_check, const Params ¶ms) {
|
||||||
|
std::cout << "Checking: " << layer_idx << std::endl;
|
||||||
|
if (layer_idx == 0) {
|
||||||
|
// first layer is usually ok
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const Layer *layer = po->get_layer(layer_idx);
|
||||||
|
EdgeGridWrapper supported_grid = compute_layer_edge_grid(layer->lower_layer);
|
||||||
|
|
||||||
|
Issues issues { };
|
||||||
|
if (full_check) {
|
||||||
|
for (const LayerRegion *layer_region : layer->regions()) {
|
||||||
|
for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) {
|
||||||
|
for (const ExtrusionEntity *perimeter : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
|
||||||
|
issues.add(check_extrusion_entity_stability(perimeter, layer_idx,
|
||||||
|
layer->slice_z, get_flow_width(layer_region, perimeter->role()),
|
||||||
|
supported_grid, params));
|
||||||
|
} // perimeter
|
||||||
|
} // ex_entity
|
||||||
|
for (const ExtrusionEntity *ex_entity : layer_region->fills.entities) {
|
||||||
|
for (const ExtrusionEntity *fill : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
|
||||||
|
if (fill->role() == ExtrusionRole::erGapFill || fill->role() == ExtrusionRole::erBridgeInfill) {
|
||||||
|
issues.add(check_extrusion_entity_stability(fill, layer_idx,
|
||||||
|
layer->slice_z, get_flow_width(layer_region, fill->role()),
|
||||||
|
supported_grid, params));
|
||||||
|
}
|
||||||
|
} // fill
|
||||||
|
} // ex_entity
|
||||||
|
} // region
|
||||||
|
} else { //check only external perimeters
|
||||||
|
for (const LayerRegion *layer_region : layer->regions()) {
|
||||||
|
for (const ExtrusionEntity *ex_entity : layer_region->perimeters.entities) {
|
||||||
|
for (const ExtrusionEntity *perimeter : static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities) {
|
||||||
|
if (perimeter->role() == ExtrusionRole::erExternalPerimeter) {
|
||||||
|
std::cout << "checking ex perimeter " << std::endl;
|
||||||
|
issues.add(check_extrusion_entity_stability(perimeter, layer_idx,
|
||||||
|
layer->slice_z, get_flow_width(layer_region, perimeter->role()),
|
||||||
|
supported_grid, params));
|
||||||
|
}; // ex_perimeter
|
||||||
|
} // perimeter
|
||||||
|
} // ex_entity
|
||||||
|
} //region
|
||||||
|
}
|
||||||
|
|
||||||
|
return issues;
|
||||||
}
|
}
|
||||||
|
|
||||||
} //Impl End
|
} //Impl End
|
||||||
|
|
||||||
void quick_search(const PrintObject *po, const Params ¶ms = Params { }) {
|
std::vector<size_t> quick_search(const PrintObject *po, const Params ¶ms) {
|
||||||
using namespace Impl;
|
using namespace Impl;
|
||||||
std::vector<LayerDescriptor> descriptors(po->layer_count());
|
std::vector<LayerDescriptor> descriptors(po->layer_count());
|
||||||
|
|
||||||
@ -129,20 +298,75 @@ void quick_search(const PrintObject *po, const Params ¶ms = Params { }) {
|
|||||||
} // thread
|
} // thread
|
||||||
);
|
);
|
||||||
|
|
||||||
for (size_t desc_idx = 0; desc_idx < descriptors.size(); ++desc_idx) {
|
std::vector<size_t> suspicious_layers_indices { };
|
||||||
|
|
||||||
|
for (size_t desc_idx = 1; desc_idx < descriptors.size(); ++desc_idx) {
|
||||||
|
const LayerDescriptor &prev = descriptors[desc_idx - 1];
|
||||||
const LayerDescriptor &descriptor = descriptors[desc_idx];
|
const LayerDescriptor &descriptor = descriptors[desc_idx];
|
||||||
|
if (descriptor.segments_count - prev.segments_count != 0
|
||||||
|
||
|
||||||
|
std::abs(descriptor.perimeter_length - prev.perimeter_length)
|
||||||
|
> params.perimeter_length_diff_tolerance ||
|
||||||
|
(descriptor.centroid - prev.centroid).norm() > params.centroid_offset_tolerance
|
||||||
|
) {
|
||||||
|
suspicious_layers_indices.push_back(desc_idx);
|
||||||
|
}
|
||||||
|
#ifdef DEBUG_FILES
|
||||||
std::cout << "SIS layer idx: " << desc_idx << " reg count: " << descriptor.segments_count << " len: "
|
std::cout << "SIS layer idx: " << desc_idx << " reg count: " << descriptor.segments_count << " len: "
|
||||||
<< descriptor.perimeter_length <<
|
<< descriptor.perimeter_length <<
|
||||||
" centroid: " << descriptor.centroid.x() << " | " << descriptor.centroid.y() << std::endl;
|
" centroid: " << descriptor.centroid.x() << " | " << descriptor.centroid.y() << std::endl;
|
||||||
if (desc_idx > 0) {
|
|
||||||
const LayerDescriptor &prev = descriptors[desc_idx - 1];
|
|
||||||
std::cout << "SIS diff: " << desc_idx << " reg count: "
|
std::cout << "SIS diff: " << desc_idx << " reg count: "
|
||||||
<< (int(descriptor.segments_count) - int(prev.segments_count)) <<
|
<< (int(descriptor.segments_count) - int(prev.segments_count)) <<
|
||||||
" len: " << (descriptor.perimeter_length - prev.perimeter_length) <<
|
" len: " << (descriptor.perimeter_length - prev.perimeter_length) <<
|
||||||
" centroid: " << (descriptor.centroid - prev.centroid).norm() << std::endl;
|
" centroid: " << (descriptor.centroid - prev.centroid).norm() << std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<bool> layer_needs_supports(suspicious_layers_indices.size(), false);
|
||||||
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, suspicious_layers_indices.size()),
|
||||||
|
[&](tbb::blocked_range<size_t> r) {
|
||||||
|
for (size_t suspicious_index = r.begin(); suspicious_index < r.end(); ++suspicious_index) {
|
||||||
|
auto layer_issues = check_layer_stability(po, suspicious_layers_indices[suspicious_index],
|
||||||
|
false,
|
||||||
|
params);
|
||||||
|
if (!layer_issues.supports_nedded.empty()) {
|
||||||
|
layer_needs_supports[suspicious_index] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
std::vector<size_t> problematic_layers;
|
||||||
|
|
||||||
|
for (size_t index = suspicious_layers_indices.size() - 1; index <= 0; ++index) {
|
||||||
|
if (!layer_needs_supports[index]) {
|
||||||
|
problematic_layers.push_back(suspicious_layers_indices[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return problematic_layers;
|
||||||
|
}
|
||||||
|
|
||||||
|
Issues full_search(const PrintObject *po, const Params ¶ms) {
|
||||||
|
using namespace Impl;
|
||||||
|
Issues issues { };
|
||||||
|
for (size_t layer_idx = 1; layer_idx < po->layer_count(); ++layer_idx) {
|
||||||
|
auto layer_issues = check_layer_stability(po, layer_idx, true, params);
|
||||||
|
if (!layer_issues.empty()) {
|
||||||
|
issues.add(layer_issues);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_FILES
|
||||||
|
Impl::debug_export(issues, "issues");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// tbb::parallel_for(tbb::blocked_range<size_t>(0, suspicious_layers_indices.size()),
|
||||||
|
// [&](tbb::blocked_range<size_t> r) {
|
||||||
|
// for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++layer_idx) {
|
||||||
|
// check_layer_stability(po, suspicious_layers_indices[layer_idx], params);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
return issues;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,25 @@ namespace Slic3r {
|
|||||||
|
|
||||||
namespace SupportableIssues {
|
namespace SupportableIssues {
|
||||||
|
|
||||||
void quick_search(const PrintObject *po);
|
struct Params {
|
||||||
|
float bridge_distance = 5.0f;
|
||||||
|
float limit_curvature = 0.25f;
|
||||||
|
|
||||||
|
float perimeter_length_diff_tolerance = 8.0f;
|
||||||
|
float centroid_offset_tolerance = 1.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Issues {
|
||||||
|
std::vector<Vec3f> supports_nedded;
|
||||||
|
std::vector<Vec3f> curling_up;
|
||||||
|
|
||||||
|
void add(const Issues &layer_issues);
|
||||||
|
bool empty() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<size_t> quick_search(const PrintObject *po, const Params ¶ms = Params { });
|
||||||
|
Issues full_search(const PrintObject *po, const Params ¶ms = Params { });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
src/libslic3r/TriangleSelectorWrapper.cpp
Normal file
1
src/libslic3r/TriangleSelectorWrapper.cpp
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
42
src/libslic3r/TriangleSelectorWrapper.hpp
Normal file
42
src/libslic3r/TriangleSelectorWrapper.hpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#ifndef SRC_LIBSLIC3R_TRIANGLESELECTORWRAPPER_HPP_
|
||||||
|
#define SRC_LIBSLIC3R_TRIANGLESELECTORWRAPPER_HPP_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "TriangleSelector.hpp"
|
||||||
|
#include "AABBTreeIndirect.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class TriangleSelectorWrapper {
|
||||||
|
public:
|
||||||
|
const TriangleMesh &mesh;
|
||||||
|
TriangleSelector selector;
|
||||||
|
AABBTreeIndirect::Tree<3, float> triangles_tree;
|
||||||
|
|
||||||
|
TriangleSelectorWrapper(const TriangleMesh &mesh) :
|
||||||
|
mesh(mesh), selector(mesh), triangles_tree(AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(mesh.its.vertices, mesh.its.indices)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void enforce_spot(const Vec3f &point, float radius) {
|
||||||
|
size_t hit_face_index;
|
||||||
|
Vec3f hit_point;
|
||||||
|
auto dist = AABBTreeIndirect::squared_distance_to_indexed_triangle_set(mesh.its.vertices, mesh.its.indices,
|
||||||
|
triangles_tree,
|
||||||
|
point, hit_face_index, hit_point);
|
||||||
|
if (dist < 0 || dist > radius)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::unique_ptr<TriangleSelector::Cursor> cursor = std::make_unique<TriangleSelector::Sphere>(point, point,
|
||||||
|
radius, Transform3d::Identity(), TriangleSelector::ClippingPlane { });
|
||||||
|
|
||||||
|
selector.select_patch(hit_face_index, std::move(cursor), EnforcerBlockerType::ENFORCER, Transform3d::Identity(), true,
|
||||||
|
0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* SRC_LIBSLIC3R_TRIANGLESELECTORWRAPPER_HPP_ */
|
Loading…
x
Reference in New Issue
Block a user