Merge pull request #15262 from Rexbas/fix-alignment-direction
Move getGlobalPlacement() and fix alignment direction for transformed objects
This commit is contained in:
@@ -442,6 +442,12 @@ public:
|
||||
/* Return true to cause PropertyView to show linked object's property */
|
||||
virtual bool canLinkProperties() const {return true;}
|
||||
|
||||
/* Return whether this object is a link */
|
||||
virtual bool isLink() const {return false;};
|
||||
|
||||
/* Return whether this object is a link group */
|
||||
virtual bool isLinkGroup() const {return false;};
|
||||
|
||||
/* Return true to bypass duplicate label checking */
|
||||
virtual bool allowDuplicateLabel() const {return false;}
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
#include <App/GeoFeaturePy.h>
|
||||
|
||||
#include <Base/Tools.h>
|
||||
|
||||
#include "ComplexGeoData.h"
|
||||
#include "Document.h"
|
||||
#include "GeoFeature.h"
|
||||
@@ -270,3 +272,63 @@ GeoFeature::getHigherElements(const char *element, bool silent) const
|
||||
return {};
|
||||
return prop->getComplexData()->getHigherElements(element, silent);
|
||||
}
|
||||
|
||||
Base::Placement GeoFeature::getPlacementFromProp(App::DocumentObject* obj, const char* propName)
|
||||
{
|
||||
Base::Placement plc = Base::Placement();
|
||||
auto* propPlacement = dynamic_cast<App::PropertyPlacement*>(obj->getPropertyByName(propName));
|
||||
if (propPlacement) {
|
||||
plc = propPlacement->getValue();
|
||||
}
|
||||
return plc;
|
||||
}
|
||||
|
||||
Base::Placement GeoFeature::getGlobalPlacement(App::DocumentObject* targetObj,
|
||||
App::DocumentObject* rootObj,
|
||||
const std::string& sub)
|
||||
{
|
||||
if (!targetObj || !rootObj || sub.empty()) {
|
||||
return Base::Placement();
|
||||
}
|
||||
std::vector<std::string> names = Base::Tools::splitSubName(sub);
|
||||
|
||||
App::Document* doc = rootObj->getDocument();
|
||||
Base::Placement plc = getPlacementFromProp(rootObj, "Placement");
|
||||
|
||||
if (targetObj == rootObj) return plc;
|
||||
|
||||
for (auto& name : names) {
|
||||
App::DocumentObject* obj = doc->getObject(name.c_str());
|
||||
if (!obj) {
|
||||
return Base::Placement();
|
||||
}
|
||||
|
||||
plc = plc * getPlacementFromProp(obj, "Placement");
|
||||
|
||||
if (obj == targetObj) {
|
||||
return plc;
|
||||
}
|
||||
if (obj->isLink()) {
|
||||
// Update doc in case its an external link.
|
||||
doc = obj->getLinkedObject()->getDocument();
|
||||
}
|
||||
}
|
||||
|
||||
// If targetObj has not been found there's a problem
|
||||
return Base::Placement();
|
||||
}
|
||||
|
||||
Base::Placement GeoFeature::getGlobalPlacement(App::DocumentObject* targetObj,
|
||||
App::PropertyXLinkSub* prop)
|
||||
{
|
||||
if (!targetObj || !prop) {
|
||||
return Base::Placement();
|
||||
}
|
||||
|
||||
std::vector<std::string> subs = prop->getSubValues();
|
||||
if (subs.empty()) {
|
||||
return Base::Placement();
|
||||
}
|
||||
|
||||
return getGlobalPlacement(targetObj, prop->getValue(), subs[0]);
|
||||
}
|
||||
|
||||
@@ -179,6 +179,10 @@ public:
|
||||
/// Return the higher level element names of the given element
|
||||
virtual std::vector<Data::IndexedName> getHigherElements(const char *name, bool silent=false) const;
|
||||
|
||||
static Base::Placement getPlacementFromProp(DocumentObject* obj, const char* propName);
|
||||
static Base::Placement getGlobalPlacement(DocumentObject* targetObj, DocumentObject* rootObj, const std::string& sub);
|
||||
static Base::Placement getGlobalPlacement(DocumentObject* targetObj, PropertyXLinkSub* prop);
|
||||
|
||||
protected:
|
||||
void onChanged(const Property* prop) override;
|
||||
// void onDocumentRestored() override;
|
||||
|
||||
@@ -2282,6 +2282,16 @@ bool Link::canLinkProperties() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Link::isLink() const
|
||||
{
|
||||
return ElementCount.getValue() == 0;
|
||||
}
|
||||
|
||||
bool Link::isLinkGroup() const
|
||||
{
|
||||
return ElementCount.getValue() > 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace App {
|
||||
@@ -2309,6 +2319,11 @@ bool LinkElement::canDelete() const {
|
||||
return !owner || !owner->getDocument()->getObjectByID(_LinkOwner.getValue());
|
||||
}
|
||||
|
||||
bool LinkElement::isLink() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
App::Link* LinkElement::getLinkGroup() const
|
||||
{
|
||||
std::vector<App::DocumentObject*> inList = getInList();
|
||||
|
||||
@@ -556,6 +556,10 @@ public:
|
||||
}
|
||||
|
||||
bool canLinkProperties() const override;
|
||||
|
||||
bool isLink() const override;
|
||||
|
||||
bool isLinkGroup() const override;
|
||||
};
|
||||
|
||||
using LinkPython = App::FeaturePythonT<Link>;
|
||||
@@ -600,6 +604,8 @@ public:
|
||||
_handleChangedPropertyName(reader,TypeName,PropName);
|
||||
}
|
||||
|
||||
bool isLink() const override;
|
||||
|
||||
App::Link* getLinkGroup() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -372,3 +372,24 @@ std::string Base::Tools::currentDateTimeString()
|
||||
.toString(Qt::ISODate)
|
||||
.toStdString();
|
||||
}
|
||||
|
||||
std::vector<std::string> Base::Tools::splitSubName(const std::string& subname)
|
||||
{
|
||||
// Turns 'Part.Part001.Body.Pad.Edge1'
|
||||
// Into ['Part', 'Part001', 'Body', 'Pad', 'Edge1']
|
||||
std::vector<std::string> subNames;
|
||||
std::string subName;
|
||||
std::istringstream subNameStream(subname);
|
||||
while (std::getline(subNameStream, subName, '.')) {
|
||||
subNames.push_back(subName);
|
||||
}
|
||||
|
||||
// Check if the last character of the input string is the delimiter.
|
||||
// If so, add an empty string to the subNames vector.
|
||||
// Because the last subname is the element name and can be empty.
|
||||
if (!subname.empty() && subname.back() == '.') {
|
||||
subNames.push_back(""); // Append empty string for trailing dot.
|
||||
}
|
||||
|
||||
return subNames;
|
||||
}
|
||||
|
||||
@@ -325,6 +325,8 @@ struct BaseExport Tools
|
||||
static std::string joinList(const std::vector<std::string>& vec, const std::string& sep = ", ");
|
||||
|
||||
static std::string currentDateTimeString();
|
||||
|
||||
static std::vector<std::string> splitSubName(const std::string& subname);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -127,9 +127,9 @@
|
||||
#include "Utilities.h"
|
||||
|
||||
|
||||
FC_LOG_LEVEL_INIT("3DViewer",true,true)
|
||||
FC_LOG_LEVEL_INIT("3DViewer", true, true)
|
||||
|
||||
//#define FC_LOGGING_CB
|
||||
// #define FC_LOGGING_CB
|
||||
|
||||
using namespace Gui;
|
||||
|
||||
@@ -3358,7 +3358,7 @@ void View3DInventorViewer::alignToSelection()
|
||||
return;
|
||||
}
|
||||
|
||||
const auto selection = Selection().getSelection();
|
||||
const auto selection = Selection().getSelection(nullptr, ResolveMode::NoResolve);
|
||||
|
||||
// Empty selection
|
||||
if (selection.empty()) {
|
||||
@@ -3373,13 +3373,18 @@ void View3DInventorViewer::alignToSelection()
|
||||
// Get the geo feature
|
||||
App::GeoFeature* geoFeature = nullptr;
|
||||
App::ElementNamePair elementName;
|
||||
App::GeoFeature::resolveElement(selection[0].pObject, selection[0].SubName, elementName, false, App::GeoFeature::ElementNameType::Normal, nullptr, nullptr, &geoFeature);
|
||||
App::GeoFeature::resolveElement(selection[0].pObject, selection[0].SubName, elementName, true, App::GeoFeature::ElementNameType::Normal, nullptr, nullptr, &geoFeature);
|
||||
if (!geoFeature) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto globalPlacement = App::GeoFeature::getGlobalPlacement(selection[0].pResolvedObject, selection[0].pObject, elementName.oldName);
|
||||
const auto rotation = globalPlacement.getRotation() * geoFeature->Placement.getValue().getRotation().inverse();
|
||||
const auto geoFeatureSubName = Base::Tools::splitSubName(elementName.oldName).back();
|
||||
|
||||
Base::Vector3d direction;
|
||||
if (geoFeature->getCameraAlignmentDirection(direction, selection[0].SubName)) {
|
||||
if (geoFeature->getCameraAlignmentDirection(direction, geoFeatureSubName.c_str())) {
|
||||
rotation.multVec(direction, direction);
|
||||
const auto orientation = SbRotation(SbVec3f(0, 0, 1), Base::convertTo<SbVec3f>(direction));
|
||||
setCameraOrientation(orientation);
|
||||
}
|
||||
|
||||
@@ -111,39 +111,6 @@ static void printPlacement(Base::Placement plc, const char* name)
|
||||
angle);
|
||||
}*/
|
||||
|
||||
static bool isLink(App::DocumentObject* obj)
|
||||
{
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* link = dynamic_cast<App::Link*>(obj);
|
||||
if (link) {
|
||||
return link->ElementCount.getValue() == 0;
|
||||
}
|
||||
|
||||
auto* linkEl = dynamic_cast<App::LinkElement*>(obj);
|
||||
if (linkEl) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isLinkGroup(App::DocumentObject* obj)
|
||||
{
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* link = dynamic_cast<App::Link*>(obj);
|
||||
if (link) {
|
||||
return link->ElementCount.getValue() > 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ================================ Assembly Object ============================
|
||||
|
||||
PROPERTY_SOURCE(Assembly::AssemblyObject, App::Part)
|
||||
@@ -1733,7 +1700,7 @@ void AssemblyObject::ensureIdentityPlacements()
|
||||
std::vector<App::DocumentObject*> group = Group.getValues();
|
||||
for (auto* obj : group) {
|
||||
// When used in assembly, link groups must have identity placements.
|
||||
if (isLinkGroup(obj)) {
|
||||
if (obj->isLinkGroup()) {
|
||||
auto* link = dynamic_cast<App::Link*>(obj);
|
||||
auto* pPlc = dynamic_cast<App::PropertyPlacement*>(obj->getPropertyByName("Placement"));
|
||||
if (!pPlc || !link) {
|
||||
@@ -2078,6 +2045,7 @@ void AssemblyObject::setJointActivated(App::DocumentObject* joint, bool val)
|
||||
propActivated->setValue(val);
|
||||
}
|
||||
}
|
||||
|
||||
bool AssemblyObject::getJointActivated(App::DocumentObject* joint)
|
||||
{
|
||||
auto* propActivated = dynamic_cast<App::PropertyBool*>(joint->getPropertyByName("Activated"));
|
||||
@@ -2087,65 +2055,6 @@ bool AssemblyObject::getJointActivated(App::DocumentObject* joint)
|
||||
return false;
|
||||
}
|
||||
|
||||
Base::Placement AssemblyObject::getPlacementFromProp(App::DocumentObject* obj, const char* propName)
|
||||
{
|
||||
Base::Placement plc = Base::Placement();
|
||||
auto* propPlacement = dynamic_cast<App::PropertyPlacement*>(obj->getPropertyByName(propName));
|
||||
if (propPlacement) {
|
||||
plc = propPlacement->getValue();
|
||||
}
|
||||
return plc;
|
||||
}
|
||||
|
||||
|
||||
Base::Placement AssemblyObject::getGlobalPlacement(App::DocumentObject* targetObj,
|
||||
App::DocumentObject* rootObj,
|
||||
const std::string& sub)
|
||||
{
|
||||
if (!targetObj || !rootObj || sub == "") {
|
||||
return Base::Placement();
|
||||
}
|
||||
std::vector<std::string> names = splitSubName(sub);
|
||||
|
||||
App::Document* doc = rootObj->getDocument();
|
||||
Base::Placement plc = getPlacementFromProp(rootObj, "Placement");
|
||||
|
||||
for (auto& name : names) {
|
||||
App::DocumentObject* obj = doc->getObject(name.c_str());
|
||||
if (!obj) {
|
||||
return Base::Placement();
|
||||
}
|
||||
|
||||
plc = plc * getPlacementFromProp(obj, "Placement");
|
||||
|
||||
if (obj == targetObj) {
|
||||
return plc;
|
||||
}
|
||||
if (isLink(obj)) {
|
||||
// Update doc in case its an external link.
|
||||
doc = obj->getLinkedObject()->getDocument();
|
||||
}
|
||||
}
|
||||
|
||||
// If targetObj has not been found there's a problem
|
||||
return Base::Placement();
|
||||
}
|
||||
|
||||
Base::Placement AssemblyObject::getGlobalPlacement(App::DocumentObject* targetObj,
|
||||
App::PropertyXLinkSub* prop)
|
||||
{
|
||||
if (!targetObj || !prop) {
|
||||
return Base::Placement();
|
||||
}
|
||||
|
||||
std::vector<std::string> subs = prop->getSubValues();
|
||||
if (subs.empty()) {
|
||||
return Base::Placement();
|
||||
}
|
||||
|
||||
return getGlobalPlacement(targetObj, prop->getValue(), subs[0]);
|
||||
}
|
||||
|
||||
double AssemblyObject::getJointDistance(App::DocumentObject* joint)
|
||||
{
|
||||
double distance = 0.0;
|
||||
@@ -2193,7 +2102,7 @@ std::vector<std::string> AssemblyObject::getSubAsList(App::PropertyXLinkSub* pro
|
||||
return {};
|
||||
}
|
||||
|
||||
return splitSubName(subs[0]);
|
||||
return Base::Tools::splitSubName(subs[0]);
|
||||
}
|
||||
|
||||
std::vector<std::string> AssemblyObject::getSubAsList(App::DocumentObject* obj, const char* pName)
|
||||
@@ -2203,27 +2112,6 @@ std::vector<std::string> AssemblyObject::getSubAsList(App::DocumentObject* obj,
|
||||
return getSubAsList(prop);
|
||||
}
|
||||
|
||||
std::vector<std::string> AssemblyObject::splitSubName(const std::string& sub)
|
||||
{
|
||||
// Turns 'Part.Part001.Body.Pad.Edge1'
|
||||
// Into ['Part', 'Part001','Body','Pad','Edge1']
|
||||
std::vector<std::string> subNames;
|
||||
std::string subName;
|
||||
std::istringstream subNameStream(sub);
|
||||
while (std::getline(subNameStream, subName, '.')) {
|
||||
subNames.push_back(subName);
|
||||
}
|
||||
|
||||
// Check if the last character of the input string is the delimiter.
|
||||
// If so, add an empty string to the subNames vector.
|
||||
// Because the last subname is the element name and can be empty.
|
||||
if (!sub.empty() && sub.back() == '.') {
|
||||
subNames.push_back(""); // Append empty string for trailing dot.
|
||||
}
|
||||
|
||||
return subNames;
|
||||
}
|
||||
|
||||
std::string AssemblyObject::getElementFromProp(App::DocumentObject* obj, const char* pName)
|
||||
{
|
||||
std::vector<std::string> names = getSubAsList(obj, pName);
|
||||
@@ -2264,7 +2152,7 @@ App::DocumentObject* AssemblyObject::getObjFromRef(App::DocumentObject* obj, std
|
||||
|
||||
App::Document* doc = obj->getDocument();
|
||||
|
||||
std::vector<std::string> names = splitSubName(sub);
|
||||
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 {
|
||||
@@ -2306,7 +2194,7 @@ App::DocumentObject* AssemblyObject::getObjFromRef(App::DocumentObject* obj, std
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (obj->isDerivedFrom<App::Part>() || isLinkGroup(obj)) {
|
||||
if (obj->isDerivedFrom<App::Part>() || obj->isLinkGroup()) {
|
||||
continue;
|
||||
}
|
||||
else if (obj->isDerivedFrom<PartDesign::Body>()) {
|
||||
@@ -2316,7 +2204,7 @@ App::DocumentObject* AssemblyObject::getObjFromRef(App::DocumentObject* obj, std
|
||||
// Primitive, fastener, gear, etc.
|
||||
return obj;
|
||||
}
|
||||
else if (isLink(obj)) {
|
||||
else if (obj->isLink()) {
|
||||
App::DocumentObject* linked_obj = obj->getLinkedObject();
|
||||
if (linked_obj->isDerivedFrom<PartDesign::Body>()) {
|
||||
auto* retObj = handlePartDesignBody(linked_obj, it);
|
||||
@@ -2370,7 +2258,7 @@ App::DocumentObject* AssemblyObject::getMovingPartFromRef(App::DocumentObject* o
|
||||
|
||||
App::Document* doc = obj->getDocument();
|
||||
|
||||
std::vector<std::string> names = splitSubName(sub);
|
||||
std::vector<std::string> names = Base::Tools::splitSubName(sub);
|
||||
names.insert(names.begin(), obj->getNameInDocument());
|
||||
|
||||
bool assemblyPassed = false;
|
||||
@@ -2381,7 +2269,7 @@ App::DocumentObject* AssemblyObject::getMovingPartFromRef(App::DocumentObject* o
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isLink(obj)) { // update the document if necessary for next object
|
||||
if (obj->isLink()) { // update the document if necessary for next object
|
||||
doc = obj->getLinkedObject()->getDocument();
|
||||
}
|
||||
|
||||
@@ -2398,7 +2286,7 @@ App::DocumentObject* AssemblyObject::getMovingPartFromRef(App::DocumentObject* o
|
||||
continue; // we ignore groups.
|
||||
}
|
||||
|
||||
if (isLinkGroup(obj)) {
|
||||
if (obj->isLinkGroup()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -280,14 +280,6 @@ public:
|
||||
const char* propName);
|
||||
static std::vector<std::string> getSubAsList(App::PropertyXLinkSub* prop);
|
||||
static std::vector<std::string> getSubAsList(App::DocumentObject* joint, const char* propName);
|
||||
static std::vector<std::string> splitSubName(const std::string& subName);
|
||||
static Base::Placement getPlacementFromProp(App::DocumentObject* obj, const char* propName);
|
||||
|
||||
static Base::Placement getGlobalPlacement(App::DocumentObject* targetObj,
|
||||
App::DocumentObject* rootObj,
|
||||
const std::string& sub);
|
||||
static Base::Placement getGlobalPlacement(App::DocumentObject* targetObj,
|
||||
App::PropertyXLinkSub* prop);
|
||||
};
|
||||
|
||||
// using AssemblyObjectPython = App::FeaturePythonT<AssemblyObject>;
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
#include <App/DocumentObject.h>
|
||||
#include <App/Part.h>
|
||||
|
||||
#include <Base/Tools.h>
|
||||
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/BitmapFactory.h>
|
||||
#include <Gui/CommandT.h>
|
||||
@@ -618,7 +620,7 @@ bool ViewProviderAssembly::getSelectedObjectsWithinAssembly(bool addPreselection
|
||||
|
||||
std::vector<std::string> objsSubNames = selObj.getSubNames();
|
||||
for (auto& subNamesStr : objsSubNames) {
|
||||
std::vector<std::string> subNames = AssemblyObject::splitSubName(subNamesStr);
|
||||
std::vector<std::string> subNames = Base::Tools::splitSubName(subNamesStr);
|
||||
if (subNames.empty()) {
|
||||
continue;
|
||||
}
|
||||
@@ -764,7 +766,7 @@ ViewProviderAssembly::DragMode ViewProviderAssembly::findDragMode()
|
||||
const char* plcPropName = (pName == "Reference1") ? "Placement1" : "Placement2";
|
||||
|
||||
// jcsPlc is relative to the Object
|
||||
jcsPlc = AssemblyObject::getPlacementFromProp(movingJoint, plcPropName);
|
||||
jcsPlc = App::GeoFeature::getPlacementFromProp(movingJoint, plcPropName);
|
||||
|
||||
// Make jcsGlobalPlc relative to the origin of the doc
|
||||
auto* ref =
|
||||
@@ -773,7 +775,7 @@ ViewProviderAssembly::DragMode ViewProviderAssembly::findDragMode()
|
||||
return DragMode::Translation;
|
||||
}
|
||||
auto* obj = assemblyPart->getObjFromRef(movingJoint, pName.c_str());
|
||||
Base::Placement global_plc = AssemblyObject::getGlobalPlacement(obj, ref);
|
||||
Base::Placement global_plc = App::GeoFeature::getGlobalPlacement(obj, ref);
|
||||
jcsGlobalPlc = global_plc * jcsPlc;
|
||||
|
||||
// Add downstream parts so that they move together
|
||||
@@ -920,7 +922,7 @@ void ViewProviderAssembly::initMoveDragger()
|
||||
App::DocumentObject* part = docsToMove[0].obj;
|
||||
|
||||
draggerInitPlc =
|
||||
AssemblyObject::getGlobalPlacement(part, docsToMove[0].rootObj, docsToMove[0].sub);
|
||||
App::GeoFeature::getGlobalPlacement(part, docsToMove[0].rootObj, docsToMove[0].sub);
|
||||
std::vector<App::DocumentObject*> listOfObjs;
|
||||
std::vector<App::PropertyXLinkSub*> listOfRefs;
|
||||
for (auto& movingObj : docsToMove) {
|
||||
@@ -1130,11 +1132,11 @@ ViewProviderAssembly::getCenterOfBoundingBox(const std::vector<MovingObject>& mo
|
||||
// bboxCenter does not take into account obj global placement
|
||||
Base::Placement plc(bboxCenter, Base::Rotation());
|
||||
// Change plc to be relative to the object placement.
|
||||
Base::Placement objPlc = AssemblyObject::getPlacementFromProp(movingObj.obj, "Placement");
|
||||
Base::Placement objPlc = App::GeoFeature::getPlacementFromProp(movingObj.obj, "Placement");
|
||||
plc = objPlc.inverse() * plc;
|
||||
// Change plc to be relative to the origin of the document.
|
||||
Base::Placement global_plc =
|
||||
AssemblyObject::getGlobalPlacement(movingObj.obj, movingObj.rootObj, movingObj.sub);
|
||||
App::GeoFeature::getGlobalPlacement(movingObj.obj, movingObj.rootObj, movingObj.sub);
|
||||
plc = global_plc * plc;
|
||||
bboxCenter = plc.getPosition();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user