mirror of
https://github.com/QIDITECH/QIDISlicer.git
synced 2026-02-01 08:28:42 +03:00
QIDISlicer1.0.0
This commit is contained in:
308
src/libslic3r/OpenVDBUtils.cpp
Normal file
308
src/libslic3r/OpenVDBUtils.cpp
Normal file
@@ -0,0 +1,308 @@
|
||||
#define NOMINMAX
|
||||
#include "OpenVDBUtils.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Suppress warning C4146 in OpenVDB: unary minus operator applied to unsigned type, result still unsigned
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4146)
|
||||
#endif // _MSC_VER
|
||||
#include <openvdb/openvdb.h>
|
||||
#include <openvdb/tools/MeshToVolume.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif // _MSC_VER
|
||||
|
||||
#include <openvdb/tools/VolumeToMesh.h>
|
||||
#include <openvdb/tools/Composite.h>
|
||||
#include <openvdb/tools/LevelSetRebuild.h>
|
||||
#include <openvdb/tools/FastSweeping.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
struct VoxelGrid
|
||||
{
|
||||
openvdb::FloatGrid grid;
|
||||
|
||||
mutable std::optional<openvdb::FloatGrid::ConstAccessor> accessor;
|
||||
|
||||
template<class...Args>
|
||||
VoxelGrid(Args &&...args): grid{std::forward<Args>(args)...} {}
|
||||
};
|
||||
|
||||
void VoxelGridDeleter::operator()(VoxelGrid *ptr) { delete ptr; }
|
||||
|
||||
// Similarly to std::make_unique()
|
||||
template<class...Args>
|
||||
VoxelGridPtr make_voxelgrid(Args &&...args)
|
||||
{
|
||||
VoxelGrid *ptr = nullptr;
|
||||
try {
|
||||
ptr = new VoxelGrid(std::forward<Args>(args)...);
|
||||
} catch(...) {
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
return VoxelGridPtr{ptr};
|
||||
}
|
||||
|
||||
template VoxelGridPtr make_voxelgrid<>();
|
||||
|
||||
inline Vec3f to_vec3f(const openvdb::Vec3s &v) { return Vec3f{v.x(), v.y(), v.z()}; }
|
||||
inline Vec3d to_vec3d(const openvdb::Vec3s &v) { return to_vec3f(v).cast<double>(); }
|
||||
inline Vec3i to_vec3i(const openvdb::Vec3I &v) { return Vec3i{int(v[2]), int(v[1]), int(v[0])}; }
|
||||
|
||||
class TriangleMeshDataAdapter {
|
||||
public:
|
||||
const indexed_triangle_set &its;
|
||||
Transform3d trafo;
|
||||
|
||||
size_t polygonCount() const { return its.indices.size(); }
|
||||
size_t pointCount() const { return its.vertices.size(); }
|
||||
size_t vertexCount(size_t) const { return 3; }
|
||||
|
||||
// Return position pos in local grid index space for polygon n and vertex v
|
||||
// The actual mesh will appear to openvdb as scaled uniformly by voxel_size
|
||||
// And the voxel count per unit volume can be affected this way.
|
||||
void getIndexSpacePoint(size_t n, size_t v, openvdb::Vec3d& pos) const
|
||||
{
|
||||
auto vidx = size_t(its.indices[n](Eigen::Index(v)));
|
||||
Slic3r::Vec3d p = trafo * its.vertices[vidx].cast<double>();
|
||||
pos = {p.x(), p.y(), p.z()};
|
||||
}
|
||||
|
||||
TriangleMeshDataAdapter(const indexed_triangle_set &m, const Transform3d tr = Transform3d::Identity())
|
||||
: its{m}, trafo{tr} {}
|
||||
};
|
||||
|
||||
struct Interrupter
|
||||
{
|
||||
std::function<bool(int)> statusfn;
|
||||
|
||||
void start(const char* name = nullptr) { (void)name; }
|
||||
void end() {}
|
||||
|
||||
inline bool wasInterrupted(int percent = -1) { return statusfn && statusfn(percent); }
|
||||
};
|
||||
|
||||
VoxelGridPtr mesh_to_grid(const indexed_triangle_set &mesh,
|
||||
const MeshToGridParams ¶ms)
|
||||
{
|
||||
// Might not be needed but this is now proven to be working
|
||||
openvdb::initialize();
|
||||
|
||||
std::vector<indexed_triangle_set> meshparts = its_split(mesh);
|
||||
|
||||
auto it = std::remove_if(meshparts.begin(), meshparts.end(),
|
||||
[](auto &m) {
|
||||
return its_volume(m) < EPSILON;
|
||||
});
|
||||
|
||||
meshparts.erase(it, meshparts.end());
|
||||
|
||||
Transform3d trafo = params.trafo().cast<double>();
|
||||
trafo.prescale(params.voxel_scale());
|
||||
|
||||
Interrupter interrupter{params.statusfn()};
|
||||
|
||||
openvdb::FloatGrid::Ptr grid;
|
||||
for (auto &m : meshparts) {
|
||||
auto subgrid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
|
||||
interrupter,
|
||||
TriangleMeshDataAdapter{m, trafo},
|
||||
openvdb::math::Transform{},
|
||||
params.exterior_bandwidth(),
|
||||
params.interior_bandwidth());
|
||||
|
||||
if (interrupter.wasInterrupted())
|
||||
break;
|
||||
|
||||
if (grid && subgrid)
|
||||
openvdb::tools::csgUnion(*grid, *subgrid);
|
||||
else if (subgrid)
|
||||
grid = std::move(subgrid);
|
||||
}
|
||||
|
||||
if (interrupter.wasInterrupted())
|
||||
return {};
|
||||
|
||||
if (meshparts.empty()) {
|
||||
// Splitting failed, fall back to hollow the original mesh
|
||||
grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
|
||||
interrupter,
|
||||
TriangleMeshDataAdapter{mesh, trafo},
|
||||
openvdb::math::Transform{},
|
||||
params.exterior_bandwidth(),
|
||||
params.interior_bandwidth());
|
||||
}
|
||||
|
||||
if (interrupter.wasInterrupted())
|
||||
return {};
|
||||
|
||||
grid->transform().preScale(1./params.voxel_scale());
|
||||
grid->insertMeta("voxel_scale", openvdb::FloatMetadata(params.voxel_scale()));
|
||||
|
||||
VoxelGridPtr ret = make_voxelgrid(std::move(*grid));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
indexed_triangle_set grid_to_mesh(const VoxelGrid &vgrid,
|
||||
double isovalue,
|
||||
double adaptivity,
|
||||
bool relaxDisorientedTriangles)
|
||||
{
|
||||
openvdb::initialize();
|
||||
|
||||
std::vector<openvdb::Vec3s> points;
|
||||
std::vector<openvdb::Vec3I> triangles;
|
||||
std::vector<openvdb::Vec4I> quads;
|
||||
|
||||
auto &grid = vgrid.grid;
|
||||
|
||||
openvdb::tools::volumeToMesh(grid, points, triangles, quads, isovalue,
|
||||
adaptivity, relaxDisorientedTriangles);
|
||||
|
||||
indexed_triangle_set ret;
|
||||
ret.vertices.reserve(points.size());
|
||||
ret.indices.reserve(triangles.size() + quads.size() * 2);
|
||||
|
||||
for (auto &v : points) ret.vertices.emplace_back(to_vec3f(v) /*/ scale*/);
|
||||
for (auto &v : triangles) ret.indices.emplace_back(to_vec3i(v));
|
||||
for (auto &quad : quads) {
|
||||
ret.indices.emplace_back(quad(2), quad(1), quad(0));
|
||||
ret.indices.emplace_back(quad(3), quad(2), quad(0));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
VoxelGridPtr dilate_grid(const VoxelGrid &vgrid,
|
||||
float exteriorBandWidth,
|
||||
float interiorBandWidth)
|
||||
{
|
||||
constexpr int DilateIterations = 1;
|
||||
|
||||
openvdb::FloatGrid::Ptr new_grid;
|
||||
|
||||
float scale = get_voxel_scale(vgrid);
|
||||
|
||||
if (interiorBandWidth > 0.f)
|
||||
new_grid = openvdb::tools::dilateSdf(
|
||||
vgrid.grid, scale * interiorBandWidth, openvdb::tools::NN_FACE_EDGE,
|
||||
DilateIterations,
|
||||
openvdb::tools::FastSweepingDomain::SWEEP_LESS_THAN_ISOVALUE);
|
||||
|
||||
auto &arg = new_grid? *new_grid : vgrid.grid;
|
||||
|
||||
if (exteriorBandWidth > 0.f)
|
||||
new_grid = openvdb::tools::dilateSdf(
|
||||
arg, scale * exteriorBandWidth, openvdb::tools::NN_FACE_EDGE,
|
||||
DilateIterations,
|
||||
openvdb::tools::FastSweepingDomain::SWEEP_GREATER_THAN_ISOVALUE);
|
||||
|
||||
VoxelGridPtr ret;
|
||||
|
||||
if (new_grid)
|
||||
ret = make_voxelgrid(std::move(*new_grid));
|
||||
else
|
||||
ret = make_voxelgrid(vgrid.grid);
|
||||
|
||||
// Copies voxel_scale metadata, if it exists.
|
||||
ret->grid.insertMeta(*vgrid.grid.deepCopyMeta());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
VoxelGridPtr redistance_grid(const VoxelGrid &vgrid,
|
||||
float iso,
|
||||
float er,
|
||||
float ir)
|
||||
{
|
||||
auto new_grid = openvdb::tools::levelSetRebuild(vgrid.grid, iso, er, ir);
|
||||
|
||||
auto ret = make_voxelgrid(std::move(*new_grid));
|
||||
|
||||
// Copies voxel_scale metadata, if it exists.
|
||||
ret->grid.insertMeta(*vgrid.grid.deepCopyMeta());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
VoxelGridPtr redistance_grid(const VoxelGrid &vgrid, float iso)
|
||||
{
|
||||
auto new_grid = openvdb::tools::levelSetRebuild(vgrid.grid, iso);
|
||||
|
||||
auto ret = make_voxelgrid(std::move(*new_grid));
|
||||
|
||||
// Copies voxel_scale metadata, if it exists.
|
||||
ret->grid.insertMeta(*vgrid.grid.deepCopyMeta());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void grid_union(VoxelGrid &grid, VoxelGrid &arg)
|
||||
{
|
||||
openvdb::tools::csgUnion(grid.grid, arg.grid);
|
||||
}
|
||||
|
||||
void grid_difference(VoxelGrid &grid, VoxelGrid &arg)
|
||||
{
|
||||
openvdb::tools::csgDifference(grid.grid, arg.grid);
|
||||
}
|
||||
|
||||
void grid_intersection(VoxelGrid &grid, VoxelGrid &arg)
|
||||
{
|
||||
openvdb::tools::csgIntersection(grid.grid, arg.grid);
|
||||
}
|
||||
|
||||
void reset_accessor(const VoxelGrid &vgrid)
|
||||
{
|
||||
vgrid.accessor = vgrid.grid.getConstAccessor();
|
||||
}
|
||||
|
||||
double get_distance_raw(const Vec3f &p, const VoxelGrid &vgrid)
|
||||
{
|
||||
if (!vgrid.accessor)
|
||||
reset_accessor(vgrid);
|
||||
|
||||
auto v = (p).cast<double>();
|
||||
auto grididx = vgrid.grid.transform().worldToIndexCellCentered(
|
||||
{v.x(), v.y(), v.z()});
|
||||
|
||||
return vgrid.accessor->getValue(grididx) ;
|
||||
}
|
||||
|
||||
float get_voxel_scale(const VoxelGrid &vgrid)
|
||||
{
|
||||
float scale = 1.;
|
||||
try {
|
||||
scale = vgrid.grid.template metaValue<float>("voxel_scale");
|
||||
} catch (...) { }
|
||||
|
||||
return scale;
|
||||
}
|
||||
|
||||
VoxelGridPtr clone(const VoxelGrid &grid)
|
||||
{
|
||||
return make_voxelgrid(grid);
|
||||
}
|
||||
|
||||
void rescale_grid(VoxelGrid &grid, float scale)
|
||||
{/*
|
||||
float old_scale = get_voxel_scale(grid);
|
||||
|
||||
float nscale = scale / old_scale;*/
|
||||
// auto tr = openvdb::math::Transform::createLinearTransform(scale);
|
||||
grid.grid.transform().preScale(scale);
|
||||
|
||||
// grid.grid.insertMeta("voxel_scale", openvdb::FloatMetadata(nscale));
|
||||
|
||||
// grid.grid.setTransform(tr);
|
||||
}
|
||||
|
||||
bool is_grid_empty(const VoxelGrid &grid)
|
||||
{
|
||||
return grid.grid.empty();
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
Reference in New Issue
Block a user