mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-07-21 17:34:29 +08:00
remove colinear points
* this fix the issue that colinear points aren't anymore after the offset2 from slice_closing_radius. * this allow the XY hole compensation to apply correctly * up the max concave angle accepted to detect hole to grow by XY compensation from 0.06° to 6°.
This commit is contained in:
parent
b12f484b48
commit
3476579d44
@ -316,6 +316,35 @@ Point Polygon::point_projection(const Point &point) const
|
||||
return proj;
|
||||
}
|
||||
|
||||
size_t Polygon::remove_colinear_points(coord_t max_offset){
|
||||
size_t nb_del = 0;
|
||||
if (points.size() < 3) return 0;
|
||||
|
||||
coord_t min_dist = max_offset * max_offset;
|
||||
while (points.size() > 2 && Line::distance_to_squared(points[0], points.back(), points[1]) < min_dist){
|
||||
//colinear! delete!
|
||||
points.erase(points.begin());
|
||||
nb_del++;
|
||||
}
|
||||
for (size_t idx = 1; idx < points.size()-1; ) {
|
||||
//if (Line(previous, points[idx + 1]).distance_to(points[idx]) < SCALED_EPSILON){
|
||||
if (Line::distance_to_squared(points[idx], points[idx-1], points[idx + 1]) < min_dist){
|
||||
//colinear! delete!
|
||||
points.erase(points.begin() + idx);
|
||||
nb_del++;
|
||||
} else {
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
while (points.size() > 2 && Line::distance_to_squared(points.back(), points[points.size()-2], points.front()) < min_dist) {
|
||||
//colinear! delete!
|
||||
points.erase(points.end()-1);
|
||||
nb_del++;
|
||||
}
|
||||
|
||||
return nb_del;
|
||||
}
|
||||
|
||||
BoundingBox get_extents(const Polygon &poly)
|
||||
{
|
||||
return poly.bounding_box();
|
||||
|
@ -59,6 +59,9 @@ public:
|
||||
Points convex_points(double angle = PI) const;
|
||||
// Projection of a point onto the polygon.
|
||||
Point point_projection(const Point &point) const;
|
||||
/// remove points that are (almost) on an existing line from previous & next point.
|
||||
/// return number of point removed
|
||||
size_t remove_colinear_points(coord_t max_offset);
|
||||
};
|
||||
|
||||
extern BoundingBox get_extents(const Polygon &poly);
|
||||
|
@ -2254,6 +2254,20 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comExpert;
|
||||
def->default_value = new ConfigOptionStrings { "; Filament gcode\n" };
|
||||
|
||||
|
||||
def = this->add("model_precision", coFloat);
|
||||
def->label = L("Model rounding precision");
|
||||
def->full_label = L("Model rounding precision");
|
||||
def->category = L("Advanced");
|
||||
def->tooltip = L("This is the rounding error of the input object."
|
||||
" It's used to align points that should be in the same line."
|
||||
" Put 0 to disable.");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "model-precision=f";
|
||||
def->min = 0;
|
||||
def->mode = comExpert;
|
||||
def->default_value = new ConfigOptionFloat(0.0001);
|
||||
|
||||
def = this->add("single_extruder_multi_material", coBool);
|
||||
def->label = L("Single Extruder Multi Material");
|
||||
def->tooltip = L("The printer multiplexes filaments into a single hot end.");
|
||||
|
@ -453,13 +453,14 @@ public:
|
||||
ConfigOptionBool clip_multipart_objects;
|
||||
ConfigOptionBool dont_support_bridges;
|
||||
ConfigOptionFloat elefant_foot_compensation;
|
||||
ConfigOptionBool exact_last_layer_height;
|
||||
ConfigOptionFloatOrPercent extrusion_width;
|
||||
ConfigOptionFloatOrPercent first_layer_height;
|
||||
ConfigOptionBool infill_only_where_needed;
|
||||
// Force the generation of solid shells between adjacent materials/volumes.
|
||||
ConfigOptionBool interface_shells;
|
||||
ConfigOptionFloat layer_height;
|
||||
ConfigOptionBool exact_last_layer_height;
|
||||
ConfigOptionFloat model_precision;
|
||||
ConfigOptionInt raft_layers;
|
||||
ConfigOptionEnum<SeamPosition> seam_position;
|
||||
ConfigOptionBool seam_travel;
|
||||
@ -505,12 +506,13 @@ protected:
|
||||
OPT_PTR(clip_multipart_objects);
|
||||
OPT_PTR(dont_support_bridges);
|
||||
OPT_PTR(elefant_foot_compensation);
|
||||
OPT_PTR(exact_last_layer_height);
|
||||
OPT_PTR(extrusion_width);
|
||||
OPT_PTR(first_layer_height);
|
||||
OPT_PTR(infill_only_where_needed);
|
||||
OPT_PTR(interface_shells);
|
||||
OPT_PTR(layer_height);
|
||||
OPT_PTR(exact_last_layer_height);
|
||||
OPT_PTR(model_precision);
|
||||
OPT_PTR(raft_layers);
|
||||
OPT_PTR(seam_position);
|
||||
OPT_PTR(seam_travel);
|
||||
|
@ -813,7 +813,6 @@ void PrintObject::tag_under_bridge() {
|
||||
for (ExPolygon poly_inter : dense_polys) area_dense += poly_inter.area();
|
||||
double area_sparse = 0;
|
||||
for (ExPolygon poly_inter : sparse_polys) area_sparse += poly_inter.area();
|
||||
std::cout << "need to split? " << area_sparse << " > " << area_dense << " * " << COEFF_SPLIT << "\n";
|
||||
if (area_sparse > area_dense * COEFF_SPLIT) {
|
||||
//split
|
||||
dense_polys = union_ex(dense_polys);
|
||||
@ -1913,27 +1912,27 @@ end:
|
||||
|
||||
void PrintObject::_offsetHoles(float hole_delta, LayerRegion *layerm) {
|
||||
if (hole_delta != 0.f) {
|
||||
std::cout << "offset_hole z="<<layerm->layer()->id()<<"\n";
|
||||
ExPolygons polys = to_expolygons(std::move(layerm->slices.surfaces));
|
||||
ExPolygons new_polys;
|
||||
for (ExPolygon ex_poly : polys) {
|
||||
for (const ExPolygon &ex_poly : polys) {
|
||||
ExPolygon new_ex_poly(ex_poly);
|
||||
new_ex_poly.holes.clear();
|
||||
for (Polygon hole : ex_poly.holes) {
|
||||
for (const Polygon &hole : ex_poly.holes) {
|
||||
//check if convex to reduce it
|
||||
// check whether first point forms a convex angle
|
||||
//note: we allow a deviation of 5.7° (0.01rad = 0.57°)
|
||||
bool ok = true;
|
||||
ok = (hole.points.front().ccw_angle(hole.points.back(), *(hole.points.begin() + 1)) <= PI + 0.001);
|
||||
|
||||
|
||||
ok = (hole.points.front().ccw_angle(hole.points.back(), *(hole.points.begin() + 1)) <= PI + 0.1);
|
||||
// check whether points 1..(n-1) form convex angles
|
||||
if (ok)
|
||||
for (Points::const_iterator p = hole.points.begin() + 1; p != hole.points.end() - 1; ++p) {
|
||||
ok = (p->ccw_angle(*(p - 1), *(p + 1)) <= PI + 0.001);
|
||||
ok = (p->ccw_angle(*(p - 1), *(p + 1)) <= PI + 0.1);
|
||||
if (!ok) break;
|
||||
}
|
||||
|
||||
// check whether last point forms a convex angle
|
||||
ok &= (hole.points.back().ccw_angle(*(hole.points.end() - 2), hole.points.front()) <= PI + 0.001);
|
||||
ok &= (hole.points.back().ccw_angle(*(hole.points.end() - 2), hole.points.front()) <= PI + 0.1);
|
||||
|
||||
if (ok) {
|
||||
for (Polygon newHole : offset(hole, -hole_delta)) {
|
||||
@ -1941,9 +1940,10 @@ void PrintObject::_offsetHoles(float hole_delta, LayerRegion *layerm) {
|
||||
newHole.make_clockwise();
|
||||
new_ex_poly.holes.push_back(newHole);
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
new_ex_poly.holes.push_back(hole);
|
||||
}
|
||||
}
|
||||
new_polys.push_back(new_ex_poly);
|
||||
}
|
||||
layerm->slices.set(std::move(new_polys), stPosInternal | stDensSparse);
|
||||
@ -2007,11 +2007,11 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z,
|
||||
// apply XY shift
|
||||
mesh.translate(- unscale<float>(m_copies_shift(0)), - unscale<float>(m_copies_shift(1)), 0);
|
||||
// perform actual slicing
|
||||
TriangleMeshSlicer mslicer;
|
||||
TriangleMeshSlicer mslicer(float(m_config.slice_closing_radius.value), float(m_config.model_precision.value));
|
||||
const Print *print = this->print();
|
||||
auto callback = TriangleMeshSlicer::throw_on_cancel_callback_type([print](){print->throw_if_canceled();});
|
||||
mslicer.init(&mesh, callback);
|
||||
mslicer.slice(z, float(m_config.slice_closing_radius.value), &layers, callback);
|
||||
mslicer.slice(z, &layers, callback);
|
||||
m_print->throw_if_canceled();
|
||||
}
|
||||
}
|
||||
|
@ -561,7 +561,7 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
|
||||
heights.emplace_back(hi);
|
||||
|
||||
std::vector<ExPolygons> out; out.reserve(size_t(std::ceil(h/layerh)));
|
||||
slicer.slice(heights, 0.f, &out, thrfn);
|
||||
slicer.slice(heights, &out, thrfn);
|
||||
|
||||
size_t count = 0; for(auto& o : out) count += o.size();
|
||||
|
||||
|
@ -2105,7 +2105,7 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const
|
||||
fullmesh.merge(get_pad());
|
||||
TriangleMeshSlicer slicer(&fullmesh);
|
||||
SlicedSupports ret;
|
||||
slicer.slice(heights, 0.f, &ret, get().ctl().cancelfn);
|
||||
slicer.slice(heights, &ret, get().ctl().cancelfn);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -629,7 +629,8 @@ void SLAPrint::process()
|
||||
double lh = po.m_config.layer_height.getFloat();
|
||||
|
||||
TriangleMesh mesh = po.transformed_mesh();
|
||||
TriangleMeshSlicer slicer(&mesh);
|
||||
TriangleMeshSlicer slicer(float(po.config().slice_closing_radius.value),0);
|
||||
slicer.init(&mesh, [](){});
|
||||
|
||||
// The 1D grid heights
|
||||
std::vector<float> heights = calculate_heights(mesh.bounding_box(),
|
||||
@ -637,7 +638,7 @@ void SLAPrint::process()
|
||||
ilh, float(lh));
|
||||
|
||||
auto& layers = po.m_model_slices; layers.clear();
|
||||
slicer.slice(heights, float(po.config().slice_closing_radius.value), &layers, [this](){ throw_if_canceled(); });
|
||||
slicer.slice(heights, &layers, [this](){ throw_if_canceled(); });
|
||||
};
|
||||
|
||||
// In this step we check the slices, identify island and cover them with
|
||||
|
@ -852,7 +852,7 @@ void TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLin
|
||||
}
|
||||
}
|
||||
|
||||
void TriangleMeshSlicer::slice(const std::vector<float> &z, const float closing_radius, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const
|
||||
void TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const
|
||||
{
|
||||
std::vector<Polygons> layers_p;
|
||||
this->slice(z, &layers_p, throw_on_cancel);
|
||||
@ -861,13 +861,13 @@ void TriangleMeshSlicer::slice(const std::vector<float> &z, const float closing_
|
||||
layers->resize(z.size());
|
||||
tbb::parallel_for(
|
||||
tbb::blocked_range<size_t>(0, z.size()),
|
||||
[&layers_p, closing_radius, layers, throw_on_cancel, this](const tbb::blocked_range<size_t>& range) {
|
||||
[&layers_p, layers, throw_on_cancel, this](const tbb::blocked_range<size_t>& range) {
|
||||
for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
|
||||
#ifdef SLIC3R_TRIANGLEMESH_DEBUG
|
||||
printf("Layer " PRINTF_ZU " (slice_z = %.2f):\n", layer_id, z[layer_id]);
|
||||
#endif
|
||||
throw_on_cancel();
|
||||
this->make_expolygons(layers_p[layer_id], closing_radius, &(*layers)[layer_id]);
|
||||
this->make_expolygons(layers_p[layer_id], &(*layers)[layer_id]);
|
||||
}
|
||||
});
|
||||
BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::make_expolygons in parallel - end";
|
||||
@ -1600,7 +1600,7 @@ void TriangleMeshSlicer::make_expolygons_simple(std::vector<IntersectionLine> &l
|
||||
#endif
|
||||
}
|
||||
|
||||
void TriangleMeshSlicer::make_expolygons(const Polygons &loops, const float closing_radius, ExPolygons* slices) const
|
||||
void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slices) const
|
||||
{
|
||||
/*
|
||||
Input loops are not suitable for evenodd nor nonzero fill types, as we might get
|
||||
@ -1651,11 +1651,19 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, const float clos
|
||||
// p_slices = diff(p_slices, *loop);
|
||||
//}
|
||||
|
||||
//remove point in the same plane (have to do that before the safety offset to avoid workgin on a distored polygon)
|
||||
Polygons filered_polys = loops;
|
||||
if (this->model_precision > 0){
|
||||
for (Polygon &hole : filered_polys){
|
||||
hole.remove_colinear_points(scale_(this->model_precision));
|
||||
}
|
||||
}
|
||||
|
||||
// Perform a safety offset to merge very close facets (TODO: find test case for this)
|
||||
// 0.0499 comes from https://github.com/slic3r/Slic3r/issues/959
|
||||
// double safety_offset = scale_(0.0499);
|
||||
// 0.0001 is set to satisfy GH #520, #1029, #1364
|
||||
double safety_offset = scale_(closing_radius);
|
||||
double safety_offset = scale_(this->closing_radius);
|
||||
|
||||
/* The following line is commented out because it can generate wrong polygons,
|
||||
see for example issue #661 */
|
||||
@ -1671,16 +1679,16 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, const float clos
|
||||
|
||||
// append to the supplied collection
|
||||
if (safety_offset > 0)
|
||||
expolygons_append(*slices, offset2_ex(union_(loops, false), +safety_offset, -safety_offset));
|
||||
expolygons_append(*slices, offset2_ex(union_(filered_polys, false), +safety_offset, -safety_offset));
|
||||
else
|
||||
expolygons_append(*slices, union_ex(loops, false));
|
||||
expolygons_append(*slices, union_ex(filered_polys, false));
|
||||
}
|
||||
|
||||
void TriangleMeshSlicer::make_expolygons(std::vector<IntersectionLine> &lines, const float closing_radius, ExPolygons* slices) const
|
||||
void TriangleMeshSlicer::make_expolygons(std::vector<IntersectionLine> &lines, ExPolygons* slices) const
|
||||
{
|
||||
Polygons pp;
|
||||
this->make_loops(lines, &pp);
|
||||
this->make_expolygons(pp, closing_radius, slices);
|
||||
this->make_expolygons(pp, slices);
|
||||
}
|
||||
|
||||
void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) const
|
||||
|
@ -159,13 +159,16 @@ typedef std::vector<IntersectionLine*> IntersectionLinePtrs;
|
||||
class TriangleMeshSlicer
|
||||
{
|
||||
public:
|
||||
float closing_radius;
|
||||
float model_precision;
|
||||
|
||||
typedef std::function<void()> throw_on_cancel_callback_type;
|
||||
TriangleMeshSlicer() : mesh(nullptr) {}
|
||||
TriangleMeshSlicer(float closing_radius, float model_precision) : mesh(nullptr), closing_radius(closing_radius), model_precision(model_precision) {}
|
||||
// Not quite nice, but the constructor and init() methods require non-const mesh pointer to be able to call mesh->require_shared_vertices()
|
||||
TriangleMeshSlicer(TriangleMesh* mesh) { this->init(mesh, [](){}); }
|
||||
void init(TriangleMesh *mesh, throw_on_cancel_callback_type throw_on_cancel);
|
||||
void slice(const std::vector<float> &z, std::vector<Polygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const;
|
||||
void slice(const std::vector<float> &z, const float closing_radius, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const;
|
||||
void slice(const std::vector<float> &z, std::vector<ExPolygons>* layers, throw_on_cancel_callback_type throw_on_cancel) const;
|
||||
enum FacetSliceType {
|
||||
NoSlice = 0,
|
||||
Slicing = 1,
|
||||
@ -184,9 +187,9 @@ private:
|
||||
|
||||
void _slice_do(size_t facet_idx, std::vector<IntersectionLines>* lines, boost::mutex* lines_mutex, const std::vector<float> &z) const;
|
||||
void make_loops(std::vector<IntersectionLine> &lines, Polygons* loops) const;
|
||||
void make_expolygons(const Polygons &loops, const float closing_radius, ExPolygons* slices) const;
|
||||
void make_expolygons(const Polygons &loops, ExPolygons* slices) const;
|
||||
void make_expolygons_simple(std::vector<IntersectionLine> &lines, ExPolygons* slices) const;
|
||||
void make_expolygons(std::vector<IntersectionLine> &lines, const float closing_radius, ExPolygons* slices) const;
|
||||
void make_expolygons(std::vector<IntersectionLine> &lines, ExPolygons* slices) const;
|
||||
};
|
||||
|
||||
TriangleMesh make_cube(double x, double y, double z);
|
||||
|
@ -402,6 +402,7 @@ const std::vector<std::string>& Preset::print_options()
|
||||
, "first_layer_infill_speed"
|
||||
, "thin_walls_min_width"
|
||||
, "thin_walls_overlap"
|
||||
, "model_precision"
|
||||
};
|
||||
return s_opts;
|
||||
}
|
||||
|
@ -1179,6 +1179,7 @@ void TabPrint::build()
|
||||
optgroup = page->new_optgroup(_(L("Other")));
|
||||
optgroup->append_single_option_line("clip_multipart_objects");
|
||||
optgroup->append_single_option_line("resolution");
|
||||
optgroup->append_single_option_line("model_precision");
|
||||
|
||||
page = add_options_page(_(L("Output options")), "page_white_go.png");
|
||||
optgroup = page->new_optgroup(_(L("Sequential printing")));
|
||||
|
Loading…
x
Reference in New Issue
Block a user