mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
tree ray intersection
This commit is contained in:
+109
-1
@@ -23,6 +23,7 @@
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomIterator.h"
|
||||
#include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h"
|
||||
#include "../ifcgeom_schema_agnostic/Kernel.h"
|
||||
|
||||
#include <NCollection_UBTree.hxx>
|
||||
@@ -33,9 +34,20 @@
|
||||
#include <BRepAlgoAPI_Cut.hxx>
|
||||
#include <BRepExtrema_DistShapeShape.hxx>
|
||||
#include <BRepClass3d_SolidClassifier.hxx>
|
||||
#include <TopTools_DataMapOfShapeInteger.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
struct ray_intersection_result {
|
||||
double distance;
|
||||
int style_index;
|
||||
IfcUtil::IfcBaseEntity* instance;
|
||||
std::array<double, 3> position;
|
||||
std::array<double, 3> normal;
|
||||
double dot_product;
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
template <typename T>
|
||||
class tree {
|
||||
@@ -239,11 +251,13 @@ namespace IfcGeom {
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
typedef NCollection_UBTree<T, Bnd_Box> tree_t;
|
||||
typedef std::map<T, TopoDS_Shape> map_t;
|
||||
|
||||
tree_t tree_;
|
||||
map_t shapes_;
|
||||
|
||||
bool enable_face_styles_ = false;
|
||||
|
||||
class selector : public tree_t::Selector
|
||||
{
|
||||
@@ -317,7 +331,101 @@ namespace IfcGeom {
|
||||
auto compound = elem->geometry().as_compound();
|
||||
compound.Move(elem->transformation().data());
|
||||
add(elem->product(), compound);
|
||||
auto git = elem->geometry().begin();
|
||||
|
||||
if (enable_face_styles_) {
|
||||
TopoDS_Iterator it(compound);
|
||||
for (; it.More(); it.Next(), ++git) {
|
||||
std::unique_ptr<IfcGeom::Material> adaptor;
|
||||
if (git->hasStyle()) {
|
||||
adaptor.reset(new Material(&git->Style()));
|
||||
} else {
|
||||
adaptor.reset(new Material(IfcGeom::get_default_style(elem->type())));
|
||||
}
|
||||
|
||||
// Assumption is that the number of styles is small, so the linear lookup time is not significant.
|
||||
auto sit = std::find(styles_.begin(), styles_.end(), *adaptor);
|
||||
int index;
|
||||
if (sit == styles_.end()) {
|
||||
index = styles_.size();
|
||||
styles_.push_back(*adaptor);
|
||||
} else {
|
||||
index = std::distance(styles_.begin(), sit);
|
||||
}
|
||||
|
||||
TopExp_Explorer exp(it.Value(), TopAbs_FACE);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
face_styles_.Bind(exp.Current(), index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<IfcGeom::ray_intersection_result> select_ray(const gp_Pnt& p0, const gp_Dir& d, double length = 1000.) const {
|
||||
gp_Pnt p1 = p0.XYZ() + d.XYZ() * length;
|
||||
auto E = BRepBuilderAPI_MakeEdge(p0, p1).Edge();
|
||||
Bnd_Box bb;
|
||||
bb.Add(p0);
|
||||
bb.Add(p1);
|
||||
auto candidates = select_box(bb);
|
||||
|
||||
std::multimap<double, ray_intersection_result> ordered;
|
||||
|
||||
for (auto& c : candidates) {
|
||||
BRepExtrema_DistShapeShape dss(E, shapes_.find(c)->second);
|
||||
for (int i = 1; i <= dss.NbSolution(); ++i) {
|
||||
if (dss.SupportTypeShape1(i) != BRepExtrema_IsOnEdge) {
|
||||
// @todo set to 0, is it on the first verteX?
|
||||
continue;
|
||||
}
|
||||
if (dss.SupportTypeShape2(i) != BRepExtrema_IsInFace) {
|
||||
continue;
|
||||
}
|
||||
double u, v, w;
|
||||
dss.ParOnEdgeS1(i, u);
|
||||
auto face = TopoDS::Face(dss.SupportOnShape2(i));
|
||||
int sidx = -1;
|
||||
if (enable_face_styles_) {
|
||||
sidx = face_styles_.Find(face);
|
||||
}
|
||||
dss.ParOnFaceS2(i, v, w);
|
||||
BRepGProp_Face prop(face);
|
||||
gp_Pnt P;
|
||||
gp_Vec V;
|
||||
prop.Normal(v, w, P, V);
|
||||
ordered.insert({ u, { u, sidx, c,
|
||||
{P.X(), P.Y(), P.Z()},
|
||||
{V.X(), V.Y(), V.Z()},
|
||||
V.Dot(d)
|
||||
} });
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ray_intersection_result> result;
|
||||
for (auto& p : ordered) {
|
||||
result.push_back(p.second);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool enable_face_styles() const {
|
||||
return enable_face_styles_;
|
||||
}
|
||||
|
||||
void enable_face_styles(bool b) {
|
||||
enable_face_styles_ = b;
|
||||
}
|
||||
|
||||
const std::vector<IfcGeom::Material>& styles() const {
|
||||
return styles_;
|
||||
}
|
||||
|
||||
protected:
|
||||
typedef TopTools_DataMapOfShapeInteger face_style_map_t;
|
||||
|
||||
face_style_map_t face_styles_;
|
||||
std::vector<IfcGeom::Material> styles_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -69,6 +69,8 @@
|
||||
%include "../serializers/SvgSerializer.h"
|
||||
%include "../serializers/WavefrontObjSerializer.h"
|
||||
|
||||
%template(ray_intersection_results) std::vector<IfcGeom::ray_intersection_result>;
|
||||
|
||||
// A Template instantantation should be defined before it is used as a base class.
|
||||
// But frankly I don't care as most methods are subtlely different anyway.
|
||||
%include "../ifcgeom/IfcGeomTree.h"
|
||||
|
||||
@@ -217,6 +217,17 @@ CREATE_VECTOR_TYPEMAP_IN(std::string, STRING, str)
|
||||
$1 = new gp_Pnt(ds[0], ds[1], ds[2]);
|
||||
}
|
||||
|
||||
%typemap(in) const gp_Dir& {
|
||||
if (!check_aggregate_of_type($input, get_python_type<double>())) {
|
||||
SWIG_exception(SWIG_TypeError, "<Direction> type needs a python sequence of 3 floats");
|
||||
}
|
||||
std::vector<double> ds = python_sequence_as_vector<double>($input);
|
||||
if (ds.size() != 3) {
|
||||
SWIG_exception(SWIG_TypeError, "<Direction> type needs a python sequence of 3 floats");
|
||||
}
|
||||
$1 = new gp_Dir(ds[0], ds[1], ds[2]);
|
||||
}
|
||||
|
||||
%typemap(in) const Bnd_Box& {
|
||||
if (!check_aggregate_of_aggregate_of_type($input, get_python_type<double>())) {
|
||||
SWIG_exception(SWIG_TypeError, "<AABB> type needs a python sequence of 2 x 3 floats");
|
||||
@@ -237,6 +248,10 @@ CREATE_VECTOR_TYPEMAP_IN(std::string, STRING, str)
|
||||
$1 = check_aggregate_of_type($input, get_python_type<double>());
|
||||
}
|
||||
|
||||
%typemap(typecheck, precedence=SWIG_TYPECHECK_INTEGER) const gp_Dir& {
|
||||
$1 = check_aggregate_of_type($input, get_python_type<double>());
|
||||
}
|
||||
|
||||
%typemap(typecheck, precedence=SWIG_TYPECHECK_INTEGER) const Bnd_Box& {
|
||||
$1 = check_aggregate_of_aggregate_of_type($input, get_python_type<double>());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user