Toponaming: Bring in composite shapes for findSubshapesWithSharedVertex ( searchSubShape )
This commit is contained in:
@@ -54,11 +54,12 @@ namespace Data
|
||||
|
||||
//struct MappedChildElements;
|
||||
/// Option for App::GeoFeature::searchElementCache()
|
||||
enum class SearchOptions {
|
||||
enum class SearchOption {
|
||||
/// Whether to compare shape geometry
|
||||
CheckGeometry = 1,
|
||||
SingleResult = 2,
|
||||
};
|
||||
typedef Base::Flags<SearchOption> SearchOptions;
|
||||
|
||||
/** Segments
|
||||
* Sub-element type of the ComplexGeoData type
|
||||
@@ -483,5 +484,5 @@ protected:
|
||||
|
||||
} //namespace App
|
||||
|
||||
|
||||
ENABLE_BITMASK_OPERATORS(Data::SearchOption)
|
||||
#endif
|
||||
|
||||
@@ -165,7 +165,7 @@ public:
|
||||
* reference to the same geometry of the old element.
|
||||
*/
|
||||
virtual const std::vector<std::string>& searchElementCache(const std::string &element,
|
||||
Data::SearchOptions options = Data::SearchOptions::CheckGeometry,
|
||||
Data::SearchOptions options = Data::SearchOption::CheckGeometry,
|
||||
double tol = 1e-7,
|
||||
double atol = 1e-10) const;
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ class Flags {
|
||||
Enum i;
|
||||
|
||||
public:
|
||||
constexpr inline Flags(Enum f) : i(f) {}
|
||||
constexpr inline Flags(Enum f = Enum()) : i(f) {}
|
||||
constexpr bool testFlag(Enum f) const {
|
||||
using u = typename std::underlying_type<Enum>::type;
|
||||
return (i & f) == f && (static_cast<u>(f) != 0 || i == f);
|
||||
@@ -125,6 +125,48 @@ public:
|
||||
using u = typename std::underlying_type<Enum>::type;
|
||||
return static_cast<u>(i) == static_cast<u>(f.i);
|
||||
}
|
||||
constexpr Enum getFlags() const {
|
||||
return i;
|
||||
}
|
||||
constexpr Flags<Enum> &operator|=(const Flags<Enum> &other) {
|
||||
i |= other.i;
|
||||
return *this;
|
||||
}
|
||||
constexpr Flags<Enum> &operator|=(const Enum &f) {
|
||||
i |= f;
|
||||
return *this;
|
||||
}
|
||||
constexpr Flags<Enum> operator|(const Flags<Enum> &other) const {
|
||||
return i | other.i;
|
||||
}
|
||||
constexpr Flags<Enum> operator|(const Enum &f) const {
|
||||
return i | f;
|
||||
}
|
||||
constexpr Flags<Enum> &operator&=(const Flags<Enum> &other) {
|
||||
i &= other.i;
|
||||
return *this;
|
||||
}
|
||||
constexpr Flags<Enum> &operator&=(const Enum &f) {
|
||||
i &= f;
|
||||
return *this;
|
||||
}
|
||||
constexpr Flags<Enum> operator&(const Flags<Enum> &other) const {
|
||||
return i & other.i;
|
||||
}
|
||||
constexpr Flags<Enum> operator&(const Enum &f) const {
|
||||
return i & f;
|
||||
}
|
||||
constexpr Flags<Enum> operator~() const {
|
||||
return ~i;
|
||||
}
|
||||
|
||||
constexpr bool operator!() const {
|
||||
return !i;
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return toUnderlyingType() != 0;
|
||||
}
|
||||
typename std::underlying_type<Enum>::type toUnderlyingType() const {
|
||||
return static_cast<typename std::underlying_type<Enum>::type>(i);
|
||||
}
|
||||
|
||||
@@ -1499,7 +1499,7 @@ const std::vector<std::string>& Feature::searchElementCache(const std::string& e
|
||||
it->second.searched = true;
|
||||
propShape->getShape().findSubShapesWithSharedVertex(it->second.shape,
|
||||
&it->second.names,
|
||||
static_cast<CheckGeometry>(options),
|
||||
options,
|
||||
tol,
|
||||
atol);
|
||||
if (prefix) {
|
||||
|
||||
@@ -157,7 +157,7 @@ public:
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
|
||||
const std::vector<std::string>& searchElementCache(const std::string &element,
|
||||
Data::SearchOptions options = Data::SearchOptions::CheckGeometry,
|
||||
Data::SearchOptions options = Data::SearchOption::CheckGeometry,
|
||||
double tol = 1e-7,
|
||||
double atol = 1e-10) const override;
|
||||
#endif
|
||||
|
||||
@@ -1472,7 +1472,7 @@ public:
|
||||
*/
|
||||
std::vector<TopoShape> findSubShapesWithSharedVertex(const TopoShape &subshape,
|
||||
std::vector<std::string> *names=nullptr,
|
||||
CheckGeometry checkGeometry=CheckGeometry::checkGeometry,
|
||||
Data::SearchOptions = Data::SearchOption::CheckGeometry,
|
||||
double tol=1e-7, double atol=1e-12) const;
|
||||
//@}
|
||||
|
||||
|
||||
@@ -319,12 +319,14 @@ TopoDS_Shape TopoShape::findShape(TopAbs_ShapeEnum type, int idx) const
|
||||
return _cache->findShape(_Shape, type, idx);
|
||||
}
|
||||
|
||||
std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape& subshape,
|
||||
std::vector<std::string>* names,
|
||||
CheckGeometry checkGeometry,
|
||||
double tol,
|
||||
double atol) const
|
||||
{
|
||||
std::vector<TopoShape>
|
||||
TopoShape::findSubShapesWithSharedVertex(const TopoShape &subshape, // NOLINT(misc-no-recursion)
|
||||
std::vector<std::string> *names,
|
||||
Data::SearchOptions options,
|
||||
double tol,
|
||||
double atol) const {
|
||||
bool checkGeometry = options.testFlag(Data::SearchOption::CheckGeometry);
|
||||
bool singleSearch = options.testFlag(Data::SearchOption::SingleResult);
|
||||
std::vector<TopoShape> res;
|
||||
if (subshape.isNull() || this->isNull()) {
|
||||
return res;
|
||||
@@ -332,19 +334,104 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
|
||||
double tol2 = tol * tol;
|
||||
int index = 0;
|
||||
TopAbs_ShapeEnum shapeType = subshape.shapeType();
|
||||
|
||||
// This is an intentionally recursive method, which will exit after looking through all ancestors.
|
||||
auto searchCompositeShape = [&](TopAbs_ShapeEnum childType) { // NOLINT(misc-no-recursion)
|
||||
unsigned long count = subshape.countSubShapes(childType);
|
||||
if (!count)
|
||||
return;
|
||||
auto first = subshape.getSubTopoShape(childType, 1);
|
||||
for (const auto &child: findSubShapesWithSharedVertex(first, nullptr, options, tol, atol)) {
|
||||
for (int idx: findAncestors(child.getShape(), shapeType)) {
|
||||
auto shape = getSubTopoShape(shapeType, idx);
|
||||
if (shape.countSubShapes(childType) != count)
|
||||
continue;
|
||||
bool found = true;
|
||||
for (unsigned long i = 2; i < count; ++i) {
|
||||
if (shape.findSubShapesWithSharedVertex(subshape.getSubTopoShape(childType, i), nullptr,
|
||||
options, tol, atol).empty()) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
res.push_back(shape);
|
||||
if (names)
|
||||
names->push_back(shapeName(shapeType) + std::to_string(idx));
|
||||
if (singleSearch)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
switch (shapeType) {
|
||||
case TopAbs_WIRE:
|
||||
searchCompositeShape(TopAbs_EDGE);
|
||||
break;
|
||||
case TopAbs_SHELL:
|
||||
searchCompositeShape(TopAbs_FACE);
|
||||
break;
|
||||
case TopAbs_SOLID:
|
||||
searchCompositeShape(TopAbs_SHELL);
|
||||
break;
|
||||
case TopAbs_COMPSOLID:
|
||||
searchCompositeShape(TopAbs_SOLID);
|
||||
break;
|
||||
case TopAbs_COMPOUND:
|
||||
// special treatment of single sub-shape compound, that is, search
|
||||
// its extracting the compound
|
||||
if (countSubShapes(TopAbs_SHAPE) == 1) {
|
||||
return findSubShapesWithSharedVertex(subshape.getSubTopoShape(TopAbs_SHAPE, 1), names, options, tol,
|
||||
atol);
|
||||
} else if (unsigned long count = countSubShapes(TopAbs_SHAPE)) {
|
||||
// For multi-sub-shape compound, only search for compound with the same
|
||||
// structure
|
||||
int idx = 0;
|
||||
for (const auto &compound: getSubTopoShapes(shapeType)) {
|
||||
++idx;
|
||||
if (compound.countSubShapes(TopAbs_SHAPE) != count)
|
||||
continue;
|
||||
int i = 0;
|
||||
bool found = true;
|
||||
for (const auto &s: compound.getSubTopoShapes(TopAbs_SHAPE)) {
|
||||
++i;
|
||||
auto ss = subshape.getSubTopoShape(TopAbs_SHAPE, i);
|
||||
if (ss.isNull() && s.isNull())
|
||||
continue;
|
||||
auto options2 = options;
|
||||
options2.setFlag(Data::SearchOption::SingleResult);
|
||||
if (ss.isNull() || s.isNull()
|
||||
|| ss.shapeType() != s.shapeType()
|
||||
|| ss.findSubShapesWithSharedVertex(s, nullptr, options2, tol, atol).empty()) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
if (names)
|
||||
names->push_back(shapeName(shapeType) + std::to_string(idx));
|
||||
res.push_back(compound);
|
||||
if (singleSearch)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TopAbs_VERTEX:
|
||||
// Vertex search will do comparison with tolerance to account for
|
||||
// rounding error inccured through transformation.
|
||||
for (auto& shape : getSubTopoShapes(TopAbs_VERTEX)) {
|
||||
for (auto &shape: getSubTopoShapes(TopAbs_VERTEX)) {
|
||||
++index;
|
||||
if (BRep_Tool::Pnt(TopoDS::Vertex(shape.getShape()))
|
||||
.SquareDistance(BRep_Tool::Pnt(TopoDS::Vertex(subshape.getShape())))
|
||||
.SquareDistance(BRep_Tool::Pnt(TopoDS::Vertex(subshape.getShape())))
|
||||
<= tol2) {
|
||||
if (names) {
|
||||
names->push_back(std::string("Vertex") + std::to_string(index));
|
||||
}
|
||||
res.push_back(shape);
|
||||
if (singleSearch)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -359,12 +446,11 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
|
||||
if (shapeType == TopAbs_FACE) {
|
||||
wire = subshape.splitWires();
|
||||
vertices = wire.getSubShapes(TopAbs_VERTEX);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
vertices = subshape.getSubShapes(TopAbs_VERTEX);
|
||||
}
|
||||
|
||||
if (vertices.empty() || checkGeometry == CheckGeometry::checkGeometry) {
|
||||
if (vertices.empty() || checkGeometry) {
|
||||
geom = Geometry::fromShape(subshape.getShape());
|
||||
if (!geom) {
|
||||
return res;
|
||||
@@ -372,13 +458,12 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
|
||||
if (shapeType == TopAbs_EDGE) {
|
||||
isLine = (geom->isDerivedFrom(GeomLine::getClassTypeId())
|
||||
|| geom->isDerivedFrom(GeomLineSegment::getClassTypeId()));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
isPlane = geom->isDerivedFrom(GeomPlane::getClassTypeId());
|
||||
}
|
||||
}
|
||||
|
||||
auto compareGeometry = [&](const TopoShape& s, bool strict) {
|
||||
auto compareGeometry = [&](const TopoShape &s, bool strict) {
|
||||
std::unique_ptr<Geometry> g2(Geometry::fromShape(s.getShape()));
|
||||
if (!g2) {
|
||||
return false;
|
||||
@@ -391,16 +476,14 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
|
||||
&& !g2->isDerivedFrom(GeomLineSegment::getClassTypeId())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (isPlane && !strict) {
|
||||
} else if (isPlane && !strict) {
|
||||
// For planes, don't compare geometry either, so that
|
||||
// we don't need to worry about orientation and so on.
|
||||
// Just check the edges.
|
||||
if (!g2->isDerivedFrom(GeomPlane::getClassTypeId())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!g2 || !g2->isSame(*geom, tol, atol)) {
|
||||
} else if (!g2 || !g2->isSame(*geom, tol, atol)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -409,13 +492,15 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
|
||||
if (vertices.empty()) {
|
||||
// Probably an infinite shape, so we have to search by geometry
|
||||
int idx = 0;
|
||||
for (auto& shape : getSubTopoShapes(shapeType)) {
|
||||
for (auto &shape: getSubTopoShapes(shapeType)) {
|
||||
++idx;
|
||||
if (!shape.countSubShapes(TopAbs_VERTEX) && compareGeometry(shape, true)) {
|
||||
if (names) {
|
||||
names->push_back(shapeName(shapeType) + std::to_string(idx));
|
||||
}
|
||||
res.push_back(shape);
|
||||
if (singleSearch)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -428,9 +513,9 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
|
||||
// * Perform geometry comparison of the ancestor and input shape.
|
||||
// * For face, perform addition geometry comparison of each edge.
|
||||
std::unordered_set<TopoShape, ShapeHasher, ShapeHasher> shapeSet;
|
||||
for (auto& vert :
|
||||
findSubShapesWithSharedVertex(vertices[0], nullptr, checkGeometry, tol, atol)) {
|
||||
for (auto idx : findAncestors(vert.getShape(), shapeType)) {
|
||||
for (auto &vert:
|
||||
findSubShapesWithSharedVertex(vertices[0], nullptr, options, tol, atol)) {
|
||||
for (auto idx: findAncestors(vert.getShape(), shapeType)) {
|
||||
auto shape = getSubTopoShape(shapeType, idx);
|
||||
if (!shapeSet.insert(shape).second) {
|
||||
continue;
|
||||
@@ -444,28 +529,27 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
|
||||
continue;
|
||||
}
|
||||
otherVertices = otherWire.getSubShapes(TopAbs_VERTEX);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
otherVertices = shape.getSubShapes(TopAbs_VERTEX);
|
||||
}
|
||||
if (otherVertices.size() != vertices.size()) {
|
||||
continue;
|
||||
}
|
||||
if (checkGeometry == CheckGeometry::checkGeometry
|
||||
if (checkGeometry
|
||||
&& !compareGeometry(shape, false)) {
|
||||
continue;
|
||||
}
|
||||
unsigned ind = 0;
|
||||
bool matched = true;
|
||||
for (auto& vertex : vertices) {
|
||||
for (auto &vertex: vertices) {
|
||||
bool found = false;
|
||||
for (unsigned inner = 0; inner < otherVertices.size(); ++inner) {
|
||||
auto& vertex1 = otherVertices[ind];
|
||||
auto &vertex1 = otherVertices[ind];
|
||||
if (++ind == otherVertices.size()) {
|
||||
ind = 0;
|
||||
}
|
||||
if (BRep_Tool::Pnt(TopoDS::Vertex(vertex))
|
||||
.SquareDistance(BRep_Tool::Pnt(TopoDS::Vertex(vertex1)))
|
||||
.SquareDistance(BRep_Tool::Pnt(TopoDS::Vertex(vertex1)))
|
||||
<= tol2) {
|
||||
found = true;
|
||||
break;
|
||||
@@ -480,7 +564,7 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
|
||||
continue;
|
||||
}
|
||||
|
||||
if (shapeType == TopAbs_FACE && checkGeometry == CheckGeometry::checkGeometry) {
|
||||
if (shapeType == TopAbs_FACE && checkGeometry) {
|
||||
// Is it really necessary to check geometries of each edge of a face?
|
||||
// Right now we only do outer wire check
|
||||
auto otherEdges = otherWire.getSubShapes(TopAbs_EDGE);
|
||||
@@ -489,8 +573,8 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
|
||||
bool matched2 = true;
|
||||
unsigned i = 0;
|
||||
auto edges = wire.getSubShapes(TopAbs_EDGE);
|
||||
for (auto& edge : edges) {
|
||||
std::unique_ptr<Geometry> geom2(Geometry::fromShape(edge));
|
||||
for (auto &edge: edges) {
|
||||
std::unique_ptr<Geometry> geom2(Geometry::fromShape(edge, true));
|
||||
if (!geom2) {
|
||||
matched2 = false;
|
||||
break;
|
||||
@@ -506,13 +590,13 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
|
||||
// We will tolerate on edge reordering
|
||||
bool found = false;
|
||||
for (unsigned j = 0; j < otherEdges.size(); j++) {
|
||||
auto& e1 = otherEdges[i];
|
||||
auto& g1 = geos[i];
|
||||
auto &e1 = otherEdges[i];
|
||||
auto &g1 = geos[i];
|
||||
if (++i >= otherEdges.size()) {
|
||||
i = 0;
|
||||
}
|
||||
if (!g1) {
|
||||
g1 = Geometry::fromShape(e1);
|
||||
g1 = Geometry::fromShape(e1, true);
|
||||
if (!g1) {
|
||||
break;
|
||||
}
|
||||
@@ -521,9 +605,9 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
|
||||
if (g1->isDerivedFrom(GeomLine::getClassTypeId())
|
||||
|| g1->isDerivedFrom(GeomLineSegment::getClassTypeId())) {
|
||||
auto p1 =
|
||||
BRep_Tool::Pnt(TopExp::FirstVertex(TopoDS::Edge(e1)));
|
||||
BRep_Tool::Pnt(TopExp::FirstVertex(TopoDS::Edge(e1)));
|
||||
auto p2 =
|
||||
BRep_Tool::Pnt(TopExp::LastVertex(TopoDS::Edge(e1)));
|
||||
BRep_Tool::Pnt(TopExp::LastVertex(TopoDS::Edge(e1)));
|
||||
if ((p1.SquareDistance(pt1) <= tol2
|
||||
&& p2.SquareDistance(pt2) <= tol2)
|
||||
|| (p1.SquareDistance(pt2) <= tol2
|
||||
|
||||
@@ -3112,10 +3112,11 @@ PyObject* TopoShapePy::findSubShape(PyObject* args)
|
||||
|
||||
PyObject* TopoShapePy::findSubShapesWithSharedVertex(PyObject* args, PyObject* keywds)
|
||||
{
|
||||
static const std::array<const char*, 6> kwlist {"shape", "needName", "checkGeometry", "tol", "atol", nullptr};
|
||||
static const std::array<const char*, 7> kwlist {"shape", "needName", "checkGeometry", "tol", "atol", "singleResult", nullptr};
|
||||
PyObject* pyobj;
|
||||
PyObject* needName = Py_False;
|
||||
PyObject* checkGeometry = Py_True;
|
||||
PyObject* singleResult = Py_False;
|
||||
double tol = 1e-7;
|
||||
double atol = 1e-12;
|
||||
if (!Base::Wrapped_ParseTupleAndKeywords(args,
|
||||
@@ -3127,7 +3128,8 @@ PyObject* TopoShapePy::findSubShapesWithSharedVertex(PyObject* args, PyObject* k
|
||||
&needName,
|
||||
&checkGeometry,
|
||||
&tol,
|
||||
&atol)) {
|
||||
&atol,
|
||||
&singleResult)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -3135,13 +3137,17 @@ PyObject* TopoShapePy::findSubShapesWithSharedVertex(PyObject* args, PyObject* k
|
||||
{
|
||||
Py::List res;
|
||||
const TopoShape& shape = *static_cast<TopoShapePy*>(pyobj)->getTopoShapePtr();
|
||||
Data::SearchOptions options;
|
||||
if (PyObject_IsTrue(checkGeometry))
|
||||
options.setFlag(Data::SearchOption::CheckGeometry);
|
||||
if (PyObject_IsTrue(singleResult))
|
||||
options.setFlag(Data::SearchOption::SingleResult);
|
||||
if (PyObject_IsTrue(needName)) {
|
||||
std::vector<std::string> names;
|
||||
auto shapes = getTopoShapePtr()->findSubShapesWithSharedVertex(
|
||||
shape,
|
||||
&names,
|
||||
PyObject_IsTrue(checkGeometry) ? CheckGeometry::checkGeometry
|
||||
: CheckGeometry::ignoreGeometry,
|
||||
options,
|
||||
tol,
|
||||
atol);
|
||||
for (std::size_t i = 0; i < shapes.size(); ++i) {
|
||||
@@ -3152,8 +3158,7 @@ PyObject* TopoShapePy::findSubShapesWithSharedVertex(PyObject* args, PyObject* k
|
||||
for (auto& s : getTopoShapePtr()->findSubShapesWithSharedVertex(
|
||||
shape,
|
||||
nullptr,
|
||||
PyObject_IsTrue(checkGeometry) ? CheckGeometry::checkGeometry
|
||||
: CheckGeometry::ignoreGeometry,
|
||||
options,
|
||||
tol,
|
||||
atol)) {
|
||||
res.append(shape2pyshape(s));
|
||||
|
||||
Reference in New Issue
Block a user