Toponaming: bring in missing code fragments in App
This commit is contained in:
@@ -53,6 +53,12 @@ namespace Data
|
||||
{
|
||||
|
||||
//struct MappedChildElements;
|
||||
/// Option for App::GeoFeature::searchElementCache()
|
||||
enum class SearchOptions {
|
||||
/// Whether to compare shape geometry
|
||||
CheckGeometry = 1,
|
||||
SingleResult = 2,
|
||||
};
|
||||
|
||||
/** Segments
|
||||
* Sub-element type of the ComplexGeoData type
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "GeoFeature.h"
|
||||
#include "GeoFeatureGroupExtension.h"
|
||||
#include "ElementNamingUtils.h"
|
||||
#include "Link.h"
|
||||
|
||||
|
||||
using namespace App;
|
||||
@@ -141,6 +142,10 @@ DocumentObject *GeoFeature::resolveElement(DocumentObject *obj, const char *subn
|
||||
ElementNameType type, const DocumentObject *filter,
|
||||
const char **_element, GeoFeature **geoFeature)
|
||||
{
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
elementName.first.clear();
|
||||
elementName.second.clear();
|
||||
#endif
|
||||
if(!obj || !obj->isAttachedToDocument())
|
||||
return nullptr;
|
||||
if(!subname)
|
||||
@@ -148,13 +153,16 @@ DocumentObject *GeoFeature::resolveElement(DocumentObject *obj, const char *subn
|
||||
const char *element = Data::findElementName(subname);
|
||||
if(_element) *_element = element;
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
elementName.first.clear();
|
||||
elementName.second.clear();
|
||||
auto sobj = obj->getSubObject(std::string(subname, element).c_str());
|
||||
if(!sobj)
|
||||
return nullptr;
|
||||
auto linked = sobj->getLinkedObject(true);
|
||||
auto geo = Base::freecad_dynamic_cast<GeoFeature>(linked);
|
||||
if(!geo && linked) {
|
||||
auto ext = linked->getExtensionByType<LinkBaseExtension>(true);
|
||||
if(ext)
|
||||
geo = Base::freecad_dynamic_cast<GeoFeature>(ext->getTrueLinkedObject(true));
|
||||
}
|
||||
#else
|
||||
auto sobj = obj->getSubObject(subname);
|
||||
if(!sobj)
|
||||
@@ -202,43 +210,73 @@ void GeoFeature::setMaterialAppearance(const App::Material& material)
|
||||
}
|
||||
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
bool GeoFeature::hasMissingElement(const char *subname) {
|
||||
bool GeoFeature::hasMissingElement(const char* subname)
|
||||
{
|
||||
return Data::hasMissingElement(subname);
|
||||
if(!subname)
|
||||
if (!subname) {
|
||||
return false;
|
||||
auto dot = strrchr(subname,'.');
|
||||
if(!dot)
|
||||
return subname[0]=='?';
|
||||
return dot[1]=='?';
|
||||
}
|
||||
auto dot = strrchr(subname, '.');
|
||||
if (!dot) {
|
||||
return subname[0] == '?';
|
||||
}
|
||||
return dot[1] == '?';
|
||||
}
|
||||
|
||||
void GeoFeature::updateElementReference() {
|
||||
void GeoFeature::updateElementReference()
|
||||
{
|
||||
auto prop = getPropertyOfGeometry();
|
||||
if(!prop) return;
|
||||
if (!prop) {
|
||||
return;
|
||||
}
|
||||
auto geo = prop->getComplexData();
|
||||
if(!geo) return;
|
||||
if (!geo) {
|
||||
return;
|
||||
}
|
||||
bool reset = false;
|
||||
PropertyLinkBase::updateElementReferences(this,reset);
|
||||
PropertyLinkBase::updateElementReferences(this, reset);
|
||||
}
|
||||
|
||||
void GeoFeature::onChanged(const Property *prop) {
|
||||
if(prop==getPropertyOfGeometry()) {
|
||||
if(getDocument() && !getDocument()->testStatus(Document::Restoring)
|
||||
&& !getDocument()->isPerformingTransaction())
|
||||
{
|
||||
void GeoFeature::onChanged(const Property* prop)
|
||||
{
|
||||
if (prop == getPropertyOfGeometry()) {
|
||||
if (getDocument() && !getDocument()->testStatus(Document::Restoring)
|
||||
&& !getDocument()->isPerformingTransaction()) {
|
||||
updateElementReference();
|
||||
}
|
||||
}
|
||||
DocumentObject::onChanged(prop);
|
||||
}
|
||||
|
||||
const std::vector<std::string>& GeoFeature::searchElementCache(const std::string& element,
|
||||
Data::SearchOptions options,
|
||||
double tol,
|
||||
double atol) const
|
||||
{
|
||||
static std::vector<std::string> none;
|
||||
(void)element;
|
||||
(void)options;
|
||||
(void)tol;
|
||||
(void)atol;
|
||||
return none;
|
||||
}
|
||||
|
||||
std::vector<Data::IndexedName>
|
||||
GeoFeature::getHigherElements(const char *element, bool silent) const
|
||||
const std::vector<const char*>& GeoFeature::getElementTypes(bool /*all*/) const
|
||||
{
|
||||
static std::vector<const char*> nil;
|
||||
auto prop = getPropertyOfGeometry();
|
||||
if (!prop) {
|
||||
return nil;
|
||||
}
|
||||
return prop->getComplexData()->getElementTypes();
|
||||
}
|
||||
|
||||
std::vector<Data::IndexedName> GeoFeature::getHigherElements(const char* element, bool silent) const
|
||||
{
|
||||
auto prop = getPropertyOfGeometry();
|
||||
if (!prop)
|
||||
if (!prop) {
|
||||
return {};
|
||||
}
|
||||
return prop->getComplexData()->getHigherElements(element, silent);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "PropertyGeo.h"
|
||||
#include "MappedElement.h"
|
||||
#include "Material.h"
|
||||
#include "ComplexGeoData.h"
|
||||
|
||||
namespace App
|
||||
{
|
||||
@@ -141,12 +142,34 @@ public:
|
||||
*/
|
||||
virtual void setMaterialAppearance(const App::Material& material);
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
/** Search sub element using internal cached geometry
|
||||
*
|
||||
* @param element: element name
|
||||
* @param options: search options
|
||||
* @param tol: coordinate tolerance
|
||||
* @param atol: angle tolerance
|
||||
*
|
||||
* @return Returns a list of found element reference to the new geometry.
|
||||
* The returned value will be invalidated when the geometry is changed.
|
||||
*
|
||||
* Before changing the property of geometry, GeoFeature will internally
|
||||
* make a snapshot of all referenced element geometry. After change, user
|
||||
* code may call this function to search for the new element name that
|
||||
* 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,
|
||||
double tol = 1e-7,
|
||||
double atol = 1e-10) const;
|
||||
|
||||
static bool hasMissingElement(const char *subname);
|
||||
|
||||
/// Return the object that owns the shape that contains the give element name
|
||||
virtual DocumentObject *getElementOwner(const Data::MappedName & /*name*/) const
|
||||
{return nullptr;}
|
||||
|
||||
virtual const std::vector<const char *>& getElementTypes(bool all=true) const;
|
||||
|
||||
/// Return the higher level element names of the given element
|
||||
virtual std::vector<Data::IndexedName> getHigherElements(const char *name, bool silent=false) const;
|
||||
|
||||
|
||||
@@ -1420,8 +1420,22 @@ void LinkBaseExtension::checkGeoElementMap(const App::DocumentObject *obj,
|
||||
!PyObject_TypeCheck(*pyObj, &Data::ComplexGeoDataPy::Type))
|
||||
return;
|
||||
|
||||
// auto geoData = static_cast<Data::ComplexGeoDataPy*>(*pyObj)->getComplexGeoDataPtr();
|
||||
// geoData->reTagElementMap(obj->getID(),obj->getDocument()->Hasher,postfix);
|
||||
// auto geoData = static_cast<Data::ComplexGeoDataPy*>(*pyObj)->getComplexGeoDataPtr();
|
||||
// geoData->reTagElementMap(obj->getID(),obj->getDocument()->Hasher,postfix);
|
||||
|
||||
auto geoData = static_cast<Data::ComplexGeoDataPy*>(*pyObj)->getComplexGeoDataPtr();
|
||||
std::string _postfix;
|
||||
if (linked && obj && linked->getDocument() != obj->getDocument()) {
|
||||
_postfix = Data::POSTFIX_EXTERNAL_TAG;
|
||||
if (postfix) {
|
||||
if (!boost::starts_with(postfix, Data::ComplexGeoData::elementMapPrefix()))
|
||||
_postfix += Data::ComplexGeoData::elementMapPrefix();
|
||||
_postfix += postfix;
|
||||
}
|
||||
postfix = _postfix.c_str();
|
||||
}
|
||||
geoData->reTagElementMap(obj->getID(),obj->getDocument()->getStringHasher(),postfix);
|
||||
|
||||
}
|
||||
|
||||
void LinkBaseExtension::onExtendedUnsetupObject() {
|
||||
|
||||
@@ -218,6 +218,19 @@ static std::string propertyName(const Property *prop) {
|
||||
return prop->getFullName();
|
||||
}
|
||||
|
||||
const std::unordered_set<PropertyLinkBase*>&
|
||||
PropertyLinkBase::getElementReferences(DocumentObject* feature)
|
||||
{
|
||||
static std::unordered_set<PropertyLinkBase*> none;
|
||||
|
||||
auto it = _ElementRefMap.find(feature);
|
||||
if (it == _ElementRefMap.end()) {
|
||||
return none;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void PropertyLinkBase::updateElementReferences(DocumentObject *feature, bool reverse) {
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
if (!feature || !feature->getNameInDocument()) {
|
||||
@@ -394,15 +407,15 @@ bool PropertyLinkBase::_updateElementReference(DocumentObject *feature,
|
||||
}
|
||||
}
|
||||
|
||||
bool missing = Data::hasMissingElement(elementName.second.c_str());
|
||||
bool missing = GeoFeature::hasMissingElement(elementName.second.c_str());
|
||||
if (feature == geo && (missing || reverse)) {
|
||||
// If the referenced element is missing, or we are generating element
|
||||
// map for the first time, or we are re-generating the element map due
|
||||
// to version change, i.e. 'reverse', try search by geometry first
|
||||
const char* oldElement = Data::findElementName(shadow.second.c_str());
|
||||
if (!Data::hasMissingElement(oldElement)) {
|
||||
// const auto& names = geo->searchElementCache(oldElement);
|
||||
std::vector<std::string> names; // searchElementCache isn't implemented.
|
||||
const auto& names = geo->searchElementCache(oldElement);
|
||||
// std::vector<std::string> names; // searchElementCache isn't implemented.
|
||||
if (names.size()) {
|
||||
missing = false;
|
||||
std::string newsub(subname, strlen(subname) - strlen(element));
|
||||
@@ -502,11 +515,18 @@ bool PropertyLinkBase::_updateElementReference(DocumentObject *feature,
|
||||
}
|
||||
|
||||
std::pair<DocumentObject*, std::string>
|
||||
PropertyLinkBase::tryReplaceLink(const PropertyContainer *owner, DocumentObject *obj,
|
||||
const DocumentObject *parent, DocumentObject *oldObj, DocumentObject *newObj, const char *subname)
|
||||
PropertyLinkBase::tryReplaceLink(const PropertyContainer* owner,
|
||||
DocumentObject* obj,
|
||||
const DocumentObject* parent,
|
||||
DocumentObject* oldObj,
|
||||
DocumentObject* newObj,
|
||||
const char* subname)
|
||||
{
|
||||
std::pair<DocumentObject*, std::string> res;
|
||||
res.first = 0;
|
||||
if (!obj) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (oldObj == obj) {
|
||||
if (owner == parent) {
|
||||
@@ -536,6 +556,9 @@ PropertyLinkBase::tryReplaceLink(const PropertyContainer *owner, DocumentObject
|
||||
for (auto pos = sub.find('.'); pos != std::string::npos; pos = sub.find('.', pos)) {
|
||||
++pos;
|
||||
char c = sub[pos];
|
||||
if (c == '.') {
|
||||
continue;
|
||||
}
|
||||
sub[pos] = 0;
|
||||
auto sobj = obj->getSubObject(sub.c_str());
|
||||
sub[pos] = c;
|
||||
@@ -577,6 +600,8 @@ PropertyLinkBase::tryReplaceLinkSubs(const PropertyContainer *owner,
|
||||
{
|
||||
std::pair<DocumentObject*,std::vector<std::string> > res;
|
||||
res.first = 0;
|
||||
if (!obj)
|
||||
return res;
|
||||
|
||||
auto r = tryReplaceLink(owner,obj,parent,oldObj,newObj);
|
||||
if(r.first) {
|
||||
@@ -1545,8 +1570,12 @@ std::string PropertyLinkBase::tryImportSubName(const App::DocumentObject *obj, c
|
||||
#define ATTR_SHADOW "shadow"
|
||||
#define ATTR_MAPPED "mapped"
|
||||
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
#define IGNORE_SHADOW false
|
||||
#else
|
||||
// We do not have topo naming yet, ignore shadow sub for now
|
||||
#define IGNORE_SHADOW true
|
||||
#endif
|
||||
|
||||
void PropertyLinkSub::Save (Base::Writer &writer) const
|
||||
{
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "Property.h"
|
||||
|
||||
namespace Base {
|
||||
@@ -38,6 +41,8 @@ namespace App
|
||||
{
|
||||
class DocumentObject;
|
||||
class Document;
|
||||
class GeoFeature;
|
||||
class SubObjectT;
|
||||
|
||||
class DocInfo;
|
||||
using DocInfoPtr = std::shared_ptr<DocInfo>;
|
||||
@@ -262,7 +267,7 @@ public:
|
||||
|
||||
/// Helper function to return a map of linked object and its subname references
|
||||
void getLinkedElements(std::map<App::DocumentObject*, std::vector<std::string> > &elements,
|
||||
bool newStyle=true, bool all=true) const
|
||||
bool newStyle=true, bool all=false) const
|
||||
{
|
||||
std::vector<App::DocumentObject*> ret;
|
||||
std::vector<std::string> subs;
|
||||
@@ -275,7 +280,7 @@ public:
|
||||
|
||||
/// Helper function to return a map of linked object and its subname references
|
||||
std::map<App::DocumentObject*, std::vector<std::string> >
|
||||
linkedElements(bool newStyle=true, bool all=true) const
|
||||
linkedElements(bool newStyle=true, bool all=false) const
|
||||
{
|
||||
std::map<App::DocumentObject*, std::vector<std::string> > ret;
|
||||
getLinkedElements(ret,newStyle,all);
|
||||
@@ -346,6 +351,8 @@ public:
|
||||
/// Update all element references in all link properties of \a feature
|
||||
static void updateElementReferences(DocumentObject *feature, bool reverse=false);
|
||||
|
||||
/// Obtain link properties that contain element references to a given object
|
||||
static const std::unordered_set<PropertyLinkBase*>& getElementReferences(DocumentObject *);
|
||||
|
||||
/** Helper function for update individual element reference
|
||||
*
|
||||
|
||||
@@ -259,84 +259,6 @@ std::vector<TopoShape> DressUp::getFaces(const TopoShape& shape)
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<TopoShape> DressUp::getContinuousEdges(const TopoShape &shape) {
|
||||
std::vector<TopoShape> ret;
|
||||
std::unordered_set<TopoDS_Shape, Part::ShapeHasher, Part::ShapeHasher> shapeSet;
|
||||
|
||||
auto addEdge = [&](const TopoDS_Shape &subshape, const std::string &ref) {
|
||||
if (!shapeSet.insert(subshape).second)
|
||||
return;
|
||||
|
||||
auto faces = shape.findAncestorsShapes(subshape, TopAbs_FACE);
|
||||
if(faces.size() != 2) {
|
||||
FC_WARN(getFullName() << ": skip edge "
|
||||
<< ref << " with less two attaching faces");
|
||||
return;
|
||||
}
|
||||
const TopoDS_Shape& face1 = faces.front();
|
||||
const TopoDS_Shape& face2 = faces.back();
|
||||
GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(subshape),
|
||||
TopoDS::Face(face1),
|
||||
TopoDS::Face(face2));
|
||||
if (cont != GeomAbs_C0) {
|
||||
FC_WARN(getFullName() << ": skip edge "
|
||||
<< ref << " that is not C0 continuous");
|
||||
return;
|
||||
}
|
||||
ret.push_back(subshape);
|
||||
};
|
||||
|
||||
for(const auto &v : Base.getShadowSubs()) {
|
||||
TopoDS_Shape subshape;
|
||||
const auto &ref = v.first.size()?v.first:v.second;
|
||||
subshape = shape.getSubShape(ref.c_str(), true);
|
||||
if(subshape.IsNull())
|
||||
FC_THROWM(Base::CADKernelError, "Invalid edge link: " << v.second);
|
||||
|
||||
if (subshape.ShapeType() == TopAbs_EDGE)
|
||||
addEdge(subshape, ref);
|
||||
else if(subshape.ShapeType() == TopAbs_FACE || subshape.ShapeType() == TopAbs_WIRE) {
|
||||
for(TopExp_Explorer exp(subshape,TopAbs_EDGE);exp.More();exp.Next())
|
||||
addEdge(exp.Current(), std::string());
|
||||
} else
|
||||
FC_WARN(getFullName() << ": skip invalid shape '"
|
||||
<< ref << "' with type " << TopoShape::shapeName(subshape.ShapeType()));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<TopoShape> DressUp::getFaces(const TopoShape &shape) {
|
||||
std::vector<TopoShape> ret;
|
||||
const auto &vals = Base.getSubValues();
|
||||
const auto &subs = Base.getShadowSubs();
|
||||
size_t i=0;
|
||||
for(auto &val : vals) {
|
||||
if(!boost::starts_with(val,"Face"))
|
||||
continue;
|
||||
auto &sub = subs[i++];
|
||||
auto &ref = sub.first.size()?sub.first:val;
|
||||
TopoShape subshape;
|
||||
try {
|
||||
subshape = shape.getSubTopoShape(ref.c_str());
|
||||
}catch(...)
|
||||
{
|
||||
}
|
||||
|
||||
if(subshape.isNull()) {
|
||||
FC_ERR(getFullName() << ": invalid face reference '" << ref << "'");
|
||||
throw Part::NullShapeException("Invalid Invalid face link");
|
||||
}
|
||||
|
||||
if(subshape.shapeType() != TopAbs_FACE) {
|
||||
FC_WARN(getFullName() << ": skip invalid shape '"
|
||||
<< ref << "' with type " << subshape.shapeName());
|
||||
continue;
|
||||
}
|
||||
ret.push_back(subshape);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DressUp::onChanged(const App::Property* prop)
|
||||
{
|
||||
// the BaseFeature property should track the Base and vice-versa as long as
|
||||
|
||||
@@ -1362,4 +1362,4 @@ class TestTopologicalNamingProblem(unittest.TestCase):
|
||||
|
||||
def tearDown(self):
|
||||
""" Close our test document """
|
||||
# App.closeDocument("PartDesignTestTNP")
|
||||
App.closeDocument("PartDesignTestTNP")
|
||||
|
||||
Reference in New Issue
Block a user