Assembly: Enable the use of App::Datums

This commit is contained in:
PaddleStroke
2024-10-15 18:37:34 +02:00
parent 9bfb0e3a5d
commit 1806857c42
7 changed files with 95 additions and 144 deletions

View File

@@ -33,6 +33,7 @@
#include <chrono>
#include <App/Application.h>
#include <App/Datums.h>
#include <App/Document.h>
#include <App/DocumentObjectGroup.h>
#include <App/FeaturePythonPyImp.h>
@@ -45,6 +46,7 @@
#include <Base/Interpreter.h>
#include <Mod/Part/App/TopoShape.h>
#include <Mod/Part/App/AttachExtension.h>
#include <OndselSolver/CREATE.h>
#include <OndselSolver/ASMTSimulationParameters.h>
@@ -92,6 +94,9 @@ FC_LOG_LEVEL_INIT("Assembly", true, true, true)
using namespace Assembly;
using namespace MbD;
namespace PartApp = Part;
/*
static void printPlacement(Base::Placement plc, const char* name)
{
@@ -370,7 +375,8 @@ Base::Placement AssemblyObject::getMbdPlacement(std::shared_ptr<ASMTPart> mbdPar
bool AssemblyObject::validateNewPlacements()
{
// First we check if a grounded object has moved. It can happen that they flip.
for (auto* obj : getGroundedParts()) {
std::vector<App::DocumentObject*> groundedParts = getGroundedParts();
for (auto* obj : groundedParts) {
auto* propPlacement =
dynamic_cast<App::PropertyPlacement*>(obj->getPropertyByName("Placement"));
if (propPlacement) {
@@ -386,7 +392,8 @@ bool AssemblyObject::validateNewPlacements()
if (!oldPlc.isSame(newPlacement)) {
Base::Console().Warning(
"Assembly : Ignoring bad solve, a grounded object moved.\n");
"Assembly : Ignoring bad solve, a grounded object (%s) moved.\n",
obj->getFullLabel());
return false;
}
}
@@ -783,34 +790,54 @@ std::vector<App::DocumentObject*> AssemblyObject::getGroundedParts()
if (propObj) {
App::DocumentObject* objToGround = propObj->getValue();
groundedObjs.push_back(objToGround);
if (objToGround) {
if (std::find(groundedObjs.begin(), groundedObjs.end(), objToGround)
== groundedObjs.end()) {
groundedObjs.push_back(objToGround);
}
}
}
}
// We also need to add all the root-level datums objects that are not attached.
std::vector<App::DocumentObject*> objs = Group.getValues();
for (auto* obj : objs) {
if (obj->isDerivedFrom<App::LocalCoordinateSystem>()
|| obj->isDerivedFrom<App::DatumElement>()) {
auto* pcAttach = obj->getExtensionByType<PartApp::AttachExtension>();
if (pcAttach) {
// If it's a Part datums, we check if it's attached. If yes then we ignore it.
std::string mode = pcAttach->MapMode.getValueAsString();
if (mode != "Deactivated") {
continue;
}
}
if (std::find(groundedObjs.begin(), groundedObjs.end(), obj) == groundedObjs.end()) {
groundedObjs.push_back(obj);
}
}
}
// Origin is not in Group so we add it separately
groundedObjs.push_back(Origin.getValue());
return groundedObjs;
}
std::vector<App::DocumentObject*> AssemblyObject::fixGroundedParts()
{
std::vector<App::DocumentObject*> groundedJoints = getGroundedJoints();
std::vector<App::DocumentObject*> groundedParts = getGroundedParts();
std::vector<App::DocumentObject*> groundedObjs;
for (auto obj : groundedJoints) {
for (auto obj : groundedParts) {
if (!obj) {
continue;
}
auto* propObj = dynamic_cast<App::PropertyLink*>(obj->getPropertyByName("ObjectToGround"));
if (propObj) {
App::DocumentObject* objToGround = propObj->getValue();
Base::Placement plc = getPlacementFromProp(obj, "Placement");
std::string str = obj->getFullName();
fixGroundedPart(objToGround, plc, str);
groundedObjs.push_back(objToGround);
}
Base::Placement plc = getPlacementFromProp(obj, "Placement");
std::string str = obj->getFullName();
fixGroundedPart(obj, plc, str);
}
return groundedObjs;
return groundedParts;
}
void AssemblyObject::fixGroundedPart(App::DocumentObject* obj,
@@ -1984,29 +2011,6 @@ std::vector<AssemblyLink*> AssemblyObject::getSubAssemblies()
return subAssemblies;
}
void AssemblyObject::updateGroundedJointsPlacements()
{
std::vector<App::DocumentObject*> groundedJoints = getGroundedJoints();
for (auto gJoint : groundedJoints) {
if (!gJoint) {
continue;
}
auto* propObj =
dynamic_cast<App::PropertyLink*>(gJoint->getPropertyByName("ObjectToGround"));
auto* propPlc =
dynamic_cast<App::PropertyPlacement*>(gJoint->getPropertyByName("Placement"));
if (propObj && propPlc) {
App::DocumentObject* obj = propObj->getValue();
auto* propObjPlc =
dynamic_cast<App::PropertyPlacement*>(obj->getPropertyByName("Placement"));
propPlc->setValue(propObjPlc->getValue());
}
}
}
void AssemblyObject::ensureIdentityPlacements()
{
std::vector<App::DocumentObject*> group = Group.getValues();
@@ -2037,36 +2041,3 @@ void AssemblyObject::ensureIdentityPlacements()
}
}
}
/*void Part::handleChangedPropertyType(Base::XMLReader& reader, const char* TypeName, App::Property*
prop)
{
App::Part::handleChangedPropertyType(reader, TypeName, prop);
}*/
/* Apparently not necessary as App::Part doesn't have this.
// Python Assembly feature ---------------------------------------------------------
namespace App
{
/// @cond DOXERR
PROPERTY_SOURCE_TEMPLATE(Assembly::AssemblyObjectPython, Assembly::AssemblyObject)
template<>
const char* Assembly::AssemblyObjectPython::getViewProviderName() const
{
return "AssemblyGui::ViewProviderAssembly";
}
template<>
PyObject* Assembly::AssemblyObjectPython::getPyObject()
{
if (PythonObject.is(Py::_None())) {
// ref counter is set to 1
PythonObject = Py::Object(new FeaturePythonPyT<AssemblyObjectPy>(this), true);
}
return Py::new_reference_to(PythonObject);
}
/// @endcond
// explicit template instantiation
template class AssemblyExport FeaturePythonT<Assembly::AssemblyObject>;
}// namespace App*/

View File

@@ -186,7 +186,6 @@ public:
void setObjMasses(std::vector<std::pair<App::DocumentObject*, double>> objectMasses);
std::vector<AssemblyLink*> getSubAssemblies();
void updateGroundedJointsPlacements();
std::vector<App::DocumentObject*> getMotionsFromSimulation(App::DocumentObject* sim);

View File

@@ -33,6 +33,7 @@
#endif
#include <App/Application.h>
#include <App/Datums.h>
#include <App/Document.h>
#include <App/DocumentObject.h>
#include <App/PropertyStandard.h>
@@ -536,7 +537,9 @@ App::DocumentObject* getObjFromRef(const App::DocumentObject* obj, const std::st
// getViewProviderName instead of isDerivedFrom to avoid dependency on sketcher
const auto isDerivedFromVpSketch =
strcmp(obj->getViewProviderName(), "SketcherGui::ViewProviderSketch") == 0;
return isDerivedFromVpSketch || obj->isDerivedFrom<PartApp::Datum>();
return isDerivedFromVpSketch || obj->isDerivedFrom<PartApp::Datum>()
|| obj->isDerivedFrom<App::DatumElement>()
|| obj->isDerivedFrom<App::LocalCoordinateSystem>();
};
// Helper function to handle PartDesign::Body objects

View File

@@ -47,11 +47,7 @@ def noOtherTaskActive():
def isCreateJointActive():
return (
UtilsAssembly.isAssemblyGrounded()
and UtilsAssembly.assembly_has_at_least_n_parts(2)
and noOtherTaskActive()
)
return UtilsAssembly.assembly_has_at_least_n_parts(1) and noOtherTaskActive()
def activateJoint(index):

View File

@@ -233,12 +233,6 @@ bool ViewProviderAssembly::setEdit(int mode)
PARTKEY,
this->getObject()->getNameInDocument());
// When we set edit, we update the grounded joints placements to support :
// - If user transformed the grounded object
// - For nested assemblies where the grounded object moves around.
auto* assembly = getObject<AssemblyObject>();
assembly->updateGroundedJointsPlacements();
setDragger();
attachSelection();

View File

@@ -956,18 +956,6 @@ class GroundedJoint:
joint.ObjectToGround = obj_to_ground
joint.addProperty(
"App::PropertyPlacement",
"Placement",
"Ground",
QT_TRANSLATE_NOOP(
"App::Property",
"This is where the part is grounded.",
),
)
joint.Placement = obj_to_ground.Placement
def dumps(self):
return None
@@ -1160,24 +1148,33 @@ class MakeJointSelGate:
return False
ref = [obj, [sub]]
selected_object = UtilsAssembly.getObject(ref)
sel_obj = UtilsAssembly.getObject(ref)
if not (
selected_object.isDerivedFrom("Part::Feature")
or selected_object.isDerivedFrom("App::Part")
if UtilsAssembly.isLink(sel_obj):
linked = sel_obj.getLinkedObject()
if linked == sel_obj:
return True # We accept empty links
sel_obj = linked
if sel_obj.isDerivedFrom("Part::Feature") or sel_obj.isDerivedFrom("App::Part"):
return True
if sel_obj.isDerivedFrom("App::LocalCoordinateSystem") or sel_obj.isDerivedFrom(
"App::DatumElement"
):
if UtilsAssembly.isLink(selected_object):
linked = selected_object.getLinkedObject()
if linked == selected_object:
# We accept empty links
return True
datum = sel_obj
if datum.isDerivedFrom("App::DatumElement"):
parent = datum.getParent()
if parent.isDerivedFrom("App::LocalCoordinateSystem"):
datum = parent
if not (linked.isDerivedFrom("Part::Feature") or linked.isDerivedFrom("App::Part")):
return False
else:
return False
if self.assembly.hasObject(datum) and hasattr(datum, "MapMode"):
# accept only datum that are not attached
return datum.MapMode == "Deactivated"
return True
return True
return False
activeTask = None

View File

@@ -161,6 +161,21 @@ def getObject(ref):
if obj.TypeId in {"App::Part", "Assembly::AssemblyObject"} or isLinkGroup(obj):
continue
elif obj.isDerivedFrom("App::LocalCoordinateSystem"):
# 2 cases possible, either we have the LCS itself: "part.LCS."
# or we have a datum: "part.LCS.X_Axis"
if i + 1 < len(names):
obj2 = None
for obji in obj.OutList:
if obji.Name == names[i + 1]:
obj2 = obji
break
if obj2 and obj2.isDerivedFrom("App::DatumElement"):
return obj2
elif obj.isDerivedFrom("App::DatumElement"):
return obj
elif obj.TypeId == "PartDesign::Body":
if i + 1 < len(names):
obj2 = None
@@ -168,7 +183,7 @@ def getObject(ref):
if obji.Name == names[i + 1]:
obj2 = obji
break
if obj2 and isBodySubObject(obj2.TypeId):
if obj2 and isBodySubObject(obj2):
return obj2
return obj
@@ -185,7 +200,7 @@ def getObject(ref):
if obji.Name == names[i + 1]:
obj2 = obji
break
if obj2 and isBodySubObject(obj2.TypeId):
if obj2 and isBodySubObject(obj2):
return obj2
return obj
elif linked_obj.isDerivedFrom("Part::Feature"):
@@ -197,13 +212,12 @@ def getObject(ref):
return None
def isBodySubObject(typeId):
def isBodySubObject(obj):
return (
typeId == "Sketcher::SketchObject"
or typeId == "PartDesign::Point"
or typeId == "PartDesign::Line"
or typeId == "PartDesign::Plane"
or typeId == "PartDesign::CoordinateSystem"
obj.isDerivedFrom("Sketcher::SketchObject")
or obj.isDerivedFrom("PartDesign::Datum")
or obj.isDerivedFrom("App::DatumElement")
or obj.isDerivedFrom("App::LocalCoordinateSystem")
)
@@ -348,21 +362,6 @@ def getElementName(full_name):
if parts[-1] in {"X", "Y", "Z", "Point", "Line", "Plane"}:
return ""
# Case of origin objects
if parts[-1] == "":
if "X_Axis" in parts[-2]:
return "X_Axis"
if "Y_Axis" in parts[-2]:
return "Y_Axis"
if "Z_Axis" in parts[-2]:
return "Z_Axis"
if "XY_Plane" in parts[-2]:
return "XY_Plane"
if "XZ_Plane" in parts[-2]:
return "XZ_Plane"
if "YZ_Plane" in parts[-2]:
return "YZ_Plane"
return parts[-1]
@@ -946,16 +945,8 @@ def findPlacement(ref, ignoreVertex=False):
elt = getElementName(ref[1][0])
vtx = getElementName(ref[1][1])
# case of origin objects.
if elt == "X_Axis" or elt == "YZ_Plane":
return App.Placement(App.Vector(), App.Rotation(App.Vector(0, 1, 0), -90))
if elt == "Y_Axis" or elt == "XZ_Plane":
return App.Placement(App.Vector(), App.Rotation(App.Vector(1, 0, 0), 90))
if elt == "Z_Axis" or elt == "XY_Plane":
return App.Placement()
if not elt or not vtx:
# case of whole parts such as PartDesign::Body or PartDesign::CordinateSystem/Point/Line/Plane.
# case of whole parts such as PartDesign::Body or App/PartDesign::CordinateSystem/Point/Line/Plane.
return App.Placement()
plc = App.Placement()