From 47b30aa689e3f48f524d73bc4c9e989afdfe280b Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sun, 15 Aug 2021 20:42:36 +0200 Subject: [PATCH] tree ray intersection --- src/ifcgeom/IfcGeomTree.h | 110 +++++++++++++++++++++++++++++++- src/ifcwrap/IfcGeomWrapper.i | 2 + src/ifcwrap/utils/typemaps_in.i | 15 +++++ 3 files changed, 126 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/IfcGeomTree.h b/src/ifcgeom/IfcGeomTree.h index e0e836fdcd..190f7e5f3c 100644 --- a/src/ifcgeom/IfcGeomTree.h +++ b/src/ifcgeom/IfcGeomTree.h @@ -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 @@ -33,9 +34,20 @@ #include #include #include +#include +#include namespace IfcGeom { + struct ray_intersection_result { + double distance; + int style_index; + IfcUtil::IfcBaseEntity* instance; + std::array position; + std::array normal; + double dot_product; + }; + namespace impl { template class tree { @@ -239,11 +251,13 @@ namespace IfcGeom { } protected: - typedef NCollection_UBTree tree_t; typedef std::map 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 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 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 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 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& styles() const { + return styles_; + } + + protected: + typedef TopTools_DataMapOfShapeInteger face_style_map_t; + + face_style_map_t face_styles_; + std::vector styles_; }; } diff --git a/src/ifcwrap/IfcGeomWrapper.i b/src/ifcwrap/IfcGeomWrapper.i index 24636efbb6..815faf49b6 100644 --- a/src/ifcwrap/IfcGeomWrapper.i +++ b/src/ifcwrap/IfcGeomWrapper.i @@ -69,6 +69,8 @@ %include "../serializers/SvgSerializer.h" %include "../serializers/WavefrontObjSerializer.h" +%template(ray_intersection_results) std::vector; + // 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" diff --git a/src/ifcwrap/utils/typemaps_in.i b/src/ifcwrap/utils/typemaps_in.i index 19588c1584..a377dc62a2 100644 --- a/src/ifcwrap/utils/typemaps_in.i +++ b/src/ifcwrap/utils/typemaps_in.i @@ -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())) { + SWIG_exception(SWIG_TypeError, " type needs a python sequence of 3 floats"); + } + std::vector ds = python_sequence_as_vector($input); + if (ds.size() != 3) { + SWIG_exception(SWIG_TypeError, " 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())) { SWIG_exception(SWIG_TypeError, " 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()); } +%typemap(typecheck, precedence=SWIG_TYPECHECK_INTEGER) const gp_Dir& { + $1 = check_aggregate_of_type($input, get_python_type()); +} + %typemap(typecheck, precedence=SWIG_TYPECHECK_INTEGER) const Bnd_Box& { $1 = check_aggregate_of_aggregate_of_type($input, get_python_type()); }