Skip to content

Commit 96ec925

Browse files
authored
Spatial Querying: Implementation of BVH tree for IFC files using NCollection_UBTree (#130)
* Implementation of BVH tree for IFC files using NCollection_UBTree * Fixes for gcc and OCCT < v6.8 * Enable BVH selection by TopoDS_Shape * Small fixes to tree * Merge conflicted files and other changes * Eliminate one warning (some remain) + add tree test
1 parent ee16dea commit 96ec925

File tree

10 files changed

+447
-14
lines changed

10 files changed

+447
-14
lines changed

src/ifcgeom/IfcGeom.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ class IFC_GEOM_API Kernel {
205205
bool closest(const gp_Pnt&, const std::vector<gp_Pnt>&, gp_Pnt&);
206206
bool project(const Handle_Geom_Curve&, const gp_Pnt&, gp_Pnt& p, double& u, double& d);
207207
bool project(const Handle_Geom_Surface&, const TopoDS_Shape&, double& u1, double& v1, double& u2, double& v2, double widen=0.1);
208-
int count(const TopoDS_Shape&, TopAbs_ShapeEnum);
208+
static int count(const TopoDS_Shape&, TopAbs_ShapeEnum);
209209

210210
bool find_wall_end_points(const IfcSchema::IfcWall*, gp_Pnt& start, gp_Pnt& end);
211211

src/ifcgeom/IfcGeomIterator.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ namespace IfcGeom {
433433
IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation_mapped_to->OfProductRepresentation();
434434

435435
bool all_product_without_openings = true;
436-
IfcSchema::IfcProduct::list::ptr products;
436+
IfcSchema::IfcProduct::list::ptr products(new IfcSchema::IfcProduct::list);
437437

438438
for (IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it) {
439439
IfcSchema::IfcProduct::list::ptr products_of_prodrep = (*it)->entity->getInverse(IfcSchema::Type::IfcProduct, -1)->as<IfcSchema::IfcProduct>();

src/ifcgeom/IfcGeomRepresentation.cpp

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,8 @@ IfcGeom::Representation::Serialization::Serialization(const BRep& brep)
3131
: Representation(brep.settings())
3232
, id_(brep.id())
3333
{
34-
TopoDS_Compound compound;
35-
BRep_Builder builder;
36-
builder.MakeCompound(compound);
34+
TopoDS_Compound compound = brep.as_compound();
3735
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = brep.begin(); it != brep.end(); ++ it) {
38-
const TopoDS_Shape& s = it->Shape();
39-
gp_GTrsf trsf = it->Placement();
40-
4136
if (it->hasStyle() && it->Style().Diffuse()) {
4237
const IfcGeom::SurfaceStyle::ColorComponent& clr = *it->Style().Diffuse();
4338
surface_styles_.push_back(clr.R());
@@ -53,18 +48,28 @@ IfcGeom::Representation::Serialization::Serialization(const BRep& brep)
5348
} else {
5449
surface_styles_.push_back(1.);
5550
}
56-
51+
}
52+
std::stringstream sstream;
53+
BRepTools::Write(compound,sstream);
54+
brep_data_ = sstream.str();
55+
}
56+
57+
TopoDS_Compound IfcGeom::Representation::BRep::as_compound() const {
58+
TopoDS_Compound compound;
59+
BRep_Builder builder;
60+
builder.MakeCompound(compound);
61+
for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = begin(); it != end(); ++it) {
62+
const TopoDS_Shape& s = it->Shape();
63+
gp_GTrsf trsf = it->Placement();
64+
5765
if (settings().get(IteratorSettings::CONVERT_BACK_UNITS)) {
5866
gp_Trsf scale;
5967
scale.SetScaleFactor(1.0 / settings().unit_magnitude());
6068
trsf.PreMultiply(scale);
6169
}
62-
63-
const TopoDS_Shape moved_shape = IfcGeom::Kernel::apply_transformation(s, trsf);
6470

71+
const TopoDS_Shape moved_shape = IfcGeom::Kernel::apply_transformation(s, trsf);
6572
builder.Add(compound, moved_shape);
6673
}
67-
std::stringstream sstream;
68-
BRepTools::Write(compound,sstream);
69-
brep_data_ = sstream.str();
74+
return compound;
7075
}

src/ifcgeom/IfcGeomRepresentation.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
#include "../ifcgeom/IfcGeomMaterial.h"
3939
#include "../ifcgeom/IfcRepresentationShapeItem.h"
4040

41+
#include <TopoDS_Compound.hxx>
42+
4143
namespace IfcGeom {
4244

4345
namespace Representation {
@@ -72,6 +74,7 @@ namespace IfcGeom {
7274
IfcGeom::IfcRepresentationShapeItems::const_iterator end() const { return shapes_.end(); }
7375
const IfcGeom::IfcRepresentationShapeItems& shapes() const { return shapes_; }
7476
const std::string& id() const { return id_; }
77+
TopoDS_Compound as_compound() const;
7578
};
7679

7780
class IFC_GEOM_API Serialization : public Representation {

src/ifcgeom/IfcGeomTree.h

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
/********************************************************************************
2+
* *
3+
* This file is part of IfcOpenShell. *
4+
* *
5+
* IfcOpenShell is free software: you can redistribute it and/or modify *
6+
* it under the terms of the Lesser GNU General Public License as published by *
7+
* the Free Software Foundation, either version 3.0 of the License, or *
8+
* (at your option) any later version. *
9+
* *
10+
* IfcOpenShell is distributed in the hope that it will be useful, *
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13+
* Lesser GNU General Public License for more details. *
14+
* *
15+
* You should have received a copy of the Lesser GNU General Public License *
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
17+
* *
18+
********************************************************************************/
19+
20+
#ifndef IFCGEOMTREE_H
21+
#define IFCGEOMTREE_H
22+
23+
#include "../ifcparse/IfcFile.h"
24+
#include "../ifcgeom/IfcGeomIterator.h"
25+
26+
#include <NCollection_UBTree.hxx>
27+
#include <BRepBndLib.hxx>
28+
#include <Bnd_Box.hxx>
29+
#include <BRepAlgoAPI_Common.hxx>
30+
#include <BRepAlgoAPI_Cut.hxx>
31+
#include <BRepClass3d_SolidClassifier.hxx>
32+
33+
namespace IfcGeom {
34+
35+
namespace impl {
36+
template <typename T>
37+
class tree {
38+
39+
public:
40+
41+
void add(const T& t, const Bnd_Box& b) {
42+
tree_.Add(t, b);
43+
}
44+
45+
void add(const T& t, const TopoDS_Shape& s) {
46+
Bnd_Box b;
47+
BRepBndLib::AddClose(s, b);
48+
add(t, b);
49+
shapes_[t] = s;
50+
}
51+
52+
std::vector<T> select_box(const T& t, bool completely_within = false, double extend=-1.e-5) const {
53+
typename map_t::const_iterator it = shapes_.find(t);
54+
if (it == shapes_.end()) {
55+
return std::vector<T>();
56+
}
57+
58+
Bnd_Box b;
59+
BRepBndLib::AddClose(it->second, b);
60+
61+
// Gap is assumed to be positive throughout the codebase,
62+
// but at least for IsOut() in the selector a negative
63+
// Gap should work as well.
64+
b.SetGap(b.GetGap() + extend);
65+
66+
return select_box(b, completely_within);
67+
}
68+
69+
std::vector<T> select_box(const gp_Pnt& p) const {
70+
Bnd_Box b;
71+
b.Add(p);
72+
return select_box(b);
73+
}
74+
75+
std::vector<T> select_box(const Bnd_Box& b, bool completely_within = false) const {
76+
selector s(b);
77+
tree_.Select(s);
78+
if (completely_within) {
79+
std::vector<T> ts = s.results();
80+
std::vector<T> ts_filtered;
81+
ts_filtered.reserve(ts.size());
82+
typename std::vector<T>::const_iterator it = ts.begin();
83+
for (; it != ts.end(); ++it) {
84+
const TopoDS_Shape& shp = shapes_.find(*it)->second;
85+
Bnd_Box B;
86+
BRepBndLib::AddClose(shp, B);
87+
88+
// BndBox::CornerMin() /-Max() introduced in OCCT 6.8
89+
double x1, y1, z1, x2, y2, z2;
90+
b.Get(x1, y1, z1, x2, y2, z2);
91+
double gap = B.GetGap();
92+
gp_Pnt p1(x1 - gap, y1 - gap, z1 - gap);
93+
gp_Pnt p2(x2 + gap, y2 + gap, z2 + gap);
94+
95+
if (!b.IsOut(p1) && !b.IsOut(p2)) {
96+
ts_filtered.push_back(*it);
97+
}
98+
}
99+
return ts_filtered;
100+
} else {
101+
return s.results();
102+
}
103+
}
104+
105+
std::vector<T> select(const T& t, bool completely_within = false) const {
106+
std::vector<T> ts = select_box(t);
107+
if (ts.empty()) {
108+
return ts;
109+
}
110+
111+
std::vector<T> ts_filtered;
112+
113+
const TopoDS_Shape& A = shapes_.find(t)->second;
114+
if (IfcGeom::Kernel::count(A, TopAbs_SHELL) == 0) {
115+
return ts_filtered;
116+
}
117+
118+
ts_filtered.reserve(ts.size());
119+
120+
typename std::vector<T>::const_iterator it = ts.begin();
121+
for (it = ts.begin(); it != ts.end(); ++it) {
122+
const TopoDS_Shape& B = shapes_.find(*it)->second;
123+
if (IfcGeom::Kernel::count(B, TopAbs_SHELL) == 0) {
124+
continue;
125+
}
126+
127+
if (completely_within) {
128+
BRepAlgoAPI_Cut cut(B, A);
129+
if (cut.IsDone()) {
130+
if (IfcGeom::Kernel::count(cut.Shape(), TopAbs_SHELL) == 0) {
131+
ts_filtered.push_back(*it);
132+
}
133+
}
134+
} else {
135+
BRepAlgoAPI_Common common(A, B);
136+
if (common.IsDone()) {
137+
if (IfcGeom::Kernel::count(common.Shape(), TopAbs_SHELL) > 0) {
138+
ts_filtered.push_back(*it);
139+
}
140+
}
141+
}
142+
}
143+
144+
return ts_filtered;
145+
}
146+
147+
std::vector<T> select(const TopoDS_Shape& s) const {
148+
Bnd_Box bb;
149+
BRepBndLib::AddClose(s, bb);
150+
151+
std::vector<T> ts;
152+
153+
if (IfcGeom::Kernel::count(s, TopAbs_SHELL) == 0) {
154+
return ts;
155+
}
156+
157+
ts = select_box(bb);
158+
159+
if (ts.empty()) {
160+
return ts;
161+
}
162+
163+
std::vector<T> ts_filtered;
164+
ts_filtered.reserve(ts.size());
165+
166+
typename std::vector<T>::const_iterator it = ts.begin();
167+
for (it = ts.begin(); it != ts.end(); ++it) {
168+
const TopoDS_Shape& B = shapes_.find(*it)->second;
169+
170+
if (IfcGeom::Kernel::count(B, TopAbs_SHELL) == 0) {
171+
continue;
172+
}
173+
174+
BRepAlgoAPI_Common common(s, B);
175+
if (common.IsDone()) {
176+
if (IfcGeom::Kernel::count(common.Shape(), TopAbs_SHELL) > 0) {
177+
ts_filtered.push_back(*it);
178+
}
179+
}
180+
}
181+
182+
return ts_filtered;
183+
}
184+
185+
std::vector<T> select(const gp_Pnt& p) const {
186+
std::vector<T> ts = select_box(p);
187+
if (ts.empty()) {
188+
return ts;
189+
}
190+
191+
std::vector<T> ts_filtered;
192+
ts_filtered.reserve(ts.size());
193+
194+
typename std::vector<T>::const_iterator it = ts.begin();
195+
for (it = ts.begin(); it != ts.end(); ++it) {
196+
const TopoDS_Shape& B = shapes_.find(*it)->second;
197+
TopExp_Explorer exp(B, TopAbs_SOLID);
198+
for (; exp.More(); exp.Next()) {
199+
BRepClass3d_SolidClassifier cls(exp.Current(), p, 1e-5);
200+
if (cls.State() != TopAbs_OUT) {
201+
ts_filtered.push_back(*it);
202+
break;
203+
}
204+
}
205+
}
206+
207+
return ts_filtered;
208+
}
209+
210+
protected:
211+
212+
typedef NCollection_UBTree<T, Bnd_Box> tree_t;
213+
typedef std::map<T, TopoDS_Shape> map_t;
214+
tree_t tree_;
215+
map_t shapes_;
216+
217+
class selector : public tree_t::Selector
218+
{
219+
public:
220+
selector(const Bnd_Box& b)
221+
: tree_t::Selector()
222+
, bounds_(b)
223+
{}
224+
225+
Standard_Boolean Reject(const Bnd_Box& b) const {
226+
return bounds_.IsOut(b);
227+
}
228+
229+
Standard_Boolean Accept(const T& o) {
230+
results_.push_back(o);
231+
return Standard_True;
232+
}
233+
234+
const std::vector<T>& results() const {
235+
return results_;
236+
}
237+
238+
private:
239+
std::vector<T> results_;
240+
const Bnd_Box& bounds_;
241+
};
242+
243+
};
244+
}
245+
246+
class tree : public impl::tree<IfcSchema::IfcProduct*> {
247+
public:
248+
249+
tree() {};
250+
251+
tree(IfcParse::IfcFile& f) {
252+
add_file(f, IfcGeom::IteratorSettings());
253+
}
254+
255+
tree(IfcParse::IfcFile& f, const IfcGeom::IteratorSettings& settings) {
256+
add_file(f, settings);
257+
}
258+
259+
void add_file(IfcParse::IfcFile& f, const IfcGeom::IteratorSettings& settings) {
260+
IfcGeom::IteratorSettings settings_ = settings;
261+
settings_.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true);
262+
settings_.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true);
263+
settings_.set(IfcGeom::IteratorSettings::SEW_SHELLS, true);
264+
265+
IfcGeom::Iterator<double> it(settings_, &f);
266+
267+
if (it.initialize()) {
268+
do {
269+
IfcGeom::BRepElement<double>* elem = (IfcGeom::BRepElement<double>*)it.get();
270+
add((IfcSchema::IfcProduct*)f.entityById(elem->id()), elem->geometry().as_compound());
271+
} while (it.next());
272+
}
273+
}
274+
};
275+
276+
}
277+
278+
#endif

0 commit comments

Comments
 (0)