Merge pull request #13773 from bgbsww/bgbsww-toponamingMissingAppMethods

Toponaming: Add toponaming missing methods in app
This commit is contained in:
Chris Hennes
2024-05-03 13:44:09 -05:00
committed by GitHub
7 changed files with 602 additions and 197 deletions

View File

@@ -637,6 +637,11 @@ unsigned int ComplexGeoData::getMemSize() const
return 0;
}
std::vector<IndexedName> ComplexGeoData::getHigherElements(const char *, bool) const
{
return {};
}
void ComplexGeoData::setMappedChildElements(const std::vector<Data::ElementMap::MappedChildElements> & children)
{
// DO NOT reset element map if there is one. Because we allow mixing child

View File

@@ -321,6 +321,9 @@ public:
/// Get the current element map size
size_t getElementMapSize(bool flush=true) const;
/// Return the higher level element names of the given element
virtual std::vector<IndexedName> getHigherElements(const char *name, bool silent=false) const;
/// Return the current element map version
virtual std::string getElementMapVersion() const;

View File

@@ -26,6 +26,7 @@
#include <App/GeoFeaturePy.h>
#include "ComplexGeoData.h"
#include "Document.h"
#include "GeoFeature.h"
#include "GeoFeatureGroupExtension.h"
#include "ElementNamingUtils.h"
@@ -146,12 +147,22 @@ DocumentObject *GeoFeature::resolveElement(DocumentObject *obj, const char *subn
subname = "";
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);
#else
auto sobj = obj->getSubObject(subname);
if(!sobj)
return nullptr;
obj = sobj->getLinkedObject(true);
auto geo = dynamic_cast<GeoFeature*>(obj);
if(geoFeature)
#endif
if(geoFeature)
*geoFeature = geo;
if(!obj || (filter && obj!=filter))
return nullptr;
@@ -189,3 +200,45 @@ void GeoFeature::setMaterialAppearance(const App::Material& material)
{
Q_UNUSED(material)
}
#ifdef FC_USE_TNP_FIX
bool GeoFeature::hasMissingElement(const char *subname) {
return Data::hasMissingElement(subname);
if(!subname)
return false;
auto dot = strrchr(subname,'.');
if(!dot)
return subname[0]=='?';
return dot[1]=='?';
}
void GeoFeature::updateElementReference() {
auto prop = getPropertyOfGeometry();
if(!prop) return;
auto geo = prop->getComplexData();
if(!geo) return;
bool reset = false;
PropertyLinkBase::updateElementReferences(this,reset);
}
void GeoFeature::onChanged(const Property *prop) {
if(prop==getPropertyOfGeometry()) {
if(getDocument() && !getDocument()->testStatus(Document::Restoring)
&& !getDocument()->isPerformingTransaction())
{
updateElementReference();
}
}
DocumentObject::onChanged(prop);
}
std::vector<Data::IndexedName>
GeoFeature::getHigherElements(const char *element, bool silent) const
{
auto prop = getPropertyOfGeometry();
if (!prop)
return {};
return prop->getComplexData()->getHigherElements(element, silent);
}
#endif

View File

@@ -140,7 +140,21 @@ public:
* appearance from an App::Material object.
*/
virtual void setMaterialAppearance(const App::Material& material);
#ifdef FC_USE_TNP_FIX
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;}
/// Return the higher level element names of the given element
virtual std::vector<Data::IndexedName> getHigherElements(const char *name, bool silent=false) const;
protected:
void onChanged(const Property* prop) override;
// void onDocumentRestored() override;
void updateElementReference();
#endif
protected:
std::pair<std::string, std::string> _getElementName(const char* name,
const Data::MappedElement& mapped) const;

View File

