new_helper

This commit is contained in:
Thomas Krijnen
2021-05-11 22:35:46 +02:00
parent 34386ea27c
commit cf68cf6f5c
3 changed files with 373 additions and 260 deletions
+186 -3
View File
@@ -4426,11 +4426,32 @@ namespace {
}
}
IfcGeom::Kernel::faceset_helper::~faceset_helper() {
template <typename CP, typename LP>
IfcGeom::Kernel::faceset_helper<CP, LP>::~faceset_helper() {
// @todo this is super ugly, but how else can we be notified that the unique_ptr goes out of scope?
// Perhaps just supply a custom std::deleter?
kernel_->faceset_helper_ = nullptr;
}
IfcGeom::Kernel::faceset_helper::faceset_helper(Kernel* kernel, const IfcSchema::IfcConnectedFaceSet* l)
template <typename CP, typename LP>
bool IfcGeom::Kernel::faceset_helper<CP, LP>::construct(const IfcSchema::IfcCartesianPoint* cp, gp_Pnt* l) {
return kernel_->convert(cp, *l);
}
template <typename CP, typename LP>
bool IfcGeom::Kernel::faceset_helper<CP, LP>::construct(const std::vector<double>& cp, gp_Pnt* l) {
if (cp.size() != 3) {
return false;
}
auto LU = kernel_->getValue(GV_LENGTH_UNIT);
l->SetCoord(cp[0] * LU, cp[1] * LU, cp[2] * LU);
}
/*
template <typename CP, typename LP>
IfcGeom::Kernel::faceset_helper<CP, LP>::faceset_helper(Kernel* kernel, const IfcSchema::IfcConnectedFaceSet* l)
: kernel_(kernel)
, non_manifold_(false)
{
@@ -4519,7 +4540,7 @@ IfcGeom::Kernel::faceset_helper::faceset_helper(Kernel* kernel, const IfcSchema:
for (int v : vs) {
auto pt = *(points->begin() + v);
// NB: insert() ignores duplicate keys
vertex_mapping_.insert({ pt->data().id() , pnt_i });
vertex_mapping_.insert({ get_idx(pt), pnt_i });
}
}
}
@@ -4576,3 +4597,165 @@ IfcGeom::Kernel::faceset_helper::faceset_helper(Kernel* kernel, const IfcSchema:
Logger::Warning(boost::lexical_cast<std::string>(duplicate_faces) + " duplicate faces removed, " + boost::lexical_cast<std::string>(loops_removed) + " loops removed and " + boost::lexical_cast<std::string>(non_manifold) + " non-manifold edges for:", l);
}
}
*/
namespace {
const std::vector<std::vector<double>>* store_cache(const std::vector<std::vector<double>>& p) {
return &p;
}
const std::vector<std::vector<double>>* store_cache(const std::vector<const IfcSchema::IfcCartesianPoint*>& p) {
return nullptr;
}
}
template <typename CP, typename LP>
IfcGeom::Kernel::faceset_helper<CP, LP>::faceset_helper(
Kernel* kernel,
const std::vector<CP>& points,
const std::vector<LP>& indices,
bool should_be_closed
)
: kernel_(kernel)
, non_manifold_(false)
, points_(store_cache(points))
{
std::vector<std::unique_ptr<gp_Pnt>> pnts(std::distance(points.begin(), points.end()));
std::vector<TopoDS_Vertex> vertices(pnts.size());
auto LU = kernel_->getValue(GV_LENGTH_UNIT);
IfcGeom::impl::tree<int> tree;
BRep_Builder B;
Bnd_Box box;
for (size_t i = 0; i < points.size(); ++i) {
gp_Pnt* p = new gp_Pnt;
if (construct(points[i], p)) {
pnts[i].reset(p);
B.MakeVertex(vertices[i], *p, Precision::Confusion());
tree.add(i, vertices[i]);
box.Add(*p);
} else {
delete p;
}
}
// Use the bbox diagonal to influence local epsilon
// double bdiff = std::sqrt(box.SquareExtent());
// @todo the bounding box diagonal is not used (see above)
// because we're explicitly interested in the miminal
// dimension of the element to limit the tolerance (for sheet-
// like elements for example). But the way below is very
// dependent on orientation due to the usage of the
// axis-aligned bounding box. Use PCA to find three non-aligned
// set of dimensions and use the one with the smallest eigenvalue.
// Find the minimal bounding box edge
double bmin[3], bmax[3];
box.Get(bmin[0], bmin[1], bmin[2], bmax[0], bmax[1], bmax[2]);
double bdiff = std::numeric_limits<double>::infinity();
for (size_t i = 0; i < 3; ++i) {
const double d = bmax[i] - bmin[i];
if (d > kernel->getValue(GV_PRECISION) * 10. && d < bdiff) {
bdiff = d;
}
}
eps_ = kernel->getValue(GV_PRECISION) * 10. * (std::min)(1.0, bdiff);
size_t loops_removed, non_manifold, duplicate_faces;
std::map<std::pair<int, int>, int> edge_use;
for (int i = 0; i < 3; ++i) {
// Some times files, have large tolerance values specified collapsing too many vertices.
// This case we detect below and re-run the loop with smaller epsilon. Normally
// the body of this loop would only be executed once.
loops_removed = 0;
non_manifold = 0;
duplicate_faces = 0;
vertex_mapping_.clear();
duplicates_.clear();
edge_use.clear();
if (eps_ < Precision::Confusion()) {
// occt uses some hard coded precision values, don't go smaller than that.
// @todo, can be reset though with BRepLib::Precision(double)
eps_ = Precision::Confusion();
}
for (int pnt_i = 0; pnt_i < (int)pnts.size(); ++pnt_i) {
if (pnts[pnt_i]) {
std::set<int> vs;
find_neighbours(tree, pnts, vs, pnt_i, eps_);
for (int v : vs) {
// NB: insert() ignores duplicate keys
// v-1?
vertex_mapping_.insert({ get_idx(points[v]), pnt_i });
}
}
}
typedef std::array<int, 2> edge_t;
typedef std::set<edge_t> edge_set_t;
std::set<edge_set_t> edge_sets;
for (auto ps = indices.begin(); ps != indices.end(); ++ps) {
std::vector<std::pair<int, int> > segments;
edge_set_t segment_set;
loop_(*ps, [&segments, &segment_set](int C, int D, bool) {
segment_set.insert(edge_t{ C,D });
segments.push_back(std::make_pair(C, D));
});
if (edge_sets.find(segment_set) != edge_sets.end()) {
duplicate_faces++;
duplicates_.insert(*ps);
continue;
}
edge_sets.insert(segment_set);
if (segments.size() >= 3) {
for (auto& p : segments) {
edge_use[p] ++;
}
}
else {
loops_removed += 1;
}
}
if (edge_use.size() != 0) {
break;
}
else {
eps_ /= 10.;
}
}
for (auto& p : edge_use) {
int a, b;
std::tie(a, b) = p.first;
edges_[p.first] = BRepBuilderAPI_MakeEdge(vertices[a], vertices[b]);
if (p.second != 2) {
non_manifold += 1;
}
}
if (loops_removed || (non_manifold && should_be_closed)) {
Logger::Warning(boost::lexical_cast<std::string>(duplicate_faces) + " duplicate faces removed, " + boost::lexical_cast<std::string>(loops_removed) + " loops removed and " + boost::lexical_cast<std::string>(non_manifold) + " non-manifold edges");
}
}
template class IfcGeom::Kernel::faceset_helper<const IfcSchema::IfcCartesianPoint*, const IfcSchema::IfcPolyLoop*>;
template class IfcGeom::Kernel::faceset_helper<std::vector<double>, std::vector<int>>;