Merge pull request #15504 from bgbsww/bgbsww-toponamingSaveRestore5

Toponaming: update findSubShapesWithSharedVertex
This commit is contained in:
Chris Hennes
2024-07-22 15:28:18 -05:00
committed by GitHub
13 changed files with 250 additions and 93 deletions
+3 -2
View File
@@ -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
+1 -1
View File
@@ -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;
+12 -16
View File
@@ -1105,22 +1105,18 @@ void PropertyExpressionEngine::getLinksTo(std::vector<App::ObjectIdentifier>& id
identifiers.push_back(expressionId);
break;
}
bool found = false;
for (const auto& path : paths) {
if (path.getSubObjectName() == subname) {
identifiers.push_back(expressionId);
found = true;
break;
}
App::SubObjectT sobjT(obj, path.getSubObjectName().c_str());
if (sobjT.getSubObject() == sobj && sobjT.getOldElementName() == subElement) {
identifiers.push_back(expressionId);
found = true;
break;
}
}
if (found) {
break;
if (std::any_of(paths.begin(),
paths.end(),
[subname, obj, sobj, &subElement](const auto& path) {
if (path.getSubObjectName() == subname) {
return true;
}
App::SubObjectT sobjT(obj, path.getSubObjectName().c_str());
return (sobjT.getSubObject() == sobj
&& sobjT.getOldElementName() == subElement);
})) {
identifiers.push_back(expressionId);
}
}
}
+25 -20
View File
@@ -73,7 +73,7 @@ void PropertyLinkBase::setAllowExternal(bool allow) {
}
void PropertyLinkBase::setSilentRestore(bool allow) {
setFlag(LinkSilentRestore,allow);
setFlag(LinkSilentRestore, allow);
}
void PropertyLinkBase::setReturnNewElement(bool enable) {
@@ -800,13 +800,15 @@ void PropertyLink::getLinks(std::vector<App::DocumentObject *> &objs,
objs.push_back(_pcLink);
}
void PropertyLink::getLinksTo(std::vector<App::ObjectIdentifier>& identifiers,
App::DocumentObject* obj,
const char* subname,
bool all) const
{
(void)subname;
if ((all || _pcScope != LinkScope::Hidden) && obj && _pcLink == obj) {
void PropertyLink::getLinksTo(std::vector<App::ObjectIdentifier> &identifiers,
App::DocumentObject *obj,
const char *subname,
bool all) const {
(void) subname;
if (!all && _pcScope == LinkScope::Hidden) {
return; // Don't get hidden links unless all is specified.
}
if (obj && _pcLink == obj) {
identifiers.emplace_back(*this);
}
}
@@ -1165,9 +1167,9 @@ void PropertyLinkList::getLinksTo(std::vector<App::ObjectIdentifier>& identifier
return;
}
int i = -1;
for (auto o : _lValueList) {
for (auto docObj : _lValueList) {
++i;
if (o == obj) {
if (docObj == obj) {
identifiers.emplace_back(*this, i);
break;
}
@@ -1658,13 +1660,13 @@ void PropertyLinkBase::_getLinksTo(std::vector<App::ObjectIdentifier>& identifie
if (!subObject) {
continue;
}
// There is a subobject and the subname doesn't match our current entry
// After above, there is a subobject and the subname doesn't match our current entry
App::SubObjectT sobjT(obj, sub.c_str());
if (sobjT.getSubObject() == subObject && sobjT.getOldElementName() == subElement) {
identifiers.emplace_back(*this);
return;
}
// The oldElementName ( short, I.E. "Edge5" ) doesn't match.
// And the oldElementName ( short, I.E. "Edge5" ) doesn't match.
if (i < (int)shadows.size()) {
const auto& [shadowNewName, shadowOldName] = shadows[i];
if (shadowNewName == subname || shadowOldName == subname) {
@@ -2909,15 +2911,18 @@ void PropertyLinkSubList::getLinksTo(std::vector<App::ObjectIdentifier>& identif
auto subElement = objT.getOldElementName();
int i = -1;
for (const auto& o : _lValueList) {
for (const auto& docObj : _lValueList) {
++i;
if (o != obj) {
if (docObj != obj) {
continue;
}
// If we don't specify a subname we looking for all; or if the subname is in our
// property, add this entry to our result
if (!subname || (i < (int)_lSubList.size() && subname == _lSubList[i])) {
identifiers.emplace_back(*this, i);
continue;
}
// If we couldn't find any subobjects or this object's index is in our list, ignore it
if (!subObject || i < (int)_lSubList.size()) {
continue;
}
@@ -4917,12 +4922,12 @@ void PropertyXLinkSubList::getLinksTo(std::vector<App::ObjectIdentifier>& identi
const char* subname,
bool all) const
{
if (all || _pcScope != LinkScope::Hidden) {
for (auto& l : _Links) {
// This is the same algorithm as _getLinksTo, but returns lists, not single entries
if (obj && obj == l._pcLink) {
_getLinksToList(identifiers, obj, subname, l._SubList, l._ShadowSubList);
}
if ( ! all && _pcScope != LinkScope::Hidden) {
return;
}
for (auto& l : _Links) {
if (obj && obj == l._pcLink) {
_getLinksToList(identifiers, obj, subname, l._SubList, l._ShadowSubList);
}
}
}
+1 -1
View File
@@ -183,7 +183,7 @@ public:
virtual void getLinks(std::vector<App::DocumentObject *> &objs,
bool all=false, std::vector<std::string> *subs=nullptr, bool newStyle=true) const = 0;
/** Obtain identifiers from this link property that link to a give object
/** Obtain identifiers from this link property that link to a given object
* @param identifiers: holds the returned identifier to reference the given object
* @param obj: the referenced object
* @param subname: optional subname reference
+44 -1
View File
@@ -113,7 +113,8 @@ class Flags {
Enum i;
public:
constexpr inline Flags(Enum f) : i(f) {}
// Linter seems wrong on next line, don't want explicit here forcing downstream changes
constexpr inline Flags(Enum f = Enum()) : i(f) {} // NOLINT (runtime/explicit)
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 +126,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);
}
+1 -1
View File
@@ -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) {
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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;
//@}
+117 -14
View File
@@ -41,7 +41,6 @@
#include <BRepTools.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <BRepAdaptor_CompCurve.hxx>
#include <BRepAlgoAPI_BooleanOperation.hxx>
#include <BRepAlgoAPI_Common.hxx>
#include <BRepAlgoAPI_Cut.hxx>
@@ -55,9 +54,6 @@
#include <BRepBuilderAPI_MakeSolid.hxx>
#include <BRepBuilderAPI_NurbsConvert.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepBuilderAPI_MakeSolid.hxx>
#include <BRepBuilderAPI_NurbsConvert.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepFilletAPI_MakeChamfer.hxx>
#include <BRepFilletAPI_MakeFillet.hxx>
#include <BRepLib.hxx>
@@ -81,7 +77,6 @@
#include <TopTools_HSequenceOfShape.hxx>
#include <ShapeFix_Shape.hxx>
#include <ShapeFix_ShapeTolerance.hxx>
#include <TopTools_HSequenceOfShape.hxx>
#include <gp_Pln.hxx>
#include <utility>
@@ -106,7 +101,6 @@
#include <App/ElementMap.h>
#include <App/ElementNamingUtils.h>
#include <ShapeAnalysis_FreeBoundsProperties.hxx>
#include <BRepBuilderAPI_MakeSolid.hxx>
#include <BRepFeat_MakeRevol.hxx>
FC_LOG_LEVEL_INIT("TopoShape", true, true) // NOLINT
@@ -321,10 +315,12 @@ TopoDS_Shape TopoShape::findShape(TopAbs_ShapeEnum type, int idx) const
std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape& subshape,
std::vector<std::string>* names,
CheckGeometry checkGeometry,
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,7 +328,109 @@ 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-recu2rsive)
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.
@@ -345,6 +443,9 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
names->push_back(std::string("Vertex") + std::to_string(index));
}
res.push_back(shape);
if (singleSearch) {
return res;
}
}
}
break;
@@ -364,7 +465,7 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
vertices = subshape.getSubShapes(TopAbs_VERTEX);
}
if (vertices.empty() || checkGeometry == CheckGeometry::checkGeometry) {
if (vertices.empty() || checkGeometry) {
geom = Geometry::fromShape(subshape.getShape());
if (!geom) {
return res;
@@ -416,6 +517,9 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
names->push_back(shapeName(shapeType) + std::to_string(idx));
}
res.push_back(shape);
if (singleSearch) {
return res;
}
}
}
break;
@@ -429,7 +533,7 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
// * 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)) {
findSubShapesWithSharedVertex(vertices[0], nullptr, options, tol, atol)) {
for (auto idx : findAncestors(vert.getShape(), shapeType)) {
auto shape = getSubTopoShape(shapeType, idx);
if (!shapeSet.insert(shape).second) {
@@ -451,8 +555,7 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
if (otherVertices.size() != vertices.size()) {
continue;
}
if (checkGeometry == CheckGeometry::checkGeometry
&& !compareGeometry(shape, false)) {
if (checkGeometry && !compareGeometry(shape, false)) {
continue;
}
unsigned ind = 0;
@@ -480,7 +583,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);
@@ -490,7 +593,7 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
unsigned i = 0;
auto edges = wire.getSubShapes(TopAbs_EDGE);
for (auto& edge : edges) {
std::unique_ptr<Geometry> geom2(Geometry::fromShape(edge));
std::unique_ptr<Geometry> geom2(Geometry::fromShape(edge, true));
if (!geom2) {
matched2 = false;
break;
@@ -512,7 +615,7 @@ std::vector<TopoShape> TopoShape::findSubShapesWithSharedVertex(const TopoShape&
i = 0;
}
if (!g1) {
g1 = Geometry::fromShape(e1);
g1 = Geometry::fromShape(e1, true);
if (!g1) {
break;
}
+11 -6
View File
@@ -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));
+12 -17
View File
@@ -2295,23 +2295,18 @@ void PropertySheet::getLinksTo(std::vector<App::ObjectIdentifier>& identifiers,
identifiers.emplace_back(owner, cellName.toString().c_str());
break;
}
bool found = false;
for (const auto& path : paths) {
if (path.getSubObjectName() == subname) {
identifiers.emplace_back(owner, cellName.toString().c_str());
found = true;
break;
}
App::SubObjectT sobjT(obj, path.getSubObjectName().c_str());
if (sobjT.getSubObject() == subObject
&& sobjT.getOldElementName() == subElement) {
identifiers.emplace_back(owner, cellName.toString().c_str());
found = true;
break;
}
}
if (found) {
break;
if (std::any_of(paths.begin(),
paths.end(),
[subname, obj, subObject, &subElement](const auto& path) {
if (path.getSubObjectName() == subname) {
return true;
}
App::SubObjectT sobjT(obj, path.getSubObjectName().c_str());
return (sobjT.getSubObject() == subObject
&& sobjT.getOldElementName() == subElement);
})) {
identifiers.emplace_back(owner, cellName.toString().c_str());
}
}
}
+21 -12
View File
@@ -1140,16 +1140,19 @@ TEST_F(TopoShapeExpansionTest, findSubShapesWithSharedVertexEverything)
exp.Init(box1, TopAbs_VERTEX);
auto vertex = exp.Current();
// Act
auto shapes =
box1TS.findSubShapesWithSharedVertex(face, &names, CheckGeometry::checkGeometry, tol, atol);
auto shapes = box1TS.findSubShapesWithSharedVertex(face,
&names,
Data::SearchOption::CheckGeometry,
tol,
atol);
auto shapes1 = box1TS.findSubShapesWithSharedVertex(edge,
&names1,
CheckGeometry::checkGeometry,
Data::SearchOption::CheckGeometry,
tol,
atol);
auto shapes2 = box1TS.findSubShapesWithSharedVertex(vertex,
&names2,
CheckGeometry::checkGeometry,
Data::SearchOption::CheckGeometry,
tol,
atol);
// Assert
@@ -1185,16 +1188,19 @@ TEST_F(TopoShapeExpansionTest, findSubShapesWithSharedVertexMid)
exp.Init(box1, TopAbs_VERTEX);
auto vertex = exp.Current();
// Act
auto shapes =
box1TS.findSubShapesWithSharedVertex(face, &names, CheckGeometry::checkGeometry, tol, atol);
auto shapes = box1TS.findSubShapesWithSharedVertex(face,
&names,
Data::SearchOption::CheckGeometry,
tol,
atol);
auto shapes1 = box1TS.findSubShapesWithSharedVertex(edge,
&names1,
CheckGeometry::checkGeometry,
Data::SearchOption::CheckGeometry,
tol,
atol);
auto shapes2 = box1TS.findSubShapesWithSharedVertex(vertex,
&names2,
CheckGeometry::checkGeometry,
Data::SearchOption::CheckGeometry,
tol,
atol);
// Assert
@@ -1224,16 +1230,19 @@ TEST_F(TopoShapeExpansionTest, findSubShapesWithSharedVertexClose)
exp.Init(box1, TopAbs_VERTEX);
auto vertex = exp.Current();
// Act
auto shapes =
box1TS.findSubShapesWithSharedVertex(face, &names, CheckGeometry::checkGeometry, tol, atol);
auto shapes = box1TS.findSubShapesWithSharedVertex(face,
&names,
Data::SearchOption::CheckGeometry,
tol,
atol);
auto shapes1 = box1TS.findSubShapesWithSharedVertex(edge,
&names1,
CheckGeometry::checkGeometry,
Data::SearchOption::CheckGeometry,
tol,
atol);
auto shapes2 = box1TS.findSubShapesWithSharedVertex(vertex,
&names2,
CheckGeometry::checkGeometry,
Data::SearchOption::CheckGeometry,
tol,
atol);
// Assert