@@ -38,6 +38,8 @@
#include "DocumentObject.h"
#include "DocumentObjectPy.h"
#include "ObjectIdentifier.h"
#include "ElementNamingUtils.h"
#include "GeoFeature.h"
FC_LOG_LEVEL_INIT("PropertyLinks",true,true)
@@ -55,6 +57,9 @@ namespace sp = std::placeholders;
TYPESYSTEM_SOURCE_ABSTRACT(App::PropertyLinkBase , App::Property)
static std::unordered_map<std::string, std::set<PropertyLinkBase*> > _LabelMap;
static std::unordered_map<App::DocumentObject *, std::unordered_set<PropertyLinkBase*> > _ElementRefMap;
PropertyLinkBase::PropertyLinkBase() = default;
PropertyLinkBase::~PropertyLinkBase() {
@@ -97,6 +102,18 @@ bool PropertyLinkBase::isSame(const Property &other) const
}
void PropertyLinkBase::unregisterElementReference() {
#ifdef FC_USE_TNP_FIX
for (auto obj : _ElementRefs) {
auto it = _ElementRefMap.find(obj);
if (it != _ElementRefMap.end()) {
it->second.erase(this);
if (it->second.empty()) {
_ElementRefMap.erase(it);
}
}
}
_ElementRefs.clear();
#endif
}
void PropertyLinkBase::unregisterLabelReferences()
@@ -202,15 +219,71 @@ static std::string propertyName(const Property *prop) {
}
void PropertyLinkBase::updateElementReferences(DocumentObject *feature, bool reverse) {
#ifdef FC_USE_TNP_FIX
if (!feature || !feature->getNameInDocument()) {
return;
}
auto it = _ElementRefMap.find(feature);
if (it == _ElementRefMap.end()) {
return;
}
std::vector<PropertyLinkBase*> props;
props.reserve(it->second.size());
props.insert(props.end(), it->second.begin(), it->second.end());
for (auto prop : props) {
if (prop->getContainer()) {
try {
prop->updateElementReference(feature, reverse, true);
}
catch (Base::Exception& e) {
e.ReportException();
FC_ERR("Failed to update element reference of " << propertyName(prop));
}
catch (std::exception& e) {
FC_ERR("Failed to update element reference of " << propertyName(prop) << ": "
<< e.what());
}
}
}
#else
(void)feature;
(void)reverse;
#endif
}
void PropertyLinkBase::_registerElementReference(App::DocumentObject *obj, std::string &sub, ShadowSub &shadow)
{
#ifdef FC_USE_TNP_FIX
if (!obj || !obj->getNameInDocument() || sub.empty()) {
return;
}
if (shadow.first.empty()) {
_updateElementReference(0, obj, sub, shadow, false);
return;
}
GeoFeature* geo = nullptr;
const char* element = nullptr;
std::pair<std::string, std::string> elementName;
GeoFeature::resolveElement(obj,
sub.c_str(),
elementName,
true,
GeoFeature::ElementNameType::Export,
0,
&element,
&geo);
if (!geo || !element || !element[0]) {
return;
}
if (_ElementRefs.insert(geo).second) {
_ElementRefMap[geo].insert(this);
}
#else
(void)obj;
(void)sub;
(void)shadow;
#endif
}
class StringGuard {
@@ -275,12 +348,157 @@ bool PropertyLinkBase::_updateElementReference(DocumentObject *feature,
App::DocumentObject *obj, std::string &sub, ShadowSub &shadow,
bool reverse, bool notify)
{
#ifdef FC_USE_TNP_FIX
if (!obj || !obj->getNameInDocument()) {
return false;
}
ShadowSub elementName;
const char* subname;
if (shadow.first.size()) {
subname = shadow.first.c_str();
}
else if (shadow.second.size()) {
subname = shadow.second.c_str();
}
else {
subname = sub.c_str();
}
GeoFeature* geo = nullptr;
const char* element = nullptr;
auto ret = GeoFeature::resolveElement(obj,
subname,
elementName,
true,
GeoFeature::ElementNameType::Export,
feature,
&element,
&geo);
if (!ret || !geo || !element || !element[0]) {
if (elementName.second.size()) {
shadow.second.swap(elementName.second);
}
return false;
}
if (_ElementRefs.insert(geo).second) {
_ElementRefMap[geo].insert(this);
}
if (!reverse) {
if (elementName.first.empty()) {
shadow.second.swap(elementName.second);
return false;
}
if (shadow == elementName) {
return false;
}
}
bool missing = Data::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.
if (names.size()) {
missing = false;
std::string newsub(subname, strlen(subname) - strlen(element));
newsub += names.front();
GeoFeature::resolveElement(obj,
newsub.c_str(),
elementName,
true,
GeoFeature::ElementNameType::Export,
feature);
const auto& oldName = shadow.first.size() ? shadow.first : shadow.second;
const auto& newName =
elementName.first.size() ? elementName.first : elementName.second;
if (oldName != newName) {
FC_WARN(propertyName(this)
<< " auto change element reference " << ret->getFullName() << " "
<< oldName << " -> " << newName);
}
}
}
}
if (notify) {
aboutToSetValue();
}
auto updateSub = [&](const std::string& newSub) {
if (sub != newSub) {
// signalUpdateElementReference(sub, newSub);
sub = newSub;
}
};
if (missing) {
FC_WARN(propertyName(this)
<< " missing element reference " << ret->getFullName() << " "
<< (elementName.first.size() ? elementName.first : elementName.second));
shadow.second.swap(elementName.second);
}
else {
FC_TRACE(propertyName(this) << " element reference shadow update " << ret->getFullName()
<< " " << shadow.first << " -> " << elementName.first);
shadow.swap(elementName);
if (shadow.first.size() && Data::hasMappedElementName(sub.c_str())) {
updateSub(shadow.first);
}
}
if (reverse) {
if (shadow.first.size() && Data::hasMappedElementName(sub.c_str())) {
updateSub(shadow.first);
}
else {
updateSub(shadow.second);
}
return true;
}
if (missing) {
if (sub != shadow.first) {
updateSub(shadow.second);
}
return true;
}
auto pos2 = shadow.first.rfind('.');
if (pos2 == std::string::npos) {
return true;
}
++pos2;
auto pos = sub.rfind('.');
if (pos == std::string::npos) {
pos = 0;
}
else {
++pos;
}
if (pos == pos2) {
if (sub.compare(pos, sub.size() - pos, &shadow.first[pos2]) != 0) {
FC_LOG("element reference update " << sub << " -> " << shadow.first);
std::string newSub(sub);
newSub.replace(pos, sub.size() - pos, &shadow.first[pos2]);
updateSub(newSub);
}
}
else if (sub != shadow.second) {
FC_LOG("element reference update " << sub << " -> " << shadow.second);
updateSub(shadow.second);
}
return true;
#else
(void)feature;
(void)obj;
(void)reverse;
(void)notify;
shadow.second = sub;
return false;
#endif
}
std::pair<DocumentObject*, std::string>
@@ -290,41 +508,62 @@ PropertyLinkBase::tryReplaceLink(const PropertyContainer *owner, DocumentObject
std::pair<DocumentObject*, std::string> res;
res.first = 0;
if(oldObj == obj) {
if(owner == parent) {
if (oldObj == obj) {
if (owner == parent) {
res.first = newObj;
if(subname) res.second = subname;
if (subname) {
res.second = subname;
}
return res;
}
return res;
#ifdef FC_USE_TNP_FIX
}
if(!subname || !subname[0])
else if (newObj == obj) {
// This means the new object is already sub-object of this parent
// (consider a case of swapping the tool and base object of the Cut
// feature). We'll swap the old and new object.
return tryReplaceLink(owner, obj, parent, newObj, oldObj, subname);
#endif
}
if (!subname || !subname[0]) {
return res;
}
App::DocumentObject *prev = obj;
App::DocumentObject* prev = obj;
std::size_t prevPos = 0;
std::string sub = subname;
for(auto pos=sub.find('.');pos!=std::string::npos;pos=sub.find('.',pos)) {
for (auto pos = sub.find('.'); pos != std::string::npos; pos = sub.find('.', pos)) {
++pos;
char c = sub[pos];
sub[pos] = 0;
auto sobj = obj->getSubObject(sub.c_str());
sub[pos] = c;
if(!sobj)
if (!sobj) {
break;
if(sobj == oldObj) {
if(prev == parent) {
if(sub[prevPos] == '$')
sub.replace(prevPos+1,pos-1-prevPos,newObj->Label.getValue());
else
sub.replace(prevPos,pos-1-prevPos,newObj->getNameInDocument());
}
if (sobj == oldObj) {
if (prev == parent) {
if (sub[prevPos] == '$') {
sub.replace(prevPos + 1, pos - 1 - prevPos, newObj->Label.getValue());
}
else {
sub.replace(prevPos, pos - 1 - prevPos, newObj->getNameInDocument());
}
res.first = obj;
res.second = std::move(sub);
return res;
}
break;
}else if(prev == parent)
#ifdef FC_USE_TNP_FIX
}
else if (sobj == newObj) {
return tryReplaceLink(owner, obj, parent, newObj, oldObj, subname);
#endif
}
else if (prev == parent) {
break;
}
prev = sobj;
prevPos = pos;
}
@@ -381,7 +620,6 @@ TYPESYSTEM_SOURCE(App::PropertyLinkHidden , App::PropertyLink)
PropertyLink::PropertyLink() = default;
PropertyLink::~PropertyLink()
{
resetLink();
@@ -910,18 +1148,19 @@ void PropertyLinkSub::setValue(App::DocumentObject * lValue,
std::vector<std::string> &&subs, std::vector<ShadowSub> &&shadows)
{
auto parent = Base::freecad_dynamic_cast<App::DocumentObject>(getContainer());
if(lValue) {
if(!lValue->isAttachedToDocument())
if (lValue) {
if (!lValue->isAttachedToDocument())
throw Base::ValueError("PropertyLinkSub: invalid document object");
if(!testFlag(LinkAllowExternal) && parent && parent->getDocument()!=lValue->getDocument())
if (!testFlag(LinkAllowExternal) && parent
&& parent->getDocument() != lValue->getDocument())
throw Base::ValueError("PropertyLinkSub does not support external object");
}
aboutToSetValue();
#ifndef USE_OLD_DAG
if(parent) {
if (parent) {
// before accessing internals make sure the object is not about to be destroyed
// otherwise the backlink contains dangling pointers
if (!parent->testStatus(ObjectStatus::Destroy) && _pcScope!=LinkScope::Hidden) {
if (!parent->testStatus(ObjectStatus::Destroy) && _pcScope != LinkScope::Hidden) {
if (_pcLinkSub)
_pcLinkSub->_removeBackLink(parent);
if (lValue)
@@ -929,11 +1168,12 @@ void PropertyLinkSub::setValue(App::DocumentObject * lValue,
}
}
#endif
_pcLinkSub=lValue;
_cSubList=std::move(subs);
if(shadows.size()==_cSubList.size())
_pcLinkSub = lValue;
_cSubList = std::move(subs);
if (shadows.size() == _cSubList.size()) {
_ShadowSubList = std::move(shadows);
else
onContainerRestored(); // re-register element references
} else
updateElementReference(nullptr);
checkLabelReferences(_cSubList);
hasSetValue();
@@ -950,13 +1190,26 @@ const std::vector<std::string>& PropertyLinkSub::getSubValues() const
}
static inline const std::string &getSubNameWithStyle(const std::string &subName,
const PropertyLinkBase::ShadowSub &shadow, bool newStyle)
const PropertyLinkBase::ShadowSub &shadow, bool newStyle, std::string &tmp)
{
if(!newStyle) {
if(!shadow.second.empty())
return shadow.second;
}else if(!shadow.first.empty())
}else if(!shadow.first.empty()) {
#ifdef FC_USE_TNP_FIX
if (Data::hasMissingElement(shadow.second.c_str())) {
auto pos = shadow.first.rfind('.');
if (pos != std::string::npos) {
tmp = shadow.first.substr(0, pos+1);
tmp += shadow.second;
return tmp;
}
}
#else
(void) tmp;
#endif
return shadow.first;
}
return subName;
}
@@ -964,13 +1217,27 @@ std::vector<std::string> PropertyLinkSub::getSubValues(bool newStyle) const {
assert(_cSubList.size() == _ShadowSubList.size());
std::vector<std::string> ret;
ret.reserve(_cSubList.size());
std::string tmp;
for(size_t i=0;i<_ShadowSubList.size();++i)
ret.push_back(getSubNameWithStyle(_cSubList[i],_ShadowSubList[i],newStyle));
ret.push_back(getSubNameWithStyle(_cSubList[i],_ShadowSubList[i],newStyle,tmp));
return ret;
}
std::vector<std::string> PropertyLinkSub::getSubValuesStartsWith(const char* starter, bool newStyle) const
{
#ifdef FC_USE_TNP_FIX
assert(_cSubList.size() == _ShadowSubList.size());
std::vector<std::string> ret;
std::string tmp;
for(size_t i=0;i<_ShadowSubList.size();++i) {
const auto &sub = getSubNameWithStyle(_cSubList[i],_ShadowSubList[i],newStyle,tmp);
auto element = Data::findElementName(sub.c_str());
if(element && boost::starts_with(element,starter))
ret.emplace_back(element);
}
return ret;
#else
(void)newStyle;
std::vector<std::string> temp;
@@ -980,6 +1247,7 @@ std::vector<std::string> PropertyLinkSub::getSubValuesStartsWith(const char* sta
}
}
return temp;
#endif
}
App::DocumentObject * PropertyLinkSub::getValue(Base::Type t) const
@@ -993,8 +1261,14 @@ PyObject *PropertyLinkSub::getPyObject()
Py::List list(static_cast<int>(_cSubList.size()));
if (_pcLinkSub) {
tup[0] = Py::asObject(_pcLinkSub->getPyObject());
#ifdef FC_USE_TNP_FIX
int i = 0;
for (auto &sub : getSubValues(true))
list[i++] = Py::String(sub);
#else
for(unsigned int i = 0;i<_cSubList.size(); i++)
list[i] = Py::String(_cSubList[i]);
#endif
tup[1] = list;
return Py::new_reference_to(tup);
}
@@ -1460,6 +1734,9 @@ Property *PropertyLinkSub::Copy() const
PropertyLinkSub *p= new PropertyLinkSub();
p->_pcLinkSub = _pcLinkSub;
p->_cSubList = _cSubList;
#ifdef FC_USE_TNP_FIX
p->_ShadowSubList = _ShadowSubList;
#endif
return p;
}
@@ -1468,7 +1745,12 @@ void PropertyLinkSub::Paste(const Property &from)
if(!from.isDerivedFrom(PropertyLinkSub::getClassTypeId()))
throw Base::TypeError("Incompatible property to paste to");
auto &link = static_cast<const PropertyLinkSub&>(from);
#ifdef FC_USE_TNP_FIX
setValue(link._pcLinkSub, link._cSubList,
std::vector<ShadowSub>(link._ShadowSubList));
#else
setValue(link._pcLinkSub, link._cSubList);
#endif
}
void PropertyLinkSub::getLinks(std::vector<App::DocumentObject *> &objs,
@@ -1727,9 +2009,10 @@ void PropertyLinkSubList::setValues(std::vector<DocumentObject*>&& lValue,
aboutToSetValue();
_lValueList = std::move(lValue);
_lSubList = std::move(lSubNames);
if(ShadowSubList.size()==_lSubList.size())
if(ShadowSubList.size()==_lSubList.size()) {
_ShadowSubList = std::move(ShadowSubList);
else
onContainerRestored(); // re-register element references
} else
updateElementReference(nullptr);
checkLabelReferences(_lSubList);
hasSetValue();
@@ -1914,14 +2197,26 @@ void PropertyLinkSubList::setSubListValues(const std::vector<PropertyLinkSubList
{
std::vector<DocumentObject*> links;
std::vector<std::string> subs;
#ifdef FC_USE_TNP_FIX
for (std::vector<PropertyLinkSubList::SubSet>::const_iterator it = values.begin(); it != values.end(); ++it) {
if (it->second.empty()) {
links.push_back(it->first);
subs.emplace_back();
continue;
}
for (std::vector<std::string>::const_iterator jt = it->second.begin(); jt != it->second.end(); ++jt) {
links.push_back(it->first);
subs.push_back(*jt);
}
}
#else
for (const auto & value : values) {
for (const auto& jt : value.second) {
links.push_back(value.first);
subs.push_back(jt);
}
}
#endif
setValues(links, subs);
}
@@ -2386,6 +2681,9 @@ Property *PropertyLinkSubList::Copy() const
PropertyLinkSubList *p = new PropertyLinkSubList();
p->_lValueList = _lValueList;
p->_lSubList = _lSubList;
#ifdef FC_USE_TNP_FIX
p->_ShadowSubList = _ShadowSubList;
#endif
return p;
}
@@ -2394,7 +2692,12 @@ void PropertyLinkSubList::Paste(const Property &from)
if(!from.isDerivedFrom(PropertyLinkSubList::getClassTypeId()))
throw Base::TypeError("Incompatible property to paste to");
auto &link = static_cast<const PropertyLinkSubList&>(from);
#ifdef FC_USE_TNP_FIX
setValues(link._lValueList, link._lSubList,
std::vector<ShadowSub>(link._ShadowSubList));
#else
setValues(link._lValueList, link._lSubList);
#endif
}
unsigned int PropertyLinkSubList::getMemSize () const
@@ -2409,8 +2712,9 @@ std::vector<std::string> PropertyLinkSubList::getSubValues(bool newStyle) const
assert(_lSubList.size() == _ShadowSubList.size());
std::vector<std::string> ret;
ret.reserve(_ShadowSubList.size());
std::string tmp;
for(size_t i=0;i<_ShadowSubList.size();++i)
ret.push_back(getSubNameWithStyle(_lSubList[i],_ShadowSubList[i],newStyle));
ret.push_back(getSubNameWithStyle(_lSubList[i],_ShadowSubList[i],newStyle,tmp));
return ret;
}
@@ -2965,9 +3269,12 @@ void PropertyXLink::setSubValues(std::vector<std::string> &&subs,
{
_SubList = std::move(subs);
_ShadowSubList.clear();
if(shadows.size() == _SubList.size())
if(shadows.size() == _SubList.size()) {
_ShadowSubList = std::move(shadows);
else
#ifdef FC_USE_TNP_FIX
onContainerRestored(); // re-register element references
#endif
} else
updateElementReference(nullptr);
checkLabelReferences(_SubList);
}
@@ -3468,8 +3775,12 @@ void PropertyXLink::copyTo(PropertyXLink &other,
}
if(subs)
other._SubList = std::move(*subs);
else
else {
other._SubList = _SubList;
#ifdef FC_USE_TNP_FIX
other._ShadowSubList = _ShadowSubList;
#endif
}
other._Flags = _Flags;
}
@@ -3497,10 +3808,19 @@ void PropertyXLink::Paste(const Property &from)
FC_WARN("Object '" << other.docName << '#' << other.objectName << "' not found");
return;
}
#ifdef FC_USE_TNP_FIX
setValue(obj,std::vector<std::string>(other._SubList),
std::vector<ShadowSub>(other._ShadowSubList));
} else
setValue(std::string(other.filePath),std::string(other.objectName),
std::vector<std::string>(other._SubList),
std::vector<ShadowSub>(other._ShadowSubList));
#else
setValue(obj,std::vector<std::string>(other._SubList));
} else
setValue(std::string(other.filePath),std::string(other.objectName),
std::vector<std::string>(other._SubList));
#endif
setFlag(LinkAllowPartial,other.testFlag(LinkAllowPartial));
}
@@ -3652,7 +3972,7 @@ void PropertyXLink::setPyObject(PyObject *value) {
const char *PropertyXLink::getSubName(bool newStyle) const {
if(_SubList.empty() || _ShadowSubList.empty())
return "";
return getSubNameWithStyle(_SubList[0],_ShadowSubList[0],newStyle).c_str();
return getSubNameWithStyle(_SubList[0],_ShadowSubList[0],newStyle,tmpShadow).c_str();
}
void PropertyXLink::getLinks(std::vector<App::DocumentObject *> &objs,
@@ -3683,8 +4003,9 @@ std::vector<std::string> PropertyXLink::getSubValues(bool newStyle) const {
assert(_SubList.size() == _ShadowSubList.size());
std::vector<std::string> ret;
ret.reserve(_SubList.size());
std::string tmp;
for(size_t i=0;i<_ShadowSubList.size();++i)
ret.push_back(getSubNameWithStyle(_SubList[i],_ShadowSubList[i],newStyle));
ret.push_back(getSubNameWithStyle(_SubList[i],_ShadowSubList[i],newStyle,tmp));
return ret;
}

View File

@@ -1169,6 +1169,7 @@ protected:
std::vector<ShadowSub> _ShadowSubList;
std::vector<int> _mapped;
PropertyLinkBase *parentProp;
mutable std::string tmpShadow;
};

View File

@@ -782,165 +782,173 @@ class TestTopologicalNamingProblem(unittest.TestCase):
self.assertEqual(plane.Shape.ElementMapSize, 0)
self.assertEqual(pad.Shape.ElementMapSize, 26)
# def testChangeSketch(self):
# # Arrange
# self.Body = self.Doc.addObject('PartDesign::Body', 'Body')
# # Make first offset cube Pad
# self.PadSketch = self.Doc.addObject('Sketcher::SketchObject', 'Sketch')
# self.Body.addObject(self.PadSketch)
# TestSketcherApp.CreateRectangleSketch(self.PadSketch, (0, 0), (31.37, 25.2))
# self.Doc.recompute()
# self.Pad = self.Doc.addObject("PartDesign::Pad", "Pad")
# self.Body.addObject(self.Pad)
# self.Pad.Profile = self.PadSketch
# self.Pad.Length = 10
# self.Doc.recompute()
#
# self.Sketch001 = self.Body.newObject('Sketcher::SketchObject','Sketch001')
# self.Sketch001.AttachmentSupport = (self.Doc.getObject('Pad'),['Face6',])
# self.Sketch001.MapMode = 'FlatFace'
# App.ActiveDocument.recompute()
#
# self.Sketch001.addExternal("Pad","Edge10")
# self.Sketch001.addExternal("Pad","Edge7")
#
# geoList = []
# geoList.append(Part.Circle(App.Vector(15.093666, 13.036922, 0.000000),
# App.Vector(0.000000, 0.000000, 1.000000), 5.000000))
# self.Sketch001.addGeometry(geoList,False)
# del geoList
# self.Sketch001.addConstraint(Sketcher.Constraint('Radius',0,5.000000))
# self.Sketch001.addConstraint(Sketcher.Constraint('Symmetric',-3,2,-4,1,0,3))
# App.ActiveDocument.recompute()
# self.Doc.recompute()
#
# self.Pad001 = self.Body.newObject('PartDesign::Pad','Pad001')
# self.Pad001.Profile = self.Doc.getObject('Sketch001')
# self.Pad001.Length = 10
# App.ActiveDocument.recompute()
# self.Pad001.ReferenceAxis = (self.Doc.getObject('Sketch001'),['N_Axis'])
# self.Sketch001.Visibility = False
# App.ActiveDocument.recompute()
#
# self.Pad001.Length = 10.000000
# self.Pad001.TaperAngle = 0.000000
# self.Pad001.UseCustomVector = 0
# self.Pad001.Direction = (0, 0, 1)
# self.Pad001.ReferenceAxis = (self.Doc.getObject('Sketch001'), ['N_Axis'])
# self.Pad001.AlongSketchNormal = 1
# self.Pad001.Type = 0
# self.Pad001.UpToFace = None
# self.Pad001.Reversed = 0
# self.Pad001.Midplane = 0
# self.Pad001.Offset = 0
# self.Doc.recompute()
# self.Doc.getObject('Pad').Visibility = False
#
# self.Doc.getObject('Sketch001').Visibility = False
#
# # Modify the original sketch to generate TNP issue
# geoList = []
# geoList.append(Part.LineSegment(App.Vector(2.510468, 22.837425, 0.000000),
# App.Vector(2.510468, 19.933617, 0.000000)))
# geoList.append(Part.LineSegment(App.Vector(2.510468, 19.933617, 0.000000),
# App.Vector(4.869811, 19.933617, 0.000000)))
# geoList.append(Part.LineSegment(App.Vector(4.869811, 19.933617, 0.000000),
# App.Vector(4.869811, 22.837425, 0.000000)))
# geoList.append(Part.LineSegment(App.Vector(4.869811, 22.837425, 0.000000),
# App.Vector(2.510468, 22.837425, 0.000000)))
# self.PadSketch.addGeometry(geoList,False)
# del geoList
#
# constraintList = []
# constraintList.append(Sketcher.Constraint('Coincident', 4, 2, 5, 1))
# constraintList.append(Sketcher.Constraint('Coincident', 5, 2, 6, 1))
# constraintList.append(Sketcher.Constraint('Coincident', 6, 2, 7, 1))
# constraintList.append(Sketcher.Constraint('Coincident', 7, 2, 4, 1))
# constraintList.append(Sketcher.Constraint('Vertical', 4))
# constraintList.append(Sketcher.Constraint('Vertical', 6))
# constraintList.append(Sketcher.Constraint('Horizontal', 5))
# constraintList.append(Sketcher.Constraint('Horizontal', 7))
# self.PadSketch.addConstraint(constraintList)
# del constraintList
# self.Doc.recompute()
# # Assert
# if self.Body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023.
# return
# self.assertEqual(self.Body.Shape.BoundBox.XMin,0)
# self.assertEqual(self.Body.Shape.BoundBox.YMin,0)
# self.assertEqual(self.Body.Shape.BoundBox.ZMin,0)
# self.assertEqual(self.Body.Shape.BoundBox.XMax,31.37)
# self.assertEqual(self.Body.Shape.BoundBox.YMax,25.2)
# self.assertEqual(self.Body.Shape.BoundBox.ZMax,20)
#
# def testApplyFillet(self):
# # Arrange
# self.Body = self.Doc.addObject('PartDesign::Body', 'Body')
# # Make first offset cube Pad
# self.PadSketch = self.Doc.addObject('Sketcher::SketchObject', 'Sketch')
# self.Body.addObject(self.PadSketch)
# TestSketcherApp.CreateRectangleSketch(self.PadSketch, (0, 0), (31.37, 25.2))
# self.Doc.recompute()
# self.Pad = self.Doc.addObject("PartDesign::Pad", "Pad")
# self.Body.addObject(self.Pad)
# self.Pad.Profile = self.PadSketch
# self.Pad.Length = 10
# self.Doc.recompute()
#
# self.Sketch001 = self.Body.newObject('Sketcher::SketchObject','Sketch001')
# self.Sketch001.AttachmentSupport = (self.Doc.getObject('Pad'),['Face6',])
# self.Sketch001.MapMode = 'FlatFace'
# App.ActiveDocument.recompute()
#
# self.Sketch001.addExternal("Pad","Edge10")
# self.Sketch001.addExternal("Pad","Edge7")
#
# geoList = []
# geoList.append(Part.Circle(App.Vector(15.093666, 13.036922, 0.000000),
# App.Vector(0.000000, 0.000000, 1.000000), 5.000000))
# self.Sketch001.addGeometry(geoList,False)
# del geoList
# self.Sketch001.addConstraint(Sketcher.Constraint('Radius',0,5.000000))
# self.Sketch001.addConstraint(Sketcher.Constraint('Symmetric',-3,2,-4,1,0,3))
# App.ActiveDocument.recompute()
# self.Doc.recompute()
#
# self.Pad001 = self.Body.newObject('PartDesign::Pad','Pad001')
# self.Pad001.Profile = self.Doc.getObject('Sketch001')
# self.Pad001.Length = 10
# App.ActiveDocument.recompute()
# self.Pad001.ReferenceAxis = (self.Doc.getObject('Sketch001'),['N_Axis'])
# self.Sketch001.Visibility = False
# App.ActiveDocument.recompute()
#
# self.Pad001.Length = 10.000000
# self.Pad001.TaperAngle = 0.000000
# self.Pad001.UseCustomVector = 0
# self.Pad001.Direction = (0, 0, 1)
# self.Pad001.ReferenceAxis = (self.Doc.getObject('Sketch001'), ['N_Axis'])
# self.Pad001.AlongSketchNormal = 1
# self.Pad001.Type = 0
# self.Pad001.UpToFace = None
# self.Pad001.Reversed = 0
# self.Pad001.Midplane = 0
# self.Pad001.Offset = 0
# self.Doc.recompute()
# self.Doc.getObject('Pad').Visibility = False
#
# self.Doc.getObject('Sketch001').Visibility = False
# filleted = self.Pad001.Shape.makeFillet(1,self.Pad001.Shape.Edges[0:2])
# self.filleted = Part.show(filleted,"Filleted")
# # self.Body.addObject(self.filleted)
# self.Doc.recompute()
# # Assert
# if self.Body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023.
# return
# self.assertEqual(self.Body.Shape.BoundBox.XMin,0)
# self.assertEqual(self.Body.Shape.BoundBox.YMin,0)
# self.assertEqual(self.Body.Shape.BoundBox.ZMin,0)
# self.assertEqual(self.Body.Shape.BoundBox.XMax,31.37)
# self.assertEqual(self.Body.Shape.BoundBox.YMax,25.2)
# self.assertEqual(self.Body.Shape.BoundBox.ZMax,20)
def testChangeSketch(self):
# Arrange
self.Body = self.Doc.addObject('PartDesign::Body', 'Body')
# Make first offset cube Pad
self.PadSketch = self.Doc.addObject('Sketcher::SketchObject', 'Sketch')
self.Body.addObject(self.PadSketch)
TestSketcherApp.CreateRectangleSketch(self.PadSketch, (0, 0), (31.37, 25.2))
self.Doc.recompute()
self.Pad = self.Doc.addObject("PartDesign::Pad", "Pad")
self.Body.addObject(self.Pad)
self.Pad.Profile = self.PadSketch
self.Pad.Length = 10
self.Doc.recompute()
self.Sketch001 = self.Body.newObject('Sketcher::SketchObject','Sketch001')
self.Sketch001.AttachmentSupport = (self.Doc.getObject('Pad'),['Face6',])
self.Sketch001.MapMode = 'FlatFace'
App.ActiveDocument.recompute()
self.Sketch001.addExternal("Pad","Edge10")
self.Sketch001.addExternal("Pad","Edge7")
geoList = []
geoList.append(Part.Circle(App.Vector(15.093666, 13.036922, 0.000000),
App.Vector(0.000000, 0.000000, 1.000000), 5.000000))
self.Sketch001.addGeometry(geoList,False)
del geoList
self.Sketch001.addConstraint(Sketcher.Constraint('Radius',0,5.000000))
self.Sketch001.addConstraint(Sketcher.Constraint('Symmetric',-3,2,-4,1,0,3))
App.ActiveDocument.recompute()
self.Doc.recompute()
self.Pad001 = self.Body.newObject('PartDesign::Pad','Pad001')
self.Pad001.Profile = self.Doc.getObject('Sketch001')
self.Pad001.Length = 10
App.ActiveDocument.recompute()
self.Pad001.ReferenceAxis = (self.Doc.getObject('Sketch001'),['N_Axis'])
self.Sketch001.Visibility = False
App.ActiveDocument.recompute()
self.Pad001.Length = 10.000000
self.Pad001.TaperAngle = 0.000000
self.Pad001.UseCustomVector = 0
self.Pad001.Direction = (0, 0, 1)
self.Pad001.ReferenceAxis = (self.Doc.getObject('Sketch001'), ['N_Axis'])
self.Pad001.AlongSketchNormal = 1
self.Pad001.Type = 0
self.Pad001.UpToFace = None
self.Pad001.Reversed = 0
self.Pad001.Midplane = 0
self.Pad001.Offset = 0
self.Doc.recompute()
self.Doc.getObject('Pad').Visibility = False
self.Doc.getObject('Sketch001').Visibility = False
# Modify the original sketch to generate TNP issue
geoList = []
geoList.append(Part.LineSegment(App.Vector(2.510468, 22.837425, 0.000000),
App.Vector(2.510468, 19.933617, 0.000000)))
geoList.append(Part.LineSegment(App.Vector(2.510468, 19.933617, 0.000000),
App.Vector(4.869811, 19.933617, 0.000000)))
geoList.append(Part.LineSegment(App.Vector(4.869811, 19.933617, 0.000000),
App.Vector(4.869811, 22.837425, 0.000000)))
geoList.append(Part.LineSegment(App.Vector(4.869811, 22.837425, 0.000000),
App.Vector(2.510468, 22.837425, 0.000000)))
self.PadSketch.addGeometry(geoList,False)
del geoList
constraintList = []
constraintList.append(Sketcher.Constraint('Coincident', 4, 2, 5, 1))
constraintList.append(Sketcher.Constraint('Coincident', 5, 2, 6, 1))
constraintList.append(Sketcher.Constraint('Coincident', 6, 2, 7, 1))
constraintList.append(Sketcher.Constraint('Coincident', 7, 2, 4, 1))
constraintList.append(Sketcher.Constraint('Vertical', 4))
constraintList.append(Sketcher.Constraint('Vertical', 6))
constraintList.append(Sketcher.Constraint('Horizontal', 5))
constraintList.append(Sketcher.Constraint('Horizontal', 7))
self.PadSketch.addConstraint(constraintList)
del constraintList
self.Doc.recompute()
# Assert
if self.Body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023.
return
self.assertEqual(self.Body.Shape.BoundBox.XMin,0)
self.assertEqual(self.Body.Shape.BoundBox.YMin,0)
self.assertEqual(self.Body.Shape.BoundBox.ZMin,0)
self.assertEqual(self.Body.Shape.BoundBox.XMax,31.37)
self.assertEqual(self.Body.Shape.BoundBox.YMax,25.2)
self.assertEqual(self.Body.Shape.BoundBox.ZMax,20)
def testApplyFillet(self):
# Arrange
self.Body = self.Doc.addObject('PartDesign::Body', 'Body')
# Make first offset cube Pad
self.PadSketch = self.Doc.addObject('Sketcher::SketchObject', 'Sketch')
self.Body.addObject(self.PadSketch)
TestSketcherApp.CreateRectangleSketch(self.PadSketch, (0, 0), (31.37, 25.2))
self.Doc.recompute()
self.Pad = self.Doc.addObject("PartDesign::Pad", "Pad")
self.Body.addObject(self.Pad)
self.Pad.Profile = self.PadSketch
self.Pad.Length = 10
self.Doc.recompute()
self.Sketch001 = self.Body.newObject('Sketcher::SketchObject','Sketch001')
self.Sketch001.AttachmentSupport = (self.Doc.getObject('Pad'),['Face6',])
self.Sketch001.MapMode = 'FlatFace'
App.ActiveDocument.recompute()
self.Sketch001.addExternal("Pad","Edge10")
self.Sketch001.addExternal("Pad","Edge7")
geoList = []
geoList.append(Part.Circle(App.Vector(15.093666, 13.036922, 0.000000),
App.Vector(0.000000, 0.000000, 1.000000), 5.000000))
self.Sketch001.addGeometry(geoList,False)
del geoList
self.Sketch001.addConstraint(Sketcher.Constraint('Radius',0,5.000000))
self.Sketch001.addConstraint(Sketcher.Constraint('Symmetric',-3,2,-4,1,0,3))
App.ActiveDocument.recompute()
self.Doc.recompute()
self.Pad001 = self.Body.newObject('PartDesign::Pad','Pad001')
self.Pad001.Profile = self.Doc.getObject('Sketch001')
self.Pad001.Length = 10
App.ActiveDocument.recompute()
self.Pad001.ReferenceAxis = (self.Doc.getObject('Sketch001'),['N_Axis'])
self.Sketch001.Visibility = False
App.ActiveDocument.recompute()
self.Pad001.Length = 10.000000
self.Pad001.TaperAngle = 0.000000
self.Pad001.UseCustomVector = 0
self.Pad001.Direction = (0, 0, 1)
self.Pad001.ReferenceAxis = (self.Doc.getObject('Sketch001'), ['N_Axis'])
self.Pad001.AlongSketchNormal = 1
self.Pad001.Type = 0
self.Pad001.UpToFace = None
self.Pad001.Reversed = 0
self.Pad001.Midplane = 0
self.Pad001.Offset = 0
self.Doc.recompute()
self.Doc.getObject('Pad').Visibility = False
self.Doc.getObject('Sketch001').Visibility = False
area1 = self.Pad.Shape.Area
# Act
self.Doc.getObject('Sketch').fillet(2,3,App.Vector(6.673934,25.000000,0),App.Vector(0.000000,21.980343,0),4.740471,True,True,False)
self.Doc.recompute()
# filleted = self.Pad001.Shape.makeFillet(1,self.Pad001.Shape.Edges[0:2])
# self.filleted = Part.show(filleted,"Filleted")
# self.Body.addObject(self.filleted)
area2 = self.Pad.Shape.Area
print(area1,area2)
# Assert
if self.Body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023.
return
self.assertEqual(self.Body.Shape.BoundBox.XMin,0)
self.assertEqual(self.Body.Shape.BoundBox.YMin,0)
self.assertEqual(self.Body.Shape.BoundBox.ZMin,0)
self.assertEqual(self.Body.Shape.BoundBox.XMax,31.37)
self.assertEqual(self.Body.Shape.BoundBox.YMax,25.2)
self.assertEqual(self.Body.Shape.BoundBox.ZMax,20)
def create_t_sketch(self):
self.Doc.getObject('Body').newObject('Sketcher::SketchObject', 'Sketch')