Merge pull request #15262 from Rexbas/fix-alignment-direction

Move getGlobalPlacement() and fix alignment direction for transformed objects
This commit is contained in:
Chris Hennes
2024-09-13 13:09:23 -06:00
committed by GitHub
11 changed files with 143 additions and 140 deletions

View File

@@ -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;}

View File

@@ -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]);
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;
};

View File

@@ -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;
}

View File

@@ -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);
};

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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>;

View File

@@ -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();