WIP: Optimization of the object's 2D convex silhouette for arrangement,
not working yet.
This commit is contained in:
parent
282ef552f9
commit
adb96bdc2e
@ -207,8 +207,7 @@ static bool sort_pointfs(const Vec3d& a, const Vec3d& b)
|
||||
}
|
||||
|
||||
// This implementation is based on Andrew's monotone chain 2D convex hull algorithm
|
||||
Polygon
|
||||
convex_hull(Points points)
|
||||
Polygon convex_hull(Points points)
|
||||
{
|
||||
assert(points.size() >= 3);
|
||||
// sort input points
|
||||
|
@ -912,6 +912,60 @@ BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_
|
||||
return bb;
|
||||
}
|
||||
|
||||
// Calculate 2D convex hull of of a projection of the transformed printable volumes into the XY plane.
|
||||
// This method is cheap in that it does not make any unnecessary copy of the volume meshes.
|
||||
// This method is used by the auto arrange function.
|
||||
Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance)
|
||||
{
|
||||
Points pts;
|
||||
for (const ModelVolume *v : this->volumes)
|
||||
if (v->is_model_part()) {
|
||||
const stl_file &stl = v->mesh.stl;
|
||||
Transform3d trafo = trafo_instance * v->get_matrix();
|
||||
if (stl.v_shared == nullptr) {
|
||||
// Using the STL faces.
|
||||
for (unsigned int i = 0; i < stl.stats.number_of_facets; ++ i) {
|
||||
const stl_facet &facet = stl.facet_start[i];
|
||||
for (size_t j = 0; j < 3; ++ j) {
|
||||
Vec3d p = trafo * facet.vertex[j].cast<double>();
|
||||
pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y())));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Using the shared vertices should be a bit quicker than using the STL faces.
|
||||
for (int i = 0; i < stl.stats.shared_vertices; ++ i) {
|
||||
Vec3d p = trafo * stl.v_shared[i].cast<double>();
|
||||
pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y())));
|
||||
}
|
||||
}
|
||||
}
|
||||
std::sort(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) < b(0) || (a(0) == b(0) && a(1) < b(1)); });
|
||||
pts.erase(std::unique(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) == b(0) && a(1) == b(1); }), pts.end());
|
||||
|
||||
Polygon hull;
|
||||
int n = (int)pts.size();
|
||||
if (n >= 3) {
|
||||
int k = 0;
|
||||
hull.points.resize(2 * n);
|
||||
// Build lower hull
|
||||
for (int i = 0; i < n; ++ i) {
|
||||
while (k >= 2 && pts[i].ccw(hull[k-2], hull[k-1]) <= 0)
|
||||
-- k;
|
||||
hull[k ++] = pts[i];
|
||||
}
|
||||
// Build upper hull
|
||||
for (int i = n-2, t = k+1; i >= 0; i--) {
|
||||
while (k >= t && pts[i].ccw(hull[k-2], hull[k-1]) <= 0)
|
||||
-- k;
|
||||
hull[k ++] = pts[i];
|
||||
}
|
||||
hull.points.resize(k);
|
||||
assert(hull.points.front() == hull.points.back());
|
||||
hull.points.pop_back();
|
||||
}
|
||||
return hull;
|
||||
}
|
||||
|
||||
void ModelObject::center_around_origin()
|
||||
{
|
||||
// calculate the displacements needed to
|
||||
@ -1099,7 +1153,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
||||
|
||||
// Perform cut
|
||||
TriangleMeshSlicer tms(&volume->mesh);
|
||||
tms.cut(z, &upper_mesh, &lower_mesh);
|
||||
tms.cut(float(z), &upper_mesh, &lower_mesh);
|
||||
|
||||
// Reset volume transformation except for offset
|
||||
const Vec3d offset = volume->get_offset();
|
||||
|
@ -223,6 +223,12 @@ public:
|
||||
BoundingBoxf3 raw_mesh_bounding_box() const;
|
||||
// A snug bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes.
|
||||
BoundingBoxf3 full_raw_mesh_bounding_box() const;
|
||||
|
||||
// Calculate 2D convex hull of of a projection of the transformed printable volumes into the XY plane.
|
||||
// This method is cheap in that it does not make any unnecessary copy of the volume meshes.
|
||||
// This method is used by the auto arrange function.
|
||||
Polygon convex_hull_2d(const Transform3d &trafo_instance);
|
||||
|
||||
void center_around_origin();
|
||||
void ensure_on_bed();
|
||||
void translate_instances(const Vec3d& vector);
|
||||
|
@ -553,6 +553,12 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
|
||||
for(ModelObject* objptr : model.objects) {
|
||||
if(objptr) {
|
||||
|
||||
// TODO export the exact 2D projection. Cannot do it as libnest2d
|
||||
// does not support concave shapes (yet).
|
||||
ClipperLib::Path clpath;
|
||||
//WIP Vojtech's optimization of the calculation of the convex hull is not working correctly yet.
|
||||
#if 1
|
||||
{
|
||||
TriangleMesh rmesh = objptr->raw_mesh();
|
||||
|
||||
ModelInstance * finst = objptr->instances.front();
|
||||
@ -570,7 +576,24 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
|
||||
|
||||
p.make_clockwise();
|
||||
p.append(p.first_point());
|
||||
auto clpath = Slic3rMultiPoint_to_ClipperPath(p);
|
||||
clpath = Slic3rMultiPoint_to_ClipperPath(p);
|
||||
}
|
||||
#else
|
||||
// Object instances should carry the same scaling and
|
||||
// x, y rotation that is why we use the first instance.
|
||||
{
|
||||
ModelInstance *finst = objptr->instances.front();
|
||||
Vec3d rotation = finst->get_rotation();
|
||||
rotation.z() = 0.;
|
||||
Transform3d trafo_instance = Geometry::assemble_transform(Vec3d::Zero(), rotation, finst->get_scaling_factor(), finst->get_mirror());
|
||||
Polygon p = objptr->convex_hull_2d(trafo_instance);
|
||||
assert(! p.points.empty());
|
||||
p.reverse();
|
||||
assert(! p.is_counter_clockwise());
|
||||
p.append(p.first_point());
|
||||
clpath = Slic3rMultiPoint_to_ClipperPath(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
for(ModelInstance* objinst : objptr->instances) {
|
||||
if(objinst) {
|
||||
|
Loading…
Reference in New Issue
Block a user