24
#include "PreCompiled.h"
26
#include <BRepAdaptor_Curve.hxx>
27
#include <BRepAdaptor_Surface.hxx>
29
#include <TopoDS_Face.hxx>
31
#include <gp_Cylinder.hxx>
32
#include <gp_Sphere.hxx>
35
#include <unordered_map>
38
#include <App/Application.h>
39
#include <App/Document.h>
40
#include <App/DocumentObjectGroup.h>
41
#include <App/FeaturePythonPyImp.h>
43
#include <App/PropertyPythonObject.h>
44
#include <Base/Console.h>
45
#include <Base/Placement.h>
46
#include <Base/Rotation.h>
47
#include <Base/Tools.h>
48
#include <Base/Interpreter.h>
50
#include <Mod/Part/App/PartFeature.h>
51
#include <Mod/Part/App/TopoShape.h>
52
#include <Mod/PartDesign/App/Body.h>
54
#include <OndselSolver/CREATE.h>
55
#include <OndselSolver/ASMTSimulationParameters.h>
56
#include <OndselSolver/ASMTAssembly.h>
57
#include <OndselSolver/ASMTMarker.h>
58
#include <OndselSolver/ASMTPart.h>
59
#include <OndselSolver/ASMTJoint.h>
60
#include <OndselSolver/ASMTFixedJoint.h>
61
#include <OndselSolver/ASMTRevoluteJoint.h>
62
#include <OndselSolver/ASMTCylindricalJoint.h>
63
#include <OndselSolver/ASMTTranslationalJoint.h>
64
#include <OndselSolver/ASMTSphericalJoint.h>
65
#include <OndselSolver/ASMTPointInPlaneJoint.h>
66
#include <OndselSolver/ASMTPointInLineJoint.h>
67
#include <OndselSolver/ASMTLineInPlaneJoint.h>
68
#include <OndselSolver/ASMTPlanarJoint.h>
69
#include <OndselSolver/ASMTRevCylJoint.h>
70
#include <OndselSolver/ASMTCylSphJoint.h>
71
#include <OndselSolver/ASMTSphSphJoint.h>
72
#include <OndselSolver/ASMTTime.h>
73
#include <OndselSolver/ASMTConstantGravity.h>
75
#include "AssemblyObject.h"
76
#include "AssemblyObjectPy.h"
77
#include "JointGroup.h"
79
namespace PartApp = Part;
81
using namespace Assembly;
86
PROPERTY_SOURCE(Assembly::AssemblyObject, App::Part)
88
AssemblyObject::AssemblyObject()
89
: mbdAssembly(std::make_shared<ASMTAssembly>())
92
AssemblyObject::~AssemblyObject() = default;
94
PyObject* AssemblyObject::getPyObject()
96
if (PythonObject.is(Py::_None())) {
98
PythonObject = Py::Object(new AssemblyObjectPy(this), true);
100
return Py::new_reference_to(PythonObject);
104
int AssemblyObject::solve(bool enableRedo)
106
mbdAssembly = makeMbdAssembly();
107
objectPartMap.clear();
109
std::vector<App::DocumentObject*> groundedObjs = fixGroundedParts();
110
if (groundedObjs.empty()) {
115
std::vector<App::DocumentObject*> joints = getJoints();
117
removeUnconnectedJoints(joints, groundedObjs);
122
savePlacementsForUndo();
126
mbdAssembly->solve();
129
Base::Console().Error("Solve failed\n");
135
redrawJointPlacements(joints);
140
void AssemblyObject::preDrag(std::vector<App::DocumentObject*> dragParts)
144
dragMbdParts.clear();
145
for (auto part : dragParts) {
146
dragMbdParts.push_back(getMbDPart(part));
149
mbdAssembly->runPreDrag();
152
void AssemblyObject::doDragStep()
154
for (auto& mbdPart : dragMbdParts) {
155
App::DocumentObject* part = nullptr;
156
for (auto& pair : objectPartMap) {
157
if (pair.second == mbdPart) {
166
Base::Placement plc = getPlacementFromProp(part, "Placement");
167
Base::Vector3d pos = plc.getPosition();
168
mbdPart->setPosition3D(pos.x, pos.y, pos.z);
170
Base::Rotation rot = plc.getRotation();
173
Base::Vector3d r0 = mat.getRow(0);
174
Base::Vector3d r1 = mat.getRow(1);
175
Base::Vector3d r2 = mat.getRow(2);
176
mbdPart->setRotationMatrix(r0.x, r0.y, r0.z, r1.x, r1.y, r1.z, r2.x, r2.y, r2.z);
179
auto dragPartsVec = std::make_shared<std::vector<std::shared_ptr<ASMTPart>>>(dragMbdParts);
180
mbdAssembly->runDragStep(dragPartsVec);
182
redrawJointPlacements(getJoints());
185
void AssemblyObject::postDrag()
187
mbdAssembly->runPostDrag();
190
void AssemblyObject::savePlacementsForUndo()
192
previousPositions.clear();
194
for (auto& pair : objectPartMap) {
195
App::DocumentObject* obj = pair.first;
200
std::pair<App::DocumentObject*, Base::Placement> savePair;
201
savePair.first = obj;
204
auto* propPlc = dynamic_cast<App::PropertyPlacement*>(obj->getPropertyByName("Placement"));
208
savePair.second = propPlc->getValue();
210
previousPositions.push_back(savePair);
214
void AssemblyObject::undoSolve()
216
if (previousPositions.size() == 0) {
220
for (auto& pair : previousPositions) {
221
App::DocumentObject* obj = pair.first;
227
auto* propPlacement =
228
dynamic_cast<App::PropertyPlacement*>(obj->getPropertyByName("Placement"));
229
if (!propPlacement) {
233
propPlacement->setValue(pair.second);
235
previousPositions.clear();
241
void AssemblyObject::clearUndo()
243
previousPositions.clear();
246
void AssemblyObject::exportAsASMT(std::string fileName)
248
mbdAssembly = makeMbdAssembly();
249
objectPartMap.clear();
252
std::vector<App::DocumentObject*> joints = getJoints();
256
mbdAssembly->outputFile(fileName);
259
void AssemblyObject::setNewPlacements()
261
for (auto& pair : objectPartMap) {
262
App::DocumentObject* obj = pair.first;
263
std::shared_ptr<ASMTPart> mbdPart = pair.second;
265
if (!obj || !mbdPart) {
270
auto* propPlacement =
271
dynamic_cast<App::PropertyPlacement*>(obj->getPropertyByName("Placement"));
272
if (!propPlacement) {
277
mbdPart->getPosition3D(x, y, z);
279
Base::Vector3d pos = Base::Vector3d(x, y, z);
282
auto& r0 = mbdPart->rotationMatrix->at(0);
283
auto& r1 = mbdPart->rotationMatrix->at(1);
284
auto& r2 = mbdPart->rotationMatrix->at(2);
285
Base::Vector3d row0 = Base::Vector3d(r0->at(0), r0->at(1), r0->at(2));
286
Base::Vector3d row1 = Base::Vector3d(r1->at(0), r1->at(1), r1->at(2));
287
Base::Vector3d row2 = Base::Vector3d(r2->at(0), r2->at(1), r2->at(2));
292
Base::Rotation rot = Base::Rotation(mat);
298
Base::Placement newPlacement = Base::Placement(pos, rot);
300
propPlacement->setValue(newPlacement);
304
void AssemblyObject::redrawJointPlacements(std::vector<App::DocumentObject*> joints)
307
for (auto* joint : joints) {
308
auto* propPlacement =
309
dynamic_cast<App::PropertyPlacement*>(joint->getPropertyByName("Placement1"));
311
propPlacement->setValue(propPlacement->getValue());
314
dynamic_cast<App::PropertyPlacement*>(joint->getPropertyByName("Placement2"));
316
propPlacement->setValue(propPlacement->getValue());
321
void AssemblyObject::recomputeJointPlacements(std::vector<App::DocumentObject*> joints)
324
for (auto* joint : joints) {
325
App::PropertyPythonObject* proxy = joint
326
? dynamic_cast<App::PropertyPythonObject*>(joint->getPropertyByName("Proxy"))
333
Py::Object jointPy = proxy->getValue();
335
if (!jointPy.hasAttr("updateJCSPlacements")) {
339
Py::Object attr = jointPy.getAttr("updateJCSPlacements");
340
if (attr.ptr() && attr.isCallable()) {
342
args.setItem(0, Py::asObject(joint->getPyObject()));
343
Py::Callable(attr).apply(args);
348
std::shared_ptr<ASMTAssembly> AssemblyObject::makeMbdAssembly()
350
auto assembly = CREATE<ASMTAssembly>::With();
351
assembly->setName("OndselAssembly");
356
App::DocumentObject* AssemblyObject::getJointOfPartConnectingToGround(App::DocumentObject* part,
359
std::vector<App::DocumentObject*> joints = getJointsOfPart(part);
361
for (auto joint : joints) {
365
App::DocumentObject* part1 = getLinkObjFromProp(joint, "Part1");
366
App::DocumentObject* part2 = getLinkObjFromProp(joint, "Part2");
367
if (!part1 || !part2) {
371
if (part == part1 && isJointConnectingPartToGround(joint, "Part1")) {
375
if (part == part2 && isJointConnectingPartToGround(joint, "Part2")) {
384
JointGroup* AssemblyObject::getJointGroup()
386
App::Document* doc = getDocument();
388
std::vector<DocumentObject*> jointGroups =
389
doc->getObjectsOfType(Assembly::JointGroup::getClassTypeId());
390
if (jointGroups.empty()) {
393
for (auto jointGroup : jointGroups) {
394
if (hasObject(jointGroup)) {
395
return dynamic_cast<JointGroup*>(jointGroup);
401
std::vector<App::DocumentObject*> AssemblyObject::getJoints(bool updateJCS)
403
std::vector<App::DocumentObject*> joints = {};
405
JointGroup* jointGroup = getJointGroup();
410
Base::PyGILStateLocker lock;
411
for (auto joint : jointGroup->getObjects()) {
416
auto* prop = dynamic_cast<App::PropertyBool*>(joint->getPropertyByName("Activated"));
417
if (prop && !prop->getValue()) {
421
auto proxy = dynamic_cast<App::PropertyPythonObject*>(joint->getPropertyByName("Proxy"));
423
if (proxy->getValue().hasAttr("setJointConnectors")) {
424
joints.push_back(joint);
431
recomputeJointPlacements(joints);
437
std::vector<App::DocumentObject*> AssemblyObject::getGroundedJoints()
439
std::vector<App::DocumentObject*> joints = {};
441
JointGroup* jointGroup = getJointGroup();
446
Base::PyGILStateLocker lock;
447
for (auto obj : jointGroup->getObjects()) {
452
auto* propObj = dynamic_cast<App::PropertyLink*>(obj->getPropertyByName("ObjectToGround"));
455
joints.push_back(obj);
462
std::vector<App::DocumentObject*> AssemblyObject::getJointsOfObj(App::DocumentObject* obj)
464
std::vector<App::DocumentObject*> joints = getJoints(false);
465
std::vector<App::DocumentObject*> jointsOf;
467
for (auto joint : joints) {
468
App::DocumentObject* obj1 = getObjFromNameProp(joint, "object1", "Part1");
469
App::DocumentObject* obj2 = getObjFromNameProp(joint, "Object2", "Part2");
470
if (obj == obj1 || obj == obj2) {
471
jointsOf.push_back(obj);
478
std::vector<App::DocumentObject*> AssemblyObject::getJointsOfPart(App::DocumentObject* part)
480
std::vector<App::DocumentObject*> joints = getJoints(false);
481
std::vector<App::DocumentObject*> jointsOf;
483
for (auto joint : joints) {
484
App::DocumentObject* part1 = getLinkObjFromProp(joint, "Part1");
485
App::DocumentObject* part2 = getLinkObjFromProp(joint, "Part2");
486
if (part == part1 || part == part2) {
487
jointsOf.push_back(joint);
494
std::vector<App::DocumentObject*> AssemblyObject::getGroundedParts()
496
std::vector<App::DocumentObject*> groundedJoints = getGroundedJoints();
498
std::vector<App::DocumentObject*> groundedObjs;
499
for (auto gJoint : groundedJoints) {
505
dynamic_cast<App::PropertyLink*>(gJoint->getPropertyByName("ObjectToGround"));
508
App::DocumentObject* objToGround = propObj->getValue();
509
groundedObjs.push_back(objToGround);
515
std::vector<App::DocumentObject*> AssemblyObject::fixGroundedParts()
517
std::vector<App::DocumentObject*> groundedJoints = getGroundedJoints();
519
std::vector<App::DocumentObject*> groundedObjs;
520
for (auto obj : groundedJoints) {
525
auto* propObj = dynamic_cast<App::PropertyLink*>(obj->getPropertyByName("ObjectToGround"));
528
App::DocumentObject* objToGround = propObj->getValue();
530
Base::Placement plc = getPlacementFromProp(obj, "Placement");
531
std::string str = obj->getFullName();
532
fixGroundedPart(objToGround, plc, str);
533
groundedObjs.push_back(objToGround);
539
void AssemblyObject::fixGroundedPart(App::DocumentObject* obj,
540
Base::Placement& plc,
543
std::string markerName1 = "marker-" + obj->getFullName();
544
auto mbdMarker1 = makeMbdMarker(markerName1, plc);
545
mbdAssembly->addMarker(mbdMarker1);
547
std::shared_ptr<ASMTPart> mbdPart = getMbDPart(obj);
549
std::string markerName2 = "FixingMarker";
550
Base::Placement basePlc = Base::Placement();
551
auto mbdMarker2 = makeMbdMarker(markerName2, basePlc);
552
mbdPart->addMarker(mbdMarker2);
554
markerName1 = "/OndselAssembly/" + mbdMarker1->name;
555
markerName2 = "/OndselAssembly/" + mbdPart->name + "/" + mbdMarker2->name;
557
auto mbdJoint = CREATE<ASMTFixedJoint>::With();
558
mbdJoint->setName(name);
559
mbdJoint->setMarkerI(markerName1);
560
mbdJoint->setMarkerJ(markerName2);
562
mbdAssembly->addJoint(mbdJoint);
565
bool AssemblyObject::isJointConnectingPartToGround(App::DocumentObject* joint, const char* propname)
568
auto* propPart = dynamic_cast<App::PropertyLink*>(joint->getPropertyByName(propname));
572
App::DocumentObject* part = propPart->getValue();
574
bool isConnected = isPartConnected(part);
580
std::vector<App::DocumentObject*> jointsOfPart = getJointsOfPart(part);
581
std::vector<bool> activatedStates;
583
for (auto jointi : jointsOfPart) {
584
if (jointi->getFullName() == joint->getFullName()) {
588
activatedStates.push_back(getJointActivated(jointi));
589
setJointActivated(jointi, false);
592
isConnected = isPartConnected(part);
595
for (auto jointi : jointsOfPart) {
596
if (jointi->getFullName() == joint->getFullName() || activatedStates.empty()) {
600
setJointActivated(jointi, activatedStates[0]);
601
activatedStates.erase(activatedStates.begin());
607
void AssemblyObject::removeUnconnectedJoints(std::vector<App::DocumentObject*>& joints,
608
std::vector<App::DocumentObject*> groundedObjs)
610
std::set<App::DocumentObject*> connectedParts;
613
for (auto* groundedObj : groundedObjs) {
614
connectedParts.insert(groundedObj);
618
for (auto* groundedObj : groundedObjs) {
619
traverseAndMarkConnectedParts(groundedObj, connectedParts, joints);
627
[&connectedParts](App::DocumentObject* joint) {
628
App::DocumentObject* obj1 = getLinkObjFromProp(joint, "Part1");
629
App::DocumentObject* obj2 = getLinkObjFromProp(joint, "Part2");
630
if ((connectedParts.find(obj1) == connectedParts.end())
631
|| (connectedParts.find(obj2) == connectedParts.end())) {
632
Base::Console().Warning(
633
"%s is unconnected to a grounded part so it is ignored.\n",
634
joint->getFullName());
642
void AssemblyObject::traverseAndMarkConnectedParts(App::DocumentObject* currentObj,
643
std::set<App::DocumentObject*>& connectedParts,
644
const std::vector<App::DocumentObject*>& joints)
647
auto connectedObjs = getConnectedParts(currentObj, joints);
648
for (auto* nextObj : connectedObjs) {
649
if (connectedParts.find(nextObj) == connectedParts.end()) {
650
connectedParts.insert(nextObj);
651
traverseAndMarkConnectedParts(nextObj, connectedParts, joints);
656
std::vector<App::DocumentObject*>
657
AssemblyObject::getConnectedParts(App::DocumentObject* part,
658
const std::vector<App::DocumentObject*>& joints)
660
std::vector<App::DocumentObject*> connectedParts;
661
for (auto joint : joints) {
662
App::DocumentObject* obj1 = getLinkObjFromProp(joint, "Part1");
663
App::DocumentObject* obj2 = getLinkObjFromProp(joint, "Part2");
665
connectedParts.push_back(obj2);
667
else if (obj2 == part) {
668
connectedParts.push_back(obj1);
671
return connectedParts;
674
bool AssemblyObject::isPartGrounded(App::DocumentObject* obj)
676
std::vector<App::DocumentObject*> groundedObjs = fixGroundedParts();
678
for (auto* groundedObj : groundedObjs) {
679
if (groundedObj->getFullName() == obj->getFullName()) {
687
bool AssemblyObject::isPartConnected(App::DocumentObject* obj)
689
std::vector<App::DocumentObject*> groundedObjs = getGroundedParts();
690
std::vector<App::DocumentObject*> joints = getJoints(false);
692
std::set<App::DocumentObject*> connectedParts;
695
for (auto* groundedObj : groundedObjs) {
696
connectedParts.insert(groundedObj);
700
for (auto* groundedObj : groundedObjs) {
701
traverseAndMarkConnectedParts(groundedObj, connectedParts, joints);
704
for (auto part : connectedParts) {
713
void AssemblyObject::jointParts(std::vector<App::DocumentObject*> joints)
715
for (auto* joint : joints) {
720
std::vector<std::shared_ptr<MbD::ASMTJoint>> mbdJoints = makeMbdJoint(joint);
721
for (auto& mbdJoint : mbdJoints) {
722
mbdAssembly->addJoint(mbdJoint);
727
std::shared_ptr<ASMTJoint> AssemblyObject::makeMbdJointOfType(App::DocumentObject* joint,
730
if (type == JointType::Fixed) {
731
return CREATE<ASMTFixedJoint>::With();
733
else if (type == JointType::Revolute) {
734
return CREATE<ASMTRevoluteJoint>::With();
736
else if (type == JointType::Cylindrical) {
737
return CREATE<ASMTCylindricalJoint>::With();
739
else if (type == JointType::Slider) {
740
return CREATE<ASMTTranslationalJoint>::With();
742
else if (type == JointType::Ball) {
743
return CREATE<ASMTSphericalJoint>::With();
745
else if (type == JointType::Distance) {
746
return makeMbdJointDistance(joint);
752
std::shared_ptr<ASMTJoint> AssemblyObject::makeMbdJointDistance(App::DocumentObject* joint)
755
std::string type1 = getElementTypeFromProp(joint, "Element1");
756
std::string type2 = getElementTypeFromProp(joint, "Element2");
758
if (type1 == "Vertex" && type2 == "Vertex") {
760
auto mbdJoint = CREATE<ASMTSphSphJoint>::With();
761
mbdJoint->distanceIJ = getJointDistance(joint);
764
else if (type1 == "Edge" && type2 == "Edge") {
765
return makeMbdJointDistanceEdgeEdge(joint);
767
else if (type1 == "Face" && type2 == "Face") {
768
return makeMbdJointDistanceFaceFace(joint);
770
else if ((type1 == "Vertex" && type2 == "Face") || (type1 == "Face" && type2 == "Vertex")) {
771
if (type1 == "Vertex") {
774
return makeMbdJointDistanceFaceVertex(joint);
776
else if ((type1 == "Edge" && type2 == "Face") || (type1 == "Face" && type2 == "Edge")) {
777
if (type1 == "Edge") {
780
return makeMbdJointDistanceFaceEdge(joint);
782
else if ((type1 == "Vertex" && type2 == "Edge") || (type1 == "Edge" && type2 == "Vertex")) {
783
if (type1 == "Vertex") {
786
return makeMbdJointDistanceEdgeVertex(joint);
792
std::shared_ptr<ASMTJoint> AssemblyObject::makeMbdJointDistanceEdgeEdge(App::DocumentObject* joint)
794
const char* elt1 = getElementFromProp(joint, "Element1");
795
const char* elt2 = getElementFromProp(joint, "Element2");
796
auto* obj1 = getLinkedObjFromNameProp(joint, "Object1", "Part1");
797
auto* obj2 = getLinkedObjFromNameProp(joint, "Object2", "Part2");
799
if (isEdgeType(obj1, elt1, GeomAbs_Line) || isEdgeType(obj2, elt2, GeomAbs_Line)) {
800
if (!isEdgeType(obj1, elt1, GeomAbs_Line)) {
802
std::swap(elt1, elt2);
803
std::swap(obj1, obj2);
806
if (isEdgeType(obj2, elt2, GeomAbs_Line)) {
807
auto mbdJoint = CREATE<ASMTRevCylJoint>::With();
808
mbdJoint->distanceIJ = getJointDistance(joint);
811
else if (isEdgeType(obj2, elt2, GeomAbs_Circle)) {
812
auto mbdJoint = CREATE<ASMTRevCylJoint>::With();
813
mbdJoint->distanceIJ = getJointDistance(joint) + getEdgeRadius(obj2, elt2);
819
else if (isEdgeType(obj1, elt1, GeomAbs_Circle) || isEdgeType(obj2, elt2, GeomAbs_Circle)) {
820
if (!isEdgeType(obj1, elt1, GeomAbs_Circle)) {
822
std::swap(elt1, elt2);
823
std::swap(obj1, obj2);
826
if (isEdgeType(obj2, elt2, GeomAbs_Circle)) {
827
auto mbdJoint = CREATE<ASMTRevCylJoint>::With();
828
mbdJoint->distanceIJ =
829
getJointDistance(joint) + getEdgeRadius(obj1, elt1) + getEdgeRadius(obj2, elt2);
840
std::shared_ptr<ASMTJoint> AssemblyObject::makeMbdJointDistanceFaceFace(App::DocumentObject* joint)
842
const char* elt1 = getElementFromProp(joint, "Element1");
843
const char* elt2 = getElementFromProp(joint, "Element2");
844
auto* obj1 = getLinkedObjFromNameProp(joint, "Object1", "Part1");
845
auto* obj2 = getLinkedObjFromNameProp(joint, "Object2", "Part2");
847
if (isFaceType(obj1, elt1, GeomAbs_Plane) || isFaceType(obj2, elt2, GeomAbs_Plane)) {
848
if (!isFaceType(obj1, elt1, GeomAbs_Plane)) {
850
std::swap(elt1, elt2);
851
std::swap(obj1, obj2);
854
if (isFaceType(obj2, elt2, GeomAbs_Plane)) {
855
auto mbdJoint = CREATE<ASMTPlanarJoint>::With();
856
mbdJoint->offset = getJointDistance(joint);
859
else if (isFaceType(obj2, elt2, GeomAbs_Cylinder)) {
860
auto mbdJoint = CREATE<ASMTLineInPlaneJoint>::With();
861
mbdJoint->offset = getJointDistance(joint) + getFaceRadius(obj2, elt2);
864
else if (isFaceType(obj2, elt2, GeomAbs_Sphere)) {
865
auto mbdJoint = CREATE<ASMTPointInPlaneJoint>::With();
866
mbdJoint->offset = getJointDistance(joint) + getFaceRadius(obj2, elt2);
869
else if (isFaceType(obj2, elt2, GeomAbs_Cone)) {
872
else if (isFaceType(obj2, elt2, GeomAbs_Torus)) {
873
auto mbdJoint = CREATE<ASMTPlanarJoint>::With();
874
mbdJoint->offset = getJointDistance(joint);
879
else if (isFaceType(obj1, elt1, GeomAbs_Cylinder) || isFaceType(obj2, elt2, GeomAbs_Cylinder)) {
880
if (!isFaceType(obj1, elt1, GeomAbs_Cylinder)) {
882
std::swap(elt1, elt2);
883
std::swap(obj1, obj2);
886
if (isFaceType(obj2, elt2, GeomAbs_Cylinder)) {
887
auto mbdJoint = CREATE<ASMTRevCylJoint>::With();
888
mbdJoint->distanceIJ =
889
getJointDistance(joint) + getFaceRadius(obj1, elt1) + getFaceRadius(obj2, elt2);
892
else if (isFaceType(obj2, elt2, GeomAbs_Sphere)) {
893
auto mbdJoint = CREATE<ASMTCylSphJoint>::With();
894
mbdJoint->distanceIJ =
895
getJointDistance(joint) + getFaceRadius(obj1, elt1) + getFaceRadius(obj2, elt2);
898
else if (isFaceType(obj2, elt2, GeomAbs_Cone)) {
901
else if (isFaceType(obj2, elt2, GeomAbs_Torus)) {
902
auto mbdJoint = CREATE<ASMTRevCylJoint>::With();
903
mbdJoint->distanceIJ =
904
getJointDistance(joint) + getFaceRadius(obj1, elt1) + getFaceRadius(obj2, elt2);
909
else if (isFaceType(obj1, elt1, GeomAbs_Cone) || isFaceType(obj2, elt2, GeomAbs_Cone)) {
910
if (!isFaceType(obj1, elt1, GeomAbs_Cone)) {
912
std::swap(elt1, elt2);
913
std::swap(obj1, obj2);
916
if (isFaceType(obj2, elt2, GeomAbs_Cone)) {
919
else if (isFaceType(obj2, elt2, GeomAbs_Torus)) {
922
else if (isFaceType(obj2, elt2, GeomAbs_Sphere)) {
927
else if (isFaceType(obj1, elt1, GeomAbs_Torus) || isFaceType(obj2, elt2, GeomAbs_Torus)) {
928
if (!isFaceType(obj1, elt1, GeomAbs_Torus)) {
930
std::swap(elt1, elt2);
931
std::swap(obj1, obj2);
934
if (isFaceType(obj2, elt2, GeomAbs_Torus)) {
935
auto mbdJoint = CREATE<ASMTPlanarJoint>::With();
936
mbdJoint->offset = getJointDistance(joint);
939
else if (isFaceType(obj2, elt2, GeomAbs_Sphere)) {
940
auto mbdJoint = CREATE<ASMTCylSphJoint>::With();
941
mbdJoint->distanceIJ =
942
getJointDistance(joint) + getFaceRadius(obj1, elt1) + getFaceRadius(obj2, elt2);
947
else if (isFaceType(obj1, elt1, GeomAbs_Sphere) || isFaceType(obj2, elt2, GeomAbs_Sphere)) {
948
if (!isFaceType(obj1, elt1, GeomAbs_Sphere)) {
950
std::swap(elt1, elt2);
951
std::swap(obj1, obj2);
954
if (isFaceType(obj2, elt2, GeomAbs_Sphere)) {
955
auto mbdJoint = CREATE<ASMTSphSphJoint>::With();
956
mbdJoint->distanceIJ =
957
getJointDistance(joint) + getFaceRadius(obj1, elt1) + getFaceRadius(obj2, elt2);
963
auto mbdJoint = CREATE<ASMTPlanarJoint>::With();
964
mbdJoint->offset = getJointDistance(joint);
971
std::shared_ptr<ASMTJoint>
972
AssemblyObject::makeMbdJointDistanceFaceVertex(App::DocumentObject* joint)
974
const char* elt1 = getElementFromProp(joint, "Element1");
975
auto* obj1 = getLinkedObjFromNameProp(joint, "Object1", "Part1");
977
if (isFaceType(obj1, elt1, GeomAbs_Plane)) {
978
auto mbdJoint = CREATE<ASMTPointInPlaneJoint>::With();
979
mbdJoint->offset = getJointDistance(joint);
982
else if (isFaceType(obj1, elt1, GeomAbs_Cylinder)) {
983
auto mbdJoint = CREATE<ASMTCylSphJoint>::With();
984
mbdJoint->distanceIJ = getJointDistance(joint) + getFaceRadius(obj1, elt1);
987
else if (isFaceType(obj1, elt1, GeomAbs_Sphere)) {
988
auto mbdJoint = CREATE<ASMTSphSphJoint>::With();
989
mbdJoint->distanceIJ = getJointDistance(joint) + getFaceRadius(obj1, elt1);
1002
std::shared_ptr<ASMTJoint>
1003
AssemblyObject::makeMbdJointDistanceEdgeVertex(App::DocumentObject* joint)
1005
const char* elt1 = getElementFromProp(joint, "Element1");
1006
auto* obj1 = getLinkedObjFromNameProp(joint, "Object1", "Part1");
1008
if (isEdgeType(obj1, elt1, GeomAbs_Line)) {
1009
auto mbdJoint = CREATE<ASMTCylSphJoint>::With();
1010
mbdJoint->distanceIJ = getJointDistance(joint);
1017
auto mbdJoint = CREATE<ASMTPointInPlaneJoint>::With();
1018
mbdJoint->offset = getJointDistance(joint);
1025
std::shared_ptr<ASMTJoint> AssemblyObject::makeMbdJointDistanceFaceEdge(App::DocumentObject* joint)
1027
const char* elt2 = getElementFromProp(joint, "Element2");
1028
auto* obj2 = getLinkedObjFromNameProp(joint, "Object2", "Part2");
1030
if (isEdgeType(obj2, elt2, GeomAbs_Line)) {
1032
auto mbdJoint = CREATE<ASMTLineInPlaneJoint>::With();
1033
mbdJoint->offset = getJointDistance(joint);
1038
auto mbdJoint = CREATE<ASMTPlanarJoint>::With();
1039
mbdJoint->offset = getJointDistance(joint);
1047
std::vector<std::shared_ptr<MbD::ASMTJoint>>
1048
AssemblyObject::makeMbdJoint(App::DocumentObject* joint)
1050
JointType jointType = getJointType(joint);
1052
std::shared_ptr<ASMTJoint> mbdJoint = makeMbdJointOfType(joint, jointType);
1057
std::string fullMarkerName1 = handleOneSideOfJoint(joint, "Object1", "Part1", "Placement1");
1058
std::string fullMarkerName2 = handleOneSideOfJoint(joint, "Object2", "Part2", "Placement2");
1060
mbdJoint->setName(joint->getFullName());
1061
mbdJoint->setMarkerI(fullMarkerName1);
1062
mbdJoint->setMarkerJ(fullMarkerName2);
1067
std::string AssemblyObject::handleOneSideOfJoint(App::DocumentObject* joint,
1068
const char* propObjName,
1069
const char* propPartName,
1070
const char* propPlcName)
1072
App::DocumentObject* part = getLinkObjFromProp(joint, propPartName);
1073
App::DocumentObject* obj = getObjFromNameProp(joint, propObjName, propPartName);
1075
std::shared_ptr<ASMTPart> mbdPart = getMbDPart(part);
1076
Base::Placement plc = getPlacementFromProp(joint, propPlcName);
1080
if (obj->getNameInDocument() != part->getNameInDocument()) {
1084
Base::Placement obj_global_plc = getGlobalPlacement(obj, part);
1085
plc = obj_global_plc * plc;
1087
Base::Placement part_global_plc = getGlobalPlacement(part);
1088
plc = part_global_plc.inverse() * plc;
1091
std::string markerName = joint->getFullName();
1092
auto mbdMarker = makeMbdMarker(markerName, plc);
1093
mbdPart->addMarker(mbdMarker);
1095
return "/OndselAssembly/" + mbdPart->name + "/" + markerName;
1098
std::shared_ptr<ASMTPart> AssemblyObject::getMbDPart(App::DocumentObject* obj)
1100
std::shared_ptr<ASMTPart> mbdPart;
1102
Base::Placement plc = getPlacementFromProp(obj, "Placement");
1104
auto it = objectPartMap.find(obj);
1105
if (it != objectPartMap.end()) {
1107
mbdPart = it->second;
1111
std::string str = obj->getFullName();
1112
mbdPart = makeMbdPart(str, plc);
1113
mbdAssembly->addPart(mbdPart);
1114
objectPartMap[obj] = mbdPart;
1120
std::shared_ptr<ASMTPart>
1121
AssemblyObject::makeMbdPart(std::string& name, Base::Placement plc, double mass)
1123
auto mbdPart = CREATE<ASMTPart>::With();
1124
mbdPart->setName(name);
1126
auto massMarker = CREATE<ASMTPrincipalMassMarker>::With();
1127
massMarker->setMass(mass);
1128
massMarker->setDensity(1.0);
1129
massMarker->setMomentOfInertias(1.0, 1.0, 1.0);
1130
mbdPart->setPrincipalMassMarker(massMarker);
1132
Base::Vector3d pos = plc.getPosition();
1133
mbdPart->setPosition3D(pos.x, pos.y, pos.z);
1137
Base::Rotation rot = plc.getRotation();
1140
Base::Vector3d r0 = mat.getRow(0);
1141
Base::Vector3d r1 = mat.getRow(1);
1142
Base::Vector3d r2 = mat.getRow(2);
1143
mbdPart->setRotationMatrix(r0.x, r0.y, r0.z, r1.x, r1.y, r1.z, r2.x, r2.y, r2.z);
1151
std::shared_ptr<ASMTMarker> AssemblyObject::makeMbdMarker(std::string& name, Base::Placement& plc)
1153
auto mbdMarker = CREATE<ASMTMarker>::With();
1154
mbdMarker->setName(name);
1156
Base::Vector3d pos = plc.getPosition();
1157
mbdMarker->setPosition3D(pos.x, pos.y, pos.z);
1160
Base::Rotation rot = plc.getRotation();
1163
Base::Vector3d r0 = mat.getRow(0);
1164
Base::Vector3d r1 = mat.getRow(1);
1165
Base::Vector3d r2 = mat.getRow(2);
1166
mbdMarker->setRotationMatrix(r0.x, r0.y, r0.z, r1.x, r1.y, r1.z, r2.x, r2.y, r2.z);
1173
std::vector<App::DocumentObject*> AssemblyObject::getDownstreamParts(App::DocumentObject* part,
1174
App::DocumentObject* joint)
1177
bool state = getJointActivated(joint);
1178
setJointActivated(joint, false);
1180
std::vector<App::DocumentObject*> joints = getJoints(false);
1182
std::set<App::DocumentObject*> connectedParts = {part};
1183
traverseAndMarkConnectedParts(part, connectedParts, joints);
1185
std::vector<App::DocumentObject*> downstreamParts;
1186
for (auto parti : connectedParts) {
1187
if (!isPartConnected(parti) && (parti != part)) {
1188
downstreamParts.push_back(parti);
1192
AssemblyObject::setJointActivated(joint, state);
1240
return downstreamParts;
1243
std::vector<App::DocumentObject*> AssemblyObject::getUpstreamParts(App::DocumentObject* part,
1251
if (isPartGrounded(part)) {
1256
App::DocumentObject* connectingJoint = getJointOfPartConnectingToGround(part, name);
1257
App::DocumentObject* upPart =
1258
getLinkObjFromProp(connectingJoint, name == "Part1" ? "Part2" : "Part1");
1260
std::vector<App::DocumentObject*> upstreamParts = getUpstreamParts(upPart, limit);
1261
upstreamParts.push_back(part);
1262
return upstreamParts;
1265
App::DocumentObject* AssemblyObject::getUpstreamMovingPart(App::DocumentObject* part)
1267
if (isPartGrounded(part)) {
1272
App::DocumentObject* connectingJoint = getJointOfPartConnectingToGround(part, name);
1273
JointType jointType = getJointType(connectingJoint);
1274
if (jointType != JointType::Fixed) {
1278
App::DocumentObject* upPart =
1279
getLinkObjFromProp(connectingJoint, name == "Part1" ? "Part2" : "Part1");
1281
return getUpstreamMovingPart(upPart);
1284
double AssemblyObject::getObjMass(App::DocumentObject* obj)
1286
for (auto& pair : objMasses) {
1287
if (pair.first == obj) {
1294
void AssemblyObject::setObjMasses(std::vector<std::pair<App::DocumentObject*, double>> objectMasses)
1296
objMasses = objectMasses;
1301
void AssemblyObject::swapJCS(App::DocumentObject* joint)
1303
auto propElement1 = dynamic_cast<App::PropertyString*>(joint->getPropertyByName("Element1"));
1304
auto propElement2 = dynamic_cast<App::PropertyString*>(joint->getPropertyByName("Element2"));
1305
if (propElement1 && propElement2) {
1306
auto temp = std::string(propElement1->getValue());
1307
propElement1->setValue(propElement2->getValue());
1308
propElement2->setValue(temp);
1310
auto propVertex1 = dynamic_cast<App::PropertyString*>(joint->getPropertyByName("Vertex1"));
1311
auto propVertex2 = dynamic_cast<App::PropertyString*>(joint->getPropertyByName("Vertex2"));
1312
if (propVertex1 && propVertex2) {
1313
auto temp = std::string(propVertex1->getValue());
1314
propVertex1->setValue(propVertex2->getValue());
1315
propVertex2->setValue(temp);
1317
auto propPlacement1 =
1318
dynamic_cast<App::PropertyPlacement*>(joint->getPropertyByName("Placement1"));
1319
auto propPlacement2 =
1320
dynamic_cast<App::PropertyPlacement*>(joint->getPropertyByName("Placement2"));
1321
if (propPlacement1 && propPlacement2) {
1322
auto temp = propPlacement1->getValue();
1323
propPlacement1->setValue(propPlacement2->getValue());
1324
propPlacement2->setValue(temp);
1326
auto propObject1 = dynamic_cast<App::PropertyString*>(joint->getPropertyByName("Object1"));
1327
auto propObject2 = dynamic_cast<App::PropertyString*>(joint->getPropertyByName("Object2"));
1328
if (propObject1 && propObject2) {
1329
auto temp = std::string(propObject1->getValue());
1330
propObject1->setValue(propObject2->getValue());
1331
propObject2->setValue(temp);
1333
auto propPart1 = dynamic_cast<App::PropertyLink*>(joint->getPropertyByName("Part1"));
1334
auto propPart2 = dynamic_cast<App::PropertyLink*>(joint->getPropertyByName("Part2"));
1335
if (propPart1 && propPart2) {
1336
auto temp = propPart1->getValue();
1337
propPart1->setValue(propPart2->getValue());
1338
propPart2->setValue(temp);
1342
bool AssemblyObject::isEdgeType(App::DocumentObject* obj,
1344
GeomAbs_CurveType type)
1346
PartApp::Feature* base = static_cast<PartApp::Feature*>(obj);
1347
const PartApp::TopoShape& TopShape = base->Shape.getShape();
1350
TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(elName));
1351
BRepAdaptor_Curve sf(edge);
1353
if (sf.GetType() == type) {
1360
bool AssemblyObject::isFaceType(App::DocumentObject* obj,
1362
GeomAbs_SurfaceType type)
1364
auto base = static_cast<PartApp::Feature*>(obj);
1365
PartApp::TopoShape TopShape = base->Shape.getShape();
1368
TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(elName));
1369
BRepAdaptor_Surface sf(face);
1371
if (sf.GetType() == type) {
1378
double AssemblyObject::getFaceRadius(App::DocumentObject* obj, const char* elt)
1380
auto base = static_cast<PartApp::Feature*>(obj);
1381
const PartApp::TopoShape& TopShape = base->Shape.getShape();
1384
TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(elt));
1385
BRepAdaptor_Surface sf(face);
1387
if (sf.GetType() == GeomAbs_Cylinder) {
1388
return sf.Cylinder().Radius();
1390
else if (sf.GetType() == GeomAbs_Sphere) {
1391
return sf.Sphere().Radius();
1397
double AssemblyObject::getEdgeRadius(App::DocumentObject* obj, const char* elt)
1399
auto base = static_cast<PartApp::Feature*>(obj);
1400
const PartApp::TopoShape& TopShape = base->Shape.getShape();
1403
TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(elt));
1404
BRepAdaptor_Curve sf(edge);
1406
if (sf.GetType() == GeomAbs_Circle) {
1407
return sf.Circle().Radius();
1413
void printPlacement(Base::Placement plc, const char* name)
1415
Base::Vector3d pos = plc.getPosition();
1416
Base::Vector3d axis;
1418
Base::Rotation rot = plc.getRotation();
1419
rot.getRawValue(axis, angle);
1420
Base::Console().Warning(
1421
"placement %s : position (%.1f, %.1f, %.1f) - axis (%.1f, %.1f, %.1f) angle %.1f\n",
1432
void AssemblyObject::setJointActivated(App::DocumentObject* joint, bool val)
1434
auto* propActivated = dynamic_cast<App::PropertyBool*>(joint->getPropertyByName("Activated"));
1435
if (propActivated) {
1436
propActivated->setValue(val);
1439
bool AssemblyObject::getJointActivated(App::DocumentObject* joint)
1441
auto* propActivated = dynamic_cast<App::PropertyBool*>(joint->getPropertyByName("Activated"));
1442
if (propActivated) {
1443
return propActivated->getValue();
1448
Base::Placement AssemblyObject::getPlacementFromProp(App::DocumentObject* obj, const char* propName)
1450
Base::Placement plc = Base::Placement();
1451
auto* propPlacement = dynamic_cast<App::PropertyPlacement*>(obj->getPropertyByName(propName));
1452
if (propPlacement) {
1453
plc = propPlacement->getValue();
1458
bool AssemblyObject::getTargetPlacementRelativeTo(Base::Placement& foundPlc,
1459
App::DocumentObject* targetObj,
1460
App::DocumentObject* part,
1461
App::DocumentObject* container,
1462
bool inContainerBranch,
1463
bool ignorePlacement)
1465
inContainerBranch = inContainerBranch || (!ignorePlacement && part == container);
1467
if (targetObj == part && inContainerBranch && !ignorePlacement) {
1468
foundPlc = getPlacementFromProp(targetObj, "Placement");
1472
if (part->isDerivedFrom(App::DocumentObjectGroup::getClassTypeId())) {
1473
for (auto& obj : part->getOutList()) {
1474
bool found = getTargetPlacementRelativeTo(foundPlc,
1485
else if (part->isDerivedFrom(Assembly::AssemblyObject::getClassTypeId())
1486
|| part->isDerivedFrom(App::Part::getClassTypeId())
1487
|| part->isDerivedFrom(PartDesign::Body::getClassTypeId())) {
1488
for (auto& obj : part->getOutList()) {
1489
bool found = getTargetPlacementRelativeTo(foundPlc,
1498
if (!ignorePlacement) {
1499
foundPlc = getPlacementFromProp(part, "Placement") * foundPlc;
1505
else if (auto link = dynamic_cast<App::Link*>(part)) {
1506
auto linked_obj = link->getLinkedObject();
1508
if (dynamic_cast<App::Part*>(linked_obj) || dynamic_cast<AssemblyObject*>(linked_obj)) {
1509
for (auto& obj : linked_obj->getOutList()) {
1510
bool found = getTargetPlacementRelativeTo(foundPlc,
1519
foundPlc = getPlacementFromProp(link, "Placement") * foundPlc;
1524
bool found = getTargetPlacementRelativeTo(foundPlc,
1532
if (!ignorePlacement) {
1533
foundPlc = getPlacementFromProp(link, "Placement") * foundPlc;
1543
Base::Placement AssemblyObject::getGlobalPlacement(App::DocumentObject* targetObj,
1544
App::DocumentObject* container)
1546
bool inContainerBranch = (container == nullptr);
1547
auto rootObjects = App::GetApplication().getActiveDocument()->getRootObjects();
1548
for (auto& part : rootObjects) {
1549
Base::Placement foundPlc;
1551
getTargetPlacementRelativeTo(foundPlc, targetObj, part, container, inContainerBranch);
1557
return Base::Placement();
1560
Base::Placement AssemblyObject::getGlobalPlacement(App::DocumentObject* joint,
1561
const char* targetObj,
1562
const char* container)
1564
App::DocumentObject* obj = getObjFromNameProp(joint, targetObj, container);
1565
App::DocumentObject* part = getLinkObjFromProp(joint, container);
1566
return getGlobalPlacement(obj, part);
1569
double AssemblyObject::getJointDistance(App::DocumentObject* joint)
1571
double distance = 0.0;
1573
auto* prop = dynamic_cast<App::PropertyFloat*>(joint->getPropertyByName("Distance"));
1575
distance = prop->getValue();
1581
JointType AssemblyObject::getJointType(App::DocumentObject* joint)
1583
JointType jointType = JointType::Fixed;
1585
auto* prop = dynamic_cast<App::PropertyEnumeration*>(joint->getPropertyByName("JointType"));
1587
jointType = static_cast<JointType>(prop->getValue());
1593
const char* AssemblyObject::getElementFromProp(App::DocumentObject* obj, const char* propName)
1595
auto* prop = dynamic_cast<App::PropertyString*>(obj->getPropertyByName(propName));
1600
return prop->getValue();
1603
std::string AssemblyObject::getElementTypeFromProp(App::DocumentObject* obj, const char* propName)
1606
std::string elementType;
1607
for (char ch : std::string(getElementFromProp(obj, propName))) {
1608
if (std::isalpha(ch)) {
1615
App::DocumentObject* AssemblyObject::getLinkObjFromProp(App::DocumentObject* joint,
1616
const char* propLinkName)
1618
auto* propObj = dynamic_cast<App::PropertyLink*>(joint->getPropertyByName(propLinkName));
1622
return propObj->getValue();
1625
App::DocumentObject* AssemblyObject::getObjFromNameProp(App::DocumentObject* joint,
1626
const char* pObjName,
1629
auto* propObjName = dynamic_cast<App::PropertyString*>(joint->getPropertyByName(pObjName));
1633
std::string objName = std::string(propObjName->getValue());
1635
App::DocumentObject* containingPart = getLinkObjFromProp(joint, pPart);
1636
if (!containingPart) {
1640
if (objName == containingPart->getNameInDocument()) {
1641
return containingPart;
1653
for (auto obj : containingPart->getOutListRecursive()) {
1654
if (objName == obj->getNameInDocument()) {
1662
App::DocumentObject* AssemblyObject::getLinkedObjFromNameProp(App::DocumentObject* joint,
1663
const char* pObjName,
1666
auto* obj = getObjFromNameProp(joint, pObjName, pPart);
1668
return obj->getLinkedObject(true);