diff --git a/src/Mod/PartDesign/App/ShapeBinder.cpp b/src/Mod/PartDesign/App/ShapeBinder.cpp index 3fcfd10160..d96e0a4758 100644 --- a/src/Mod/PartDesign/App/ShapeBinder.cpp +++ b/src/Mod/PartDesign/App/ShapeBinder.cpp @@ -32,6 +32,7 @@ # include #endif +#include #include #include @@ -296,13 +297,17 @@ SubShapeBinder::SubShapeBinder() } void SubShapeBinder::setupObject() { - _Version.setValue(1); + _Version.setValue(2); checkPropertyStatus(); } -void SubShapeBinder::update() { +void SubShapeBinder::update(int options) { Part::TopoShape result; std::vector shapes; + std::vector shapeMats; + + bool forced = (Shape.getValue().IsNull() || (options & UpdateForced)) ? true : false; + bool init = (!forced && (options & UpdateForced)) ? true : false; std::string errMsg; auto parent = Context.getValue(); @@ -329,7 +334,7 @@ void SubShapeBinder::update() { Context.setValue(parent,parentSub.c_str()); } bool first = false; - std::map mats; + std::unordered_map mats; for(auto &l : Support.getSubListValues()) { auto obj = l.getValue(); if(!obj || !obj->getNameInDocument()) @@ -373,6 +378,9 @@ void SubShapeBinder::update() { } } } + if(init) + continue; + const auto &subvals = l.getSubValues(); std::set subs(subvals.begin(),subvals.end()); static std::string none(""); @@ -384,15 +392,8 @@ void SubShapeBinder::update() { try { auto shape = Part::Feature::getTopoShape(obj,sub.c_str(),true); if(!shape.isNull()) { - shape = shape.makETransform(res.first->second); - // if(shape.Hasher - // && shape.getElementMapSize() - // && shape.Hasher != getDocument()->getStringHasher()) - // { - // shape.reTagElementMap(getID(), - // getDocument()->getStringHasher(),TOPOP_SHAPEBINDER); - // } shapes.push_back(shape); + shapeMats.push_back(&res.first->second); } } catch(Base::Exception &e) { e.ReportException(); @@ -408,59 +409,130 @@ void SubShapeBinder::update() { } } } - if(errMsg.size()) - FC_THROWM(Base::RuntimeError, errMsg); - if(shapes.size()==_Cache.size()) { - bool hit = true; - for(size_t i=0;igetNameInDocument(); + if(obj->getDocument() != getDocument()) { + objName += "_"; + objName += obj->getDocument()->getName(); + } + return objName.c_str(); + }; + + if(!init) { + + if(errMsg.size()) { + if(!(options & UpdateInit)) + FC_THROWM(Base::RuntimeError, errMsg); + if(!Shape.getValue().IsNull()) + return; + } + + // If not forced, only rebuild when there is any change in + // transformation matrix + if(!forced) { + bool hit = true; + for(auto &v : mats) { + auto prop = Base::freecad_dynamic_cast( + getDynamicPropertyByName(cacheName(v.first))); + if(!prop || prop->getValue()!=v.second) { + hit = false; + break; + } + } + if(hit) + return; + } + + if(shapes.size()==1 && !Relative.getValue()) + shapes.back().setPlacement(Base::Placement()); + else { + for(size_t i=0;igetStringHasher()) + // { + // shape.reTagElementMap(getID(), + // getDocument()->getStringHasher(),TOPOP_SHAPEBINDER); + // } } } - if(hit) + + if(shapes.empty()) { + // Shape.resetElementMapVersion(); return; - } - _Cache = std::move(shapes); + } - if(_Cache.empty()) { - // Shape.resetElementMapVersion(); - return; + result.makECompound(shapes); + + bool fused = false; + if(Fuse.getValue()) { + // If the compound has solid, fuse them together, and ignore other type of + // shapes + std::vector solids; + Part::TopoShape solid; + for(auto &s : result.getSubTopoShapes(TopAbs_SOLID)) { + if(!solid.isNull()) + solid = s; + else + solids.push_back(s.getShape()); + } + if(solids.size()) { + solid.fuse(solids); + result = solid.makERefine(); + fused = true; + } else if (!solid.isNull()) { + // wrap the single solid in compound to keep its placement + result.makECompound({solid}); + fused = true; + } + } + + if(!fused && MakeFace.getValue() + && !result.hasSubShape(TopAbs_FACE) + && result.hasSubShape(TopAbs_EDGE)) + { + result = result.makEWires(); + try { + result = result.makEFace(0); + }catch(...){} + } + + result.setPlacement(Placement.getValue()); + Shape.setValue(result); } - result.makECompound(_Cache); + // collect transformation matrix cache entires + std::unordered_set caches; + for(const auto &name : getDynamicPropertyNames()) { + if(boost::starts_with(name,"Cache_")) + caches.emplace(name); + } - bool fused = false; - if(Fuse.getValue()) { - // If the compound has solid, fuse them together, and ignore other type of - // shapes - std::vector solids; - for(auto &s : _Cache) { - if(s.shapeType(true) == TopAbs_SOLID) - solids.push_back(s.getShape()); + // update transformation matrix cache + for(auto &v : mats) { + const char *name = cacheName(v.first); + auto prop = getDynamicPropertyByName(name); + if(!prop || !prop->isDerivedFrom(App::PropertyMatrix::getClassTypeId())) { + if(prop) + removeDynamicProperty(name); + prop = addDynamicProperty("App::PropertyMatrix",name,"Cache",0,0,false,true); } - if(solids.size()) { - result.fuse(solids); - result = result.makERefine(); - fused = true; - } - } - - if(!fused && MakeFace.getValue() && - !result.hasSubShape(TopAbs_FACE) && - result.hasSubShape(TopAbs_EDGE)) - { - result = result.makEWires(); + caches.erase(name); + static_cast(prop)->setValue(v.second); + } + + // remove any non-used cache entries. + for(const auto &name : caches) { try { - result = result.makEFace(0); - }catch(...){} + removeDynamicProperty(name.c_str()); + } catch(...) {} } - - result.setPlacement(Placement.getValue()); - Shape.setValue(result); } void SubShapeBinder::slotRecomputedObject(const App::DocumentObject& Obj) { @@ -473,13 +545,13 @@ void SubShapeBinder::slotRecomputedObject(const App::DocumentObject& Obj) { App::DocumentObjectExecReturn* SubShapeBinder::execute(void) { if(BindMode.getValue()==0) - update(); + update(UpdateForced); return inherited::execute(); } void SubShapeBinder::onDocumentRestored() { - if(Shape.testStatus(App::Property::Transient)) - update(); + if(_Version.getValue()<2) + update(UpdateInit); inherited::onDocumentRestored(); } diff --git a/src/Mod/PartDesign/App/ShapeBinder.h b/src/Mod/PartDesign/App/ShapeBinder.h index e02b83acd1..5d8aca2b32 100644 --- a/src/Mod/PartDesign/App/ShapeBinder.h +++ b/src/Mod/PartDesign/App/ShapeBinder.h @@ -93,7 +93,11 @@ public: App::PropertyXLink Context; App::PropertyInteger _Version; - void update(); + enum UpdateOption { + UpdateInit = 1, + UpdateForced = 2, + }; + void update(int options=0); virtual int canLoadPartial() const override { return PartialLoad.getValue()?1:0; @@ -118,8 +122,6 @@ protected: typedef boost::signals2::scoped_connection Connection; Connection connRecomputedObj; App::Document *contextDoc=0; - - std::vector _Cache; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp index 2835e26754..e630e070e1 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp @@ -317,7 +317,7 @@ void ViewProviderSubShapeBinder::updatePlacement(bool transaction) { if(!transaction) { if(relative) self->Context.setValue(parent,parentSub.c_str()); - self->update(); + self->update(PartDesign::SubShapeBinder::UpdateForced); return; } @@ -325,7 +325,7 @@ void ViewProviderSubShapeBinder::updatePlacement(bool transaction) { try{ if(relative) self->Context.setValue(parent,parentSub.c_str()); - self->update(); + self->update(PartDesign::SubShapeBinder::UpdateForced); App::GetApplication().closeActiveTransaction(); return; }catch(Base::Exception &e) {