Assembly: Enable the use of App::Datums
This commit is contained in:
@@ -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*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user