Toposhape/Part: Transfer in FeatureFillet, FeatureChamfer and dependencies
This commit is contained in:
@@ -53,7 +53,7 @@ App::DocumentObjectExecReturn *Chamfer::execute()
|
||||
TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace;
|
||||
TopExp::MapShapesAndAncestors(baseShape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace);
|
||||
TopExp::MapShapes(baseShape, TopAbs_EDGE, mapOfEdges);
|
||||
|
||||
#ifndef FC_USE_TNP_FIX
|
||||
std::vector<FilletElement> values = Edges.getValues();
|
||||
for (const auto & value : values) {
|
||||
int id = value.edgeid;
|
||||
@@ -89,6 +89,36 @@ App::DocumentObjectExecReturn *Chamfer::execute()
|
||||
prop.touch();
|
||||
|
||||
return App::DocumentObject::StdReturn;
|
||||
#else
|
||||
const auto &vals = EdgeLinks.getSubValues();
|
||||
const auto &subs = EdgeLinks.getShadowSubs();
|
||||
if(subs.size()!=(size_t)Edges.getSize())
|
||||
return new App::DocumentObjectExecReturn("Edge link size mismatch");
|
||||
size_t i=0;
|
||||
for(const auto &info : Edges.getValues()) {
|
||||
auto &sub = subs[i];
|
||||
auto &ref = sub.first.size()?sub.first:vals[i];
|
||||
++i;
|
||||
TopoDS_Shape edge;
|
||||
try {
|
||||
edge = baseTopoShape.getSubShape(ref.c_str());
|
||||
}catch(...){}
|
||||
if(edge.IsNull())
|
||||
return new App::DocumentObjectExecReturn("Invalid edge link");
|
||||
double radius1 = info.radius1;
|
||||
double radius2 = info.radius2;
|
||||
const TopoDS_Face& face = TopoDS::Face(mapEdgeFace.FindFromKey(edge).First());
|
||||
mkChamfer.Add(radius1, radius2, TopoDS::Edge(edge), face);
|
||||
}
|
||||
|
||||
TopoDS_Shape shape = mkChamfer.Shape();
|
||||
if (shape.IsNull())
|
||||
return new App::DocumentObjectExecReturn("Resulting shape is null");
|
||||
|
||||
TopoShape res(0,getDocument()->getStringHasher());
|
||||
this->Shape.setValue(res.makEShape(mkChamfer,baseTopoShape,Part::OpCodes::Chamfer));
|
||||
return Part::Feature::execute();
|
||||
#endif
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
return new App::DocumentObjectExecReturn(e.GetMessageString());
|
||||
|
||||
@@ -48,13 +48,15 @@ App::DocumentObjectExecReturn *Fillet::execute()
|
||||
if (!link)
|
||||
return new App::DocumentObjectExecReturn("No object linked");
|
||||
|
||||
auto baseShape = Feature::getShape(link);
|
||||
|
||||
try {
|
||||
#if defined(__GNUC__) && defined (FC_OS_LINUX)
|
||||
Base::SignalException se;
|
||||
#endif
|
||||
auto baseShape = Feature::getShape(link);
|
||||
TopoShape baseTopoShape = Feature::getTopoShape(link);
|
||||
BRepFilletAPI_MakeFillet mkFillet(baseShape);
|
||||
#ifndef FC_USE_TNP_FIX
|
||||
TopTools_IndexedMapOfShape mapOfShape;
|
||||
TopExp::MapShapes(baseShape, TopAbs_EDGE, mapOfShape);
|
||||
|
||||
@@ -92,6 +94,35 @@ App::DocumentObjectExecReturn *Fillet::execute()
|
||||
prop.touch();
|
||||
|
||||
return App::DocumentObject::StdReturn;
|
||||
#else
|
||||
const auto &vals = EdgeLinks.getSubValues();
|
||||
const auto &subs = EdgeLinks.getShadowSubs();
|
||||
if(subs.size()!=(size_t)Edges.getSize())
|
||||
return new App::DocumentObjectExecReturn("Edge link size mismatch");
|
||||
size_t i=0;
|
||||
for(const auto &info : Edges.getValues()) {
|
||||
auto &sub = subs[i];
|
||||
auto &ref = sub.first.size()?sub.first:vals[i];
|
||||
++i;
|
||||
TopoDS_Shape edge;
|
||||
try {
|
||||
edge = baseTopoShape.getSubShape(ref.c_str());
|
||||
}catch(...){}
|
||||
if(edge.IsNull())
|
||||
return new App::DocumentObjectExecReturn("Invalid edge link");
|
||||
double radius1 = info.radius1;
|
||||
double radius2 = info.radius2;
|
||||
mkFillet.Add(radius1, radius2, TopoDS::Edge(edge));
|
||||
}
|
||||
|
||||
TopoDS_Shape shape = mkFillet.Shape();
|
||||
if (shape.IsNull())
|
||||
return new App::DocumentObjectExecReturn("Resulting shape is null");
|
||||
|
||||
TopoShape res(0,getDocument()->getStringHasher());
|
||||
this->Shape.setValue(res.makEShape(mkFillet,baseTopoShape,Part::OpCodes::Fillet));
|
||||
return Part::Feature::execute();
|
||||
#endif
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
return new App::DocumentObjectExecReturn(e.GetMessageString());
|
||||
|
||||
@@ -1217,16 +1217,69 @@ FilletBase::FilletBase()
|
||||
{
|
||||
ADD_PROPERTY(Base,(nullptr));
|
||||
ADD_PROPERTY(Edges,(0,0,0));
|
||||
ADD_PROPERTY_TYPE(EdgeLinks,(0), 0,
|
||||
(App::PropertyType)(App::Prop_ReadOnly|App::Prop_Hidden),0);
|
||||
Edges.setSize(0);
|
||||
}
|
||||
|
||||
short FilletBase::mustExecute() const
|
||||
{
|
||||
if (Base.isTouched() || Edges.isTouched())
|
||||
if (Base.isTouched() || Edges.isTouched() || EdgeLinks.isTouched())
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FilletBase::onChanged(const App::Property *prop) {
|
||||
if(getDocument() && !getDocument()->testStatus(App::Document::Restoring)) {
|
||||
if(prop == &Edges || prop == &Base) {
|
||||
if(!prop->testStatus(App::Property::User3))
|
||||
syncEdgeLink();
|
||||
}
|
||||
}
|
||||
Feature::onChanged(prop);
|
||||
}
|
||||
|
||||
void FilletBase::onDocumentRestored() {
|
||||
if(EdgeLinks.getSubValues().empty())
|
||||
syncEdgeLink();
|
||||
Feature::onDocumentRestored();
|
||||
}
|
||||
|
||||
void FilletBase::syncEdgeLink() {
|
||||
if(!Base.getValue() || !Edges.getSize()) {
|
||||
EdgeLinks.setValue(0);
|
||||
return;
|
||||
}
|
||||
std::vector<std::string> subs;
|
||||
std::string sub("Edge");
|
||||
for(auto &info : Edges.getValues())
|
||||
subs.emplace_back(sub+std::to_string(info.edgeid));
|
||||
EdgeLinks.setValue(Base.getValue(),subs);
|
||||
}
|
||||
|
||||
void FilletBase::onUpdateElementReference(const App::Property *prop) {
|
||||
if(prop!=&EdgeLinks || !getNameInDocument())
|
||||
return;
|
||||
auto values = Edges.getValues();
|
||||
const auto &subs = EdgeLinks.getSubValues();
|
||||
for(size_t i=0;i<values.size();++i) {
|
||||
if(i>=subs.size()) {
|
||||
FC_WARN("fillet edge count mismatch in object " << getFullName());
|
||||
break;
|
||||
}
|
||||
int idx = 0;
|
||||
sscanf(subs[i].c_str(),"Edge%d",&idx);
|
||||
if(idx)
|
||||
values[i].edgeid = idx;
|
||||
else
|
||||
FC_WARN("invalid fillet edge link '" << subs[i] << "' in object "
|
||||
<< getFullName());
|
||||
}
|
||||
Edges.setStatus(App::Property::User3,true);
|
||||
Edges.setValues(values);
|
||||
Edges.setStatus(App::Property::User3,false);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
|
||||
PROPERTY_SOURCE(Part::FeatureExt, Part::Feature)
|
||||
|
||||
@@ -175,8 +175,15 @@ public:
|
||||
|
||||
App::PropertyLink Base;
|
||||
PropertyFilletEdges Edges;
|
||||
App::PropertyLinkSub EdgeLinks;
|
||||
|
||||
short mustExecute() const override;
|
||||
virtual void onUpdateElementReference(const App::Property *prop) override;
|
||||
|
||||
protected:
|
||||
virtual void onDocumentRestored() override;
|
||||
virtual void onChanged(const App::Property *) override;
|
||||
void syncEdgeLink();
|
||||
};
|
||||
|
||||
using FeaturePython = App::FeaturePythonT<Feature>;
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
#include "Geometry.h"
|
||||
#include "BRepOffsetAPI_MakeOffsetFix.h"
|
||||
|
||||
#include <App/ElementMap.h>
|
||||
#include <App/ElementNamingUtils.h>
|
||||
#include <ShapeAnalysis_FreeBoundsProperties.hxx>
|
||||
#include <BRepBuilderAPI_MakeSolid.hxx>
|
||||
@@ -814,6 +815,7 @@ void TopoShape::mapSubElementForShape(const TopoShape& other, const char* op)
|
||||
|
||||
void TopoShape::mapSubElement(const TopoShape& other, const char* op, bool forceHasher)
|
||||
{
|
||||
#ifndef FC_USE_TNP_FIX
|
||||
if (!canMapElement(other)) {
|
||||
return;
|
||||
}
|
||||
@@ -831,6 +833,102 @@ void TopoShape::mapSubElement(const TopoShape& other, const char* op, bool force
|
||||
}
|
||||
|
||||
mapSubElementForShape(other, op);
|
||||
#else
|
||||
if(!canMapElement(other))
|
||||
return;
|
||||
|
||||
if (!getElementMapSize(false) && this->_Shape.IsPartner(other._Shape)) {
|
||||
if (!this->Hasher)
|
||||
this->Hasher = other.Hasher;
|
||||
copyElementMap(other, op);
|
||||
return;
|
||||
}
|
||||
|
||||
bool warned = false;
|
||||
static const std::array<TopAbs_ShapeEnum, 3> types = {TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE};
|
||||
|
||||
auto checkHasher = [this](const TopoShape &other) {
|
||||
if(Hasher) {
|
||||
if(other.Hasher!=Hasher) {
|
||||
if(!getElementMapSize(false)) {
|
||||
if(FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG))
|
||||
FC_WARN("hasher mismatch");
|
||||
}else {
|
||||
// FC_THROWM(Base::RuntimeError, "hasher mismatch");
|
||||
FC_ERR("hasher mismatch");
|
||||
}
|
||||
Hasher = other.Hasher;
|
||||
}
|
||||
}else
|
||||
Hasher = other.Hasher;
|
||||
};
|
||||
|
||||
for(auto type : types) {
|
||||
auto &shapeMap = _cache->getAncestry(type);
|
||||
auto &otherMap = other._cache->getAncestry(type);
|
||||
if(!shapeMap.count() || !otherMap.count())
|
||||
continue;
|
||||
if(!forceHasher && other.Hasher) {
|
||||
forceHasher = true;
|
||||
checkHasher(other);
|
||||
}
|
||||
const char *shapetype = shapeName(type).c_str();
|
||||
std::ostringstream ss;
|
||||
|
||||
bool forward;
|
||||
int count;
|
||||
if(otherMap.count()<=shapeMap.count()) {
|
||||
forward = true;
|
||||
count = otherMap.count();
|
||||
}else{
|
||||
forward = false;
|
||||
count = shapeMap.count();
|
||||
}
|
||||
for(int k=1;k<=count;++k) {
|
||||
int i,idx;
|
||||
if(forward) {
|
||||
i = k;
|
||||
idx = shapeMap.find(_Shape,otherMap.find(other._Shape,k));
|
||||
if(!idx) continue;
|
||||
} else {
|
||||
idx = k;
|
||||
i = otherMap.find(other._Shape,shapeMap.find(_Shape,k));
|
||||
if(!i) continue;
|
||||
}
|
||||
Data::IndexedName element = Data::IndexedName::fromConst(shapetype, idx);
|
||||
for(auto &v : other.getElementMappedNames(
|
||||
Data::IndexedName::fromConst(shapetype,i),true))
|
||||
{
|
||||
auto &name = v.first;
|
||||
auto &sids = v.second;
|
||||
if(sids.size()) {
|
||||
if (!Hasher)
|
||||
Hasher = sids[0].getHasher();
|
||||
else if (!sids[0].isFromSameHasher(Hasher)) {
|
||||
if (!warned) {
|
||||
warned = true;
|
||||
FC_WARN("hasher mismatch");
|
||||
}
|
||||
sids.clear();
|
||||
}
|
||||
}
|
||||
ss.str("");
|
||||
|
||||
// Originally in ComplexGeoData::setElementName
|
||||
// LinkStable/src/App/ComplexGeoData.cpp#L1631
|
||||
// No longer possible after map separated in ElementMap.cpp
|
||||
|
||||
if (!elementMap()) {
|
||||
resetElementMap(std::make_shared<Data::ElementMap>());
|
||||
}
|
||||
|
||||
elementMap()->encodeElementName(shapetype[0],name,ss,&sids,Tag,op,other.Tag);
|
||||
elementMap()->setElementName(element,name,Tag,&sids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void TopoShape::mapSubElementsTo(std::vector<TopoShape>& shapes, const char* op) const
|
||||
@@ -892,6 +990,7 @@ void TopoShape::mapCompoundSubElements(const std::vector<TopoShape>& shapes, con
|
||||
|
||||
void TopoShape::mapSubElement(const std::vector<TopoShape>& shapes, const char* op)
|
||||
{
|
||||
#ifndef FC_USE_TNP_FIX
|
||||
if (shapes.empty()) {
|
||||
return;
|
||||
}
|
||||
@@ -904,6 +1003,52 @@ void TopoShape::mapSubElement(const std::vector<TopoShape>& shapes, const char*
|
||||
mapSubElement(shape, op);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (shapes.empty())
|
||||
return;
|
||||
|
||||
if (shapeType(true) == TopAbs_COMPOUND) {
|
||||
int count = 0;
|
||||
for (auto & s : shapes) {
|
||||
if (s.isNull())
|
||||
continue;
|
||||
if (!getSubShape(TopAbs_SHAPE, ++count, true).IsPartner(s._Shape)) {
|
||||
count = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count) {
|
||||
std::vector<Data::ElementMap::MappedChildElements> children;
|
||||
children.reserve(count*3);
|
||||
TopAbs_ShapeEnum types[] = {TopAbs_VERTEX, TopAbs_EDGE, TopAbs_FACE};
|
||||
for (unsigned i=0; i<sizeof(types)/sizeof(types[0]); ++i) {
|
||||
int offset = 0;
|
||||
for (auto & s : shapes) {
|
||||
if (s.isNull())
|
||||
continue;
|
||||
int count = s.countSubShapes(types[i]);
|
||||
if (!count)
|
||||
continue;
|
||||
children.emplace_back();
|
||||
auto & child = children.back();
|
||||
child.indexedName = Data::IndexedName::fromConst(shapeName(types[i]).c_str(), 1);
|
||||
child.offset = offset;
|
||||
offset += count;
|
||||
child.count = count;
|
||||
child.elementMap = s.elementMap();
|
||||
child.tag = s.Tag;
|
||||
if (op)
|
||||
child.postfix = op;
|
||||
}
|
||||
}
|
||||
setMappedChildElements(children);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &shape : shapes)
|
||||
mapSubElement(shape,op);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<TopoDS_Shape> TopoShape::getSubShapes(TopAbs_ShapeEnum type,
|
||||
|
||||
@@ -592,6 +592,16 @@ void DlgFilletEdges::setupFillet(const std::vector<App::DocumentObject*>& objs)
|
||||
{
|
||||
App::DocumentObject* base = d->fillet->Base.getValue();
|
||||
const std::vector<Part::FilletElement>& e = d->fillet->Edges.getValues();
|
||||
const auto &subs = d->fillet->EdgeLinks.getShadowSubs();
|
||||
if(subs.size()!=e.size()) {
|
||||
FC_ERR("edge link size mismatch");
|
||||
return;
|
||||
}
|
||||
std::set<std::string> subSet;
|
||||
for(auto &sub : subs)
|
||||
subSet.insert(sub.first.empty()?sub.second:sub.first);
|
||||
|
||||
std::string tmp;
|
||||
std::vector<App::DocumentObject*>::const_iterator it = std::find(objs.begin(), objs.end(), base);
|
||||
if (it != objs.end()) {
|
||||
// toggle visibility
|
||||
@@ -613,6 +623,40 @@ void DlgFilletEdges::setupFillet(const std::vector<App::DocumentObject*>& objs)
|
||||
std::vector<std::string> subElements;
|
||||
QStandardItemModel *model = qobject_cast<QStandardItemModel*>(ui->treeView->model());
|
||||
bool block = model->blockSignals(true); // do not call toggleCheckState
|
||||
auto baseShape = Part::Feature::getTopoShape(base);
|
||||
std::set<Part::FilletElement> elements;
|
||||
for(size_t i=0;i<e.size();++i) {
|
||||
auto &sub = subs[i];
|
||||
if(sub.first.empty()) {
|
||||
int idx = 0;
|
||||
sscanf(sub.second.c_str(),"Edge%d",&idx);
|
||||
if(idx==0)
|
||||
FC_WARN("missing element reference: " << sub.second);
|
||||
else
|
||||
elements.insert(e[i]);
|
||||
continue;
|
||||
}
|
||||
auto &ref = sub.first;
|
||||
Part::TopoShape edge;
|
||||
try {
|
||||
edge = baseShape.getSubShape(ref.c_str());
|
||||
}catch(...) {}
|
||||
if(!edge.isNull()) {
|
||||
elements.insert(e[i]);
|
||||
continue;
|
||||
}
|
||||
FC_WARN("missing element reference: " << base->getFullName() << "." << ref);
|
||||
|
||||
for(auto &mapped : Part::Feature::getRelatedElements(base,ref.c_str())) {
|
||||
tmp.clear();
|
||||
if(!subSet.insert(mapped.index.toString(tmp)).second
|
||||
|| !subSet.insert(mapped.name.toString(0)).second)
|
||||
continue;
|
||||
FC_WARN("guess element reference: " << ref << " -> " << mapped.index);
|
||||
elements.emplace(mapped.index.getIndex(),e[i].radius1,e[i].radius2);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto & et : e) {
|
||||
std::vector<int>::iterator it = std::find(d->edge_ids.begin(), d->edge_ids.end(), et.edgeid);
|
||||
if (it != d->edge_ids.end()) {
|
||||
|
||||
Reference in New Issue
Block a user