diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index a3c3f94f33..728c604d00 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -1225,6 +1225,39 @@ public: } + /** Make a new shape with transformation that may contain non-uniform scaling + * + * @param source: input shape + * @param mat: transformation matrix + * @param op: optional string to be encoded into topo naming for indicating + * the operation + * @param copy: whether to perform deep copy of the shape. If false, the + * shape will still be copied if there is scaling. + * + * @return The original content of this TopoShape is discarded and replaced + * with the new transformed shape. The function returns the + * TopoShape itself as a self reference so that multiple operations + * can be carried out for the same shape in the same line of code. + */ + TopoShape &makeElementGTransform(const TopoShape &source, const Base::Matrix4D &mat, + const char *op=nullptr, bool copy=false); + + /** Make a new shape with transformation that may contain non-uniform scaling + * + * @param source: input shape + * @param mat: transformation matrix + * @param op: optional string to be encoded into topo naming for indicating + * the operation + * @param copy: whether to perform deep copy of the shape. If false, the + * shape will still be copied if there is scaling. + * + * @return Return a new shape with transformation. The shape itself is not + * modified + */ + TopoShape makeElementGTransform(const Base::Matrix4D &mat, const char *op=nullptr, bool copy=false) const { + return TopoShape(Tag,Hasher).makeElementGTransform(*this,mat,op,copy); + } + /** Make a deep copy of the shape * * @param source: input shape @@ -1313,6 +1346,109 @@ public: { return TopoShape(0, Hasher).makeElementBoolean(maker, *this, op, tol); } + + /** Make a new shape with transformation + * + * @param source: input shape + * @param mat: transformation matrix + * @param op: optional string to be encoded into topo naming for indicating + * the operation + * @param checkScale: whether to check if the transformation matrix + * contains scaling factor. + * @param copy: whether to perform deep copy of the shape. If false, and + * checkScale is true, then the shape will be copied if there + * is scaling. + * + * @return Returns true if scaling is performed. + * + * The original content of this TopoShape is discarded and replaced with + * the new transformed shape. + */ + bool _makeElementTransform(const TopoShape &source, const Base::Matrix4D &mat, + const char *op=nullptr, bool checkScale=false, bool copy=false); + + /** Make a new shape with transformation + * + * @param source: input shape + * @param mat: transformation matrix + * @param op: optional string to be encoded into topo naming for indicating + * the operation + * @param checkScale: whether to check if the transformation matrix + * contains scaling factor. + * @param copy: whether to perform deep copy of the shape. If false, and + * checkScale is true, then the shape will be copied if there + * is scaling. + * + * @return The original content of this TopoShape is discarded and replaced + * with the new transformed shape. The function returns the + * TopoShape itself as a self reference so that multiple operations + * can be carried out for the same shape in the same line of code. + */ + TopoShape &makeElementTransform(const TopoShape &source, const Base::Matrix4D &mat, + const char *op=nullptr, bool checkScale=false, bool copy=false) { + _makeElementTransform(source,mat,op,checkScale,copy); + return *this; + } + + /** Make a new shape with transformation + * + * @param source: input shape + * @param mat: transformation matrix + * @param op: optional string to be encoded into topo naming for indicating + * the operation + * @param checkScale: whether to check if the transformation matrix + * contains scaling factor. + * @param copy: whether to perform deep copy of the shape. If false, and + * checkScale is true, then the shape will be copied if there + * is scaling. + * + * @return Return a new shape with transformation. The shape itself is not + * modified + */ + TopoShape makeElementTransform(const Base::Matrix4D &mat, const char *op=nullptr, + bool checkScale=false, bool copy=false) const { + return TopoShape(Tag,Hasher).makeElementTransform(*this,mat,op,checkScale,copy); + } + + /** Make a new shape with transformation + * + * @param source: input shape + * @param trsf: OCCT transformation matrix + * @param op: optional string to be encoded into topo naming for indicating + * the operation + * @param checkScale: whether to check if the transformation matrix + * contains scaling factor. + * @param copy: whether to perform deep copy of the shape. If false, and + * checkScale is true, then the shape will be copied if there + * is scaling. + * + * @return The original content of this TopoShape is discarded and replaced + * with the new transformed shape. The function returns the + * TopoShape itself as a self reference so that multiple operations + * can be carried out for the same shape in the same line of code. + */ + TopoShape &makeElementTransform(const TopoShape &shape, const gp_Trsf &trsf, + const char *op=nullptr, bool copy=false); + + /** Make a new shape with transformation + * + * @param source: input shape + * @param trsf: OCCT transformation matrix + * @param op: optional string to be encoded into topo naming for indicating + * the operation + * @param checkScale: whether to check if the transformation matrix + * contains scaling factor. + * @param copy: whether to perform deep copy of the shape. If false, and + * checkScale is true, then the shape will be copied if there + * is scaling. + * + * @return Return a new shape with transformation. The shape itself is not + * modified + */ + TopoShape makeElementTransform(const gp_Trsf &trsf, const char *op=nullptr, bool copy=false) const { + return TopoShape(Tag,Hasher).makeElementTransform(*this,trsf,op,copy); + } + /* Make draft shape * * @param source: the source shape diff --git a/src/Mod/Part/App/TopoShapeExpansion.cpp b/src/Mod/Part/App/TopoShapeExpansion.cpp index a68ff8a85d..5caa9e64f3 100644 --- a/src/Mod/Part/App/TopoShapeExpansion.cpp +++ b/src/Mod/Part/App/TopoShapeExpansion.cpp @@ -82,6 +82,8 @@ #include #include +#include +#include #include "Geometry.h" FC_LOG_LEVEL_INIT("TopoShape", true, true) // NOLINT @@ -2450,6 +2452,88 @@ TopoShape& TopoShape::makeElementOrderedWires(const std::vector& shap return makeElementCompound(wires, nullptr, SingleShapeCompoundCreationPolicy::returnShape); } +bool TopoShape::_makeElementTransform(const TopoShape &shape, + const Base::Matrix4D &rclTrf, const char *op, bool checkScale, bool copy) +{ + if(checkScale) { + auto scaleType = rclTrf.hasScale(); + if (scaleType != Base::ScaleType::NoScaling && scaleType != Base::ScaleType::Uniform) { + makeElementGTransform(shape,rclTrf,op,copy); + return true; + } + } + makeElementTransform(shape,convert(rclTrf),op,copy); + return false; +} + +TopoShape &TopoShape::makeElementTransform(const TopoShape &shape, const gp_Trsf &trsf, const char *op, bool copy) { + 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) { + if(shape.isNull()) + FC_THROWM(NullShapeException, "Null input shape"); + + 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.setShape(mkTrf.Shape().Moved(gp_Trsf()), false); + } else + tmp.move(trsf); + + if(op || (shape.Tag && shape.Tag!=Tag)) { + setShape(tmp._Shape); + initCache(); + if (!Hasher) + Hasher = tmp.Hasher; + copyElementMap(tmp, op); + } else + *this = tmp; + return *this; +} + +TopoShape &TopoShape::makeElementGTransform(const TopoShape &shape, + const Base::Matrix4D &rclTrf, const char *op, bool copy) +{ + if(shape.isNull()) + FC_THROWM(NullShapeException, "Null input shape"); + + // if(!op) op = Part::OpCodes::Gtransform; + 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 + TopoShape tmp(shape); + BRepBuilderAPI_GTransform mkTrf(shape.getShape(), mat, copy); + tmp.setShape(mkTrf.Shape(), false); + if(op || (shape.Tag && shape.Tag!=Tag)) { + setShape(tmp._Shape); + initCache(); + if (!Hasher) + Hasher = tmp.Hasher; + copyElementMap(tmp, op); + } else + *this = tmp; + return *this; +} TopoShape& TopoShape::makeElementCopy(const TopoShape& shape, const char* op, bool copyGeom, bool copyMesh)