mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-11 16:57:53 -06:00
WIP: Optimization of the object's 2D convex silhouette for arrangement,
not working yet.
This commit is contained in:
parent
282ef552f9
commit
adb96bdc2e
4 changed files with 100 additions and 18 deletions
|
@ -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
|
// This implementation is based on Andrew's monotone chain 2D convex hull algorithm
|
||||||
Polygon
|
Polygon convex_hull(Points points)
|
||||||
convex_hull(Points points)
|
|
||||||
{
|
{
|
||||||
assert(points.size() >= 3);
|
assert(points.size() >= 3);
|
||||||
// sort input points
|
// sort input points
|
||||||
|
|
|
@ -912,6 +912,60 @@ BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_
|
||||||
return bb;
|
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()
|
void ModelObject::center_around_origin()
|
||||||
{
|
{
|
||||||
// calculate the displacements needed to
|
// calculate the displacements needed to
|
||||||
|
@ -1099,7 +1153,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
||||||
|
|
||||||
// Perform cut
|
// Perform cut
|
||||||
TriangleMeshSlicer tms(&volume->mesh);
|
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
|
// Reset volume transformation except for offset
|
||||||
const Vec3d offset = volume->get_offset();
|
const Vec3d offset = volume->get_offset();
|
||||||
|
|
|
@ -223,6 +223,12 @@ public:
|
||||||
BoundingBoxf3 raw_mesh_bounding_box() const;
|
BoundingBoxf3 raw_mesh_bounding_box() const;
|
||||||
// A snug bounding box of non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes.
|
// 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;
|
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 center_around_origin();
|
||||||
void ensure_on_bed();
|
void ensure_on_bed();
|
||||||
void translate_instances(const Vec3d& vector);
|
void translate_instances(const Vec3d& vector);
|
||||||
|
|
|
@ -553,6 +553,12 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
|
||||||
for(ModelObject* objptr : model.objects) {
|
for(ModelObject* objptr : model.objects) {
|
||||||
if(objptr) {
|
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();
|
TriangleMesh rmesh = objptr->raw_mesh();
|
||||||
|
|
||||||
ModelInstance * finst = objptr->instances.front();
|
ModelInstance * finst = objptr->instances.front();
|
||||||
|
@ -570,7 +576,24 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
|
||||||
|
|
||||||
p.make_clockwise();
|
p.make_clockwise();
|
||||||
p.append(p.first_point());
|
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) {
|
for(ModelInstance* objinst : objptr->instances) {
|
||||||
if(objinst) {
|
if(objinst) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue