Fem: Update constraint symbols when moving reference shape - fixes #6093

This commit is contained in:
marioalexis
2024-02-20 19:16:27 -03:00
parent 6132f25fdf
commit 5938489654
4 changed files with 80 additions and 17 deletions

View File

@@ -55,16 +55,19 @@
#endif
#endif
#include <App/Document.h>
#include <App/DocumentObjectPy.h>
#include <App/FeaturePythonPyImp.h>
#include <App/OriginFeature.h>
#include <Mod/Part/App/PartFeature.h>
#include <Mod/Part/App/Tools.h>
#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<App::GeoFeature>()
&& (prop.isDerivedFrom<App::PropertyPlacement>() || 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<Base::Vector3d>& 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);

View File

@@ -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<Constraint>;

View File

@@ -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)

View File

@@ -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
## @}