Part: changes to Part Module
* Added Part::Feature::getTopoShape/getShape() function that can obtain
shape from any object with proper implementation of getSubObject(). It
can even construct compound from group object with proper implementation
of getSubObjects().
* Modified ViewProviderExt to work on any object, because it now obtain
the shape using Part::Feature::getShape()
* Modified various Part features to obtain base/tool shapes using
Part::getShape(), which allows them to be any type of object,
including Link and groups.
* Modified various Part command to relax type requirement on selected
objects.
* Add support of link and group to dimension, and add dimension refresh
command
* Support link and group in simple command command, and add a few more
copy command variations.
* Add special handling of 'Shape' attribute in PropertyContainerPy and
use Part::Feature::getShape() to return shape for any object without
Shape property. This allows many python feature work with any object
without modification.
* GeometrySurface/CurvePy, add convenience attribute 'Rotation'
* TopoShapePy:
* Extended support of sub shape attribute, e.g. Compound1, Solid2,
SubShape3 ('SubShape' is used to access child shape of a compound)
* makeWires(), new API to sort and return wires given a list of edges.
* transformed/translated/rotated/scaled(), return a new shape with
some transformation.
* findPlane(), find the plane of a planar shape
* isCoplanar(), check if two shape are coplanar
This commit is contained in:
@@ -181,6 +181,8 @@
|
||||
#endif
|
||||
#endif // _PreComp_
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
#include <Base/Builder3D.h>
|
||||
#include <Base/FileInfo.h>
|
||||
#include <Base/Exception.h>
|
||||
@@ -188,6 +190,7 @@
|
||||
#include <Base/Console.h>
|
||||
#include <App/Material.h>
|
||||
|
||||
#include "PartPyCXX.h"
|
||||
#include "TopoShape.h"
|
||||
#include "CrossSection.h"
|
||||
#include "TopoShapeFacePy.h"
|
||||
@@ -200,6 +203,8 @@
|
||||
#include "FaceMakerBullseye.h"
|
||||
#include "BRepOffsetAPI_MakeOffsetFix.h"
|
||||
|
||||
FC_LOG_LEVEL_INIT("TopoShape",true,true);
|
||||
|
||||
using namespace Part;
|
||||
|
||||
const char* BRepBuilderAPI_FaceErrorText(BRepBuilderAPI_FaceError et)
|
||||
@@ -298,6 +303,7 @@ TopoShape::TopoShape(const TopoDS_Shape& shape)
|
||||
TopoShape::TopoShape(const TopoShape& shape)
|
||||
: _Shape(shape._Shape)
|
||||
{
|
||||
Tag = shape.Tag;
|
||||
}
|
||||
|
||||
std::vector<const char*> TopoShape::getElementTypes(void) const
|
||||
@@ -323,88 +329,188 @@ Data::Segment* TopoShape::getSubElement(const char* Type, unsigned long n) const
|
||||
return new ShapeSegment(getSubShape(temp.c_str()));
|
||||
}
|
||||
|
||||
TopoDS_Shape TopoShape::getSubShape(const char* Type) const
|
||||
TopoDS_Shape TopoShape::getSubShape(const char* Type, bool silent) const
|
||||
{
|
||||
if (!Type)
|
||||
Standard_Failure::Raise("No sub-shape type given");
|
||||
if (this->_Shape.IsNull())
|
||||
auto res = shapeTypeAndIndex(Type);
|
||||
return getSubShape(res.first,res.second,silent);
|
||||
}
|
||||
|
||||
TopoDS_Shape TopoShape::getSubShape(TopAbs_ShapeEnum type, int index, bool silent) const
|
||||
{
|
||||
if(index <= 0) {
|
||||
if(silent)
|
||||
return TopoDS_Shape();
|
||||
Standard_Failure::Raise("Unsupported sub-shape type");
|
||||
}
|
||||
|
||||
if (this->_Shape.IsNull()) {
|
||||
if(silent)
|
||||
return TopoDS_Shape();
|
||||
Standard_Failure::Raise("Cannot get sub-shape from empty shape");
|
||||
|
||||
std::string shapetype(Type);
|
||||
if (shapetype.size() > 4 && shapetype.substr(0,4) == "Face") {
|
||||
int index=std::atoi(&shapetype[4]);
|
||||
TopTools_IndexedMapOfShape anIndices;
|
||||
TopExp::MapShapes(this->_Shape, TopAbs_FACE, anIndices);
|
||||
// To avoid a segmentation fault we have to check if container is empty
|
||||
if (anIndices.IsEmpty())
|
||||
Standard_Failure::Raise("Shape has no faces");
|
||||
return anIndices.FindKey(index);
|
||||
}
|
||||
else if (shapetype.size() > 4 && shapetype.substr(0,4) == "Edge") {
|
||||
int index=std::atoi(&shapetype[4]);
|
||||
TopTools_IndexedMapOfShape anIndices;
|
||||
TopExp::MapShapes(this->_Shape, TopAbs_EDGE, anIndices);
|
||||
// To avoid a segmentation fault we have to check if container is empty
|
||||
if (anIndices.IsEmpty())
|
||||
Standard_Failure::Raise("Shape has no edges");
|
||||
return anIndices.FindKey(index);
|
||||
}
|
||||
else if (shapetype.size() > 6 && shapetype.substr(0,6) == "Vertex") {
|
||||
int index=std::atoi(&shapetype[6]);
|
||||
TopTools_IndexedMapOfShape anIndices;
|
||||
TopExp::MapShapes(this->_Shape, TopAbs_VERTEX, anIndices);
|
||||
// To avoid a segmentation fault we have to check if container is empty
|
||||
if (anIndices.IsEmpty())
|
||||
Standard_Failure::Raise("Shape has no vertexes");
|
||||
return anIndices.FindKey(index);
|
||||
}
|
||||
|
||||
Standard_Failure::Raise("Unsupported sub-shape type");
|
||||
return TopoDS_Shape(); // avoid compiler warning
|
||||
try {
|
||||
if(type == TopAbs_SHAPE) {
|
||||
int i=1;
|
||||
for(TopoDS_Iterator it(_Shape);it.More();it.Next(),++i) {
|
||||
if(i == index)
|
||||
return it.Value();
|
||||
}
|
||||
} else {
|
||||
TopTools_IndexedMapOfShape anIndices;
|
||||
TopExp::MapShapes(this->_Shape, type, anIndices);
|
||||
if(index <= anIndices.Extent())
|
||||
return anIndices.FindKey(index);
|
||||
}
|
||||
} catch(Standard_Failure &) {
|
||||
if(silent)
|
||||
return TopoDS_Shape();
|
||||
throw;
|
||||
}
|
||||
if(!silent)
|
||||
Standard_Failure::Raise("Index out of bound");
|
||||
return TopoDS_Shape();
|
||||
}
|
||||
|
||||
unsigned long TopoShape::countSubShapes(const char* Type) const
|
||||
{
|
||||
std::string shapetype(Type);
|
||||
if (shapetype == "Face") {
|
||||
TopTools_IndexedMapOfShape anIndices;
|
||||
TopExp::MapShapes(this->_Shape, TopAbs_FACE, anIndices);
|
||||
return anIndices.Extent();
|
||||
}
|
||||
else if (shapetype == "Edge") {
|
||||
TopTools_IndexedMapOfShape anIndices;
|
||||
TopExp::MapShapes(this->_Shape, TopAbs_EDGE, anIndices);
|
||||
return anIndices.Extent();
|
||||
}
|
||||
else if (shapetype == "Vertex") {
|
||||
TopTools_IndexedMapOfShape anIndices;
|
||||
TopExp::MapShapes(this->_Shape, TopAbs_VERTEX, anIndices);
|
||||
return anIndices.Extent();
|
||||
}
|
||||
|
||||
return 0;
|
||||
if(!Type) return 0;
|
||||
if(strcmp(Type,"SubShape")==0)
|
||||
return countSubShapes(TopAbs_SHAPE);
|
||||
auto type = shapeType(Type,true);
|
||||
if(type == TopAbs_SHAPE)
|
||||
return 0;
|
||||
return countSubShapes(type);
|
||||
}
|
||||
|
||||
PyObject * TopoShape::getPySubShape(const char* Type) const
|
||||
unsigned long TopoShape::countSubShapes(TopAbs_ShapeEnum Type) const
|
||||
{
|
||||
// get the shape
|
||||
TopoDS_Shape Shape = getSubShape(Type);
|
||||
// destinquish the return type
|
||||
std::string shapetype(Type);
|
||||
if (shapetype.size() > 4 && shapetype.substr(0,4) == "Face")
|
||||
return new TopoShapeFacePy(new TopoShape(Shape));
|
||||
else if (shapetype.size() > 4 && shapetype.substr(0,4) == "Edge")
|
||||
return new TopoShapeEdgePy(new TopoShape(Shape));
|
||||
else if (shapetype.size() > 6 && shapetype.substr(0,6) == "Vertex")
|
||||
return new TopoShapeVertexPy(new TopoShape(Shape));
|
||||
else
|
||||
return 0;
|
||||
if(Type == TopAbs_SHAPE) {
|
||||
int count = 0;
|
||||
for(TopoDS_Iterator it(_Shape);it.More();it.Next())
|
||||
++count;
|
||||
return count;
|
||||
}
|
||||
TopTools_IndexedMapOfShape anIndices;
|
||||
TopExp::MapShapes(this->_Shape, Type, anIndices);
|
||||
return anIndices.Extent();
|
||||
}
|
||||
|
||||
bool TopoShape::hasSubShape(TopAbs_ShapeEnum type) const {
|
||||
if(type == TopAbs_SHAPE) {
|
||||
TopoDS_Iterator it(_Shape);
|
||||
return !!it.More();
|
||||
}
|
||||
TopExp_Explorer exp(_Shape,type);
|
||||
return !!exp.More();
|
||||
}
|
||||
|
||||
bool TopoShape::hasSubShape(const char *Type) const {
|
||||
auto idx = shapeTypeAndIndex(Type);
|
||||
return idx.second>0 && idx.second<=(int)countSubShapes(idx.first);
|
||||
}
|
||||
|
||||
static std::array<std::string,TopAbs_SHAPE> _ShapeNames;
|
||||
|
||||
static void initShapeNameMap() {
|
||||
if(_ShapeNames[TopAbs_VERTEX].empty()) {
|
||||
_ShapeNames[TopAbs_VERTEX] = "Vertex";
|
||||
_ShapeNames[TopAbs_EDGE] = "Edge";
|
||||
_ShapeNames[TopAbs_FACE] = "Face";
|
||||
_ShapeNames[TopAbs_WIRE] = "Wire";
|
||||
_ShapeNames[TopAbs_SHELL] = "Shell";
|
||||
_ShapeNames[TopAbs_SOLID] = "Solid";
|
||||
_ShapeNames[TopAbs_COMPOUND] = "Compound";
|
||||
_ShapeNames[TopAbs_COMPSOLID] = "CompSolid";
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<TopAbs_ShapeEnum,int> TopoShape::shapeTypeAndIndex(const char *name) {
|
||||
int idx = 0;
|
||||
TopAbs_ShapeEnum type = TopAbs_SHAPE;
|
||||
static const std::string _subshape("SubShape");
|
||||
if(boost::starts_with(name,_subshape)) {
|
||||
std::istringstream iss(name+_subshape.size());
|
||||
iss >> idx;
|
||||
if(!iss.eof())
|
||||
idx = 0;
|
||||
} else {
|
||||
type = shapeType(name,true);
|
||||
if(type != TopAbs_SHAPE) {
|
||||
std::istringstream iss(name+shapeName(type).size());
|
||||
iss >> idx;
|
||||
if(!iss.eof()) {
|
||||
idx = 0;
|
||||
type = TopAbs_SHAPE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::make_pair(type,idx);
|
||||
}
|
||||
|
||||
TopAbs_ShapeEnum TopoShape::shapeType(const char *type, bool silent) {
|
||||
if(type) {
|
||||
initShapeNameMap();
|
||||
for(size_t idx=0;idx<_ShapeNames.size();++idx) {
|
||||
if(_ShapeNames[idx].size() && boost::starts_with(type,_ShapeNames[idx]))
|
||||
return (TopAbs_ShapeEnum)idx;
|
||||
}
|
||||
}
|
||||
if(!silent) {
|
||||
if(Data::ComplexGeoData::hasMissingElement(type))
|
||||
FC_THROWM(Base::CADKernelError,"missing shape element: " << (type?type:"?"));
|
||||
FC_THROWM(Base::CADKernelError,"invalid shape type: " << (type?type:"?"));
|
||||
}
|
||||
return TopAbs_SHAPE;
|
||||
}
|
||||
|
||||
TopAbs_ShapeEnum TopoShape::shapeType(char type, bool silent) {
|
||||
switch(type) {
|
||||
case 'E':
|
||||
return TopAbs_EDGE;
|
||||
case 'V':
|
||||
return TopAbs_VERTEX;
|
||||
case 'F':
|
||||
return TopAbs_FACE;
|
||||
default:
|
||||
if(!silent)
|
||||
FC_THROWM(Base::CADKernelError, "invalid shape type '" << type << "'");
|
||||
return TopAbs_SHAPE;
|
||||
}
|
||||
}
|
||||
|
||||
TopAbs_ShapeEnum TopoShape::shapeType(bool silent) const {
|
||||
if(isNull()) {
|
||||
if(!silent)
|
||||
FC_THROWM(NullShapeException, "Input shape is null");
|
||||
return TopAbs_SHAPE;
|
||||
}
|
||||
return getShape().ShapeType();
|
||||
}
|
||||
|
||||
const std::string &TopoShape::shapeName(TopAbs_ShapeEnum type, bool silent) {
|
||||
initShapeNameMap();
|
||||
if(type>=0 && type<_ShapeNames.size() && _ShapeNames[type].size())
|
||||
return _ShapeNames[type];
|
||||
if(!silent)
|
||||
FC_THROWM(Base::CADKernelError, "invalid shape type '" << type << "'");
|
||||
static std::string ret("");
|
||||
return ret;
|
||||
}
|
||||
|
||||
const std::string &TopoShape::shapeName(bool silent) const {
|
||||
return shapeName(shapeType(silent),silent);
|
||||
}
|
||||
|
||||
PyObject * TopoShape::getPySubShape(const char* Type, bool silent) const
|
||||
{
|
||||
return Py::new_reference_to(shape2pyshape(getSubShape(Type,silent)));
|
||||
}
|
||||
|
||||
void TopoShape::operator = (const TopoShape& sh)
|
||||
{
|
||||
if (this != &sh) {
|
||||
this->Tag = sh.Tag;
|
||||
this->_Shape = sh._Shape;
|
||||
}
|
||||
}
|
||||
@@ -470,6 +576,18 @@ void TopoShape::convertToMatrix(const gp_Trsf& trsf, Base::Matrix4D& mtrx)
|
||||
#endif
|
||||
}
|
||||
|
||||
Base::Matrix4D TopoShape::convert(const gp_Trsf& trsf) {
|
||||
Base::Matrix4D mat;
|
||||
convertToMatrix(trsf,mat);
|
||||
return mat;
|
||||
}
|
||||
|
||||
gp_Trsf TopoShape::convert(const Base::Matrix4D& mtrx) {
|
||||
gp_Trsf trsf;
|
||||
convertTogpTrsf(mtrx,trsf);
|
||||
return trsf;
|
||||
}
|
||||
|
||||
void TopoShape::setTransform(const Base::Matrix4D& rclTrf)
|
||||
{
|
||||
gp_Trsf mov;
|
||||
@@ -2841,7 +2959,10 @@ TopoDS_Shape TopoShape::makeThickSolid(const TopTools_ListOfShape& remFace,
|
||||
|
||||
void TopoShape::transformGeometry(const Base::Matrix4D &rclMat)
|
||||
{
|
||||
this->_Shape = transformGShape(rclMat);
|
||||
if (this->_Shape.IsNull())
|
||||
Standard_Failure::Raise("Cannot transform null shape");
|
||||
|
||||
*this = makEGTransform(rclMat);
|
||||
}
|
||||
|
||||
TopoDS_Shape TopoShape::transformGShape(const Base::Matrix4D& rclTrf) const
|
||||
@@ -2868,23 +2989,12 @@ TopoDS_Shape TopoShape::transformGShape(const Base::Matrix4D& rclTrf) const
|
||||
return mkTrf.Shape();
|
||||
}
|
||||
|
||||
void TopoShape::transformShape(const Base::Matrix4D& rclTrf, bool copy)
|
||||
bool TopoShape::transformShape(const Base::Matrix4D& rclTrf, bool copy, bool checkScale)
|
||||
{
|
||||
if (this->_Shape.IsNull())
|
||||
Standard_Failure::Raise("Cannot transform null shape");
|
||||
|
||||
gp_Trsf mat;
|
||||
mat.SetValues(rclTrf[0][0],rclTrf[0][1],rclTrf[0][2],rclTrf[0][3],
|
||||
rclTrf[1][0],rclTrf[1][1],rclTrf[1][2],rclTrf[1][3],
|
||||
rclTrf[2][0],rclTrf[2][1],rclTrf[2][2],rclTrf[2][3]
|
||||
#if OCC_VERSION_HEX < 0x060800
|
||||
, 0.00001,0.00001
|
||||
#endif
|
||||
); //precision was removed in OCCT CR0025194
|
||||
|
||||
// location transformation
|
||||
BRepBuilderAPI_Transform mkTrf(this->_Shape, mat, copy ? Standard_True : Standard_False);
|
||||
this->_Shape = mkTrf.Shape();
|
||||
return _makETransform(TopoShape(*this),rclTrf,0,checkScale,copy);
|
||||
}
|
||||
|
||||
TopoDS_Shape TopoShape::mirror(const gp_Ax2& ax2) const
|
||||
@@ -3428,6 +3538,10 @@ void TopoShape::getLinesFromSubelement(const Data::Segment* element,
|
||||
return;
|
||||
}
|
||||
|
||||
// build up map edge->face
|
||||
TopTools_IndexedDataMapOfShapeListOfShape edge2Face;
|
||||
TopExp::MapShapesAndAncestors(this->_Shape, TopAbs_EDGE, TopAbs_FACE, edge2Face);
|
||||
|
||||
for(TopExp_Explorer exp(shape,TopAbs_EDGE);exp.More();exp.Next()) {
|
||||
|
||||
TopoDS_Edge aEdge = TopoDS::Edge(exp.Current());
|
||||
@@ -3460,12 +3574,16 @@ void TopoShape::getLinesFromSubelement(const Data::Segment* element,
|
||||
// must provide this triangulation
|
||||
|
||||
// Look for one face in our map (it doesn't care which one we take)
|
||||
auto aFace = findAncestorShape(aEdge, TopAbs_FACE);
|
||||
if(aFace.IsNull())
|
||||
int index = edge2Face.FindIndex(aEdge);
|
||||
if(!index)
|
||||
continue;
|
||||
const auto &faces = edge2Face.FindFromIndex(index);
|
||||
if(!faces.Extent())
|
||||
continue;
|
||||
const TopoDS_Face& aFace = TopoDS::Face(faces.First());
|
||||
|
||||
// take the face's triangulation instead
|
||||
Handle(Poly_Triangulation) aPolyTria = BRep_Tool::Triangulation(TopoDS::Face(aFace),aLoc);
|
||||
Handle(Poly_Triangulation) aPolyTria = BRep_Tool::Triangulation(aFace,aLoc);
|
||||
if (!aLoc.IsIdentity()) {
|
||||
myTransf = aLoc.Transformation();
|
||||
}
|
||||
@@ -3691,3 +3809,286 @@ TopoDS_Shape TopoShape::makeShell(const TopoDS_Shape& input) const
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
#define _HANDLE_NULL_SHAPE(_msg,_throw) do {\
|
||||
if(_throw) {\
|
||||
FC_THROWM(NullShapeException,_msg);\
|
||||
}\
|
||||
FC_WARN(_msg);\
|
||||
}while(0)
|
||||
|
||||
#define HANDLE_NULL_SHAPE _HANDLE_NULL_SHAPE("Null shape",true)
|
||||
#define HANDLE_NULL_INPUT _HANDLE_NULL_SHAPE("Null input shape",true)
|
||||
#define WARN_NULL_INPUT _HANDLE_NULL_SHAPE("Null input shape",false)
|
||||
|
||||
TopoShape &TopoShape::makEWires(const TopoShape &shape, const char *op, bool fix, double tol)
|
||||
{
|
||||
_Shape.Nullify();
|
||||
|
||||
if(shape.isNull())
|
||||
HANDLE_NULL_INPUT;
|
||||
|
||||
if(tol<Precision::Confusion()) tol = Precision::Confusion();
|
||||
|
||||
(void)op;
|
||||
(void)fix;
|
||||
std::vector<TopoShape> edges;
|
||||
std::list<TopoShape> edge_list;
|
||||
std::vector<TopoShape> wires;
|
||||
|
||||
TopTools_IndexedMapOfShape anIndices;
|
||||
TopExp::MapShapes(shape.getShape(), TopAbs_EDGE, anIndices);
|
||||
for(int i=1;i<=anIndices.Extent();++i)
|
||||
edge_list.push_back(anIndices.FindKey(i));
|
||||
|
||||
edges.reserve(edge_list.size());
|
||||
wires.reserve(edge_list.size());
|
||||
|
||||
// sort them together to wires
|
||||
while (edge_list.size() > 0) {
|
||||
BRepBuilderAPI_MakeWire mkWire;
|
||||
// add and erase first edge
|
||||
edges.push_back(edge_list.front());
|
||||
edge_list.pop_front();
|
||||
mkWire.Add(TopoDS::Edge(edges.back().getShape()));
|
||||
edges.back().setShape(mkWire.Edge());
|
||||
|
||||
TopoDS_Wire new_wire = mkWire.Wire(); // current new wire
|
||||
|
||||
// try to connect each edge to the wire, the wire is complete if no more edges are connectible
|
||||
bool found = false;
|
||||
do {
|
||||
found = false;
|
||||
for (auto it=edge_list.begin();it!=edge_list.end();++it) {
|
||||
mkWire.Add(TopoDS::Edge(it->getShape()));
|
||||
if (mkWire.Error() != BRepBuilderAPI_DisconnectedWire) {
|
||||
// edge added ==> remove it from list
|
||||
found = true;
|
||||
edges.push_back(*it);
|
||||
edges.back().setShape(mkWire.Edge());
|
||||
edge_list.erase(it);
|
||||
new_wire = mkWire.Wire();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (found);
|
||||
|
||||
// Fix any topological issues of the wire
|
||||
ShapeFix_Wire aFix;
|
||||
aFix.SetPrecision(tol);
|
||||
aFix.Load(new_wire);
|
||||
|
||||
aFix.FixReorder();
|
||||
// Assuming FixReorder() just reorder and don't change the underlying
|
||||
// edges, we get the wire and do a name mapping now, as the following
|
||||
// two operations (FixConnected and FixClosed) may change the edges.
|
||||
wires.push_back(aFix.Wire());
|
||||
|
||||
aFix.FixConnected();
|
||||
aFix.FixClosed();
|
||||
// Now retrieve the shape and set it without touching element map
|
||||
wires.back().setShape(aFix.Wire());
|
||||
}
|
||||
return makECompound(wires,0,false);
|
||||
}
|
||||
|
||||
TopoShape &TopoShape::makECompound(const std::vector<TopoShape> &shapes, const char *op, bool force)
|
||||
{
|
||||
(void)op;
|
||||
_Shape.Nullify();
|
||||
|
||||
if(shapes.empty())
|
||||
HANDLE_NULL_INPUT;
|
||||
|
||||
if(!force && shapes.size()==1) {
|
||||
*this = shapes[0];
|
||||
return *this;
|
||||
}
|
||||
|
||||
BRep_Builder builder;
|
||||
TopoDS_Compound comp;
|
||||
builder.MakeCompound(comp);
|
||||
int count = 0;
|
||||
for(auto &s : shapes) {
|
||||
if(s.isNull()) {
|
||||
WARN_NULL_INPUT;
|
||||
continue;
|
||||
}
|
||||
builder.Add(comp,s.getShape());
|
||||
++count;
|
||||
}
|
||||
if(!count)
|
||||
HANDLE_NULL_SHAPE;
|
||||
_Shape = comp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TopoShape &TopoShape::makEFace(const TopoShape &shape, const char *op, const char *maker)
|
||||
{
|
||||
std::vector<TopoShape> shapes;
|
||||
if(shape.getShape().ShapeType() == TopAbs_COMPOUND) {
|
||||
for(TopoDS_Iterator it(_Shape);it.More();it.Next())
|
||||
shapes.push_back(it.Value());
|
||||
} else
|
||||
shapes.push_back(shape);
|
||||
return makEFace(shapes,op,maker);
|
||||
}
|
||||
|
||||
TopoShape &TopoShape::makEFace(const std::vector<TopoShape> &shapes, const char *op, const char *maker)
|
||||
{
|
||||
(void)op;
|
||||
_Shape.Nullify();
|
||||
|
||||
if(!maker || !maker[0]) maker = "Part::FaceMakerBullseye";
|
||||
std::unique_ptr<FaceMaker> mkFace = FaceMaker::ConstructFromType(maker);
|
||||
for(auto &s : shapes) {
|
||||
if (s.getShape().ShapeType() == TopAbs_COMPOUND)
|
||||
mkFace->useCompound(TopoDS::Compound(s.getShape()));
|
||||
else
|
||||
mkFace->addShape(s.getShape());
|
||||
}
|
||||
mkFace->Build();
|
||||
_Shape = mkFace->Shape();
|
||||
return *this;
|
||||
}
|
||||
|
||||
TopoShape &TopoShape::makERefine(const TopoShape &shape, const char *op, bool no_fail) {
|
||||
(void)op;
|
||||
_Shape.Nullify();
|
||||
if(shape.isNull()) {
|
||||
if(!no_fail)
|
||||
HANDLE_NULL_SHAPE;
|
||||
return *this;
|
||||
}
|
||||
try {
|
||||
BRepBuilderAPI_RefineModel mkRefine(shape.getShape());
|
||||
_Shape = mkRefine.Shape();
|
||||
return *this;
|
||||
}catch (Standard_Failure &) {
|
||||
if(!no_fail) throw;
|
||||
}
|
||||
*this = shape;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool TopoShape::findPlane(gp_Pln &pln, double tol) const {
|
||||
if(_Shape.IsNull())
|
||||
return false;
|
||||
TopoDS_Shape shape = _Shape;
|
||||
TopExp_Explorer exp(_Shape,TopAbs_FACE);
|
||||
if(exp.More()) {
|
||||
auto face = exp.Current();
|
||||
exp.Next();
|
||||
if(!exp.More()) {
|
||||
BRepAdaptor_Surface adapt(TopoDS::Face(face));
|
||||
if(adapt.GetType() != GeomAbs_Plane)
|
||||
return false;
|
||||
pln = adapt.Plane();
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
TopExp_Explorer exp(_Shape,TopAbs_EDGE);
|
||||
if(exp.More()) {
|
||||
TopoDS_Shape edge = exp.Current();
|
||||
exp.Next();
|
||||
if(!exp.More()) {
|
||||
// To deal with OCCT bug of wrong edge transformation
|
||||
shape = BRepBuilderAPI_Copy(edge).Shape();
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
BRepLib_FindSurface finder(shape,tol,Standard_True);
|
||||
if (!finder.Found())
|
||||
return false;
|
||||
pln = GeomAdaptor_Surface(finder.Surface()).Plane();
|
||||
return true;
|
||||
}catch (Standard_Failure &e) {
|
||||
// For some reason the above BRepBuilderAPI_Copy failed to copy
|
||||
// the geometry of some edge, causing exception with message
|
||||
// BRepAdaptor_Curve::No geometry. However, without the above
|
||||
// copy, circular edges often have the wrong transformation!
|
||||
FC_LOG("failed to find surface: " << e.GetMessageString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TopoShape::isCoplanar(const TopoShape &other, double tol) const {
|
||||
if(isNull() || other.isNull())
|
||||
return false;
|
||||
if(_Shape.IsEqual(other._Shape))
|
||||
return true;
|
||||
gp_Pln pln1,pln2;
|
||||
if(!findPlane(pln1,tol) || !other.findPlane(pln2,tol))
|
||||
return false;
|
||||
if(tol<0.0)
|
||||
tol = Precision::Confusion();
|
||||
return pln1.Position().IsCoplanar(pln2.Position(),tol,tol);
|
||||
}
|
||||
|
||||
bool TopoShape::_makETransform(const TopoShape &shape,
|
||||
const Base::Matrix4D &rclTrf, const char *op, bool checkScale, bool copy)
|
||||
{
|
||||
if(checkScale) {
|
||||
if(rclTrf.hasScale()<0) {
|
||||
makEGTransform(shape,rclTrf,op,copy);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
makETransform(shape,convert(rclTrf),op,copy);
|
||||
return false;
|
||||
}
|
||||
|
||||
TopoShape &TopoShape::makETransform(const TopoShape &shape, const gp_Trsf &trsf, const char *op, bool copy) {
|
||||
// resetElementMap();
|
||||
|
||||
if(!copy) {
|
||||
// OCCT checks the ScaleFactor against gp::Resolution() which is DBL_MIN!!!
|
||||
copy = trsf.ScaleFactor()*trsf.HVectorialPart().Determinant() < 0. ||
|
||||
Abs(Abs(trsf.ScaleFactor()) - 1) > Precision::Confusion();
|
||||
}
|
||||
TopoShape tmp(shape);
|
||||
if(copy) {
|
||||
BRepBuilderAPI_Transform mkTrf(shape.getShape(), trsf, Standard_True);
|
||||
// TODO: calling Moved() is to make sure the shape has some Location,
|
||||
// which is necessary for STEP export to work. However, if we reach
|
||||
// here, it porabably means BRepBuilderAPI_Transform has modified
|
||||
// underlying shapes (because of scaling), it will break compound child
|
||||
// parent relationship anyway. In short, STEP import/export will most
|
||||
// likely break badly if there is any scaling involved
|
||||
tmp._Shape = mkTrf.Shape().Moved(gp_Trsf());
|
||||
}else
|
||||
tmp._Shape.Move(trsf);
|
||||
if(op || (shape.Tag && shape.Tag!=Tag)) {
|
||||
_Shape = tmp._Shape;
|
||||
// tmp.initCache(1);
|
||||
// mapSubElement(tmp,op);
|
||||
} else
|
||||
*this = tmp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TopoShape &TopoShape::makEGTransform(const TopoShape &shape,
|
||||
const Base::Matrix4D &rclTrf, const char *op, bool copy)
|
||||
{
|
||||
(void)op;
|
||||
gp_GTrsf mat;
|
||||
mat.SetValue(1,1,rclTrf[0][0]);
|
||||
mat.SetValue(2,1,rclTrf[1][0]);
|
||||
mat.SetValue(3,1,rclTrf[2][0]);
|
||||
mat.SetValue(1,2,rclTrf[0][1]);
|
||||
mat.SetValue(2,2,rclTrf[1][1]);
|
||||
mat.SetValue(3,2,rclTrf[2][1]);
|
||||
mat.SetValue(1,3,rclTrf[0][2]);
|
||||
mat.SetValue(2,3,rclTrf[1][2]);
|
||||
mat.SetValue(3,3,rclTrf[2][2]);
|
||||
mat.SetValue(1,4,rclTrf[0][3]);
|
||||
mat.SetValue(2,4,rclTrf[1][3]);
|
||||
mat.SetValue(3,4,rclTrf[2][3]);
|
||||
|
||||
// geometric transformation
|
||||
BRepBuilderAPI_GTransform mkTrf(shape.getShape(), mat, copy);
|
||||
_Shape = mkTrf.Shape();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user