diff --git a/src/Mod/Fem/App/FemConstraint.cpp b/src/Mod/Fem/App/FemConstraint.cpp index 8609d1e722..2ea98ec940 100644 --- a/src/Mod/Fem/App/FemConstraint.cpp +++ b/src/Mod/Fem/App/FemConstraint.cpp @@ -147,18 +147,6 @@ float Constraint::getScaleFactor() const return Scale.getValue() * sizeFactor; } -void setSubShapeLocation(const Part::Feature* feat, TopoDS_Shape& sh) -{ - // subshape placement is not necessarily the same as the - // feature placement. - Base::Matrix4D matrix = Part::TopoShape::convert(sh.Location().Transformation()); - Base::Placement shPla {matrix}; - Base::Placement featlPlaInv = feat->Placement.getValue().inverse(); - Base::Placement shGlobalPla = feat->globalPlacement() * featlPlaInv * shPla; - - sh.Location(Part::Tools::fromPlacement(shGlobalPla)); -} - constexpr int CONSTRAINTSTEPLIMIT = 50; void Constraint::onChanged(const App::Property* prop) @@ -177,26 +165,20 @@ void Constraint::onChanged(const App::Property* prop) for (std::size_t i = 0; i < Objects.size(); i++) { App::DocumentObject* obj = Objects[i]; Part::Feature* feat = static_cast(obj); - const Part::TopoShape& toposhape = feat->Shape.getShape(); - if (!toposhape.getShape().IsNull()) { - sh = toposhape.getSubShape(SubElements[i].c_str(), !execute); - - if (!sh.IsNull() && sh.ShapeType() == TopAbs_FACE) { - setSubShapeLocation(feat, sh); - - // Get face normal in center point - TopoDS_Face face = TopoDS::Face(sh); - BRepGProp_Face props(face); - gp_Vec normal; - gp_Pnt center; - double u1, u2, v1, v2; - props.Bounds(u1, u2, v1, v2); - props.Normal((u1 + u2) / 2.0, (v1 + v2) / 2.0, center, normal); - normal.Normalize(); - NormalDirection.setValue(normal.X(), normal.Y(), normal.Z()); - // One face is enough... - break; - } + sh = Tools::getFeatureSubShape(feat, SubElements[i].c_str(), !execute); + if (!sh.IsNull() && sh.ShapeType() == TopAbs_FACE) { + // Get face normal in center point + TopoDS_Face face = TopoDS::Face(sh); + BRepGProp_Face props(face); + gp_Vec normal; + gp_Pnt center; + double u1, u2, v1, v2; + props.Bounds(u1, u2, v1, v2); + props.Normal((u1 + u2) / 2.0, (v1 + v2) / 2.0, center, normal); + normal.Normalize(); + NormalDirection.setValue(normal.X(), normal.Y(), normal.Z()); + // One face is enough... + break; } } @@ -274,22 +256,15 @@ bool Constraint::getPoints(std::vector& points, TopoDS_Shape sh; for (std::size_t i = 0; i < Objects.size(); i++) { - App::DocumentObject* obj = Objects[i]; - Part::Feature* feat = static_cast(obj); - const Part::TopoShape& toposhape = feat->Shape.getShape(); - if (toposhape.isNull()) { - return false; - } - - sh = toposhape.getSubShape(SubElements[i].c_str(), true); + Part::Feature* feat = static_cast(Objects[i]); + sh = Tools::getFeatureSubShape(feat, SubElements[i].c_str(), true); if (sh.IsNull()) { return false; } - setSubShapeLocation(feat, sh); // Scale by bounding box of the object Bnd_Box box; - BRepBndLib::Add(toposhape.getShape(), box); + BRepBndLib::Add(feat->Shape.getShape().getShape(), box); double l = sqrt(box.SquareExtent() / 3.0); *scale = this->calcSizeFactor(l); @@ -471,40 +446,6 @@ bool Constraint::getPoints(std::vector& points, return true; } -bool Constraint::getCylinder(double& radius, - double& height, - Base::Vector3d& base, - Base::Vector3d& axis) const -{ - std::vector Objects = References.getValues(); - std::vector SubElements = References.getSubValues(); - if (Objects.empty()) { - return false; - } - App::DocumentObject* obj = Objects[0]; - Part::Feature* feat = static_cast(obj); - const Part::TopoShape& toposhape = feat->Shape.getShape(); - if (toposhape.isNull()) { - return false; - } - TopoDS_Shape sh = toposhape.getSubShape(SubElements[0].c_str()); - - TopoDS_Face face = TopoDS::Face(sh); - BRepAdaptor_Surface surface(face); - gp_Cylinder cyl = surface.Cylinder(); - gp_Pnt start = surface.Value(surface.FirstUParameter(), surface.FirstVParameter()); - gp_Pnt end = surface.Value(surface.FirstUParameter(), surface.LastVParameter()); - height = start.Distance(end); - radius = cyl.Radius(); - - gp_Pnt b = cyl.Location(); - base = Base::Vector3d(b.X(), b.Y(), b.Z()); - gp_Dir dir = cyl.Axis().Direction(); - axis = Base::Vector3d(dir.X(), dir.Y(), dir.Z()); - - return true; -} - Base::Vector3d Constraint::getBasePoint(const Base::Vector3d& base, const Base::Vector3d& axis, const App::PropertyLinkSub& location, diff --git a/src/Mod/Fem/App/FemConstraint.h b/src/Mod/Fem/App/FemConstraint.h index 1c86166a89..1e70cf1b06 100644 --- a/src/Mod/Fem/App/FemConstraint.h +++ b/src/Mod/Fem/App/FemConstraint.h @@ -198,16 +198,6 @@ protected: std::vector& normals, double* scale) const; - /** - * @brief Extract properties of cylindrical face. - * - * @note - * This method is very specific and doesn't require access to member - * variables. It should be rewritten at a different place. - */ - bool - getCylinder(double& radius, double& height, Base::Vector3d& base, Base::Vector3d& axis) const; - /** * @brief Calculate point of cylindrical face where to render widget. * diff --git a/src/Mod/Fem/App/FemConstraintBearing.cpp b/src/Mod/Fem/App/FemConstraintBearing.cpp index 69a06a86c0..fb87cff984 100644 --- a/src/Mod/Fem/App/FemConstraintBearing.cpp +++ b/src/Mod/Fem/App/FemConstraintBearing.cpp @@ -32,7 +32,7 @@ #include #include "FemConstraintBearing.h" - +#include "FemTools.h" using namespace Fem; @@ -74,9 +74,17 @@ void ConstraintBearing::onChanged(const App::Property* prop) if (prop == &References) { // Find data of cylinder + std::vector ref = References.getValues(); + std::vector subRef = References.getSubValues(); + if (ref.empty()) { + return; + } + + Part::Feature* feat = static_cast(ref.front()); + TopoDS_Shape sh = Tools::getFeatureSubShape(feat, subRef.front().c_str(), true); double radius, height; Base::Vector3d base, axis; - if (!getCylinder(radius, height, base, axis)) { + if (!Tools::getCylinderParams(sh, base, axis, height, radius)) { return; } Radius.setValue(radius); @@ -113,12 +121,19 @@ void ConstraintBearing::onChanged(const App::Property* prop) } } - double radius, height; - Base::Vector3d base, axis; - if (!getCylinder(radius, height, base, axis)) { + std::vector ref = References.getValues(); + std::vector subRef = References.getSubValues(); + if (ref.empty()) { + return; + } + + feat = static_cast(ref.front()); + sh = Tools::getFeatureSubShape(feat, subRef.front().c_str(), true); + double radius, height; + Base::Vector3d base, axis; + if (!Tools::getCylinderParams(sh, base, axis, height, radius)) { return; } - base = getBasePoint(base + axis * height / 2, axis, Location, Dist.getValue()); BasePoint.setValue(base); BasePoint.touch(); } diff --git a/src/Mod/Fem/App/FemTools.cpp b/src/Mod/Fem/App/FemTools.cpp index 585e62c559..3739f2c42e 100644 --- a/src/Mod/Fem/App/FemTools.cpp +++ b/src/Mod/Fem/App/FemTools.cpp @@ -27,16 +27,19 @@ #include #include +#include #include #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -44,6 +47,8 @@ #endif #include +#include +#include #include "FemTools.h" @@ -322,3 +327,74 @@ std::string Fem::Tools::checkIfBinaryExists(std::string prefSection, } return ""; } + +Base::Placement Fem::Tools::getSubShapeGlobalLocation(const Part::Feature* feat, + const TopoDS_Shape& sh) +{ + Base::Matrix4D matrix = Part::TopoShape::convert(sh.Location().Transformation()); + Base::Placement shPla {matrix}; + Base::Placement featlPlaInv = feat->Placement.getValue().inverse(); + Base::Placement shGlobalPla = feat->globalPlacement() * featlPlaInv * shPla; + + return shGlobalPla; +} + +void Fem::Tools::setSubShapeGlobalLocation(const Part::Feature* feat, TopoDS_Shape& sh) +{ + Base::Placement pla = getSubShapeGlobalLocation(feat, sh); + sh.Location(Part::Tools::fromPlacement(pla)); +} + + +TopoDS_Shape +Fem::Tools::getFeatureSubShape(const Part::Feature* feat, const char* subName, bool silent) +{ + TopoDS_Shape sh; + const Part::TopoShape& toposhape = feat->Shape.getShape(); + if (toposhape.isNull()) { + return sh; + } + + sh = toposhape.getSubShape(subName, silent); + if (sh.IsNull()) { + return sh; + } + + setSubShapeGlobalLocation(feat, sh); + + return sh; +} + +bool Fem::Tools::getCylinderParams(const TopoDS_Shape& sh, + Base::Vector3d& base, + Base::Vector3d& axis, + double& height, + double& radius) +{ + TopoDS_Face face = TopoDS::Face(sh); + BRepAdaptor_Surface surface(face); + if (!(surface.GetType() == GeomAbs_Cylinder)) { + return false; + } + + gp_Cylinder cyl = surface.Cylinder(); + gp_Pnt start = surface.Value(surface.FirstUParameter(), surface.FirstVParameter()); + gp_Pnt end = surface.Value(surface.FirstUParameter(), surface.LastVParameter()); + + Handle(Geom_Curve) handle = new Geom_Line(cyl.Axis()); + GeomAPI_ProjectPointOnCurve proj(start, handle); + gp_XYZ startProj = proj.NearestPoint().XYZ(); + proj.Perform(end); + gp_XYZ endProj = proj.NearestPoint().XYZ(); + + gp_XYZ ax(endProj - startProj); + gp_XYZ center = (startProj + endProj) / 2.0; + gp_Dir dir(ax); + + height = ax.Modulus(); + radius = cyl.Radius(); + base = Base::Vector3d(center.X(), center.Y(), center.Z()); + axis = Base::Vector3d(dir.X(), dir.Y(), dir.Z()); + + return true; +} diff --git a/src/Mod/Fem/App/FemTools.h b/src/Mod/Fem/App/FemTools.h index d5397df0df..fd6388b1cc 100644 --- a/src/Mod/Fem/App/FemTools.h +++ b/src/Mod/Fem/App/FemTools.h @@ -24,14 +24,22 @@ #ifndef FEM_TOOLS_H #define FEM_TOOLS_H +#include #include #include #include +#include -class TopoDS_Shape; class TopoDS_Edge; class TopoDS_Face; +namespace Part +{ + +class Feature; + +} + namespace Fem { @@ -75,6 +83,27 @@ public: static std::string checkIfBinaryExists(std::string prefSection, std::string prefBinaryPath, std::string prefBinaryName); + + /*! + Subshape placement is not necessarily the same as the + feature placement + */ + static Base::Placement getSubShapeGlobalLocation(const Part::Feature* feat, + const TopoDS_Shape& sh); + static void setSubShapeGlobalLocation(const Part::Feature* feat, TopoDS_Shape& sh); + /*! + Get subshape from Part Feature. The subShape is returned with global location + */ + static TopoDS_Shape + getFeatureSubShape(const Part::Feature* feat, const char* subName, bool silent); + /*! + Get cylinder parameters. Base is located at the center of the cylinder + */ + static bool getCylinderParams(const TopoDS_Shape& sh, + Base::Vector3d& base, + Base::Vector3d& axis, + double& height, + double& radius); }; } // namespace Fem