Toposhape/Part: Transfer in FeatureFillet, FeatureChamfer and dependencies

This commit is contained in:
Zheng, Lei
2024-02-26 15:52:22 -05:00
committed by bgbsww
parent 9209331e59
commit 5da174f46e
6 changed files with 313 additions and 3 deletions

View File

@@ -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());

View File

@@ -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());

View File

@@ -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)

View File

@@ -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>;

View File

@@ -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,

View File

@@ -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()) {