Merge pull request #13773 from bgbsww/bgbsww-toponamingMissingAppMethods
Toponaming: Add toponaming missing methods in app
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1169,6 +1169,7 @@ protected:
|
||||
std::vector<ShadowSub> _ShadowSubList;
|
||||
std::vector<int> _mapped;
|
||||
PropertyLinkBase *parentProp;
|
||||
mutable std::string tmpShadow;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user