Move back the assembly util functions to AssemblyUtil (#18020)
* Move back util functions to AssemblyUtils again * Add getPropertyByName<T>() helper * Improve constness in AssemblyUtils * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -173,6 +173,11 @@ public:
|
||||
//@{
|
||||
/// find a property by its name
|
||||
Property* getPropertyByName(const char* name) const override;
|
||||
/// find a property by its name, dynamic cased to specified type
|
||||
template<typename T>
|
||||
T* getPropertyByName(const char* name) const {
|
||||
return dynamic_cast<T*>(this->getPropertyByName(name));
|
||||
}
|
||||
/// get the name of a property
|
||||
const char* getPropertyName(const Property* prop) const override;
|
||||
/// get all properties of the class (including properties of the parent)
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <Mod/Part/App/DatumFeature.h>
|
||||
|
||||
#include "AssemblyObject.h"
|
||||
#include "AssemblyUtils.h"
|
||||
#include "JointGroup.h"
|
||||
|
||||
#include "AssemblyLink.h"
|
||||
@@ -468,7 +469,7 @@ void AssemblyLink::handleJointReference(App::DocumentObject* joint,
|
||||
}
|
||||
|
||||
// Lastly we need to replace the object name by its link name.
|
||||
auto* obj = AssemblyObject::getObjFromRef(prop1);
|
||||
auto* obj = getObjFromRef(prop1);
|
||||
auto* link = objLinkMap[obj];
|
||||
if (!obj || !link) {
|
||||
return;
|
||||
@@ -496,7 +497,7 @@ void AssemblyLink::handleJointReference(App::DocumentObject* joint,
|
||||
void AssemblyLink::ensureNoJointGroup()
|
||||
{
|
||||
// Make sure there is no joint group
|
||||
JointGroup* jGroup = AssemblyObject::getJointGroup(this);
|
||||
JointGroup* jGroup = getJointGroup(this);
|
||||
if (jGroup) {
|
||||
// If there is a joint group, we delete it and its content.
|
||||
jGroup->removeObjectsFromDocument();
|
||||
@@ -506,7 +507,7 @@ void AssemblyLink::ensureNoJointGroup()
|
||||
JointGroup* AssemblyLink::ensureJointGroup()
|
||||
{
|
||||
// Make sure there is a jointGroup
|
||||
JointGroup* jGroup = AssemblyObject::getJointGroup(this);
|
||||
JointGroup* jGroup = getJointGroup(this);
|
||||
if (!jGroup) {
|
||||
jGroup = new JointGroup();
|
||||
getDocument()->addObject(jGroup, tr("Joints").toStdString().c_str());
|
||||
@@ -572,7 +573,7 @@ bool AssemblyLink::isRigid()
|
||||
|
||||
std::vector<App::DocumentObject*> AssemblyLink::getJoints()
|
||||
{
|
||||
JointGroup* jointGroup = AssemblyObject::getJointGroup(this);
|
||||
JointGroup* jointGroup = getJointGroup(this);
|
||||
|
||||
if (!jointGroup) {
|
||||
return {};
|
||||
|
||||
@@ -24,13 +24,6 @@
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <BRepAdaptor_Surface.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <gp_Circ.hxx>
|
||||
#include <gp_Cylinder.hxx>
|
||||
#include <gp_Sphere.hxx>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
@@ -48,10 +41,7 @@
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/Interpreter.h>
|
||||
|
||||
#include <Mod/Part/App/PartFeature.h>
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
#include <Mod/PartDesign/App/Body.h>
|
||||
#include <Mod/Part/App/DatumFeature.h>
|
||||
|
||||
#include <OndselSolver/CREATE.h>
|
||||
#include <OndselSolver/ASMTSimulationParameters.h>
|
||||
@@ -85,13 +75,12 @@
|
||||
#include "AssemblyLink.h"
|
||||
#include "AssemblyObject.h"
|
||||
#include "AssemblyObjectPy.h"
|
||||
#include "AssemblyUtils.h"
|
||||
#include "JointGroup.h"
|
||||
#include "ViewGroup.h"
|
||||
|
||||
FC_LOG_LEVEL_INIT("Assembly", true, true, true)
|
||||
|
||||
namespace PartApp = Part;
|
||||
|
||||
using namespace Assembly;
|
||||
using namespace MbD;
|
||||
/*
|
||||
@@ -513,8 +502,8 @@ App::DocumentObject* AssemblyObject::getJointOfPartConnectingToGround(App::Docum
|
||||
if (!joint) {
|
||||
continue;
|
||||
}
|
||||
App::DocumentObject* part1 = getMovingPartFromRef(joint, "Reference1");
|
||||
App::DocumentObject* part2 = getMovingPartFromRef(joint, "Reference2");
|
||||
App::DocumentObject* part1 = getMovingPartFromRef(this, joint, "Reference1");
|
||||
App::DocumentObject* part2 = getMovingPartFromRef(this, joint, "Reference2");
|
||||
if (!part1 || !part2) {
|
||||
continue;
|
||||
}
|
||||
@@ -532,30 +521,9 @@ App::DocumentObject* AssemblyObject::getJointOfPartConnectingToGround(App::Docum
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JointGroup* AssemblyObject::getJointGroup(const App::Part* part)
|
||||
{
|
||||
if (!part) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
App::Document* doc = part->getDocument();
|
||||
|
||||
std::vector<DocumentObject*> jointGroups =
|
||||
doc->getObjectsOfType(Assembly::JointGroup::getClassTypeId());
|
||||
if (jointGroups.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
for (auto jointGroup : jointGroups) {
|
||||
if (part->hasObject(jointGroup)) {
|
||||
return dynamic_cast<JointGroup*>(jointGroup);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JointGroup* AssemblyObject::getJointGroup() const
|
||||
{
|
||||
return getJointGroup(this);
|
||||
return Assembly::getJointGroup(this);
|
||||
}
|
||||
|
||||
ViewGroup* AssemblyObject::getExplodedViewGroup() const
|
||||
@@ -596,8 +564,8 @@ AssemblyObject::getJoints(bool updateJCS, bool delBadJoints, bool subJoints)
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* part1 = getMovingPartFromRef(joint, "Reference1");
|
||||
auto* part2 = getMovingPartFromRef(joint, "Reference2");
|
||||
auto* part1 = getMovingPartFromRef(this, joint, "Reference1");
|
||||
auto* part2 = getMovingPartFromRef(this, joint, "Reference2");
|
||||
if (!part1 || !part2 || part1->getFullName() == part2->getFullName()) {
|
||||
// Remove incomplete joints. Left-over when the user deletes a part.
|
||||
// Remove incoherent joints (self-pointing joints)
|
||||
@@ -686,8 +654,8 @@ std::vector<App::DocumentObject*> AssemblyObject::getJointsOfPart(App::DocumentO
|
||||
std::vector<App::DocumentObject*> jointsOf;
|
||||
|
||||
for (auto joint : joints) {
|
||||
App::DocumentObject* part1 = getMovingPartFromRef(joint, "Reference1");
|
||||
App::DocumentObject* part2 = getMovingPartFromRef(joint, "Reference2");
|
||||
App::DocumentObject* part1 = getMovingPartFromRef(this, joint, "Reference1");
|
||||
App::DocumentObject* part2 = getMovingPartFromRef(this, joint, "Reference2");
|
||||
if (part == part1 || part == part2) {
|
||||
jointsOf.push_back(joint);
|
||||
}
|
||||
@@ -777,7 +745,7 @@ bool AssemblyObject::isJointConnectingPartToGround(App::DocumentObject* joint, c
|
||||
return false;
|
||||
}
|
||||
|
||||
App::DocumentObject* part = getMovingPartFromRef(joint, propname);
|
||||
App::DocumentObject* part = getMovingPartFromRef(this, joint, propname);
|
||||
if (!part) {
|
||||
return false;
|
||||
}
|
||||
@@ -869,8 +837,8 @@ void AssemblyObject::removeUnconnectedJoints(std::vector<App::DocumentObject*>&
|
||||
joints.begin(),
|
||||
joints.end(),
|
||||
[&](App::DocumentObject* joint) {
|
||||
App::DocumentObject* obj1 = getMovingPartFromRef(joint, "Reference1");
|
||||
App::DocumentObject* obj2 = getMovingPartFromRef(joint, "Reference2");
|
||||
App::DocumentObject* obj1 = getMovingPartFromRef(this, joint, "Reference1");
|
||||
App::DocumentObject* obj2 = getMovingPartFromRef(this, joint, "Reference2");
|
||||
if (!isObjInSetOfObjRefs(obj1, connectedParts)
|
||||
|| !isObjInSetOfObjRefs(obj2, connectedParts)) {
|
||||
Base::Console().Warning(
|
||||
@@ -913,8 +881,8 @@ AssemblyObject::getConnectedParts(App::DocumentObject* part,
|
||||
continue;
|
||||
}
|
||||
|
||||
App::DocumentObject* obj1 = getMovingPartFromRef(joint, "Reference1");
|
||||
App::DocumentObject* obj2 = getMovingPartFromRef(joint, "Reference2");
|
||||
App::DocumentObject* obj1 = getMovingPartFromRef(this, joint, "Reference1");
|
||||
App::DocumentObject* obj2 = getMovingPartFromRef(this, joint, "Reference2");
|
||||
if (obj1 == part) {
|
||||
auto* ref =
|
||||
dynamic_cast<App::PropertyXLinkSub*>(joint->getPropertyByName("Reference2"));
|
||||
@@ -1401,7 +1369,7 @@ std::string AssemblyObject::handleOneSideOfJoint(App::DocumentObject* joint,
|
||||
const char* propRefName,
|
||||
const char* propPlcName)
|
||||
{
|
||||
App::DocumentObject* part = getMovingPartFromRef(joint, propRefName);
|
||||
App::DocumentObject* part = getMovingPartFromRef(this, joint, propRefName);
|
||||
App::DocumentObject* obj = getObjFromRef(joint, propRefName);
|
||||
|
||||
if (!part || !obj) {
|
||||
@@ -1463,7 +1431,7 @@ void AssemblyObject::getRackPinionMarkers(App::DocumentObject* joint,
|
||||
swapJCS(joint); // make sure that rack is first.
|
||||
}
|
||||
|
||||
App::DocumentObject* part1 = getMovingPartFromRef(joint, "Reference1");
|
||||
App::DocumentObject* part1 = getMovingPartFromRef(this, joint, "Reference1");
|
||||
App::DocumentObject* obj1 = getObjFromRef(joint, "Reference1");
|
||||
Base::Placement plc1 = getPlacementFromProp(joint, "Placement1");
|
||||
|
||||
@@ -1537,12 +1505,12 @@ void AssemblyObject::getRackPinionMarkers(App::DocumentObject* joint,
|
||||
|
||||
int AssemblyObject::slidingPartIndex(App::DocumentObject* joint)
|
||||
{
|
||||
App::DocumentObject* part1 = getMovingPartFromRef(joint, "Reference1");
|
||||
App::DocumentObject* part1 = getMovingPartFromRef(this, joint, "Reference1");
|
||||
App::DocumentObject* obj1 = getObjFromRef(joint, "Reference1");
|
||||
boost::ignore_unused(obj1);
|
||||
Base::Placement plc1 = getPlacementFromProp(joint, "Placement1");
|
||||
|
||||
App::DocumentObject* part2 = getMovingPartFromRef(joint, "Reference2");
|
||||
App::DocumentObject* part2 = getMovingPartFromRef(this, joint, "Reference2");
|
||||
App::DocumentObject* obj2 = getObjFromRef(joint, "Reference2");
|
||||
boost::ignore_unused(obj2);
|
||||
Base::Placement plc2 = getPlacementFromProp(joint, "Placement2");
|
||||
@@ -1550,8 +1518,8 @@ int AssemblyObject::slidingPartIndex(App::DocumentObject* joint)
|
||||
int slidingFound = 0;
|
||||
for (auto* jt : getJoints(false, false)) {
|
||||
if (getJointType(jt) == JointType::Slider) {
|
||||
App::DocumentObject* jpart1 = getMovingPartFromRef(jt, "Reference1");
|
||||
App::DocumentObject* jpart2 = getMovingPartFromRef(jt, "Reference2");
|
||||
App::DocumentObject* jpart1 = getMovingPartFromRef(this, jt, "Reference1");
|
||||
App::DocumentObject* jpart2 = getMovingPartFromRef(this, jt, "Reference2");
|
||||
int found = 0;
|
||||
Base::Placement plcjt, plci;
|
||||
if (jpart1 == part1 || jpart1 == part2) {
|
||||
@@ -1604,8 +1572,8 @@ AssemblyObject::MbDPartData AssemblyObject::getMbDData(App::DocumentObject* part
|
||||
for (auto* joint : joints) {
|
||||
JointType jointType = getJointType(joint);
|
||||
if (jointType == JointType::Fixed) {
|
||||
App::DocumentObject* part1 = getMovingPartFromRef(joint, "Reference1");
|
||||
App::DocumentObject* part2 = getMovingPartFromRef(joint, "Reference2");
|
||||
App::DocumentObject* part1 = getMovingPartFromRef(this, joint, "Reference1");
|
||||
App::DocumentObject* part2 = getMovingPartFromRef(this, joint, "Reference2");
|
||||
App::DocumentObject* partToAdd = currentPart == part1 ? part2 : part1;
|
||||
|
||||
if (objectPartMap.find(partToAdd) != objectPartMap.end()) {
|
||||
@@ -1718,7 +1686,7 @@ std::vector<ObjRef> AssemblyObject::getDownstreamParts(App::DocumentObject* part
|
||||
}
|
||||
|
||||
if (joint) {
|
||||
AssemblyObject::setJointActivated(joint, state);
|
||||
setJointActivated(joint, state);
|
||||
}
|
||||
|
||||
return downstreamParts;
|
||||
@@ -1743,7 +1711,9 @@ std::vector<App::DocumentObject*> AssemblyObject::getUpstreamParts(App::Document
|
||||
std::string name;
|
||||
App::DocumentObject* connectingJoint = getJointOfPartConnectingToGround(part, name);
|
||||
App::DocumentObject* upPart =
|
||||
getMovingPartFromRef(connectingJoint, name == "Reference1" ? "Reference2" : "Reference1");
|
||||
getMovingPartFromRef(this,
|
||||
connectingJoint,
|
||||
name == "Reference1" ? "Reference2" : "Reference1");
|
||||
|
||||
std::vector<App::DocumentObject*> upstreamParts = getUpstreamParts(upPart, limit);
|
||||
upstreamParts.push_back(part);
|
||||
@@ -1764,7 +1734,7 @@ App::DocumentObject* AssemblyObject::getUpstreamMovingPart(App::DocumentObject*
|
||||
return part;
|
||||
}
|
||||
|
||||
part = getMovingPartFromRef(joint, name == "Reference1" ? "Reference2" : "Reference1");
|
||||
part = getMovingPartFromRef(this, joint, name == "Reference1" ? "Reference2" : "Reference1");
|
||||
|
||||
return getUpstreamMovingPart(part, joint, name);
|
||||
}
|
||||
@@ -1859,687 +1829,6 @@ void AssemblyObject::ensureIdentityPlacements()
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================= Utils ======================================
|
||||
|
||||
void AssemblyObject::swapJCS(App::DocumentObject* joint)
|
||||
{
|
||||
if (!joint) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto pPlc1 = dynamic_cast<App::PropertyPlacement*>(joint->getPropertyByName("Placement1"));
|
||||
auto pPlc2 = dynamic_cast<App::PropertyPlacement*>(joint->getPropertyByName("Placement2"));
|
||||
if (pPlc1 && pPlc2) {
|
||||
auto temp = pPlc1->getValue();
|
||||
pPlc1->setValue(pPlc2->getValue());
|
||||
pPlc2->setValue(temp);
|
||||
}
|
||||
auto pRef1 = dynamic_cast<App::PropertyXLinkSub*>(joint->getPropertyByName("Reference1"));
|
||||
auto pRef2 = dynamic_cast<App::PropertyXLinkSub*>(joint->getPropertyByName("Reference2"));
|
||||
if (pRef1 && pRef2) {
|
||||
auto temp = pRef1->getValue();
|
||||
auto subs1 = pRef1->getSubValues();
|
||||
auto subs2 = pRef2->getSubValues();
|
||||
pRef1->setValue(pRef2->getValue());
|
||||
pRef1->setSubValues(std::move(subs2));
|
||||
pRef2->setValue(temp);
|
||||
pRef2->setSubValues(std::move(subs1));
|
||||
}
|
||||
}
|
||||
|
||||
bool AssemblyObject::isEdgeType(App::DocumentObject* obj,
|
||||
std::string& elName,
|
||||
GeomAbs_CurveType type)
|
||||
{
|
||||
auto* base = dynamic_cast<PartApp::Feature*>(obj);
|
||||
if (!base) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const PartApp::TopoShape& TopShape = base->Shape.getShape();
|
||||
|
||||
// Check for valid face types
|
||||
TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(elName.c_str()));
|
||||
BRepAdaptor_Curve sf(edge);
|
||||
|
||||
if (sf.GetType() == type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AssemblyObject::isFaceType(App::DocumentObject* obj,
|
||||
std::string& elName,
|
||||
GeomAbs_SurfaceType type)
|
||||
{
|
||||
auto* base = dynamic_cast<PartApp::Feature*>(obj);
|
||||
if (!base) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const PartApp::TopoShape TopShape = base->Shape.getShape();
|
||||
|
||||
// Check for valid face types
|
||||
TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(elName.c_str()));
|
||||
BRepAdaptor_Surface sf(face);
|
||||
|
||||
if (sf.GetType() == type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
double AssemblyObject::getFaceRadius(App::DocumentObject* obj, std::string& elt)
|
||||
{
|
||||
auto* base = dynamic_cast<PartApp::Feature*>(obj);
|
||||
if (!base) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
const PartApp::TopoShape& TopShape = base->Shape.getShape();
|
||||
|
||||
// Check for valid face types
|
||||
TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(elt.c_str()));
|
||||
BRepAdaptor_Surface sf(face);
|
||||
|
||||
if (sf.GetType() == GeomAbs_Cylinder) {
|
||||
return sf.Cylinder().Radius();
|
||||
}
|
||||
else if (sf.GetType() == GeomAbs_Sphere) {
|
||||
return sf.Sphere().Radius();
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double AssemblyObject::getEdgeRadius(App::DocumentObject* obj, std::string& elt)
|
||||
{
|
||||
auto* base = dynamic_cast<PartApp::Feature*>(obj);
|
||||
if (!base) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
const PartApp::TopoShape& TopShape = base->Shape.getShape();
|
||||
|
||||
// Check for valid face types
|
||||
TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(elt.c_str()));
|
||||
BRepAdaptor_Curve sf(edge);
|
||||
|
||||
if (sf.GetType() == GeomAbs_Circle) {
|
||||
return sf.Circle().Radius();
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
DistanceType AssemblyObject::getDistanceType(App::DocumentObject* joint)
|
||||
{
|
||||
if (!joint) {
|
||||
return DistanceType::Other;
|
||||
}
|
||||
|
||||
std::string type1 = getElementTypeFromProp(joint, "Reference1");
|
||||
std::string type2 = getElementTypeFromProp(joint, "Reference2");
|
||||
std::string elt1 = getElementFromProp(joint, "Reference1");
|
||||
std::string elt2 = getElementFromProp(joint, "Reference2");
|
||||
auto* obj1 = getLinkedObjFromRef(joint, "Reference1");
|
||||
auto* obj2 = getLinkedObjFromRef(joint, "Reference2");
|
||||
|
||||
if (type1 == "Vertex" && type2 == "Vertex") {
|
||||
return DistanceType::PointPoint;
|
||||
}
|
||||
else if (type1 == "Edge" && type2 == "Edge") {
|
||||
if (isEdgeType(obj1, elt1, GeomAbs_Line) || isEdgeType(obj2, elt2, GeomAbs_Line)) {
|
||||
if (!isEdgeType(obj1, elt1, GeomAbs_Line)) {
|
||||
swapJCS(joint); // make sure that line is first if not 2 lines.
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
|
||||
if (isEdgeType(obj2, elt2, GeomAbs_Line)) {
|
||||
return DistanceType::LineLine;
|
||||
}
|
||||
else if (isEdgeType(obj2, elt2, GeomAbs_Circle)) {
|
||||
return DistanceType::LineCircle;
|
||||
}
|
||||
// TODO : other cases Ellipse, parabola, hyperbola...
|
||||
}
|
||||
|
||||
else if (isEdgeType(obj1, elt1, GeomAbs_Circle) || isEdgeType(obj2, elt2, GeomAbs_Circle)) {
|
||||
if (!isEdgeType(obj1, elt1, GeomAbs_Circle)) {
|
||||
swapJCS(joint); // make sure that circle is first if not 2 lines.
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
|
||||
if (isEdgeType(obj2, elt2, GeomAbs_Circle)) {
|
||||
return DistanceType::CircleCircle;
|
||||
}
|
||||
// TODO : other cases Ellipse, parabola, hyperbola...
|
||||
}
|
||||
}
|
||||
else if (type1 == "Face" && type2 == "Face") {
|
||||
if (isFaceType(obj1, elt1, GeomAbs_Plane) || isFaceType(obj2, elt2, GeomAbs_Plane)) {
|
||||
if (!isFaceType(obj1, elt1, GeomAbs_Plane)) {
|
||||
swapJCS(joint); // make sure plane is first if its not 2 planes.
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
|
||||
if (isFaceType(obj2, elt2, GeomAbs_Plane)) {
|
||||
return DistanceType::PlanePlane;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Cylinder)) {
|
||||
return DistanceType::PlaneCylinder;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Sphere)) {
|
||||
return DistanceType::PlaneSphere;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Cone)) {
|
||||
return DistanceType::PlaneCone;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Torus)) {
|
||||
return DistanceType::PlaneTorus;
|
||||
}
|
||||
}
|
||||
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Cylinder)
|
||||
|| isFaceType(obj2, elt2, GeomAbs_Cylinder)) {
|
||||
if (!isFaceType(obj1, elt1, GeomAbs_Cylinder)) {
|
||||
swapJCS(joint); // make sure cylinder is first if its not 2 cylinders.
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
|
||||
if (isFaceType(obj2, elt2, GeomAbs_Cylinder)) {
|
||||
return DistanceType::CylinderCylinder;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Sphere)) {
|
||||
return DistanceType::CylinderSphere;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Cone)) {
|
||||
return DistanceType::CylinderCone;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Torus)) {
|
||||
return DistanceType::CylinderTorus;
|
||||
}
|
||||
}
|
||||
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Cone) || isFaceType(obj2, elt2, GeomAbs_Cone)) {
|
||||
if (!isFaceType(obj1, elt1, GeomAbs_Cone)) {
|
||||
swapJCS(joint); // make sure cone is first if its not 2 cones.
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
|
||||
if (isFaceType(obj2, elt2, GeomAbs_Cone)) {
|
||||
return DistanceType::ConeCone;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Torus)) {
|
||||
return DistanceType::ConeTorus;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Sphere)) {
|
||||
return DistanceType::ConeSphere;
|
||||
}
|
||||
}
|
||||
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Torus) || isFaceType(obj2, elt2, GeomAbs_Torus)) {
|
||||
if (!isFaceType(obj1, elt1, GeomAbs_Torus)) {
|
||||
swapJCS(joint); // make sure torus is first if its not 2 torus.
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
|
||||
if (isFaceType(obj2, elt2, GeomAbs_Torus)) {
|
||||
return DistanceType::TorusTorus;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Sphere)) {
|
||||
return DistanceType::TorusSphere;
|
||||
}
|
||||
}
|
||||
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Sphere) || isFaceType(obj2, elt2, GeomAbs_Sphere)) {
|
||||
if (!isFaceType(obj1, elt1, GeomAbs_Sphere)) {
|
||||
swapJCS(joint); // make sure sphere is first if its not 2 spheres.
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
|
||||
if (isFaceType(obj2, elt2, GeomAbs_Sphere)) {
|
||||
return DistanceType::SphereSphere;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((type1 == "Vertex" && type2 == "Face") || (type1 == "Face" && type2 == "Vertex")) {
|
||||
if (type1 == "Vertex") { // Make sure face is the first.
|
||||
swapJCS(joint);
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
if (isFaceType(obj1, elt1, GeomAbs_Plane)) {
|
||||
return DistanceType::PointPlane;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Cylinder)) {
|
||||
return DistanceType::PointCylinder;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Sphere)) {
|
||||
return DistanceType::PointSphere;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Cone)) {
|
||||
return DistanceType::PointCone;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Torus)) {
|
||||
return DistanceType::PointTorus;
|
||||
}
|
||||
}
|
||||
else if ((type1 == "Edge" && type2 == "Face") || (type1 == "Face" && type2 == "Edge")) {
|
||||
if (type1 == "Edge") { // Make sure face is the first.
|
||||
swapJCS(joint);
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
if (isEdgeType(obj2, elt2, GeomAbs_Line)) {
|
||||
if (isFaceType(obj1, elt1, GeomAbs_Plane)) {
|
||||
return DistanceType::LinePlane;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Cylinder)) {
|
||||
return DistanceType::LineCylinder;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Sphere)) {
|
||||
return DistanceType::LineSphere;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Cone)) {
|
||||
return DistanceType::LineCone;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Torus)) {
|
||||
return DistanceType::LineTorus;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// For other curves we consider them as planes for now. Can be refined later.
|
||||
if (isFaceType(obj1, elt1, GeomAbs_Plane)) {
|
||||
return DistanceType::CurvePlane;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Cylinder)) {
|
||||
return DistanceType::CurveCylinder;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Sphere)) {
|
||||
return DistanceType::CurveSphere;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Cone)) {
|
||||
return DistanceType::CurveCone;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Torus)) {
|
||||
return DistanceType::CurveTorus;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((type1 == "Vertex" && type2 == "Edge") || (type1 == "Edge" && type2 == "Vertex")) {
|
||||
if (type1 == "Vertex") { // Make sure edge is the first.
|
||||
swapJCS(joint);
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
if (isEdgeType(obj1, elt1, GeomAbs_Line)) { // Point on line joint.
|
||||
return DistanceType::PointLine;
|
||||
}
|
||||
else {
|
||||
// For other curves we do a point in plane-of-the-curve.
|
||||
// Maybe it would be best tangent / distance to the conic? For arcs and
|
||||
// circles we could use ASMTRevSphJoint. But is it better than pointInPlane?
|
||||
return DistanceType::PointCurve;
|
||||
}
|
||||
}
|
||||
return DistanceType::Other;
|
||||
}
|
||||
|
||||
void AssemblyObject::setJointActivated(App::DocumentObject* joint, bool val)
|
||||
{
|
||||
if (!joint) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* propActivated = dynamic_cast<App::PropertyBool*>(joint->getPropertyByName("Activated"));
|
||||
if (propActivated) {
|
||||
propActivated->setValue(val);
|
||||
}
|
||||
}
|
||||
|
||||
bool AssemblyObject::getJointActivated(App::DocumentObject* joint)
|
||||
{
|
||||
if (!joint) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* propActivated = dynamic_cast<App::PropertyBool*>(joint->getPropertyByName("Activated"));
|
||||
if (propActivated) {
|
||||
return propActivated->getValue();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
double AssemblyObject::getJointDistance(App::DocumentObject* joint)
|
||||
{
|
||||
double distance = 0.0;
|
||||
if (!joint) {
|
||||
return distance;
|
||||
}
|
||||
|
||||
auto* prop = dynamic_cast<App::PropertyFloat*>(joint->getPropertyByName("Distance"));
|
||||
if (prop) {
|
||||
distance = prop->getValue();
|
||||
}
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
double AssemblyObject::getJointDistance2(App::DocumentObject* joint)
|
||||
{
|
||||
double distance = 0.0;
|
||||
if (!joint) {
|
||||
return distance;
|
||||
}
|
||||
|
||||
auto* prop = dynamic_cast<App::PropertyFloat*>(joint->getPropertyByName("Distance2"));
|
||||
if (prop) {
|
||||
distance = prop->getValue();
|
||||
}
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
JointType AssemblyObject::getJointType(App::DocumentObject* joint)
|
||||
{
|
||||
JointType jointType = JointType::Fixed;
|
||||
if (!joint) {
|
||||
return jointType;
|
||||
}
|
||||
|
||||
auto* prop = dynamic_cast<App::PropertyEnumeration*>(joint->getPropertyByName("JointType"));
|
||||
if (prop) {
|
||||
jointType = static_cast<JointType>(prop->getValue());
|
||||
}
|
||||
|
||||
return jointType;
|
||||
}
|
||||
|
||||
std::vector<std::string> AssemblyObject::getSubAsList(App::PropertyXLinkSub* prop)
|
||||
{
|
||||
if (!prop) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::string> subs = prop->getSubValues();
|
||||
if (subs.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return Base::Tools::splitSubName(subs[0]);
|
||||
}
|
||||
|
||||
std::vector<std::string> AssemblyObject::getSubAsList(App::DocumentObject* obj, const char* pName)
|
||||
{
|
||||
if (!obj) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto* prop = dynamic_cast<App::PropertyXLinkSub*>(obj->getPropertyByName(pName));
|
||||
|
||||
return getSubAsList(prop);
|
||||
}
|
||||
|
||||
std::string AssemblyObject::getElementFromProp(App::DocumentObject* obj, const char* pName)
|
||||
{
|
||||
if (!obj) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::vector<std::string> names = getSubAsList(obj, pName);
|
||||
|
||||
if (names.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return names.back();
|
||||
}
|
||||
|
||||
std::string AssemblyObject::getElementTypeFromProp(App::DocumentObject* obj, const char* propName)
|
||||
{
|
||||
// The prop is going to be something like 'Edge14' or 'Face7'. We need 'Edge' or 'Face'
|
||||
std::string elementType;
|
||||
for (char ch : getElementFromProp(obj, propName)) {
|
||||
if (std::isalpha(ch)) {
|
||||
elementType += ch;
|
||||
}
|
||||
}
|
||||
return elementType;
|
||||
}
|
||||
|
||||
App::DocumentObject* AssemblyObject::getObjFromProp(App::DocumentObject* joint, const char* pName)
|
||||
{
|
||||
if (!joint) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* propObj = dynamic_cast<App::PropertyLink*>(joint->getPropertyByName(pName));
|
||||
if (!propObj) {
|
||||
return nullptr;
|
||||
}
|
||||
return propObj->getValue();
|
||||
}
|
||||
|
||||
App::DocumentObject* AssemblyObject::getObjFromRef(App::DocumentObject* obj, std::string& sub)
|
||||
{
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
App::Document* doc = obj->getDocument();
|
||||
|
||||
std::vector<std::string> names = Base::Tools::splitSubName(sub);
|
||||
|
||||
// Lambda function to check if the typeId is a BodySubObject
|
||||
auto isBodySubObject = [](App::DocumentObject* obj) -> bool {
|
||||
// PartDesign::Point + Line + Plane + CoordinateSystem
|
||||
// getViewProviderName instead of isDerivedFrom to avoid dependency on sketcher
|
||||
return (strcmp(obj->getViewProviderName(), "SketcherGui::ViewProviderSketch") == 0
|
||||
|| obj->isDerivedFrom<PartApp::Datum>());
|
||||
};
|
||||
|
||||
// Helper function to handle PartDesign::Body objects
|
||||
auto handlePartDesignBody = [&](App::DocumentObject* obj,
|
||||
std::vector<std::string>::iterator it) -> App::DocumentObject* {
|
||||
auto nextIt = std::next(it);
|
||||
if (nextIt != names.end()) {
|
||||
for (auto* obji : obj->getOutList()) {
|
||||
if (*nextIt == obji->getNameInDocument()) {
|
||||
if (isBodySubObject(obji)) {
|
||||
return obji;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
for (auto it = names.begin(); it != names.end(); ++it) {
|
||||
App::DocumentObject* obj = doc->getObject(it->c_str());
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (obj->isDerivedFrom<App::DocumentObjectGroup>()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The last but one name should be the selected
|
||||
if (std::next(it) == std::prev(names.end())) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (obj->isDerivedFrom<App::Part>() || obj->isLinkGroup()) {
|
||||
continue;
|
||||
}
|
||||
else if (obj->isDerivedFrom<PartDesign::Body>()) {
|
||||
return handlePartDesignBody(obj, it);
|
||||
}
|
||||
else if (obj->isDerivedFrom<PartApp::Feature>()) {
|
||||
// Primitive, fastener, gear, etc.
|
||||
return obj;
|
||||
}
|
||||
else if (obj->isLink()) {
|
||||
App::DocumentObject* linked_obj = obj->getLinkedObject();
|
||||
if (linked_obj->isDerivedFrom<PartDesign::Body>()) {
|
||||
auto* retObj = handlePartDesignBody(linked_obj, it);
|
||||
return retObj == linked_obj ? obj : retObj;
|
||||
}
|
||||
else if (linked_obj->isDerivedFrom<PartApp::Feature>()) {
|
||||
return obj;
|
||||
}
|
||||
else {
|
||||
doc = linked_obj->getDocument();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
App::DocumentObject* AssemblyObject::getObjFromRef(App::PropertyXLinkSub* prop)
|
||||
{
|
||||
if (!prop) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
App::DocumentObject* obj = prop->getValue();
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> subs = prop->getSubValues();
|
||||
if (subs.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return getObjFromRef(obj, subs[0]);
|
||||
}
|
||||
|
||||
App::DocumentObject* AssemblyObject::getObjFromRef(App::DocumentObject* joint, const char* pName)
|
||||
{
|
||||
if (!joint) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* prop = dynamic_cast<App::PropertyXLinkSub*>(joint->getPropertyByName(pName));
|
||||
|
||||
return getObjFromRef(prop);
|
||||
}
|
||||
|
||||
App::DocumentObject* AssemblyObject::getMovingPartFromRef(App::DocumentObject* obj,
|
||||
std::string& sub)
|
||||
{
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
App::Document* doc = obj->getDocument();
|
||||
|
||||
std::vector<std::string> names = Base::Tools::splitSubName(sub);
|
||||
names.insert(names.begin(), obj->getNameInDocument());
|
||||
|
||||
bool assemblyPassed = false;
|
||||
|
||||
for (const auto& objName : names) {
|
||||
obj = doc->getObject(objName.c_str());
|
||||
if (!obj) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (obj->isLink()) { // update the document if necessary for next object
|
||||
doc = obj->getLinkedObject()->getDocument();
|
||||
}
|
||||
|
||||
if (obj == this) {
|
||||
// We make sure we pass the assembly for cases like part.assembly.part.body
|
||||
assemblyPassed = true;
|
||||
continue;
|
||||
}
|
||||
if (!assemblyPassed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (obj->isDerivedFrom<App::DocumentObjectGroup>()) {
|
||||
continue; // we ignore groups.
|
||||
}
|
||||
|
||||
if (obj->isLinkGroup()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We ignore dynamic sub-assemblies.
|
||||
if (obj->isDerivedFrom<Assembly::AssemblyLink>()) {
|
||||
auto* pRigid = dynamic_cast<App::PropertyBool*>(obj->getPropertyByName("Rigid"));
|
||||
if (pRigid && !pRigid->getValue()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
App::DocumentObject* AssemblyObject::getMovingPartFromRef(App::PropertyXLinkSub* prop)
|
||||
{
|
||||
if (!prop) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
App::DocumentObject* obj = prop->getValue();
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> subs = prop->getSubValues();
|
||||
if (subs.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return getMovingPartFromRef(obj, subs[0]);
|
||||
}
|
||||
|
||||
App::DocumentObject* AssemblyObject::getMovingPartFromRef(App::DocumentObject* joint,
|
||||
const char* pName)
|
||||
{
|
||||
if (!joint) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* prop = dynamic_cast<App::PropertyXLinkSub*>(joint->getPropertyByName(pName));
|
||||
|
||||
return getMovingPartFromRef(prop);
|
||||
}
|
||||
|
||||
App::DocumentObject* AssemblyObject::getLinkedObjFromRef(App::DocumentObject* joint,
|
||||
const char* pObj)
|
||||
{
|
||||
if (!joint) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* obj = getObjFromRef(joint, pObj);
|
||||
if (obj) {
|
||||
return obj->getLinkedObject(true);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/*void Part::handleChangedPropertyType(Base::XMLReader& reader, const char* TypeName, App::Property*
|
||||
prop)
|
||||
{
|
||||
|
||||
@@ -26,9 +26,6 @@
|
||||
#define ASSEMBLY_AssemblyObject_H
|
||||
|
||||
|
||||
#include <GeomAbs_CurveType.hxx>
|
||||
#include <GeomAbs_SurfaceType.hxx>
|
||||
|
||||
#include <Mod/Assembly/AssemblyGlobal.h>
|
||||
|
||||
#include <App/FeaturePython.h>
|
||||
@@ -62,6 +59,8 @@ namespace Assembly
|
||||
class AssemblyLink;
|
||||
class JointGroup;
|
||||
class ViewGroup;
|
||||
enum class JointType;
|
||||
|
||||
|
||||
struct ObjRef
|
||||
{
|
||||
@@ -69,72 +68,6 @@ struct ObjRef
|
||||
App::PropertyXLinkSub* ref;
|
||||
};
|
||||
|
||||
// This enum has to be the same as the one in JointObject.py
|
||||
enum class JointType
|
||||
{
|
||||
Fixed,
|
||||
Revolute,
|
||||
Cylindrical,
|
||||
Slider,
|
||||
Ball,
|
||||
Distance,
|
||||
Parallel,
|
||||
Perpendicular,
|
||||
Angle,
|
||||
RackPinion,
|
||||
Screw,
|
||||
Gears,
|
||||
Belt,
|
||||
};
|
||||
|
||||
enum class DistanceType
|
||||
{
|
||||
PointPoint,
|
||||
|
||||
LineLine,
|
||||
LineCircle,
|
||||
CircleCircle,
|
||||
|
||||
PlanePlane,
|
||||
PlaneCylinder,
|
||||
PlaneSphere,
|
||||
PlaneCone,
|
||||
PlaneTorus,
|
||||
CylinderCylinder,
|
||||
CylinderSphere,
|
||||
CylinderCone,
|
||||
CylinderTorus,
|
||||
ConeCone,
|
||||
ConeTorus,
|
||||
ConeSphere,
|
||||
TorusTorus,
|
||||
TorusSphere,
|
||||
SphereSphere,
|
||||
|
||||
PointPlane,
|
||||
PointCylinder,
|
||||
PointSphere,
|
||||
PointCone,
|
||||
PointTorus,
|
||||
|
||||
LinePlane,
|
||||
LineCylinder,
|
||||
LineSphere,
|
||||
LineCone,
|
||||
LineTorus,
|
||||
|
||||
CurvePlane,
|
||||
CurveCylinder,
|
||||
CurveSphere,
|
||||
CurveCone,
|
||||
CurveTorus,
|
||||
|
||||
PointLine,
|
||||
PointCurve,
|
||||
|
||||
Other,
|
||||
};
|
||||
|
||||
class AssemblyExport AssemblyObject: public App::Part
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(Assembly::AssemblyObject);
|
||||
@@ -257,42 +190,6 @@ private:
|
||||
bool bundleFixed;
|
||||
// void handleChangedPropertyType(Base::XMLReader &reader, const char *TypeName, App::Property
|
||||
// *prop) override;
|
||||
|
||||
public:
|
||||
// ---------------- Utils -------------------
|
||||
// Can't put the functions by themselves in AssemblyUtils.cpp :
|
||||
// see https://forum.freecad.org/viewtopic.php?p=729577#p729577
|
||||
|
||||
static void swapJCS(App::DocumentObject* joint);
|
||||
|
||||
static bool isEdgeType(App::DocumentObject* obj, std::string& elName, GeomAbs_CurveType type);
|
||||
static bool isFaceType(App::DocumentObject* obj, std::string& elName, GeomAbs_SurfaceType type);
|
||||
static double getFaceRadius(App::DocumentObject* obj, std::string& elName);
|
||||
static double getEdgeRadius(App::DocumentObject* obj, std::string& elName);
|
||||
|
||||
static DistanceType getDistanceType(App::DocumentObject* joint);
|
||||
|
||||
static JointGroup* getJointGroup(const App::Part* part);
|
||||
|
||||
// getters to get from properties
|
||||
static void setJointActivated(App::DocumentObject* joint, bool val);
|
||||
static bool getJointActivated(App::DocumentObject* joint);
|
||||
static double getJointDistance(App::DocumentObject* joint);
|
||||
static double getJointDistance2(App::DocumentObject* joint);
|
||||
static JointType getJointType(App::DocumentObject* joint);
|
||||
static std::string getElementFromProp(App::DocumentObject* obj, const char* propName);
|
||||
static std::string getElementTypeFromProp(App::DocumentObject* obj, const char* propName);
|
||||
static App::DocumentObject* getObjFromProp(App::DocumentObject* joint, const char* propName);
|
||||
static App::DocumentObject* getObjFromRef(App::DocumentObject* obj, std::string& sub);
|
||||
static App::DocumentObject* getObjFromRef(App::PropertyXLinkSub* prop);
|
||||
static App::DocumentObject* getObjFromRef(App::DocumentObject* joint, const char* propName);
|
||||
App::DocumentObject* getMovingPartFromRef(App::DocumentObject* obj, std::string& sub);
|
||||
App::DocumentObject* getMovingPartFromRef(App::PropertyXLinkSub* prop);
|
||||
App::DocumentObject* getMovingPartFromRef(App::DocumentObject* joint, const char* propName);
|
||||
static App::DocumentObject* getLinkedObjFromRef(App::DocumentObject* joint,
|
||||
const char* propName);
|
||||
static std::vector<std::string> getSubAsList(App::PropertyXLinkSub* prop);
|
||||
static std::vector<std::string> getSubAsList(App::DocumentObject* joint, const char* propName);
|
||||
};
|
||||
|
||||
// using AssemblyObjectPython = App::FeaturePythonT<AssemblyObject>;
|
||||
|
||||
@@ -23,6 +23,13 @@
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <BRepAdaptor_Surface.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <gp_Circ.hxx>
|
||||
#include <gp_Cylinder.hxx>
|
||||
#include <gp_Sphere.hxx>
|
||||
#endif
|
||||
|
||||
#include <App/Application.h>
|
||||
@@ -36,15 +43,692 @@
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/Interpreter.h>
|
||||
|
||||
#include <Mod/Part/App/DatumFeature.h>
|
||||
#include <Mod/Part/App/PartFeature.h>
|
||||
#include <Mod/PartDesign/App/Body.h>
|
||||
|
||||
#include "AssemblyUtils.h"
|
||||
#include "AssemblyObject.h"
|
||||
#include "AssemblyLink.h"
|
||||
|
||||
#include "JointGroup.h"
|
||||
|
||||
|
||||
namespace PartApp = Part;
|
||||
|
||||
// ======================================= Utils ======================================
|
||||
/*
|
||||
namespace Assembly
|
||||
{
|
||||
|
||||
void swapJCS(const App::DocumentObject* joint)
|
||||
{
|
||||
if (!joint) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto pPlc1 = joint->getPropertyByName<App::PropertyPlacement>("Placement1");
|
||||
auto pPlc2 = joint->getPropertyByName<App::PropertyPlacement>("Placement2");
|
||||
if (pPlc1 && pPlc2) {
|
||||
const auto temp = pPlc1->getValue();
|
||||
pPlc1->setValue(pPlc2->getValue());
|
||||
pPlc2->setValue(temp);
|
||||
}
|
||||
auto pRef1 = joint->getPropertyByName<App::PropertyXLinkSub>("Reference1");
|
||||
auto pRef2 = joint->getPropertyByName<App::PropertyXLinkSub>("Reference2");
|
||||
if (pRef1 && pRef2) {
|
||||
auto temp = pRef1->getValue();
|
||||
auto subs1 = pRef1->getSubValues();
|
||||
auto subs2 = pRef2->getSubValues();
|
||||
pRef1->setValue(pRef2->getValue());
|
||||
pRef1->setSubValues(std::move(subs2));
|
||||
pRef2->setValue(temp);
|
||||
pRef2->setSubValues(std::move(subs1));
|
||||
}
|
||||
}
|
||||
|
||||
bool isEdgeType(const App::DocumentObject* obj,
|
||||
const std::string& elName,
|
||||
const GeomAbs_CurveType type)
|
||||
{
|
||||
auto* base = dynamic_cast<const PartApp::Feature*>(obj);
|
||||
if (!base) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& TopShape = base->Shape.getShape();
|
||||
|
||||
// Check for valid face types
|
||||
const auto edge = TopoDS::Edge(TopShape.getSubShape(elName.c_str()));
|
||||
BRepAdaptor_Curve sf(edge);
|
||||
|
||||
return sf.GetType() == type;
|
||||
}
|
||||
|
||||
bool isFaceType(const App::DocumentObject* obj,
|
||||
const std::string& elName,
|
||||
const GeomAbs_SurfaceType type)
|
||||
{
|
||||
auto* base = dynamic_cast<const PartApp::Feature*>(obj);
|
||||
if (!base) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto TopShape = base->Shape.getShape();
|
||||
|
||||
// Check for valid face types
|
||||
const auto face = TopoDS::Face(TopShape.getSubShape(elName.c_str()));
|
||||
BRepAdaptor_Surface sf(face);
|
||||
|
||||
return sf.GetType() == type;
|
||||
}
|
||||
|
||||
double getFaceRadius(const App::DocumentObject* obj, const std::string& elt)
|
||||
{
|
||||
auto* base = dynamic_cast<const PartApp::Feature*>(obj);
|
||||
if (!base) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
const PartApp::TopoShape& TopShape = base->Shape.getShape();
|
||||
|
||||
// Check for valid face types
|
||||
TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(elt.c_str()));
|
||||
BRepAdaptor_Surface sf(face);
|
||||
|
||||
const auto type = sf.GetType();
|
||||
return type == GeomAbs_Cylinder ? sf.Cylinder().Radius()
|
||||
: type == GeomAbs_Sphere ? sf.Sphere().Radius()
|
||||
: 0.0;
|
||||
}
|
||||
|
||||
double getEdgeRadius(const App::DocumentObject* obj, const std::string& elt)
|
||||
{
|
||||
auto* base = dynamic_cast<const PartApp::Feature*>(obj);
|
||||
if (!base) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
const auto& TopShape = base->Shape.getShape();
|
||||
|
||||
// Check for valid face types
|
||||
const auto edge = TopoDS::Edge(TopShape.getSubShape(elt.c_str()));
|
||||
BRepAdaptor_Curve sf(edge);
|
||||
|
||||
return sf.GetType() == GeomAbs_Circle ? sf.Circle().Radius() : 0.0;
|
||||
}
|
||||
|
||||
DistanceType getDistanceType(App::DocumentObject* joint)
|
||||
{
|
||||
if (!joint) {
|
||||
return DistanceType::Other;
|
||||
}
|
||||
|
||||
const auto type1 = getElementTypeFromProp(joint, "Reference1");
|
||||
const auto type2 = getElementTypeFromProp(joint, "Reference2");
|
||||
auto elt1 = getElementFromProp(joint, "Reference1");
|
||||
auto elt2 = getElementFromProp(joint, "Reference2");
|
||||
auto* obj1 = getLinkedObjFromRef(joint, "Reference1");
|
||||
auto* obj2 = getLinkedObjFromRef(joint, "Reference2");
|
||||
|
||||
if (type1 == "Vertex" && type2 == "Vertex") {
|
||||
return DistanceType::PointPoint;
|
||||
}
|
||||
else if (type1 == "Edge" && type2 == "Edge") {
|
||||
if (isEdgeType(obj1, elt1, GeomAbs_Line) || isEdgeType(obj2, elt2, GeomAbs_Line)) {
|
||||
if (!isEdgeType(obj1, elt1, GeomAbs_Line)) {
|
||||
swapJCS(joint); // make sure that line is first if not 2 lines.
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
|
||||
if (isEdgeType(obj2, elt2, GeomAbs_Line)) {
|
||||
return DistanceType::LineLine;
|
||||
}
|
||||
else if (isEdgeType(obj2, elt2, GeomAbs_Circle)) {
|
||||
return DistanceType::LineCircle;
|
||||
}
|
||||
// TODO : other cases Ellipse, parabola, hyperbola...
|
||||
}
|
||||
|
||||
else if (isEdgeType(obj1, elt1, GeomAbs_Circle) || isEdgeType(obj2, elt2, GeomAbs_Circle)) {
|
||||
if (!isEdgeType(obj1, elt1, GeomAbs_Circle)) {
|
||||
swapJCS(joint); // make sure that circle is first if not 2 lines.
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
|
||||
if (isEdgeType(obj2, elt2, GeomAbs_Circle)) {
|
||||
return DistanceType::CircleCircle;
|
||||
}
|
||||
// TODO : other cases Ellipse, parabola, hyperbola...
|
||||
}
|
||||
}
|
||||
else if (type1 == "Face" && type2 == "Face") {
|
||||
if (isFaceType(obj1, elt1, GeomAbs_Plane) || isFaceType(obj2, elt2, GeomAbs_Plane)) {
|
||||
if (!isFaceType(obj1, elt1, GeomAbs_Plane)) {
|
||||
swapJCS(joint); // make sure plane is first if its not 2 planes.
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
|
||||
if (isFaceType(obj2, elt2, GeomAbs_Plane)) {
|
||||
return DistanceType::PlanePlane;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Cylinder)) {
|
||||
return DistanceType::PlaneCylinder;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Sphere)) {
|
||||
return DistanceType::PlaneSphere;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Cone)) {
|
||||
return DistanceType::PlaneCone;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Torus)) {
|
||||
return DistanceType::PlaneTorus;
|
||||
}
|
||||
}
|
||||
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Cylinder)
|
||||
|| isFaceType(obj2, elt2, GeomAbs_Cylinder)) {
|
||||
if (!isFaceType(obj1, elt1, GeomAbs_Cylinder)) {
|
||||
swapJCS(joint); // make sure cylinder is first if its not 2 cylinders.
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
|
||||
if (isFaceType(obj2, elt2, GeomAbs_Cylinder)) {
|
||||
return DistanceType::CylinderCylinder;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Sphere)) {
|
||||
return DistanceType::CylinderSphere;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Cone)) {
|
||||
return DistanceType::CylinderCone;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Torus)) {
|
||||
return DistanceType::CylinderTorus;
|
||||
}
|
||||
}
|
||||
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Cone) || isFaceType(obj2, elt2, GeomAbs_Cone)) {
|
||||
if (!isFaceType(obj1, elt1, GeomAbs_Cone)) {
|
||||
swapJCS(joint); // make sure cone is first if its not 2 cones.
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
|
||||
if (isFaceType(obj2, elt2, GeomAbs_Cone)) {
|
||||
return DistanceType::ConeCone;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Torus)) {
|
||||
return DistanceType::ConeTorus;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Sphere)) {
|
||||
return DistanceType::ConeSphere;
|
||||
}
|
||||
}
|
||||
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Torus) || isFaceType(obj2, elt2, GeomAbs_Torus)) {
|
||||
if (!isFaceType(obj1, elt1, GeomAbs_Torus)) {
|
||||
swapJCS(joint); // make sure torus is first if its not 2 torus.
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
|
||||
if (isFaceType(obj2, elt2, GeomAbs_Torus)) {
|
||||
return DistanceType::TorusTorus;
|
||||
}
|
||||
else if (isFaceType(obj2, elt2, GeomAbs_Sphere)) {
|
||||
return DistanceType::TorusSphere;
|
||||
}
|
||||
}
|
||||
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Sphere) || isFaceType(obj2, elt2, GeomAbs_Sphere)) {
|
||||
if (!isFaceType(obj1, elt1, GeomAbs_Sphere)) {
|
||||
swapJCS(joint); // make sure sphere is first if its not 2 spheres.
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
|
||||
if (isFaceType(obj2, elt2, GeomAbs_Sphere)) {
|
||||
return DistanceType::SphereSphere;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((type1 == "Vertex" && type2 == "Face") || (type1 == "Face" && type2 == "Vertex")) {
|
||||
if (type1 == "Vertex") { // Make sure face is the first.
|
||||
swapJCS(joint);
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
if (isFaceType(obj1, elt1, GeomAbs_Plane)) {
|
||||
return DistanceType::PointPlane;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Cylinder)) {
|
||||
return DistanceType::PointCylinder;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Sphere)) {
|
||||
return DistanceType::PointSphere;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Cone)) {
|
||||
return DistanceType::PointCone;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Torus)) {
|
||||
return DistanceType::PointTorus;
|
||||
}
|
||||
}
|
||||
else if ((type1 == "Edge" && type2 == "Face") || (type1 == "Face" && type2 == "Edge")) {
|
||||
if (type1 == "Edge") { // Make sure face is the first.
|
||||
swapJCS(joint);
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
if (isEdgeType(obj2, elt2, GeomAbs_Line)) {
|
||||
if (isFaceType(obj1, elt1, GeomAbs_Plane)) {
|
||||
return DistanceType::LinePlane;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Cylinder)) {
|
||||
return DistanceType::LineCylinder;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Sphere)) {
|
||||
return DistanceType::LineSphere;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Cone)) {
|
||||
return DistanceType::LineCone;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Torus)) {
|
||||
return DistanceType::LineTorus;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// For other curves we consider them as planes for now. Can be refined later.
|
||||
if (isFaceType(obj1, elt1, GeomAbs_Plane)) {
|
||||
return DistanceType::CurvePlane;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Cylinder)) {
|
||||
return DistanceType::CurveCylinder;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Sphere)) {
|
||||
return DistanceType::CurveSphere;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Cone)) {
|
||||
return DistanceType::CurveCone;
|
||||
}
|
||||
else if (isFaceType(obj1, elt1, GeomAbs_Torus)) {
|
||||
return DistanceType::CurveTorus;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((type1 == "Vertex" && type2 == "Edge") || (type1 == "Edge" && type2 == "Vertex")) {
|
||||
if (type1 == "Vertex") { // Make sure edge is the first.
|
||||
swapJCS(joint);
|
||||
std::swap(elt1, elt2);
|
||||
std::swap(obj1, obj2);
|
||||
}
|
||||
if (isEdgeType(obj1, elt1, GeomAbs_Line)) { // Point on line joint.
|
||||
return DistanceType::PointLine;
|
||||
}
|
||||
else {
|
||||
// For other curves we do a point in plane-of-the-curve.
|
||||
// Maybe it would be best tangent / distance to the conic? For arcs and
|
||||
// circles we could use ASMTRevSphJoint. But is it better than pointInPlane?
|
||||
return DistanceType::PointCurve;
|
||||
}
|
||||
}
|
||||
return DistanceType::Other;
|
||||
}
|
||||
|
||||
JointGroup* getJointGroup(const App::Part* part)
|
||||
{
|
||||
if (!part) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto* doc = part->getDocument();
|
||||
|
||||
const auto jointGroups = doc->getObjectsOfType(JointGroup::getClassTypeId());
|
||||
if (jointGroups.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
for (auto jointGroup : jointGroups) {
|
||||
if (part->hasObject(jointGroup)) {
|
||||
return dynamic_cast<JointGroup*>(jointGroup);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void setJointActivated(const App::DocumentObject* joint, bool val)
|
||||
{
|
||||
if (!joint) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto propActivated = joint->getPropertyByName<App::PropertyBool>("Activated")) {
|
||||
propActivated->setValue(val);
|
||||
}
|
||||
}
|
||||
|
||||
bool getJointActivated(const App::DocumentObject* joint)
|
||||
{
|
||||
if (!joint) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (const auto propActivated = joint->getPropertyByName<App::PropertyBool>("Activated")) {
|
||||
return propActivated->getValue();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
double getJointDistance(const App::DocumentObject* joint, const char* propertyName)
|
||||
{
|
||||
if (!joint) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
const auto* prop = joint->getPropertyByName<App::PropertyFloat>(propertyName);
|
||||
if (!prop) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return prop->getValue();
|
||||
}
|
||||
|
||||
double getJointDistance(const App::DocumentObject* joint)
|
||||
{
|
||||
return getJointDistance(joint, "Distance");
|
||||
}
|
||||
|
||||
double getJointDistance2(const App::DocumentObject* joint)
|
||||
{
|
||||
return getJointDistance(joint, "Distance2");
|
||||
}
|
||||
|
||||
JointType getJointType(const App::DocumentObject* joint)
|
||||
{
|
||||
if (!joint) {
|
||||
return JointType::Fixed;
|
||||
}
|
||||
|
||||
const auto* prop = joint->getPropertyByName<App::PropertyEnumeration>("JointType");
|
||||
if (!prop) {
|
||||
return JointType::Fixed;
|
||||
}
|
||||
|
||||
return static_cast<JointType>(prop->getValue());
|
||||
}
|
||||
|
||||
std::vector<std::string> getSubAsList(const App::PropertyXLinkSub* prop)
|
||||
{
|
||||
if (!prop) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto subs = prop->getSubValues();
|
||||
if (subs.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return Base::Tools::splitSubName(subs[0]);
|
||||
}
|
||||
|
||||
std::vector<std::string> getSubAsList(const App::DocumentObject* obj, const char* pName)
|
||||
{
|
||||
if (!obj) {
|
||||
return {};
|
||||
}
|
||||
return getSubAsList(obj->getPropertyByName<App::PropertyXLinkSub>(pName));
|
||||
}
|
||||
|
||||
std::string getElementFromProp(const App::DocumentObject* obj, const char* pName)
|
||||
{
|
||||
if (!obj) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const auto names = getSubAsList(obj, pName);
|
||||
if (names.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return names.back();
|
||||
}
|
||||
|
||||
std::string getElementTypeFromProp(const App::DocumentObject* obj, const char* propName)
|
||||
{
|
||||
// The prop is going to be something like 'Edge14' or 'Face7'. We need 'Edge' or 'Face'
|
||||
std::string elementType;
|
||||
for (const char ch : getElementFromProp(obj, propName)) {
|
||||
if (std::isalpha(ch)) {
|
||||
elementType += ch;
|
||||
}
|
||||
}
|
||||
return elementType;
|
||||
}
|
||||
|
||||
App::DocumentObject* getObjFromProp(const App::DocumentObject* joint, const char* pName)
|
||||
{
|
||||
if (!joint) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto* propObj = joint->getPropertyByName<App::PropertyLink>(pName);
|
||||
if (!propObj) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return propObj->getValue();
|
||||
}
|
||||
|
||||
App::DocumentObject* getObjFromRef(const App::DocumentObject* obj, const std::string& sub)
|
||||
{
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto* doc = obj->getDocument();
|
||||
const auto names = Base::Tools::splitSubName(sub);
|
||||
|
||||
// Lambda function to check if the typeId is a BodySubObject
|
||||
const auto isBodySubObject = [](App::DocumentObject* obj) -> bool {
|
||||
// PartDesign::Point + Line + Plane + CoordinateSystem
|
||||
// getViewProviderName instead of isDerivedFrom to avoid dependency on sketcher
|
||||
const auto isDerivedFromVpSketch =
|
||||
strcmp(obj->getViewProviderName(), "SketcherGui::ViewProviderSketch") == 0;
|
||||
return isDerivedFromVpSketch || obj->isDerivedFrom<PartApp::Datum>();
|
||||
};
|
||||
|
||||
// Helper function to handle PartDesign::Body objects
|
||||
const auto handlePartDesignBody =
|
||||
[&](App::DocumentObject* obj,
|
||||
std::vector<std::string>::const_iterator it) -> App::DocumentObject* {
|
||||
const auto nextIt = std::next(it);
|
||||
if (nextIt != names.end()) {
|
||||
for (auto* obji : obj->getOutList()) {
|
||||
if (*nextIt == obji->getNameInDocument() && isBodySubObject(obji)) {
|
||||
return obji;
|
||||
}
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
for (auto it = names.begin(); it != names.end(); ++it) {
|
||||
App::DocumentObject* obj = doc->getObject(it->c_str());
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (obj->isDerivedFrom<App::DocumentObjectGroup>()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The last but one name should be the selected
|
||||
if (std::next(it) == std::prev(names.end())) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (obj->isDerivedFrom<App::Part>() || obj->isLinkGroup()) {
|
||||
continue;
|
||||
}
|
||||
else if (obj->isDerivedFrom<PartDesign::Body>()) {
|
||||
return handlePartDesignBody(obj, it);
|
||||
}
|
||||
else if (obj->isDerivedFrom<PartApp::Feature>()) {
|
||||
// Primitive, fastener, gear, etc.
|
||||
return obj;
|
||||
}
|
||||
else if (obj->isLink()) {
|
||||
App::DocumentObject* linked_obj = obj->getLinkedObject();
|
||||
if (linked_obj->isDerivedFrom<PartDesign::Body>()) {
|
||||
auto* retObj = handlePartDesignBody(linked_obj, it);
|
||||
return retObj == linked_obj ? obj : retObj;
|
||||
}
|
||||
else if (linked_obj->isDerivedFrom<PartApp::Feature>()) {
|
||||
return obj;
|
||||
}
|
||||
else {
|
||||
doc = linked_obj->getDocument();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
App::DocumentObject* getObjFromRef(const App::PropertyXLinkSub* prop)
|
||||
{
|
||||
if (!prop) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const App::DocumentObject* obj = prop->getValue();
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::vector<std::string> subs = prop->getSubValues();
|
||||
if (subs.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return getObjFromRef(obj, subs[0]);
|
||||
}
|
||||
|
||||
App::DocumentObject* getObjFromRef(const App::DocumentObject* joint, const char* pName)
|
||||
{
|
||||
if (!joint) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto* prop = joint->getPropertyByName<App::PropertyXLinkSub>(pName);
|
||||
return getObjFromRef(prop);
|
||||
}
|
||||
|
||||
App::DocumentObject* getLinkedObjFromRef(const App::DocumentObject* joint, const char* pObj)
|
||||
{
|
||||
if (!joint) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (const auto* obj = getObjFromRef(joint, pObj)) {
|
||||
return obj->getLinkedObject(true);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
App::DocumentObject* getMovingPartFromRef(const AssemblyObject* assemblyObject,
|
||||
App::DocumentObject* obj,
|
||||
const std::string& sub)
|
||||
{
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* doc = obj->getDocument();
|
||||
|
||||
auto names = Base::Tools::splitSubName(sub);
|
||||
names.insert(names.begin(), obj->getNameInDocument());
|
||||
|
||||
bool assemblyPassed = false;
|
||||
|
||||
for (const auto& objName : names) {
|
||||
obj = doc->getObject(objName.c_str());
|
||||
if (!obj) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (obj->isLink()) { // update the document if necessary for next object
|
||||
doc = obj->getLinkedObject()->getDocument();
|
||||
}
|
||||
|
||||
if (obj == assemblyObject) {
|
||||
// We make sure we pass the assembly for cases like part.assembly.part.body
|
||||
assemblyPassed = true;
|
||||
continue;
|
||||
}
|
||||
if (!assemblyPassed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (obj->isDerivedFrom<App::DocumentObjectGroup>()) {
|
||||
continue; // we ignore groups.
|
||||
}
|
||||
|
||||
if (obj->isLinkGroup()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We ignore dynamic sub-assemblies.
|
||||
if (obj->isDerivedFrom<Assembly::AssemblyLink>()) {
|
||||
const auto* pRigid = obj->getPropertyByName<App::PropertyBool>("Rigid");
|
||||
if (pRigid && !pRigid->getValue()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
App::DocumentObject* getMovingPartFromRef(const AssemblyObject* assemblyObject,
|
||||
App::PropertyXLinkSub* prop)
|
||||
{
|
||||
if (!prop) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
App::DocumentObject* obj = prop->getValue();
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::vector<std::string> subs = prop->getSubValues();
|
||||
if (subs.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return getMovingPartFromRef(assemblyObject, obj, subs[0]);
|
||||
}
|
||||
|
||||
App::DocumentObject* getMovingPartFromRef(const AssemblyObject* assemblyObject,
|
||||
App::DocumentObject* joint,
|
||||
const char* pName)
|
||||
{
|
||||
if (!joint) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* prop = joint->getPropertyByName<App::PropertyXLinkSub>(pName);
|
||||
return getMovingPartFromRef(assemblyObject, prop);
|
||||
}
|
||||
|
||||
/*
|
||||
Base::Placement getPlacementFromProp(App::DocumentObject* obj, const char* propName)
|
||||
{
|
||||
Base::Placement plc = Base::Placement();
|
||||
@@ -140,110 +824,6 @@ foundPlacement = getTargetPlacementRelativeTo(targetObj, part, container, inCont
|
||||
return Base::Placement();
|
||||
}
|
||||
*/
|
||||
/*
|
||||
double getJointDistance(App::DocumentObject* joint)
|
||||
{
|
||||
double distance = 0.0;
|
||||
|
||||
auto* prop = dynamic_cast<App::PropertyFloat*>(joint->getPropertyByName("Distance"));
|
||||
if (prop) {
|
||||
distance = prop->getValue();
|
||||
}
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
JointType getJointType(App::DocumentObject* joint)
|
||||
{
|
||||
JointType jointType = JointType::Fixed;
|
||||
|
||||
auto* prop = dynamic_cast<App::PropertyEnumeration*>(joint->getPropertyByName("JointType"));
|
||||
if (prop) {
|
||||
jointType = static_cast<JointType>(prop->getValue());
|
||||
}
|
||||
|
||||
return jointType;
|
||||
}
|
||||
|
||||
const char* getElementFromProp(App::DocumentObject* obj, const char* propName)
|
||||
{
|
||||
auto* prop = dynamic_cast<App::PropertyString*>(obj->getPropertyByName(propName));
|
||||
if (!prop) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return prop->getValue();
|
||||
}
|
||||
|
||||
std::string getElementTypeFromProp(App::DocumentObject* obj, const char* propName)
|
||||
{
|
||||
// The prop is going to be something like 'Edge14' or 'Face7'. We need 'Edge' or 'Face'
|
||||
std::string elementType;
|
||||
for (char ch : std::string(getElementFromProp(obj, propName))) {
|
||||
if (std::isalpha(ch)) {
|
||||
elementType += ch;
|
||||
}
|
||||
}
|
||||
return elementType;
|
||||
}
|
||||
|
||||
App::DocumentObject* getLinkObjFromProp(App::DocumentObject* joint,
|
||||
const char* propLinkName)
|
||||
{
|
||||
auto* propObj = dynamic_cast<App::PropertyLink*>(joint->getPropertyByName(propLinkName));
|
||||
if (!propObj) {
|
||||
return nullptr;
|
||||
}
|
||||
return propObj->getValue();
|
||||
}
|
||||
|
||||
App::DocumentObject* getObjFromNameProp(App::DocumentObject* joint,
|
||||
const char* pObjName,
|
||||
const char* pPart)
|
||||
{
|
||||
auto* propObjName = dynamic_cast<App::PropertyString*>(joint->getPropertyByName(pObjName));
|
||||
if (!propObjName) {
|
||||
return nullptr;
|
||||
}
|
||||
std::string objName = std::string(propObjName->getValue());
|
||||
|
||||
App::DocumentObject* containingPart = getLinkObjFromProp(joint, pPart);
|
||||
if (!containingPart) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (objName == containingPart->getNameInDocument()) {
|
||||
return containingPart;
|
||||
}
|
||||
|
||||
if (containingPart->getTypeId().isDerivedFrom(App::Link::getClassTypeId())) {
|
||||
App::Link* link = dynamic_cast<App::Link*>(containingPart);
|
||||
|
||||
containingPart = link->getLinkedObject();
|
||||
if (!containingPart) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto obj : containingPart->getOutList()) {
|
||||
if (objName == obj->getNameInDocument()) {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
App::DocumentObject* getLinkedObjFromNameProp(App::DocumentObject* joint,
|
||||
const char* pObjName,
|
||||
const char* pPart)
|
||||
{
|
||||
auto* obj = getObjFromNameProp(joint, pObjName, pPart);
|
||||
if (obj) {
|
||||
return obj->getLinkedObject(true);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace Assembly
|
||||
*/
|
||||
} // namespace Assembly
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
#define ASSEMBLY_AssemblyUtils_H
|
||||
|
||||
|
||||
#include <GeomAbs_CurveType.hxx>
|
||||
#include <GeomAbs_SurfaceType.hxx>
|
||||
|
||||
#include <Mod/Assembly/AssemblyGlobal.h>
|
||||
|
||||
#include <App/FeaturePython.h>
|
||||
@@ -43,7 +46,7 @@ class Placement;
|
||||
|
||||
namespace Assembly
|
||||
{
|
||||
/*
|
||||
|
||||
// This enum has to be the same as the one in JointObject.py
|
||||
enum class JointType
|
||||
{
|
||||
@@ -52,19 +55,126 @@ enum class JointType
|
||||
Cylindrical,
|
||||
Slider,
|
||||
Ball,
|
||||
Distance
|
||||
Distance,
|
||||
Parallel,
|
||||
Perpendicular,
|
||||
Angle,
|
||||
RackPinion,
|
||||
Screw,
|
||||
Gears,
|
||||
Belt,
|
||||
};
|
||||
|
||||
enum class GeometryType
|
||||
{
|
||||
Point = 0,
|
||||
|
||||
// Edges
|
||||
Line = 1,
|
||||
Curve = 2,
|
||||
Circle = 3,
|
||||
|
||||
// Faces
|
||||
Place = 4,
|
||||
Cylinder = 5,
|
||||
Sphere = 6,
|
||||
Cone = 7,
|
||||
Torus = 8,
|
||||
};
|
||||
|
||||
enum class DistanceType
|
||||
{
|
||||
PointPoint,
|
||||
|
||||
LineLine,
|
||||
LineCircle,
|
||||
CircleCircle,
|
||||
|
||||
PlanePlane,
|
||||
PlaneCylinder,
|
||||
PlaneSphere,
|
||||
PlaneCone,
|
||||
PlaneTorus,
|
||||
CylinderCylinder,
|
||||
CylinderSphere,
|
||||
CylinderCone,
|
||||
CylinderTorus,
|
||||
ConeCone,
|
||||
ConeTorus,
|
||||
ConeSphere,
|
||||
TorusTorus,
|
||||
TorusSphere,
|
||||
SphereSphere,
|
||||
|
||||
PointPlane,
|
||||
PointCylinder,
|
||||
PointSphere,
|
||||
PointCone,
|
||||
PointTorus,
|
||||
|
||||
LinePlane,
|
||||
LineCylinder,
|
||||
LineSphere,
|
||||
LineCone,
|
||||
LineTorus,
|
||||
|
||||
CurvePlane,
|
||||
CurveCylinder,
|
||||
CurveSphere,
|
||||
CurveCone,
|
||||
CurveTorus,
|
||||
|
||||
PointLine,
|
||||
PointCurve,
|
||||
|
||||
Other,
|
||||
};
|
||||
|
||||
class AssemblyObject;
|
||||
class JointGroup;
|
||||
|
||||
AssemblyExport void swapJCS(const App::DocumentObject* joint);
|
||||
|
||||
AssemblyExport bool
|
||||
isEdgeType(const App::DocumentObject* obj, const std::string& elName, const GeomAbs_CurveType type);
|
||||
AssemblyExport bool isFaceType(const App::DocumentObject* obj,
|
||||
const std::string& elName,
|
||||
const GeomAbs_SurfaceType type);
|
||||
AssemblyExport double getFaceRadius(const App::DocumentObject* obj, const std::string& elName);
|
||||
AssemblyExport double getEdgeRadius(const App::DocumentObject* obj, const std::string& elName);
|
||||
|
||||
AssemblyExport DistanceType getDistanceType(App::DocumentObject* joint);
|
||||
AssemblyExport JointGroup* getJointGroup(const App::Part* part);
|
||||
|
||||
// getters to get from properties
|
||||
double getJointDistance(App::DocumentObject* joint);
|
||||
JointType getJointType(App::DocumentObject* joint);
|
||||
const char* getElementFromProp(App::DocumentObject* obj, const char* propName);
|
||||
std::string getElementTypeFromProp(App::DocumentObject* obj, const char* propName);
|
||||
App::DocumentObject* getLinkObjFromProp(App::DocumentObject* joint, const char* propName);
|
||||
App::DocumentObject* getObjFromNameProp(App::DocumentObject* joint, const char* pObjName, const
|
||||
char* pPart); App::DocumentObject* getLinkedObjFromNameProp(App::DocumentObject* joint, const char*
|
||||
pObjName, const char* pPart); Base::Placement getPlacementFromProp(App::DocumentObject* obj, const
|
||||
char* propName);*/
|
||||
AssemblyExport void setJointActivated(const App::DocumentObject* joint, bool val);
|
||||
AssemblyExport bool getJointActivated(const App::DocumentObject* joint);
|
||||
AssemblyExport double getJointDistance(const App::DocumentObject* joint);
|
||||
AssemblyExport double getJointDistance2(const App::DocumentObject* joint);
|
||||
AssemblyExport JointType getJointType(const App::DocumentObject* joint);
|
||||
AssemblyExport std::string getElementFromProp(const App::DocumentObject* obj, const char* propName);
|
||||
AssemblyExport std::string getElementTypeFromProp(const App::DocumentObject* obj,
|
||||
const char* propName);
|
||||
AssemblyExport App::DocumentObject* getObjFromProp(const App::DocumentObject* joint,
|
||||
const char* propName);
|
||||
AssemblyExport App::DocumentObject* getObjFromRef(const App::DocumentObject* obj,
|
||||
const std::string& sub);
|
||||
AssemblyExport App::DocumentObject* getObjFromRef(const App::PropertyXLinkSub* prop);
|
||||
AssemblyExport App::DocumentObject* getObjFromRef(const App::DocumentObject* joint,
|
||||
const char* propName);
|
||||
AssemblyExport App::DocumentObject* getLinkedObjFromRef(const App::DocumentObject* joint,
|
||||
const char* propName);
|
||||
AssemblyExport App::DocumentObject* getMovingPartFromRef(const AssemblyObject* assemblyObject,
|
||||
App::DocumentObject* obj,
|
||||
const std::string& sub);
|
||||
AssemblyExport App::DocumentObject* getMovingPartFromRef(const AssemblyObject* assemblyObject,
|
||||
const App::PropertyXLinkSub* prop);
|
||||
AssemblyExport App::DocumentObject* getMovingPartFromRef(const AssemblyObject* assemblyObject,
|
||||
App::DocumentObject* joint,
|
||||
const char* pName);
|
||||
AssemblyExport std::vector<std::string> getSubAsList(const App::PropertyXLinkSub* prop);
|
||||
AssemblyExport std::vector<std::string> getSubAsList(const App::DocumentObject* joint,
|
||||
const char* propName);
|
||||
|
||||
} // namespace Assembly
|
||||
|
||||
|
||||
@@ -54,6 +54,8 @@ SET(Assembly_SRCS
|
||||
AssemblyObject.h
|
||||
AssemblyLink.cpp
|
||||
AssemblyLink.h
|
||||
AssemblyUtils.cpp
|
||||
AssemblyUtils.h
|
||||
BomObject.cpp
|
||||
BomObject.h
|
||||
BomGroup.cpp
|
||||
|
||||
@@ -189,11 +189,11 @@ bool ViewProviderAssembly::canDragObjectToTarget(App::DocumentObject* obj,
|
||||
|
||||
for (auto joint : allJoints) {
|
||||
// getLinkObjFromProp returns nullptr if the property doesn't exist.
|
||||
App::DocumentObject* obj1 = AssemblyObject::getObjFromRef(joint, "Reference1");
|
||||
App::DocumentObject* obj2 = AssemblyObject::getObjFromRef(joint, "Reference2");
|
||||
App::DocumentObject* part1 = assemblyPart->getMovingPartFromRef(joint, "Reference1");
|
||||
App::DocumentObject* part2 = assemblyPart->getMovingPartFromRef(joint, "Reference2");
|
||||
App::DocumentObject* obj3 = AssemblyObject::getObjFromProp(joint, "ObjectToGround");
|
||||
App::DocumentObject* part1 = getMovingPartFromRef(assemblyPart, joint, "Reference1");
|
||||
App::DocumentObject* part2 = getMovingPartFromRef(assemblyPart, joint, "Reference2");
|
||||
App::DocumentObject* obj1 = getObjFromRef(joint, "Reference1");
|
||||
App::DocumentObject* obj2 = getObjFromRef(joint, "Reference2");
|
||||
App::DocumentObject* obj3 = getObjFromProp(joint, "ObjectToGround");
|
||||
if (obj == obj1 || obj == obj2 || obj == part1 || obj == part2 || obj == obj3) {
|
||||
if (!prompted) {
|
||||
prompted = true;
|
||||
@@ -662,13 +662,13 @@ bool ViewProviderAssembly::getSelectedObjectsWithinAssembly(bool addPreselection
|
||||
}
|
||||
|
||||
App::DocumentObject* selRoot = selObj.getObject();
|
||||
App::DocumentObject* obj = assemblyPart->getObjFromRef(selRoot, subNamesStr);
|
||||
App::DocumentObject* obj = getObjFromRef(selRoot, subNamesStr);
|
||||
if (!obj) {
|
||||
// In case of sub-assembly, the jointgroup would trigger the dragger.
|
||||
continue;
|
||||
}
|
||||
App::DocumentObject* part =
|
||||
assemblyPart->getMovingPartFromRef(selRoot, subNamesStr);
|
||||
getMovingPartFromRef(assemblyPart, selRoot, subNamesStr);
|
||||
|
||||
if (!canDragObjectIn3d(part)) {
|
||||
continue;
|
||||
@@ -694,7 +694,7 @@ bool ViewProviderAssembly::getSelectedObjectsWithinAssembly(bool addPreselection
|
||||
App::DocumentObject* selRoot = Gui::Selection().getPreselection().Object.getObject();
|
||||
std::string sub = Gui::Selection().getPreselection().pSubName;
|
||||
|
||||
App::DocumentObject* obj = assemblyPart->getMovingPartFromRef(selRoot, sub);
|
||||
App::DocumentObject* obj = getMovingPartFromRef(assemblyPart, selRoot, sub);
|
||||
if (canDragObjectIn3d(obj)) {
|
||||
|
||||
bool alreadyIn = false;
|
||||
@@ -760,7 +760,7 @@ ViewProviderAssembly::DragMode ViewProviderAssembly::findDragMode()
|
||||
return DragMode::TranslationNoSolve;
|
||||
}
|
||||
|
||||
JointType jointType = AssemblyObject::getJointType(movingJoint);
|
||||
JointType jointType = getJointType(movingJoint);
|
||||
if (jointType == JointType::Fixed) {
|
||||
// If fixed joint we need to find the upstream joint to find move mode.
|
||||
// For example : Gnd -(revolute)- A -(fixed)- B : if user try to move B, then we should
|
||||
@@ -793,7 +793,7 @@ ViewProviderAssembly::DragMode ViewProviderAssembly::findDragMode()
|
||||
docsToMove.emplace_back(upPart, pPlc->getValue(), selRoot, subs[0]);
|
||||
}
|
||||
|
||||
jointType = AssemblyObject::getJointType(movingJoint);
|
||||
jointType = getJointType(movingJoint);
|
||||
}
|
||||
|
||||
const char* plcPropName = (pName == "Reference1") ? "Placement1" : "Placement2";
|
||||
@@ -807,7 +807,7 @@ ViewProviderAssembly::DragMode ViewProviderAssembly::findDragMode()
|
||||
if (!ref) {
|
||||
return DragMode::Translation;
|
||||
}
|
||||
auto* obj = assemblyPart->getObjFromRef(movingJoint, pName.c_str());
|
||||
auto* obj = getObjFromRef(movingJoint, pName.c_str());
|
||||
Base::Placement global_plc = App::GeoFeature::getGlobalPlacement(obj, ref);
|
||||
jcsGlobalPlc = global_plc * jcsPlc;
|
||||
|
||||
@@ -830,7 +830,7 @@ ViewProviderAssembly::DragMode ViewProviderAssembly::findDragMode()
|
||||
}
|
||||
else if (jointType == JointType::Distance) {
|
||||
// depends on the type of distance. For example plane-plane:
|
||||
DistanceType distanceType = AssemblyObject::getDistanceType(movingJoint);
|
||||
DistanceType distanceType = getDistanceType(movingJoint);
|
||||
if (distanceType == DistanceType::PlanePlane || distanceType == DistanceType::Other) {
|
||||
return DragMode::TranslationOnPlane;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user