Toponaming move makEFace as makeElementFace and dependencies

This commit is contained in:
Zheng, Lei
2024-01-17 20:38:50 -05:00
committed by bgbsww
parent af76942a0b
commit e425b5b2db
8 changed files with 543 additions and 22 deletions

View File

@@ -26,11 +26,19 @@
#include "PreCompiled.h"
#ifndef _PreComp_
#include <BRep_Builder.hxx>
# include <BRepBuilderAPI_MakeWire.hxx>
#include <BRep_Tool.hxx>
#include <BRepTools.hxx>
# include <ShapeFix_Shape.hxx>
# include <ShapeFix_ShapeTolerance.hxx>
#endif
#include "TopoShape.h"
#include "TopoShapeCache.h"
#include "FaceMaker.h"
FC_LOG_LEVEL_INIT("TopoShape", true, true) // NOLINT
@@ -540,4 +548,202 @@ TopoShape::makeElementCompound(const std::vector<TopoShape>& shapes, const char*
return *this;
}
TopoShape &TopoShape::makeElementFace(const TopoShape &shape,
const char *op,
const char *maker,
const gp_Pln *pln)
{
std::vector<TopoShape> shapes;
if (shape.isNull())
FC_THROWM(NullShapeException, "Null shape");
if(shape.getShape().ShapeType() == TopAbs_COMPOUND)
shapes = shape.getSubTopoShapes();
else
shapes.push_back(shape);
return makeElementFace(shapes,op,maker,pln);
}
TopoShape &TopoShape::makeElementFace(const std::vector<TopoShape> &shapes,
const char *op,
const char *maker,
const gp_Pln *pln)
{
if(!maker || !maker[0]) maker = "Part::FaceMakerBullseye";
std::unique_ptr<FaceMaker> mkFace = FaceMaker::ConstructFromType(maker);
mkFace->MyHasher = Hasher;
mkFace->MyOp = op;
if (pln)
mkFace->setPlane(*pln);
for(auto &s : shapes) {
if (s.getShape().ShapeType() == TopAbs_COMPOUND)
mkFace->useTopoCompound(s);
else
mkFace->addTopoShape(s);
}
mkFace->Build();
const auto &ret = mkFace->getTopoShape();
setShape(ret._Shape);
Hasher = ret.Hasher;
resetElementMap(ret.elementMap());
if (!isValid()) {
ShapeFix_ShapeTolerance aSFT;
aSFT.LimitTolerance(getShape(),
Precision::Confusion(), Precision::Confusion(), TopAbs_SHAPE);
// In some cases, the OCC reports the returned shape having invalid
// tolerance. Not sure about the real cause.
//
// Update: one of the cause is related to OCC bug in
// BRepBuilder_FindPlane, A possible call sequence is,
//
// makEOffset2D() -> TopoShape::findPlane() -> BRepLib_FindSurface
//
// See code comments in findPlane() for the description of the bug and
// work around.
ShapeFix_Shape fixer(getShape());
fixer.Perform();
setShape(fixer.Shape(), false);
if (!isValid())
FC_WARN("makeElementFace: resulting face is invalid");
}
return *this;
}
Data::MappedName TopoShape::setElementComboName(const Data::IndexedName & element,
const std::vector<Data::MappedName> &names,
const char *marker,
const char *op,
const Data::ElementIDRefs *_sids)
{
if(names.empty())
return Data::MappedName();
std::string _marker;
if(!marker)
marker = elementMapPrefix().c_str();
else if(!boost::starts_with(marker,elementMapPrefix())){
_marker = elementMapPrefix() + marker;
marker = _marker.c_str();
}
auto it = names.begin();
Data::MappedName newName = *it;
std::ostringstream ss;
Data::ElementIDRefs sids;
if (_sids)
sids = *_sids;
if(names.size() == 1)
ss << marker;
else {
bool first = true;
ss.str("");
if(!Hasher)
ss << marker;
ss << '(';
for(++it;it!=names.end();++it) {
if(first)
first = false;
else
ss << '|';
ss << *it;
}
ss << ')';
if(Hasher) {
sids.push_back(Hasher->getID(ss.str().c_str()));
ss.str("");
ss << marker << sids.back().toString();
}
}
elementMap()->encodeElementName(element[0],newName,ss,&sids,Tag,op);
return elementMap()->setElementName(element,newName, Tag, &sids);
}
TopoShape TopoShape::splitWires(std::vector<TopoShape> *inner,
SplitWireReorient reorient) const
{
// ShapeAnalysis::OuterWire() is un-reliable for some reason. OCC source
// code shows it works by creating face using each wire, and then test using
// BRepTopAdaptor_FClass2d::PerformInfinitePoint() to check if it is an out
// bound wire. And practice shows it sometimes returns the incorrect
// result. Need more investigation. Note that this may be related to
// unreliable solid face orientation
// (https://forum.freecadweb.org/viewtopic.php?p=446006#p445674)
//
// Use BrepTools::OuterWire() instead. OCC source code shows it is
// implemented using simple bound box checking. This should be a
// reliable method, especially so for a planar face.
TopoDS_Shape tmp;
if (shapeType(true) == TopAbs_FACE)
tmp = BRepTools::OuterWire(TopoDS::Face(_Shape));
else if (countSubShapes(TopAbs_FACE) == 1)
tmp = BRepTools::OuterWire(
TopoDS::Face(getSubShape(TopAbs_FACE, 1)));
if (tmp.IsNull())
return TopoShape();
const auto & wires = getSubTopoShapes(TopAbs_WIRE);
auto it = wires.begin();
TopAbs_Orientation orientOuter, orientInner;
switch(reorient) {
case ReorientReversed:
orientOuter = orientInner = TopAbs_REVERSED;
break;
case ReorientForward:
orientOuter = orientInner = TopAbs_FORWARD;
break;
default:
orientOuter = TopAbs_FORWARD;
orientInner = TopAbs_REVERSED;
break;
}
auto doReorient = [](TopoShape &s, TopAbs_Orientation orient) {
// Special case of single edge wire. Make sure the edge is in the
// required orientation. This is necessary because BRepFill_OffsetWire
// has special handling of circular edge offset, which seem to only
// respect the edge orientation and disregard the wire orientation. The
// orientation is used to determine whether to shrink or expand.
if (s.countSubShapes(TopAbs_EDGE) == 1) {
TopoDS_Shape e = s.getSubShape(TopAbs_EDGE, 1);
if (e.Orientation() == orient) {
if (s._Shape.Orientation() == orient)
return;
} else
e = e.Oriented(orient);
BRepBuilderAPI_MakeWire mkWire(TopoDS::Edge(e));
s.setShape(mkWire.Shape(), false);
}
else if (s._Shape.Orientation() != orient)
s.setShape(s._Shape.Oriented(orient), false);
};
for (; it != wires.end(); ++it) {
auto & wire = *it;
if (wire.getShape().IsSame(tmp)) {
if (inner) {
for (++it; it != wires.end(); ++it) {
inner->push_back(*it);
if (reorient)
doReorient(inner->back(), orientInner);
}
}
auto res = wire;
if (reorient)
doReorient(res, orientOuter);
return res;
}
if (inner) {
inner->push_back(wire);
if (reorient)
doReorient(inner->back(), orientInner);
}
}
return TopoShape();
}
} // namespace Part