diff --git a/src/Mod/Fem/App/FemConstraint.cpp b/src/Mod/Fem/App/FemConstraint.cpp index 606e373b92..816151f7bc 100644 --- a/src/Mod/Fem/App/FemConstraint.cpp +++ b/src/Mod/Fem/App/FemConstraint.cpp @@ -55,16 +55,19 @@ #endif #endif +#include #include #include #include #include +#include #include "FemConstraint.h" #include "FemTools.h" using namespace Fem; +namespace sp = std::placeholders; #if OCC_VERSION_HEX >= 0x070600 using Adaptor3d_HSurface = Adaptor3d_Surface; @@ -140,6 +143,18 @@ int Constraint::calcDrawScaleFactor() const return 1; } +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) @@ -163,6 +178,8 @@ void Constraint::onChanged(const App::Property* prop) 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); @@ -193,6 +210,37 @@ void Constraint::onChanged(const App::Property* prop) App::DocumentObject::onChanged(prop); } +void Constraint::slotChangedObject(const App::DocumentObject& obj, const App::Property& prop) +{ + if (obj.isDerivedFrom() + && (prop.isDerivedFrom() || obj.isRemoving())) { + auto values = References.getValues(); + for (const auto ref : values) { + auto v = ref->getInListEx(true); + if ((&obj == ref) || (std::find(v.begin(), v.end(), &obj) != v.end())) { + this->touch(); + return; + } + } + } +} + +void Constraint::onSettingDocument() +{ + App::Document* doc = getDocument(); + if (doc) { + connDocChangedObject = doc->signalChangedObject.connect( + std::bind(&Constraint::slotChangedObject, this, sp::_1, sp::_2)); + } + + App::DocumentObject::onSettingDocument(); +} + +void Constraint::unsetupObject() +{ + connDocChangedObject.disconnect(); +} + void Constraint::onDocumentRestored() { // This seems to be the only way to make the ViewProvider display the constraint @@ -223,6 +271,8 @@ bool Constraint::getPoints(std::vector& points, return false; } + setSubShapeLocation(feat, sh); + if (sh.ShapeType() == TopAbs_VERTEX) { const TopoDS_Vertex& vertex = TopoDS::Vertex(sh); gp_Pnt p = BRep_Tool::Pnt(vertex); diff --git a/src/Mod/Fem/App/FemConstraint.h b/src/Mod/Fem/App/FemConstraint.h index dba4804af3..9542f00f43 100644 --- a/src/Mod/Fem/App/FemConstraint.h +++ b/src/Mod/Fem/App/FemConstraint.h @@ -179,6 +179,8 @@ protected: * of FemConstraint. */ void onDocumentRestored() override; + void onSettingDocument() override; + void unsetupObject() override; /** * @brief Returns data based on References relevant for rendering widgets. @@ -247,6 +249,10 @@ protected: * variables. It should be rewritten at a different place. */ const Base::Vector3d getDirection(const App::PropertyLinkSub& direction); + +private: + void slotChangedObject(const App::DocumentObject& Obj, const App::Property& Prop); + boost::signals2::connection connDocChangedObject; }; using ConstraintPython = App::FeaturePythonT; diff --git a/src/Mod/Fem/femmesh/gmshtools.py b/src/Mod/Fem/femmesh/gmshtools.py index 604ce5db0f..b29114ada9 100644 --- a/src/Mod/Fem/femmesh/gmshtools.py +++ b/src/Mod/Fem/femmesh/gmshtools.py @@ -717,7 +717,12 @@ class GmshTools(): geo.write("// no boundary layer settings for this mesh\n") def write_part_file(self): - self.part_obj.Shape.exportBrep(self.temp_file_geometry) + global_pla = self.part_obj.getGlobalPlacement() + geom = self.part_obj.getPropertyOfGeometry() + # get partner shape + geom_trans = geom.transformed(FreeCAD.Placement().Matrix) + geom_trans.Placement = global_pla + geom_trans.exportBrep(self.temp_file_geometry) def write_geo(self): temp_dir = os.path.dirname(self.temp_file_geo) diff --git a/src/Mod/Fem/femmesh/meshtools.py b/src/Mod/Fem/femmesh/meshtools.py index f694f1d3c6..7fc8bd26f0 100644 --- a/src/Mod/Fem/femmesh/meshtools.py +++ b/src/Mod/Fem/femmesh/meshtools.py @@ -116,8 +116,7 @@ def get_femnodes_by_refshape( ): nodes = [] for refelement in ref[1]: - # the following method getElement(element) does not return Solid elements - r = geomtools.get_element(ref[0], refelement) + r = sub_shape_at_global_placement(ref[0], refelement) FreeCAD.Console.PrintMessage( " " "ReferenceShape ... Type: {0}, " @@ -1127,7 +1126,7 @@ def get_force_obj_face_nodeload_table( sum_node_load = 0 # for debugging for o, elem_tup in frc_obj.References: for elem in elem_tup: - ref_face = o.Shape.getElement(elem) + ref_face = sub_shape_at_global_placement(o, elem) FreeCAD.Console.PrintMessage( " " "ReferenceShape ... Type: {0}, " @@ -1142,7 +1141,7 @@ def get_force_obj_face_nodeload_table( force_per_sum_ref_face_area = force_quantity / sum_ref_face_area for o, elem_tup in frc_obj.References: for elem in elem_tup: - ref_face = o.Shape.getElement(elem) + ref_face = sub_shape_at_global_placement(o, elem) # face_table: # { meshfaceID : ( nodeID, ... , nodeID ) } @@ -1666,15 +1665,15 @@ def get_pressure_obj_faces( # How to find the orientation of a FEM mesh face? # https://forum.freecad.org/viewtopic.php?f=18&t=51898 else: - for sh, elems in femobj["Object"].References: + for obj, elems in femobj["Object"].References: for e in elems: - meshfaces = femmesh.getFacesByFace(sh.getSubObject(e)) + ref_face = sub_shape_at_global_placement(obj, e) + meshfaces = femmesh.getFacesByFace(ref_face) for mf in meshfaces: pressure_faces.append([mf, -1]) return pressure_faces - # ***** deprecated method for retrieving pressure faces ***************************************** # for constraint pressure and finite solid element mesh # it was switched to the method get_ccxelement_faces_from_binary_search @@ -1996,21 +1995,13 @@ def get_reference_group_elements( else: key = obj.Name elements = [] - stype = None for r in obj.References: parent = r[0] childs = r[1] # FreeCAD.Console.PrintMessage("{}\n".format(parent)) # FreeCAD.Console.PrintMessage("{}\n".format(childs)) for child in childs: - # the method getElement(element) does not return Solid elements - ref_shape = geomtools.get_element(parent, child) - if not stype: - stype = ref_shape.ShapeType - elif stype != ref_shape.ShapeType: - FreeCAD.Console.PrintError( - "Error, two refshapes in References with different ShapeTypes.\n" - ) + ref_shape = parent.getSubObject(child) FreeCAD.Console.PrintLog("{}\n".format(ref_shape)) found_element = geomtools.find_element_in_shape(aShape, ref_shape) if found_element is not None: @@ -2527,4 +2518,15 @@ def beam_reduced_integration( f.truncate() f.close() + +# ************************************************************************************************ +def sub_shape_at_global_placement(obj, sub_name): + sub_sh = obj.getSubObject(sub_name) + # get partner shape + partner = sub_sh.transformed(FreeCAD.Placement().Matrix) + partner.Placement = obj.getGlobalPlacement() \ + * obj.Placement.inverse() \ + * sub_sh.Placement + + return partner ## @}