mirror of
https://git.mirrors.martin98.com/https://github.com/SoftFever/OrcaSlicer.git
synced 2025-08-03 17:50:38 +08:00
Remove code duplication, clarify naming of orientation searches
This commit is contained in:
parent
74edeb147b
commit
1672130d45
@ -283,64 +283,61 @@ std::array<double, N> find_min_score(Fn &&fn, It from, It to, StopCond &&stopfn)
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Assemble the mesh with the correct transformation to be used in rotation
|
|
||||||
// optimization.
|
|
||||||
TriangleMesh get_mesh_to_rotate(const ModelObject &mo)
|
|
||||||
{
|
|
||||||
TriangleMesh mesh = mo.raw_mesh();
|
|
||||||
mesh.require_shared_vertices();
|
|
||||||
|
|
||||||
ModelInstance *mi = mo.instances[0];
|
|
||||||
auto rotation = Vec3d::Zero();
|
|
||||||
auto offset = Vec3d::Zero();
|
|
||||||
Transform3d trafo_instance = Geometry::assemble_transform(offset,
|
|
||||||
rotation,
|
|
||||||
mi->get_scaling_factor(),
|
|
||||||
mi->get_mirror());
|
|
||||||
|
|
||||||
mesh.transform(trafo_instance);
|
template<unsigned MAX_ITER>
|
||||||
|
struct RotfinderBoilerplate {
|
||||||
|
static constexpr unsigned MAX_TRIES = MAX_ITER;
|
||||||
|
|
||||||
return mesh;
|
int status = 0;
|
||||||
}
|
TriangleMesh mesh;
|
||||||
|
unsigned max_tries;
|
||||||
|
const RotOptimizeParams ¶ms;
|
||||||
|
|
||||||
|
// Assemble the mesh with the correct transformation to be used in rotation
|
||||||
|
// optimization.
|
||||||
|
static TriangleMesh get_mesh_to_rotate(const ModelObject &mo)
|
||||||
|
{
|
||||||
|
TriangleMesh mesh = mo.raw_mesh();
|
||||||
|
mesh.require_shared_vertices();
|
||||||
|
|
||||||
|
ModelInstance *mi = mo.instances[0];
|
||||||
|
auto rotation = Vec3d::Zero();
|
||||||
|
auto offset = Vec3d::Zero();
|
||||||
|
Transform3d trafo_instance =
|
||||||
|
Geometry::assemble_transform(offset, rotation,
|
||||||
|
mi->get_scaling_factor(),
|
||||||
|
mi->get_mirror());
|
||||||
|
|
||||||
|
mesh.transform(trafo_instance);
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
RotfinderBoilerplate(const ModelObject &mo, const RotOptimizeParams &p)
|
||||||
|
: mesh{get_mesh_to_rotate(mo)}
|
||||||
|
, params{p}
|
||||||
|
, max_tries(p.accuracy() * MAX_TRIES)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void statusfn() { params.statuscb()(++status * 100.0 / max_tries); }
|
||||||
|
bool stopcond() { return ! params.statuscb()(-1); }
|
||||||
|
};
|
||||||
|
|
||||||
Vec2d find_best_misalignment_rotation(const ModelObject & mo,
|
Vec2d find_best_misalignment_rotation(const ModelObject & mo,
|
||||||
const RotOptimizeParams ¶ms)
|
const RotOptimizeParams ¶ms)
|
||||||
{
|
{
|
||||||
static constexpr unsigned MAX_TRIES = 1000;
|
RotfinderBoilerplate<1000> bp{mo, params};
|
||||||
|
|
||||||
// return value
|
|
||||||
XYRotation rot;
|
|
||||||
|
|
||||||
// We will use only one instance of this converted mesh to examine different
|
|
||||||
// rotations
|
|
||||||
TriangleMesh mesh = get_mesh_to_rotate(mo);
|
|
||||||
|
|
||||||
// To keep track of the number of iterations
|
|
||||||
int status = 0;
|
|
||||||
|
|
||||||
// The maximum number of iterations
|
|
||||||
auto max_tries = unsigned(params.accuracy() * MAX_TRIES);
|
|
||||||
|
|
||||||
auto &statuscb = params.statuscb();
|
|
||||||
|
|
||||||
// call status callback with zero, because we are at the start
|
|
||||||
statuscb(status);
|
|
||||||
|
|
||||||
auto statusfn = [&statuscb, &status, &max_tries] {
|
|
||||||
// report status
|
|
||||||
statuscb(++status * 100.0/max_tries);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto stopcond = [&statuscb] {
|
|
||||||
return ! statuscb(-1);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Preparing the optimizer.
|
// Preparing the optimizer.
|
||||||
size_t gridsize = std::sqrt(max_tries);
|
size_t gridsize = std::sqrt(bp.max_tries);
|
||||||
opt::Optimizer<opt::AlgBruteForce> solver(opt::StopCriteria{}
|
opt::Optimizer<opt::AlgBruteForce> solver(
|
||||||
.max_iterations(max_tries)
|
opt::StopCriteria{}.max_iterations(bp.max_tries)
|
||||||
.stop_condition(stopcond),
|
.stop_condition([&bp] { return bp.stopcond(); }),
|
||||||
gridsize);
|
gridsize
|
||||||
|
);
|
||||||
|
|
||||||
// We are searching rotations around only two axes x, y. Thus the
|
// We are searching rotations around only two axes x, y. Thus the
|
||||||
// problem becomes a 2 dimensional optimization task.
|
// problem becomes a 2 dimensional optimization task.
|
||||||
@ -348,48 +345,19 @@ Vec2d find_best_misalignment_rotation(const ModelObject & mo,
|
|||||||
auto bounds = opt::bounds({ {-PI, PI}, {-PI, PI} });
|
auto bounds = opt::bounds({ {-PI, PI}, {-PI, PI} });
|
||||||
|
|
||||||
auto result = solver.to_max().optimize(
|
auto result = solver.to_max().optimize(
|
||||||
[&mesh, &statusfn] (const XYRotation &rot)
|
[&bp] (const XYRotation &rot)
|
||||||
{
|
{
|
||||||
statusfn();
|
bp.statusfn();
|
||||||
return get_misalginment_score(mesh, to_transform3f(rot));
|
return get_misalginment_score(bp.mesh, to_transform3f(rot));
|
||||||
}, opt::initvals({0., 0.}), bounds);
|
}, opt::initvals({0., 0.}), bounds);
|
||||||
|
|
||||||
rot = result.optimum;
|
return {result.optimum[0], result.optimum[1]};
|
||||||
|
|
||||||
return {rot[0], rot[1]};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2d find_least_supports_rotation(const ModelObject & mo,
|
Vec2d find_least_supports_rotation(const ModelObject & mo,
|
||||||
const RotOptimizeParams ¶ms)
|
const RotOptimizeParams ¶ms)
|
||||||
{
|
{
|
||||||
static const unsigned MAX_TRIES = 1000;
|
RotfinderBoilerplate<1000> bp{mo, params};
|
||||||
|
|
||||||
// return value
|
|
||||||
XYRotation rot;
|
|
||||||
|
|
||||||
// We will use only one instance of this converted mesh to examine different
|
|
||||||
// rotations
|
|
||||||
TriangleMesh mesh = get_mesh_to_rotate(mo);
|
|
||||||
|
|
||||||
// To keep track of the number of iterations
|
|
||||||
unsigned status = 0;
|
|
||||||
|
|
||||||
// The maximum number of iterations
|
|
||||||
auto max_tries = unsigned(params.accuracy() * MAX_TRIES);
|
|
||||||
|
|
||||||
auto &statuscb = params.statuscb();
|
|
||||||
|
|
||||||
// call status callback with zero, because we are at the start
|
|
||||||
statuscb(status);
|
|
||||||
|
|
||||||
auto statusfn = [&statuscb, &status, &max_tries] {
|
|
||||||
// report status
|
|
||||||
statuscb(unsigned(++status * 100.0/max_tries) );
|
|
||||||
};
|
|
||||||
|
|
||||||
auto stopcond = [&statuscb] {
|
|
||||||
return ! statuscb(-1);
|
|
||||||
};
|
|
||||||
|
|
||||||
SLAPrintObjectConfig pocfg;
|
SLAPrintObjectConfig pocfg;
|
||||||
if (params.print_config())
|
if (params.print_config())
|
||||||
@ -397,31 +365,35 @@ Vec2d find_least_supports_rotation(const ModelObject & mo,
|
|||||||
|
|
||||||
pocfg.apply(mo.config.get());
|
pocfg.apply(mo.config.get());
|
||||||
|
|
||||||
|
XYRotation rot;
|
||||||
|
|
||||||
// Different search methods have to be used depending on the model elevation
|
// Different search methods have to be used depending on the model elevation
|
||||||
if (is_on_floor(pocfg)) {
|
if (is_on_floor(pocfg)) {
|
||||||
|
|
||||||
std::vector<XYRotation> inputs = get_chull_rotations(mesh, max_tries);
|
std::vector<XYRotation> inputs = get_chull_rotations(bp.mesh, bp.max_tries);
|
||||||
max_tries = inputs.size();
|
bp.max_tries = inputs.size();
|
||||||
|
|
||||||
// If the model can be placed on the bed directly, we only need to
|
// If the model can be placed on the bed directly, we only need to
|
||||||
// check the 3D convex hull face rotations.
|
// check the 3D convex hull face rotations.
|
||||||
|
|
||||||
auto objfn = [&mesh, &statusfn](const XYRotation &rot) {
|
auto objfn = [&bp](const XYRotation &rot) {
|
||||||
statusfn();
|
bp.statusfn();
|
||||||
Transform3f tr = to_transform3f(rot);
|
Transform3f tr = to_transform3f(rot);
|
||||||
return get_supportedness_onfloor_score(mesh, tr);
|
return get_supportedness_onfloor_score(bp.mesh, tr);
|
||||||
};
|
};
|
||||||
|
|
||||||
rot = find_min_score<2>(objfn, inputs.begin(), inputs.end(), stopcond);
|
rot = find_min_score<2>(objfn, inputs.begin(), inputs.end(), [&bp] {
|
||||||
|
return bp.stopcond();
|
||||||
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Preparing the optimizer.
|
// Preparing the optimizer.
|
||||||
size_t gridsize = std::sqrt(max_tries); // 2D grid has gridsize^2 calls
|
size_t gridsize = std::sqrt(bp.max_tries); // 2D grid has gridsize^2 calls
|
||||||
opt::Optimizer<opt::AlgBruteForce> solver(opt::StopCriteria{}
|
opt::Optimizer<opt::AlgBruteForce> solver(
|
||||||
.max_iterations(max_tries)
|
opt::StopCriteria{}.max_iterations(bp.max_tries)
|
||||||
.stop_condition(stopcond),
|
.stop_condition([&bp] { return bp.stopcond(); }),
|
||||||
gridsize);
|
gridsize
|
||||||
|
);
|
||||||
|
|
||||||
// We are searching rotations around only two axes x, y. Thus the
|
// We are searching rotations around only two axes x, y. Thus the
|
||||||
// problem becomes a 2 dimensional optimization task.
|
// problem becomes a 2 dimensional optimization task.
|
||||||
@ -429,10 +401,10 @@ Vec2d find_least_supports_rotation(const ModelObject & mo,
|
|||||||
auto bounds = opt::bounds({ {-PI, PI}, {-PI, PI} });
|
auto bounds = opt::bounds({ {-PI, PI}, {-PI, PI} });
|
||||||
|
|
||||||
auto result = solver.to_min().optimize(
|
auto result = solver.to_min().optimize(
|
||||||
[&mesh, &statusfn] (const XYRotation &rot)
|
[&bp] (const XYRotation &rot)
|
||||||
{
|
{
|
||||||
statusfn();
|
bp.statusfn();
|
||||||
return get_supportedness_score(mesh, to_transform3f(rot));
|
return get_supportedness_score(bp.mesh, to_transform3f(rot));
|
||||||
}, opt::initvals({0., 0.}), bounds);
|
}, opt::initvals({0., 0.}), bounds);
|
||||||
|
|
||||||
// Save the result
|
// Save the result
|
||||||
@ -442,7 +414,8 @@ Vec2d find_least_supports_rotation(const ModelObject & mo,
|
|||||||
return {rot[0], rot[1]};
|
return {rot[0], rot[1]};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline BoundingBoxf3 bounding_box_with_tr(const indexed_triangle_set& its, const Transform3f &tr)
|
inline BoundingBoxf3 bounding_box_with_tr(const indexed_triangle_set &its,
|
||||||
|
const Transform3f &tr)
|
||||||
{
|
{
|
||||||
if (its.vertices.empty())
|
if (its.vertices.empty())
|
||||||
return {};
|
return {};
|
||||||
@ -458,38 +431,12 @@ inline BoundingBoxf3 bounding_box_with_tr(const indexed_triangle_set& its, const
|
|||||||
return {bmin.cast<double>(), bmax.cast<double>()};
|
return {bmin.cast<double>(), bmax.cast<double>()};
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2d find_min_z_height_rotation(const ModelObject &mo, const RotOptimizeParams ¶ms)
|
Vec2d find_min_z_height_rotation(const ModelObject &mo,
|
||||||
|
const RotOptimizeParams ¶ms)
|
||||||
{
|
{
|
||||||
static const unsigned MAX_TRIES = 1000;
|
RotfinderBoilerplate<1000> bp{mo, params};
|
||||||
|
|
||||||
// return value
|
TriangleMesh chull = bp.mesh.convex_hull_3d();
|
||||||
XYRotation rot;
|
|
||||||
|
|
||||||
// We will use only one instance of this converted mesh to examine different
|
|
||||||
// rotations
|
|
||||||
TriangleMesh mesh = get_mesh_to_rotate(mo);
|
|
||||||
|
|
||||||
// To keep track of the number of iterations
|
|
||||||
unsigned status = 0;
|
|
||||||
|
|
||||||
// The maximum number of iterations
|
|
||||||
auto max_tries = unsigned(params.accuracy() * MAX_TRIES);
|
|
||||||
|
|
||||||
auto &statuscb = params.statuscb();
|
|
||||||
|
|
||||||
// call status callback with zero, because we are at the start
|
|
||||||
statuscb(status);
|
|
||||||
|
|
||||||
auto statusfn = [&statuscb, &status, &max_tries] {
|
|
||||||
// report status
|
|
||||||
statuscb(unsigned(++status * 100.0/max_tries) );
|
|
||||||
};
|
|
||||||
|
|
||||||
auto stopcond = [&statuscb] {
|
|
||||||
return ! statuscb(-1);
|
|
||||||
};
|
|
||||||
|
|
||||||
TriangleMesh chull = mesh.convex_hull_3d();
|
|
||||||
chull.require_shared_vertices();
|
chull.require_shared_vertices();
|
||||||
auto inputs = reserve_vector<XYRotation>(chull.its.indices.size());
|
auto inputs = reserve_vector<XYRotation>(chull.its.indices.size());
|
||||||
auto rotcmp = [](const XYRotation &r1, const XYRotation &r2) {
|
auto rotcmp = [](const XYRotation &r1, const XYRotation &r2) {
|
||||||
@ -514,18 +461,20 @@ Vec2d find_min_z_height_rotation(const ModelObject &mo, const RotOptimizeParams
|
|||||||
}
|
}
|
||||||
|
|
||||||
inputs.shrink_to_fit();
|
inputs.shrink_to_fit();
|
||||||
max_tries = inputs.size();
|
bp.max_tries = inputs.size();
|
||||||
|
|
||||||
// If the model can be placed on the bed directly, we only need to
|
// If the model can be placed on the bed directly, we only need to
|
||||||
// check the 3D convex hull face rotations.
|
// check the 3D convex hull face rotations.
|
||||||
|
|
||||||
auto objfn = [&chull, &statusfn](const XYRotation &rot) {
|
auto objfn = [&bp, &chull](const XYRotation &rot) {
|
||||||
statusfn();
|
bp.statusfn();
|
||||||
Transform3f tr = to_transform3f(rot);
|
Transform3f tr = to_transform3f(rot);
|
||||||
return bounding_box_with_tr(chull.its, tr).size().z();
|
return bounding_box_with_tr(chull.its, tr).size().z();
|
||||||
};
|
};
|
||||||
|
|
||||||
rot = find_min_score<2>(objfn, inputs.begin(), inputs.end(), stopcond);
|
XYRotation rot = find_min_score<2>(objfn, inputs.begin(), inputs.end(), [&bp] {
|
||||||
|
return bp.stopcond();
|
||||||
|
});
|
||||||
|
|
||||||
return {rot[0], rot[1]};
|
return {rot[0], rot[1]};
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,9 @@ class RotoptimizeJob : public PlaterJob
|
|||||||
"structures.\nNote that this method will try to find the best surface of the object "
|
"structures.\nNote that this method will try to find the best surface of the object "
|
||||||
"for touching the print bed if no elevation is set.")},
|
"for touching the print bed if no elevation is set.")},
|
||||||
// Just a min area bounding box that is done for all methods anyway.
|
// Just a min area bounding box that is done for all methods anyway.
|
||||||
{L("Smallest Z height"),
|
{L("Lowest Z height"),
|
||||||
sla::find_min_z_height_rotation,
|
sla::find_min_z_height_rotation,
|
||||||
L("Rotate the model to have least z height for faster print time.")}};
|
L("Rotate the model to have the lowest z height for faster print time.")}};
|
||||||
|
|
||||||
size_t m_method_id = 0;
|
size_t m_method_id = 0;
|
||||||
float m_accuracy = 0.75;
|
float m_accuracy = 0.75;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user