Assembly: AssemblyLinks.
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
#include <Base/PyObjectBase.h>
|
||||
|
||||
#include "AssemblyObject.h"
|
||||
#include "AssemblyLink.h"
|
||||
#include "BomObject.h"
|
||||
#include "BomGroup.h"
|
||||
#include "JointGroup.h"
|
||||
@@ -61,6 +62,7 @@ PyMOD_INIT_FUNC(AssemblyApp)
|
||||
// This function is responsible for adding inherited slots from a type's base class.
|
||||
|
||||
Assembly::AssemblyObject ::init();
|
||||
Assembly::AssemblyLink ::init();
|
||||
Assembly::BomObject ::init();
|
||||
|
||||
Assembly::BomGroup ::init();
|
||||
|
||||
@@ -0,0 +1,582 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2024 Ondsel <[email protected]> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObjectGroup.h>
|
||||
#include <App/FeaturePythonPyImp.h>
|
||||
#include <App/Link.h>
|
||||
#include <App/PropertyPythonObject.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Placement.h>
|
||||
#include <Base/Rotation.h>
|
||||
#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 "AssemblyObject.h"
|
||||
#include "JointGroup.h"
|
||||
|
||||
#include "AssemblyLink.h"
|
||||
#include "AssemblyLinkPy.h"
|
||||
|
||||
namespace PartApp = Part;
|
||||
|
||||
using namespace Assembly;
|
||||
|
||||
// ================================ Assembly Object ============================
|
||||
|
||||
PROPERTY_SOURCE(Assembly::AssemblyLink, App::Part)
|
||||
|
||||
AssemblyLink::AssemblyLink()
|
||||
{
|
||||
ADD_PROPERTY_TYPE(Rigid,
|
||||
(true),
|
||||
"General",
|
||||
(App::PropertyType)(App::Prop_None),
|
||||
"If the sub-assembly is set to Rigid, it will act "
|
||||
"as a rigid body. Else its joints will be taken into account.");
|
||||
|
||||
ADD_PROPERTY_TYPE(LinkedObject,
|
||||
(nullptr),
|
||||
"General",
|
||||
(App::PropertyType)(App::Prop_None),
|
||||
"The linked assembly.");
|
||||
}
|
||||
|
||||
AssemblyLink::~AssemblyLink() = default;
|
||||
|
||||
PyObject* AssemblyLink::getPyObject()
|
||||
{
|
||||
if (PythonObject.is(Py::_None())) {
|
||||
// ref counter is set to 1
|
||||
PythonObject = Py::Object(new AssemblyLinkPy(this), true);
|
||||
}
|
||||
return Py::new_reference_to(PythonObject);
|
||||
}
|
||||
|
||||
App::DocumentObjectExecReturn* AssemblyLink::execute()
|
||||
{
|
||||
updateContents();
|
||||
|
||||
return App::Part::execute();
|
||||
}
|
||||
|
||||
void AssemblyLink::onChanged(const App::Property* prop)
|
||||
{
|
||||
if (App::GetApplication().isRestoring()) {
|
||||
App::Part::onChanged(prop);
|
||||
return;
|
||||
}
|
||||
|
||||
if (prop == &Rigid) {
|
||||
Base::Placement movePlc;
|
||||
|
||||
if (Rigid.getValue()) {
|
||||
// movePlc needs to be computed before updateContents.
|
||||
if (!objLinkMap.empty()) {
|
||||
auto firstElement = *objLinkMap.begin();
|
||||
|
||||
App::DocumentObject* obj = firstElement.first;
|
||||
App::DocumentObject* link = firstElement.second;
|
||||
auto* prop =
|
||||
dynamic_cast<App::PropertyPlacement*>(obj->getPropertyByName("Placement"));
|
||||
auto* prop2 =
|
||||
dynamic_cast<App::PropertyPlacement*>(link->getPropertyByName("Placement"));
|
||||
if (prop && prop2) {
|
||||
movePlc = prop2->getValue() * prop->getValue().inverse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateContents();
|
||||
|
||||
auto* propPlc = dynamic_cast<App::PropertyPlacement*>(getPropertyByName("Placement"));
|
||||
if (!propPlc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Rigid.getValue()) {
|
||||
// when the assemblyLink becomes flexible, we need to make sure its placement is
|
||||
// identity or it's going to mess up moving parts placement within.
|
||||
Base::Placement plc = propPlc->getValue();
|
||||
if (!plc.isIdentity()) {
|
||||
propPlc->setValue(Base::Placement());
|
||||
|
||||
// We need to apply the placement of the assembly link to the children or they will
|
||||
// move.
|
||||
std::vector<App::DocumentObject*> group = Group.getValues();
|
||||
for (auto* obj : group) {
|
||||
if (!obj->isDerivedFrom<App::Part>() && !obj->isDerivedFrom<PartApp::Feature>()
|
||||
&& !obj->isDerivedFrom<App::Link>()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* prop =
|
||||
dynamic_cast<App::PropertyPlacement*>(obj->getPropertyByName("Placement"));
|
||||
if (prop) {
|
||||
prop->setValue(plc * prop->getValue());
|
||||
}
|
||||
}
|
||||
|
||||
AssemblyObject::redrawJointPlacements(getJoints());
|
||||
}
|
||||
}
|
||||
else {
|
||||
// For the assemblylink not to move to origin, we need to update its placement.
|
||||
if (!movePlc.isIdentity()) {
|
||||
propPlc->setValue(movePlc);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
App::Part::onChanged(prop);
|
||||
}
|
||||
|
||||
void AssemblyLink::updateContents()
|
||||
{
|
||||
synchronizeComponents();
|
||||
|
||||
if (isRigid()) {
|
||||
ensureNoJointGroup();
|
||||
}
|
||||
else {
|
||||
synchronizeJoints();
|
||||
}
|
||||
|
||||
purgeTouched();
|
||||
}
|
||||
|
||||
void AssemblyLink::synchronizeComponents()
|
||||
{
|
||||
App::Document* doc = getDocument();
|
||||
|
||||
AssemblyObject* assembly = getLinkedAssembly();
|
||||
if (!assembly) {
|
||||
return;
|
||||
}
|
||||
|
||||
objLinkMap.clear();
|
||||
|
||||
std::vector<App::DocumentObject*> assemblyGroup = assembly->Group.getValues();
|
||||
std::vector<App::DocumentObject*> assemblyLinkGroup = Group.getValues();
|
||||
|
||||
// We check if a component needs to be added to the AssemblyLink
|
||||
for (auto* obj : assemblyGroup) {
|
||||
if (!obj->isDerivedFrom<App::Part>() && !obj->isDerivedFrom<PartApp::Feature>()
|
||||
&& !obj->isDerivedFrom<App::Link>()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Note, the user can have nested sub-assemblies.
|
||||
// In which case we need to add an AssemblyLink and not a Link.
|
||||
App::DocumentObject* link = nullptr;
|
||||
bool found = false;
|
||||
for (auto* obj2 : assemblyLinkGroup) {
|
||||
App::DocumentObject* linkedObj;
|
||||
|
||||
auto* subAsmLink = dynamic_cast<AssemblyLink*>(obj2);
|
||||
auto* link2 = dynamic_cast<App::Link*>(obj2);
|
||||
if (subAsmLink) {
|
||||
linkedObj = subAsmLink->getLinkedObject2(false); // not recursive
|
||||
}
|
||||
else if (link2) {
|
||||
linkedObj = link2->getLinkedObject(false); // not recursive
|
||||
}
|
||||
else {
|
||||
// We consider only Links and AssemblyLinks in the AssemblyLink.
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (linkedObj == obj) {
|
||||
found = true;
|
||||
link = obj2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
// Add a link or a AssemblyLink to it in the AssemblyLink.
|
||||
if (obj->isDerivedFrom<AssemblyLink>()) {
|
||||
auto* asmLink = static_cast<AssemblyLink*>(obj);
|
||||
auto* subAsmLink = new AssemblyLink();
|
||||
doc->addObject(subAsmLink, obj->getNameInDocument());
|
||||
subAsmLink->LinkedObject.setValue(obj);
|
||||
subAsmLink->Rigid.setValue(asmLink->Rigid.getValue());
|
||||
subAsmLink->Label.setValue(obj->Label.getValue());
|
||||
addObject(subAsmLink);
|
||||
link = subAsmLink;
|
||||
}
|
||||
else {
|
||||
auto* appLink = new App::Link();
|
||||
doc->addObject(appLink, obj->getNameInDocument());
|
||||
appLink->LinkedObject.setValue(obj);
|
||||
appLink->Label.setValue(obj->Label.getValue());
|
||||
addObject(appLink);
|
||||
link = appLink;
|
||||
}
|
||||
}
|
||||
|
||||
objLinkMap[obj] = link;
|
||||
// If the assemblyLink is rigid, then we keep the placement synchronized.
|
||||
if (isRigid()) {
|
||||
auto* plcProp =
|
||||
dynamic_cast<App::PropertyPlacement*>(obj->getPropertyByName("Placement"));
|
||||
auto* plcProp2 =
|
||||
dynamic_cast<App::PropertyPlacement*>(link->getPropertyByName("Placement"));
|
||||
if (plcProp && plcProp2) {
|
||||
if (!plcProp->getValue().isSame(plcProp2->getValue())) {
|
||||
plcProp2->setValue(plcProp->getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We check if a component needs to be removed from the AssemblyLink
|
||||
for (auto* link : assemblyLinkGroup) {
|
||||
// We don't need to update assemblyLinkGroup after the addition since we're not removing
|
||||
// something we just added.
|
||||
|
||||
if (objLinkMap.find(link) != objLinkMap.end()) {
|
||||
doc->removeObject(link->getNameInDocument());
|
||||
}
|
||||
|
||||
/*if (!link->isDerivedFrom<App::Link>() && !link->isDerivedFrom<AssemblyLink>()) {
|
||||
// AssemblyLink should contain only Links or assembly links.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* linkedObj = link->getLinkedObject(false); // not recursive
|
||||
|
||||
bool found = false;
|
||||
for (auto* obj2 : assemblyGroup) {
|
||||
if (obj2 == linkedObj) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
doc->removeObject(link->getNameInDocument());
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename T>
|
||||
void copyPropertyIfDifferent(App::DocumentObject* source,
|
||||
App::DocumentObject* target,
|
||||
const char* propertyName)
|
||||
{
|
||||
auto sourceProp = dynamic_cast<T*>(source->getPropertyByName(propertyName));
|
||||
auto targetProp = dynamic_cast<T*>(target->getPropertyByName(propertyName));
|
||||
if (sourceProp && targetProp && sourceProp->getValue() != targetProp->getValue()) {
|
||||
targetProp->setValue(sourceProp->getValue());
|
||||
}
|
||||
}
|
||||
|
||||
std::string removeUpToName(const std::string& sub, const std::string& name)
|
||||
{
|
||||
size_t pos = sub.find(name);
|
||||
if (pos != std::string::npos) {
|
||||
// Move the position to the character after the found substring and the following '.'
|
||||
pos += name.length() + 1;
|
||||
if (pos < sub.length()) {
|
||||
return sub.substr(pos);
|
||||
}
|
||||
}
|
||||
// If s2 is not found in s1, return the original string
|
||||
return sub;
|
||||
}
|
||||
|
||||
std::string
|
||||
replaceLastOccurrence(const std::string& str, const std::string& oldStr, const std::string& newStr)
|
||||
{
|
||||
size_t pos = str.rfind(oldStr);
|
||||
if (pos != std::string::npos) {
|
||||
std::string result = str;
|
||||
result.replace(pos, oldStr.length(), newStr);
|
||||
return result;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}; // namespace
|
||||
|
||||
void AssemblyLink::synchronizeJoints()
|
||||
{
|
||||
App::Document* doc = getDocument();
|
||||
AssemblyObject* assembly = getLinkedAssembly();
|
||||
if (!assembly) {
|
||||
return;
|
||||
}
|
||||
|
||||
JointGroup* jGroup = ensureJointGroup();
|
||||
|
||||
std::vector<App::DocumentObject*> assemblyJoints =
|
||||
assembly->getJoints(assembly->isTouched(), false, false);
|
||||
std::vector<App::DocumentObject*> assemblyLinkJoints = getJoints();
|
||||
|
||||
// We delete the excess of joints if any
|
||||
for (size_t i = assemblyJoints.size(); i < assemblyLinkJoints.size(); ++i) {
|
||||
doc->removeObject(assemblyLinkJoints[i]->getNameInDocument());
|
||||
}
|
||||
|
||||
// We make sure the joints match.
|
||||
for (size_t i = 0; i < assemblyJoints.size(); ++i) {
|
||||
App::DocumentObject* joint = assemblyJoints[i];
|
||||
App::DocumentObject* lJoint;
|
||||
if (i < assemblyLinkJoints.size()) {
|
||||
lJoint = assemblyLinkJoints[i];
|
||||
}
|
||||
else {
|
||||
auto ret = doc->copyObject({joint});
|
||||
if (ret.size() != 1) {
|
||||
continue;
|
||||
}
|
||||
lJoint = ret[0];
|
||||
jGroup->addObject(lJoint);
|
||||
}
|
||||
|
||||
// Then we have to check the properties one by one.
|
||||
copyPropertyIfDifferent<App::PropertyBool>(joint, lJoint, "Activated");
|
||||
copyPropertyIfDifferent<App::PropertyFloat>(joint, lJoint, "Distance");
|
||||
copyPropertyIfDifferent<App::PropertyFloat>(joint, lJoint, "Distance2");
|
||||
copyPropertyIfDifferent<App::PropertyEnumeration>(joint, lJoint, "JointType");
|
||||
copyPropertyIfDifferent<App::PropertyPlacement>(joint, lJoint, "Offset1");
|
||||
copyPropertyIfDifferent<App::PropertyPlacement>(joint, lJoint, "Offset2");
|
||||
|
||||
copyPropertyIfDifferent<App::PropertyBool>(joint, lJoint, "Detach1");
|
||||
copyPropertyIfDifferent<App::PropertyBool>(joint, lJoint, "Detach2");
|
||||
|
||||
copyPropertyIfDifferent<App::PropertyFloat>(joint, lJoint, "AngleMax");
|
||||
copyPropertyIfDifferent<App::PropertyFloat>(joint, lJoint, "AngleMin");
|
||||
copyPropertyIfDifferent<App::PropertyFloat>(joint, lJoint, "LengthMax");
|
||||
copyPropertyIfDifferent<App::PropertyFloat>(joint, lJoint, "LengthMin");
|
||||
copyPropertyIfDifferent<App::PropertyBool>(joint, lJoint, "EnableAngleMax");
|
||||
copyPropertyIfDifferent<App::PropertyBool>(joint, lJoint, "EnableAngleMin");
|
||||
copyPropertyIfDifferent<App::PropertyBool>(joint, lJoint, "EnableLengthMax");
|
||||
copyPropertyIfDifferent<App::PropertyBool>(joint, lJoint, "EnableLengthMin");
|
||||
|
||||
// The reference needs to be handled specifically
|
||||
handleJointReference(joint, lJoint, "Reference1");
|
||||
handleJointReference(joint, lJoint, "Reference2");
|
||||
}
|
||||
|
||||
assemblyLinkJoints = getJoints();
|
||||
|
||||
AssemblyObject::recomputeJointPlacements(assemblyLinkJoints);
|
||||
|
||||
for (auto* joint : assemblyLinkJoints) {
|
||||
joint->purgeTouched();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AssemblyLink::handleJointReference(App::DocumentObject* joint,
|
||||
App::DocumentObject* lJoint,
|
||||
const char* refName)
|
||||
{
|
||||
AssemblyObject* assembly = getLinkedAssembly();
|
||||
|
||||
auto prop1 = dynamic_cast<App::PropertyXLinkSubHidden*>(joint->getPropertyByName(refName));
|
||||
auto prop2 = dynamic_cast<App::PropertyXLinkSubHidden*>(lJoint->getPropertyByName(refName));
|
||||
if (!prop1 || !prop2) {
|
||||
return;
|
||||
}
|
||||
|
||||
App::DocumentObject* obj1 = nullptr;
|
||||
App::DocumentObject* obj2 = prop2->getValue();
|
||||
std::vector<std::string> subs1 = prop1->getSubValues();
|
||||
std::vector<std::string> subs2 = prop2->getSubValues();
|
||||
if (subs1.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Example :
|
||||
// Obj1 = docA-Asm1 Subs1 = ["part1.body.pad.face0", "part1.body.pad.vertex1"]
|
||||
// Obj1 = docA-Part Subs1 = ["Asm1.part1.body.pad.face0", "Asm1.part1.body.pad.vertex1"] // some
|
||||
// user may put the assembly inside a part... should become : Obj2 = docB-Asm2 Subs2 =
|
||||
// ["Asm1Link.part1.linkTobody.pad.face0", "Asm1Link.part1.linkTobody.pad.vertex1"] Obj2 =
|
||||
// docB-Part Sub2 = ["Asm2.Asm1Link.part1.linkTobody.pad.face0",
|
||||
// "Asm2.Asm1Link.part1.linkTobody.pad.vertex1"]
|
||||
|
||||
std::string asmLink = getNameInDocument();
|
||||
for (auto& sub : subs1) {
|
||||
// First let's remove 'Asm1' name and everything before if any.
|
||||
sub = removeUpToName(sub, assembly->getNameInDocument());
|
||||
// Then we add the assembly link name.
|
||||
sub = asmLink + "." + sub;
|
||||
// Then the question is, is there more to prepend? Because the parent assembly may have some
|
||||
// parents So we check assemblyLink parents and prepend necessary parents.
|
||||
bool first = true;
|
||||
std::vector<App::DocumentObject*> inList = getInList();
|
||||
int limit = 0;
|
||||
while (!inList.empty() && limit < 20) {
|
||||
++limit;
|
||||
bool found = false;
|
||||
for (auto* obj : inList) {
|
||||
if (obj->isDerivedFrom<App::Part>()) {
|
||||
found = true;
|
||||
if (first) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
std::string obj1Name = obj1->getNameInDocument();
|
||||
sub = obj1Name + "." + sub;
|
||||
}
|
||||
obj1 = obj;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
inList = obj1->getInList();
|
||||
}
|
||||
else {
|
||||
inList = {};
|
||||
}
|
||||
}
|
||||
|
||||
// Lastly we need to replace the object name by its link name.
|
||||
auto* obj = AssemblyObject::getObjFromRef(prop1);
|
||||
auto* link = objLinkMap[obj];
|
||||
if (!obj || !link) {
|
||||
return;
|
||||
}
|
||||
std::string objName = obj->getNameInDocument();
|
||||
std::string linkName = link->getNameInDocument();
|
||||
sub = replaceLastOccurrence(sub, objName, linkName);
|
||||
}
|
||||
// Now obj1 and the subs1 are what should be in obj2 and subs2 if the joint did not changed
|
||||
if (obj1 != obj2) {
|
||||
prop2->setValue(obj1);
|
||||
}
|
||||
bool changed = false;
|
||||
for (size_t i = 0; i < subs1.size(); ++i) {
|
||||
if (i >= subs2.size() || subs1[i] != subs2[i]) {
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
prop2->setSubValues(std::move(subs1));
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyLink::ensureNoJointGroup()
|
||||
{
|
||||
// Make sure there is no joint group
|
||||
JointGroup* jGroup = AssemblyObject::getJointGroup(this);
|
||||
if (jGroup) {
|
||||
// If there is a joint group, we delete it and its content.
|
||||
jGroup->removeObjectsFromDocument();
|
||||
getDocument()->removeObject(jGroup->getNameInDocument());
|
||||
}
|
||||
}
|
||||
JointGroup* AssemblyLink::ensureJointGroup()
|
||||
{
|
||||
// Make sure there is a jointGroup
|
||||
JointGroup* jGroup = AssemblyObject::getJointGroup(this);
|
||||
if (!jGroup) {
|
||||
jGroup = new JointGroup();
|
||||
getDocument()->addObject(jGroup, tr("Joints").toStdString().c_str());
|
||||
|
||||
// we want to add jgroup at the start, so we don't use
|
||||
// addObject(jGroup);
|
||||
std::vector<DocumentObject*> grp = Group.getValues();
|
||||
grp.insert(grp.begin(), jGroup);
|
||||
Group.setValues(grp);
|
||||
}
|
||||
return jGroup;
|
||||
}
|
||||
|
||||
App::DocumentObject* AssemblyLink::getLinkedObject2(bool recursive) const
|
||||
{
|
||||
auto* obj = LinkedObject.getValue();
|
||||
auto* assembly = dynamic_cast<AssemblyObject*>(obj);
|
||||
if (assembly) {
|
||||
return assembly;
|
||||
}
|
||||
else {
|
||||
auto* assemblyLink = dynamic_cast<AssemblyLink*>(obj);
|
||||
if (assemblyLink) {
|
||||
if (recursive) {
|
||||
return assemblyLink->getLinkedObject2(recursive);
|
||||
}
|
||||
else {
|
||||
return assemblyLink;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AssemblyObject* AssemblyLink::getLinkedAssembly() const
|
||||
{
|
||||
return dynamic_cast<AssemblyObject*>(getLinkedObject2());
|
||||
}
|
||||
|
||||
AssemblyObject* AssemblyLink::getParentAssembly() const
|
||||
{
|
||||
std::vector<App::DocumentObject*> inList = getInList();
|
||||
for (auto* obj : inList) {
|
||||
auto* assembly = dynamic_cast<AssemblyObject*>(obj);
|
||||
if (assembly) {
|
||||
return assembly;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool AssemblyLink::isRigid()
|
||||
{
|
||||
auto* prop = dynamic_cast<App::PropertyBool*>(getPropertyByName("Rigid"));
|
||||
if (!prop) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return prop->getValue();
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> AssemblyLink::getJoints()
|
||||
{
|
||||
JointGroup* jointGroup = AssemblyObject::getJointGroup(this);
|
||||
|
||||
if (!jointGroup) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return jointGroup->getJoints();
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2024 Ondsel <[email protected]> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef ASSEMBLY_AssemblyLink_H
|
||||
#define ASSEMBLY_AssemblyLink_H
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <Mod/Assembly/AssemblyGlobal.h>
|
||||
|
||||
#include <App/FeaturePython.h>
|
||||
#include <App/Part.h>
|
||||
#include <App/PropertyLinks.h>
|
||||
|
||||
|
||||
namespace Assembly
|
||||
{
|
||||
class AssemblyObject;
|
||||
class JointGroup;
|
||||
|
||||
class AssemblyExport AssemblyLink: public App::Part
|
||||
{
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(Assembly::AssemblyLink);
|
||||
|
||||
public:
|
||||
AssemblyLink();
|
||||
~AssemblyLink() override;
|
||||
|
||||
PyObject* getPyObject() override;
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
const char* getViewProviderName() const override
|
||||
{
|
||||
return "AssemblyGui::ViewProviderAssemblyLink";
|
||||
}
|
||||
|
||||
App::DocumentObjectExecReturn* execute() override;
|
||||
|
||||
// The linked assembly is the AssemblyObject that this AssemblyLink pseudo-links to recursively.
|
||||
AssemblyObject* getLinkedAssembly() const;
|
||||
// The parent assembly is the main assembly in which the linked assembly is contained
|
||||
AssemblyObject* getParentAssembly() const;
|
||||
|
||||
// Overriding DocumentObject::getLinkedObject is giving bugs
|
||||
// This function returns the linked object, either an AssemblyObject or an AssemblyLink
|
||||
App::DocumentObject* getLinkedObject2(bool recurse = true) const;
|
||||
|
||||
bool isRigid();
|
||||
|
||||
void updateContents();
|
||||
|
||||
void synchronizeComponents();
|
||||
void synchronizeJoints();
|
||||
void handleJointReference(App::DocumentObject* joint,
|
||||
App::DocumentObject* lJoint,
|
||||
const char* refName);
|
||||
void ensureNoJointGroup();
|
||||
JointGroup* ensureJointGroup();
|
||||
std::vector<App::DocumentObject*> getJoints();
|
||||
|
||||
App::PropertyXLink LinkedObject;
|
||||
App::PropertyBool Rigid;
|
||||
|
||||
std::unordered_map<App::DocumentObject*, App::DocumentObject*> objLinkMap;
|
||||
|
||||
protected:
|
||||
/// get called by the container whenever a property has been changed
|
||||
void onChanged(const App::Property* prop) override;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Assembly
|
||||
|
||||
|
||||
#endif // ASSEMBLY_AssemblyLink_H
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="PartPy"
|
||||
Name="AssemblyLinkPy"
|
||||
Twin="AssemblyLink"
|
||||
TwinPointer="AssemblyLink"
|
||||
Include="Mod/Assembly/App/AssemblyLink.h"
|
||||
Namespace="Assembly"
|
||||
FatherInclude="App/PartPy.h"
|
||||
FatherNamespace="App">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Ondsel" EMail="[email protected]" />
|
||||
<UserDocu>This class handles document objects in Assembly</UserDocu>
|
||||
</Documentation>
|
||||
|
||||
<CustomAttributes />
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
@@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2024 Ondsel <[email protected]> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
// inclusion of the generated files (generated out of AssemblyLink.xml)
|
||||
#include "AssemblyLinkPy.h"
|
||||
#include "AssemblyLinkPy.cpp"
|
||||
|
||||
using namespace Assembly;
|
||||
|
||||
// returns a string which represents the object e.g. when printed in python
|
||||
std::string AssemblyLinkPy::representation() const
|
||||
{
|
||||
return {"<Assembly link>"};
|
||||
}
|
||||
|
||||
PyObject* AssemblyLinkPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int AssemblyLinkPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -82,6 +82,7 @@
|
||||
#include <OndselSolver/ASMTTime.h>
|
||||
#include <OndselSolver/ASMTConstantGravity.h>
|
||||
|
||||
#include "AssemblyLink.h"
|
||||
#include "AssemblyObject.h"
|
||||
#include "AssemblyObjectPy.h"
|
||||
#include "JointGroup.h"
|
||||
@@ -445,6 +446,7 @@ void AssemblyObject::redrawJointPlacement(App::DocumentObject* joint)
|
||||
void AssemblyObject::recomputeJointPlacements(std::vector<App::DocumentObject*> joints)
|
||||
{
|
||||
// The Placement1 and Placement2 of each joint needs to be updated as the parts moved.
|
||||
Base::PyGILStateLocker lock;
|
||||
for (auto* joint : joints) {
|
||||
if (!joint) {
|
||||
continue;
|
||||
@@ -1773,17 +1775,17 @@ void AssemblyObject::setObjMasses(std::vector<std::pair<App::DocumentObject*, do
|
||||
objMasses = objectMasses;
|
||||
}
|
||||
|
||||
std::vector<AssemblyObject*> AssemblyObject::getSubAssemblies()
|
||||
std::vector<AssemblyLink*> AssemblyObject::getSubAssemblies()
|
||||
{
|
||||
std::vector<AssemblyObject*> subAssemblies = {};
|
||||
std::vector<AssemblyLink*> subAssemblies = {};
|
||||
|
||||
App::Document* doc = getDocument();
|
||||
|
||||
std::vector<DocumentObject*> assemblies =
|
||||
doc->getObjectsOfType(Assembly::AssemblyObject::getClassTypeId());
|
||||
doc->getObjectsOfType(Assembly::AssemblyLink::getClassTypeId());
|
||||
for (auto assembly : assemblies) {
|
||||
if (hasObject(assembly)) {
|
||||
subAssemblies.push_back(dynamic_cast<AssemblyObject*>(assembly));
|
||||
subAssemblies.push_back(dynamic_cast<AssemblyLink*>(assembly));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2465,6 +2467,14 @@ App::DocumentObject* AssemblyObject::getMovingPartFromRef(App::DocumentObject* o
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ class Rotation;
|
||||
namespace Assembly
|
||||
{
|
||||
|
||||
class AssemblyLink;
|
||||
class JointGroup;
|
||||
class ViewGroup;
|
||||
|
||||
@@ -241,7 +242,7 @@ public:
|
||||
double getObjMass(App::DocumentObject* obj);
|
||||
void setObjMasses(std::vector<std::pair<App::DocumentObject*, double>> objectMasses);
|
||||
|
||||
std::vector<AssemblyObject*> getSubAssemblies();
|
||||
std::vector<AssemblyLink*> getSubAssemblies();
|
||||
void updateGroundedJointsPlacements();
|
||||
|
||||
private:
|
||||
|
||||
@@ -19,6 +19,7 @@ set(Assembly_LIBS
|
||||
)
|
||||
|
||||
generate_from_xml(AssemblyObjectPy)
|
||||
generate_from_xml(AssemblyLinkPy)
|
||||
generate_from_xml(BomObjectPy)
|
||||
generate_from_xml(BomGroupPy)
|
||||
generate_from_xml(JointGroupPy)
|
||||
@@ -27,6 +28,8 @@ generate_from_xml(ViewGroupPy)
|
||||
SET(Python_SRCS
|
||||
AssemblyObjectPy.xml
|
||||
AssemblyObjectPyImp.cpp
|
||||
AssemblyLinkPy.xml
|
||||
AssemblyLinkPyImp.cpp
|
||||
BomObjectPy.xml
|
||||
BomObjectPyImp.cpp
|
||||
BomGroupPy.xml
|
||||
@@ -49,6 +52,8 @@ SOURCE_GROUP("Module" FILES ${Module_SRCS})
|
||||
SET(Assembly_SRCS
|
||||
AssemblyObject.cpp
|
||||
AssemblyObject.h
|
||||
AssemblyLink.cpp
|
||||
AssemblyLink.h
|
||||
BomObject.cpp
|
||||
BomObject.h
|
||||
BomGroup.cpp
|
||||
|
||||
@@ -53,3 +53,31 @@ PyObject* JointGroup::getPyObject()
|
||||
}
|
||||
return Py::new_reference_to(PythonObject);
|
||||
}
|
||||
|
||||
|
||||
std::vector<App::DocumentObject*> JointGroup::getJoints()
|
||||
{
|
||||
std::vector<App::DocumentObject*> joints = {};
|
||||
|
||||
Base::PyGILStateLocker lock;
|
||||
for (auto joint : getObjects()) {
|
||||
if (!joint) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* prop = dynamic_cast<App::PropertyBool*>(joint->getPropertyByName("Activated"));
|
||||
if (!prop || !prop->getValue()) {
|
||||
// Filter grounded joints and deactivated joints.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto proxy = dynamic_cast<App::PropertyPythonObject*>(joint->getPropertyByName("Proxy"));
|
||||
if (proxy) {
|
||||
if (proxy->getValue().hasAttr("setJointConnectors")) {
|
||||
joints.push_back(joint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return joints;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,8 @@ public:
|
||||
{
|
||||
return "AssemblyGui::ViewProviderJointGroup";
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> getJoints();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@ class TaskAssemblyInsertLink(QtCore.QObject):
|
||||
|
||||
pref = Preferences.preferences()
|
||||
self.form.CheckBox_ShowOnlyParts.setChecked(pref.GetBool("InsertShowOnlyParts", False))
|
||||
self.form.CheckBox_RigidSubAsm.setChecked(pref.GetBool("InsertRigidSubAssemblies", True))
|
||||
|
||||
# Actions
|
||||
self.form.openFileButton.clicked.connect(self.openFiles)
|
||||
@@ -142,6 +143,7 @@ class TaskAssemblyInsertLink(QtCore.QObject):
|
||||
def deactivated(self):
|
||||
pref = Preferences.preferences()
|
||||
pref.SetBool("InsertShowOnlyParts", self.form.CheckBox_ShowOnlyParts.isChecked())
|
||||
pref.SetBool("InsertRigidSubAssemblies", self.form.CheckBox_RigidSubAsm.isChecked())
|
||||
Gui.Selection.clearSelection()
|
||||
|
||||
def buildPartList(self):
|
||||
@@ -333,7 +335,16 @@ class TaskAssemblyInsertLink(QtCore.QObject):
|
||||
print(selectedPart.Document.Name)
|
||||
documentItem.setText(0, f"{newDocName}.FCStd")"""
|
||||
|
||||
addedObject = self.assembly.newObject("App::Link", selectedPart.Label)
|
||||
if selectedPart.isDerivedFrom("Assembly::AssemblyObject"):
|
||||
objType = "Assembly::AssemblyLink"
|
||||
else:
|
||||
objType = "App::Link"
|
||||
|
||||
addedObject = self.assembly.newObject(objType, selectedPart.Label)
|
||||
|
||||
if selectedPart.isDerivedFrom("Assembly::AssemblyObject"):
|
||||
addedObject.Rigid = self.form.CheckBox_RigidSubAsm.isChecked()
|
||||
|
||||
# set placement of the added object to the center of the screen.
|
||||
view = Gui.activeView()
|
||||
x, y = view.getSize()
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <Base/PyObjectBase.h>
|
||||
|
||||
#include "ViewProviderAssembly.h"
|
||||
#include "ViewProviderAssemblyLink.h"
|
||||
#include "ViewProviderBom.h"
|
||||
#include "ViewProviderBomGroup.h"
|
||||
#include "ViewProviderJointGroup.h"
|
||||
@@ -60,6 +61,7 @@ PyMOD_INIT_FUNC(AssemblyGui)
|
||||
// This function is responsible for adding inherited slots from a type's base class.
|
||||
|
||||
AssemblyGui::ViewProviderAssembly::init();
|
||||
AssemblyGui::ViewProviderAssemblyLink::init();
|
||||
AssemblyGui::ViewProviderBom::init();
|
||||
AssemblyGui::ViewProviderBomGroup::init();
|
||||
AssemblyGui::ViewProviderJointGroup::init();
|
||||
|
||||
@@ -40,6 +40,8 @@ SET(AssemblyGui_SRCS_Module
|
||||
PreCompiled.h
|
||||
ViewProviderAssembly.cpp
|
||||
ViewProviderAssembly.h
|
||||
ViewProviderAssemblyLink.cpp
|
||||
ViewProviderAssemblyLink.h
|
||||
ViewProviderBom.cpp
|
||||
ViewProviderBom.h
|
||||
ViewProviderBomGroup.cpp
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>icons/Assembly_AssemblyLink.svg</file>
|
||||
<file>icons/Assembly_AssemblyLinkRigid.svg</file>
|
||||
<file>icons/Assembly_InsertLink.svg</file>
|
||||
<file>icons/preferences-assembly.svg</file>
|
||||
<file>icons/Assembly_ToggleGrounded.svg</file>
|
||||
|
||||
@@ -0,0 +1,359 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="64"
|
||||
height="64"
|
||||
version="1.1"
|
||||
viewBox="0 0 64 64"
|
||||
id="svg96"
|
||||
sodipodi:docname="Assembly_AssemblyLink.svg"
|
||||
inkscape:version="1.1-beta1 (77e7b44db3, 2021-03-28)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="1571"
|
||||
id="namedview98"
|
||||
showgrid="false"
|
||||
inkscape:zoom="10.429825"
|
||||
inkscape:cx="-15.388561"
|
||||
inkscape:cy="38.303615"
|
||||
inkscape:window-x="-9"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg96"
|
||||
inkscape:pagecheckerboard="0" />
|
||||
<defs
|
||||
id="defs26">
|
||||
<linearGradient
|
||||
id="linearGradient4383">
|
||||
<stop
|
||||
stop-color="#3465a4"
|
||||
offset="0"
|
||||
id="stop2" />
|
||||
<stop
|
||||
stop-color="#729fcf"
|
||||
offset="1"
|
||||
id="stop4" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient4389"
|
||||
x1="20.244"
|
||||
x2="17.244"
|
||||
y1="37.588"
|
||||
y2="27.588"
|
||||
gradientTransform="translate(-1.2435,-2.5881)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
xlink:href="#linearGradient3774" />
|
||||
<linearGradient
|
||||
id="linearGradient4399"
|
||||
x1="48.714"
|
||||
x2="44.714"
|
||||
y1="45.586"
|
||||
y2="34.586"
|
||||
gradientTransform="translate(1.2856,1.4142)"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#c4a000"
|
||||
offset="0"
|
||||
id="stop8" />
|
||||
<stop
|
||||
stop-color="#edd400"
|
||||
offset="1"
|
||||
id="stop10" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient69042"
|
||||
x1="48.714"
|
||||
x2="44.714"
|
||||
y1="45.586"
|
||||
y2="34.586"
|
||||
gradientTransform="translate(-12.714,-17.586)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
xlink:href="#linearGradient3774" />
|
||||
<linearGradient
|
||||
id="linearGradient69056"
|
||||
x1="27.244"
|
||||
x2="22.244"
|
||||
y1="54.588"
|
||||
y2="40.588"
|
||||
gradientTransform="translate(-1.2435,-2.5881)"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#c4a000"
|
||||
offset="0"
|
||||
id="stop14" />
|
||||
<stop
|
||||
stop-color="#fce94f"
|
||||
offset="1"
|
||||
id="stop16" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient69709"
|
||||
x1="20.244"
|
||||
x2="17.244"
|
||||
y1="37.588"
|
||||
y2="27.588"
|
||||
gradientTransform="matrix(1,-0.026667,0,1,21.696,-5.3735)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
xlink:href="#linearGradient4383" />
|
||||
<linearGradient
|
||||
id="linearGradient69717"
|
||||
x1="50.714"
|
||||
x2="48.714"
|
||||
y1="25.586"
|
||||
y2="20.586"
|
||||
gradientTransform="translate(1.2256,1.0356)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
xlink:href="#linearGradient4383" />
|
||||
<linearGradient
|
||||
id="linearGradient3774">
|
||||
<stop
|
||||
stop-color="#4e9a06"
|
||||
offset="0"
|
||||
id="stop21" />
|
||||
<stop
|
||||
stop-color="#8ae234"
|
||||
offset="1"
|
||||
id="stop23" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient69056"
|
||||
id="linearGradient920"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-41.2435,-2.5881)"
|
||||
x1="20.243999"
|
||||
y1="37.588001"
|
||||
x2="17.243999"
|
||||
y2="27.587999" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4399"
|
||||
id="linearGradient922"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-52.714,-17.586)"
|
||||
x1="48.714001"
|
||||
y1="45.585999"
|
||||
x2="44.714001"
|
||||
y2="34.585999" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4383"
|
||||
id="linearGradient5137"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-0.06404665,0.06060973,-0.05836811,-0.06167792,58.951461,44.497067)"
|
||||
x1="288.11227"
|
||||
y1="358.15811"
|
||||
x2="372.52457"
|
||||
y2="7.5416322" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata28">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>Path-Stock</dc:title>
|
||||
<dc:date>2015-07-04</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Path/Gui/Resources/icons/Path-Stock.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="g40"
|
||||
style="stroke-width:2">
|
||||
<path
|
||||
d="M 9,49 V 35 l 28,10 v 14 z"
|
||||
id="path30"
|
||||
style="fill:url(#linearGradient69056);stroke:#302b00;stroke-linejoin:round"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="M 37,59 V 45 L 55,28 v 13 z"
|
||||
id="path32"
|
||||
style="fill:url(#linearGradient4399);stroke:#302b00;stroke-linejoin:round"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="M 11.008,47.606 11,37.9997 l 24,8 0.0081,10.185 z"
|
||||
id="path34"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:none;stroke:#fce94f" />
|
||||
<path
|
||||
d="M 39.005,54.168 39,45.9998 l 14,-13 0.0021,7.1768 z"
|
||||
id="path36"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:none;stroke:#edd400" />
|
||||
<path
|
||||
d="M 23,40 42,23 55,28 37,45 Z"
|
||||
id="path38"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#fce94f;stroke:#302b00;stroke-linejoin:round" />
|
||||
</g>
|
||||
<path
|
||||
d="m 31,33.5 -0.02739,-14.214 12.967,4.3352 v 14.5 z"
|
||||
id="path54"
|
||||
style="fill:url(#linearGradient69709);stroke:#0b1521;stroke-width:2;stroke-linejoin:round"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 32.927,32.029 0.04731,-10.141 8.9272,3.29 0.0781,10.042 z"
|
||||
id="path56"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:none;stroke:#729fcf;stroke-width:2" />
|
||||
<path
|
||||
d="m 43.94,38.121 v -14.5 l 11,-9 L 55,28 Z"
|
||||
id="path58"
|
||||
style="fill:url(#linearGradient69717);stroke:#0b1521;stroke-width:2;stroke-linejoin:round"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 45.94,33.621 v -9 l 7,-6 -0.0122,8.5816 z"
|
||||
id="path60"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:none;stroke:#729fcf;stroke-width:2" />
|
||||
<path
|
||||
d="M 30.973,19.286 42,9.9998 l 12.94,4.6214 -11,9 z"
|
||||
id="path62"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#729fcf;stroke:#0b1521;stroke-width:2;stroke-linejoin:round" />
|
||||
<g
|
||||
display="none"
|
||||
fill="#ef2929"
|
||||
fill-rule="evenodd"
|
||||
opacity=".588"
|
||||
stroke="#ef2929"
|
||||
stroke-width="1px"
|
||||
id="g94">
|
||||
<path
|
||||
d="m9 35v14"
|
||||
id="path66" />
|
||||
<path
|
||||
d="m9 35 28 10"
|
||||
id="path68" />
|
||||
<path
|
||||
d="m55 28v13"
|
||||
id="path70" />
|
||||
<path
|
||||
d="m37 45 18-17"
|
||||
id="path72" />
|
||||
<path
|
||||
d="m23 40v-14"
|
||||
id="path74" />
|
||||
<path
|
||||
d="m29 5 13 5"
|
||||
id="path76" />
|
||||
<path
|
||||
d="m23 26 19-16"
|
||||
id="path78" />
|
||||
<path
|
||||
d="m19 13 10-8"
|
||||
id="path80" />
|
||||
<path
|
||||
d="m55 15-9 8"
|
||||
id="path82" />
|
||||
<path
|
||||
d="m42 23v-13"
|
||||
id="path84" />
|
||||
<path
|
||||
d="m42 23 14 5"
|
||||
id="path86" />
|
||||
<path
|
||||
d="m23 40 19-17"
|
||||
id="path88" />
|
||||
<path
|
||||
d="m23 10h19"
|
||||
id="path90" />
|
||||
<path
|
||||
d="m34 17v13"
|
||||
id="path92" />
|
||||
</g>
|
||||
<g
|
||||
id="g963"
|
||||
transform="translate(40)">
|
||||
<g
|
||||
style="stroke:#172a04;stroke-width:2;stroke-linejoin:round"
|
||||
transform="translate(-40)"
|
||||
id="g48">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:url(#linearGradient4389)"
|
||||
id="path42"
|
||||
d="M 9,35 V 21 l 14,5 v 14 z" />
|
||||
<path
|
||||
style="fill:#8ae234"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path44"
|
||||
d="M 9,21 28.585,5.209 42,10.0001 l -19,16 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:url(#linearGradient69042)"
|
||||
id="path46"
|
||||
d="M 23,40 V 26 l 7.9726,-6.7138 0.02739,13.714 z" />
|
||||
</g>
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:url(#linearGradient920);fill-opacity:1;stroke:#172a04;stroke-width:2;stroke-linejoin:round"
|
||||
id="path912"
|
||||
d="M -31,35 V 21 l 14,5 v 14 z" />
|
||||
<path
|
||||
style="fill:#fce94f;fill-opacity:1;stroke:#172a04;stroke-width:2;stroke-linejoin:round;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path914"
|
||||
d="M -31,21 -11.415,5.209 2,10.0001 l -19,16 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:url(#linearGradient922);fill-opacity:1;stroke:#172a04;stroke-width:2;stroke-linejoin:round"
|
||||
id="path916"
|
||||
d="M -17,40 V 26 l 7.9726,-6.7138 0.02739,13.714 z" />
|
||||
<path
|
||||
d="m -15,36 v -9 l 4,-3.5 v 9 z"
|
||||
id="path50"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-opacity:1" />
|
||||
<path
|
||||
d="m -29.049,33.746 0.08695,-9.9796 9.9568,3.5229 -0.02105,9.9613 z"
|
||||
id="path52"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-opacity:1" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:#729fcf;fill-opacity:1;stroke:#0d0324;stroke-width:2.50001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 18.550108,61.250258 c 4.43586,0.09701 9.3144,-2.061146 14.63593,-6.473945 l 4.366056,4.613637 c 0.466586,0.493045 1.032066,0.614262 1.696497,0.364061 0.688282,-0.273708 1.03751,-0.759469 1.046541,-1.457925 l 0.829845,-17.875538 c 0.02034,-0.442612 -0.113848,-0.816106 -0.402643,-1.121278 -0.288877,-0.305258 -0.654413,-0.459727 -1.097237,-0.463654 L 21.730784,38.67955 c -0.43091,-0.01509 -0.810445,0.132693 -1.139626,0.44421 -0.146238,0.13839 -0.270757,0.311878 -0.373763,0.520542 -0.286407,0.649612 -0.197016,1.220796 0.269803,1.714086 l 4.182842,4.420033 c -2.106982,1.704541 -4.028902,2.939225 -5.766508,3.704646 C 17.166435,50.247864 15.5136,50.58264 13.94446,50.487485 10.294918,50.269492 6.5105477,47.564813 2.590594,42.37255 2.3256949,42.044414 1.9970894,41.977185 1.6033706,42.171819 1.555488,42.19447 1.4954292,42.240793 1.4222792,42.310017 1.1785117,42.540703 1.1024481,42.801809 1.1935459,43.093848 l 0.3009105,1.050389 c 0.1406611,0.49012 0.3966392,1.255013 0.7679046,2.294449 0.3718022,1.03956 0.7729408,2.0504 1.2052819,3.032319 0.4320256,0.98161 0.9640333,2.013571 1.5954771,3.096096 0.6319676,1.082684 1.2697067,1.96431 1.9139206,2.645055 3.7328644,3.944539 7.5904954,5.956866 11.5730674,6.038102 z"
|
||||
id="path4228" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5135"
|
||||
d="m 37.47401,54.811209 c 0.201583,-4.340442 0.475225,-8.67263 0.597055,-13.023013 -4.453213,0.0073 -8.917572,-0.154929 -13.368156,-0.109742 1.429429,1.514929 2.85263,3.035869 4.298909,4.534782 -3.450946,2.882394 -7.068808,5.854247 -11.601125,6.953052 -3.213878,0.803162 -6.755015,-0.104883 -9.7492117,-1.775153 2.0784758,3.078757 5.1294937,5.738765 8.7325997,6.609146 3.330465,0.796917 6.641047,-0.274127 9.409199,-1.815831 2.32694,-1.19094 4.197153,-3.034433 6.463169,-4.311377 1.479192,-0.372261 3.025339,0.624738 3.916918,1.8634 0.434637,0.47459 0.854667,0.974381 1.282337,1.461779 0.0061,-0.129026 0.01224,-0.258064 0.01835,-0.38709 z"
|
||||
style="fill:url(#linearGradient5137);fill-opacity:1.0;stroke:none;stroke-width:5.89736;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,354 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="64"
|
||||
height="64"
|
||||
version="1.1"
|
||||
viewBox="0 0 64 64"
|
||||
id="svg96"
|
||||
sodipodi:docname="Assembly_AssemblyLinkRigid.svg"
|
||||
inkscape:version="1.1-beta1 (77e7b44db3, 2021-03-28)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="3840"
|
||||
inkscape:window-height="1571"
|
||||
id="namedview98"
|
||||
showgrid="false"
|
||||
inkscape:zoom="7.375"
|
||||
inkscape:cx="-66.644068"
|
||||
inkscape:cy="61.627119"
|
||||
inkscape:window-x="-9"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg96"
|
||||
inkscape:pagecheckerboard="0" />
|
||||
<defs
|
||||
id="defs26">
|
||||
<linearGradient
|
||||
id="linearGradient4383">
|
||||
<stop
|
||||
stop-color="#3465a4"
|
||||
offset="0"
|
||||
id="stop2" />
|
||||
<stop
|
||||
stop-color="#729fcf"
|
||||
offset="1"
|
||||
id="stop4" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient4389"
|
||||
x1="20.244"
|
||||
x2="17.244"
|
||||
y1="37.588"
|
||||
y2="27.588"
|
||||
gradientTransform="translate(-1.2435,-2.5881)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
xlink:href="#linearGradient3774" />
|
||||
<linearGradient
|
||||
id="linearGradient4399"
|
||||
x1="48.714"
|
||||
x2="44.714"
|
||||
y1="45.586"
|
||||
y2="34.586"
|
||||
gradientTransform="translate(1.2856,1.4142)"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#c4a000"
|
||||
offset="0"
|
||||
id="stop8" />
|
||||
<stop
|
||||
stop-color="#edd400"
|
||||
offset="1"
|
||||
id="stop10" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient69042"
|
||||
x1="48.714"
|
||||
x2="44.714"
|
||||
y1="45.586"
|
||||
y2="34.586"
|
||||
gradientTransform="translate(-12.714,-17.586)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
xlink:href="#linearGradient3774" />
|
||||
<linearGradient
|
||||
id="linearGradient69056"
|
||||
x1="27.244"
|
||||
x2="22.244"
|
||||
y1="54.588"
|
||||
y2="40.588"
|
||||
gradientTransform="translate(-1.2435,-2.5881)"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#c4a000"
|
||||
offset="0"
|
||||
id="stop14" />
|
||||
<stop
|
||||
stop-color="#fce94f"
|
||||
offset="1"
|
||||
id="stop16" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient69709"
|
||||
x1="20.243999"
|
||||
x2="17.243999"
|
||||
y1="37.588001"
|
||||
y2="27.587999"
|
||||
gradientTransform="matrix(1,-0.026667,0,1,21.696,-5.3735)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
xlink:href="#linearGradient3774" />
|
||||
<linearGradient
|
||||
id="linearGradient69717"
|
||||
x1="50.714001"
|
||||
x2="48.714001"
|
||||
y1="25.586"
|
||||
y2="20.586"
|
||||
gradientTransform="translate(1.2256,1.0356)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
xlink:href="#linearGradient3774" />
|
||||
<linearGradient
|
||||
id="linearGradient3774">
|
||||
<stop
|
||||
stop-color="#4e9a06"
|
||||
offset="0"
|
||||
id="stop21" />
|
||||
<stop
|
||||
stop-color="#8ae234"
|
||||
offset="1"
|
||||
id="stop23" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient69056"
|
||||
id="linearGradient920"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-1.2435,-2.5881)"
|
||||
x1="20.243999"
|
||||
y1="37.588001"
|
||||
x2="17.243999"
|
||||
y2="27.587999" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4399"
|
||||
id="linearGradient922"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-12.714,-17.586)"
|
||||
x1="48.714001"
|
||||
y1="45.585999"
|
||||
x2="44.714001"
|
||||
y2="34.585999" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4383"
|
||||
id="linearGradient5137"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-0.06404665,0.06060973,-0.05836811,-0.06167792,58.951461,44.497067)"
|
||||
x1="288.11227"
|
||||
y1="358.15811"
|
||||
x2="372.52457"
|
||||
y2="7.5416322" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata28">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>Path-Stock</dc:title>
|
||||
<dc:date>2015-07-04</dc:date>
|
||||
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Path/Gui/Resources/icons/Path-Stock.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="g40"
|
||||
style="stroke-width:2">
|
||||
<path
|
||||
d="M 9,49 V 35 l 28,10 v 14 z"
|
||||
id="path30"
|
||||
style="fill:url(#linearGradient69056);stroke:#302b00;stroke-linejoin:round"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="M 37,59 V 45 L 55,28 v 13 z"
|
||||
id="path32"
|
||||
style="fill:url(#linearGradient4399);stroke:#302b00;stroke-linejoin:round"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="M 11.008,47.606 11,37.9997 l 24,8 0.0081,10.185 z"
|
||||
id="path34"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:none;stroke:#fce94f" />
|
||||
<path
|
||||
d="M 39.005,54.168 39,45.9998 l 14,-13 0.0021,7.1768 z"
|
||||
id="path36"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:none;stroke:#edd400" />
|
||||
<path
|
||||
d="M 23,40 42,23 55,28 37,45 Z"
|
||||
id="path38"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#fce94f;stroke:#302b00;stroke-linejoin:round" />
|
||||
</g>
|
||||
<path
|
||||
d="m 31,33.5 -0.02739,-14.214 12.967,4.3352 v 14.5 z"
|
||||
id="path54"
|
||||
style="fill:url(#linearGradient69709);stroke:#0b1521;stroke-width:2;stroke-linejoin:round;fill-opacity:1.0"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 32.927,32.029 0.04731,-10.141 8.9272,3.29 0.0781,10.042 z"
|
||||
id="path56"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 43.94,38.121 v -14.5 l 11,-9 L 55,28 Z"
|
||||
id="path58"
|
||||
style="fill:url(#linearGradient69717);stroke:#0b1521;stroke-width:2;stroke-linejoin:round;fill-opacity:1.0"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 45.94,33.621 v -9 l 7,-6 -0.0122,8.5816 z"
|
||||
id="path60"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-opacity:1" />
|
||||
<path
|
||||
d="M 30.973,19.286 42,9.9998 l 12.94,4.6214 -11,9 z"
|
||||
id="path62"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#fce94f;stroke:#0b1521;stroke-width:2;stroke-linejoin:round;fill-opacity:1" />
|
||||
<g
|
||||
display="none"
|
||||
fill="#ef2929"
|
||||
fill-rule="evenodd"
|
||||
opacity=".588"
|
||||
stroke="#ef2929"
|
||||
stroke-width="1px"
|
||||
id="g94">
|
||||
<path
|
||||
d="m9 35v14"
|
||||
id="path66" />
|
||||
<path
|
||||
d="m9 35 28 10"
|
||||
id="path68" />
|
||||
<path
|
||||
d="m55 28v13"
|
||||
id="path70" />
|
||||
<path
|
||||
d="m37 45 18-17"
|
||||
id="path72" />
|
||||
<path
|
||||
d="m23 40v-14"
|
||||
id="path74" />
|
||||
<path
|
||||
d="m29 5 13 5"
|
||||
id="path76" />
|
||||
<path
|
||||
d="m23 26 19-16"
|
||||
id="path78" />
|
||||
<path
|
||||
d="m19 13 10-8"
|
||||
id="path80" />
|
||||
<path
|
||||
d="m55 15-9 8"
|
||||
id="path82" />
|
||||
<path
|
||||
d="m42 23v-13"
|
||||
id="path84" />
|
||||
<path
|
||||
d="m42 23 14 5"
|
||||
id="path86" />
|
||||
<path
|
||||
d="m23 40 19-17"
|
||||
id="path88" />
|
||||
<path
|
||||
d="m23 10h19"
|
||||
id="path90" />
|
||||
<path
|
||||
d="m34 17v13"
|
||||
id="path92" />
|
||||
</g>
|
||||
<g
|
||||
style="stroke:#172a04;stroke-width:2;stroke-linejoin:round"
|
||||
id="g48">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:url(#linearGradient4389)"
|
||||
id="path42"
|
||||
d="M 9,35 V 21 l 14,5 v 14 z" />
|
||||
<path
|
||||
style="fill:#8ae234"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path44"
|
||||
d="M 9,21 28.585,5.209 42,10.0001 l -19,16 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:url(#linearGradient69042)"
|
||||
id="path46"
|
||||
d="M 23,40 V 26 l 7.9726,-6.7138 0.02739,13.714 z" />
|
||||
</g>
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:url(#linearGradient920);fill-opacity:1;stroke:#172a04;stroke-width:2;stroke-linejoin:round"
|
||||
id="path912"
|
||||
d="M 9,35 V 21 l 14,5 v 14 z" />
|
||||
<path
|
||||
style="fill:#fce94f;fill-opacity:1;stroke:#172a04;stroke-width:2;stroke-linejoin:round;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path914"
|
||||
d="M 9,21 28.585,5.209 42,10.0001 l -19,16 z" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:url(#linearGradient922);fill-opacity:1;stroke:#172a04;stroke-width:2;stroke-linejoin:round"
|
||||
id="path916"
|
||||
d="M 23,40 V 26 l 7.9726,-6.7138 0.02739,13.714 z" />
|
||||
<path
|
||||
d="m 25,36 v -9 l 4,-3.5 v 9 z"
|
||||
id="path50"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 10.951,33.746 0.08695,-9.9796 9.9568,3.5229 -0.02105,9.9613 z"
|
||||
id="path52"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:#729fcf;fill-opacity:1;stroke:#0d0324;stroke-width:2.50001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 18.550108,61.250258 c 4.43586,0.09701 9.3144,-2.061146 14.63593,-6.473945 l 4.366056,4.613637 c 0.466586,0.493045 1.032066,0.614262 1.696497,0.364061 0.688282,-0.273708 1.03751,-0.759469 1.046541,-1.457925 l 0.829845,-17.875538 c 0.02034,-0.442612 -0.113848,-0.816106 -0.402643,-1.121278 -0.288877,-0.305258 -0.654413,-0.459727 -1.097237,-0.463654 L 21.730784,38.67955 c -0.43091,-0.01509 -0.810445,0.132693 -1.139626,0.44421 -0.146238,0.13839 -0.270757,0.311878 -0.373763,0.520542 -0.286407,0.649612 -0.197016,1.220796 0.269803,1.714086 l 4.182842,4.420033 c -2.106982,1.704541 -4.028902,2.939225 -5.766508,3.704646 C 17.166435,50.247864 15.5136,50.58264 13.94446,50.487485 10.294918,50.269492 6.5105477,47.564813 2.590594,42.37255 2.3256949,42.044414 1.9970894,41.977185 1.6033706,42.171819 1.555488,42.19447 1.4954292,42.240793 1.4222792,42.310017 1.1785117,42.540703 1.1024481,42.801809 1.1935459,43.093848 l 0.3009105,1.050389 c 0.1406611,0.49012 0.3966392,1.255013 0.7679046,2.294449 0.3718022,1.03956 0.7729408,2.0504 1.2052819,3.032319 0.4320256,0.98161 0.9640333,2.013571 1.5954771,3.096096 0.6319676,1.082684 1.2697067,1.96431 1.9139206,2.645055 3.7328644,3.944539 7.5904954,5.956866 11.5730674,6.038102 z"
|
||||
id="path4228" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5135"
|
||||
d="m 37.47401,54.811209 c 0.201583,-4.340442 0.475225,-8.67263 0.597055,-13.023013 -4.453213,0.0073 -8.917572,-0.154929 -13.368156,-0.109742 1.429429,1.514929 2.85263,3.035869 4.298909,4.534782 -3.450946,2.882394 -7.068808,5.854247 -11.601125,6.953052 -3.213878,0.803162 -6.755015,-0.104883 -9.7492117,-1.775153 2.0784758,3.078757 5.1294937,5.738765 8.7325997,6.609146 3.330465,0.796917 6.641047,-0.274127 9.409199,-1.815831 2.32694,-1.19094 4.197153,-3.034433 6.463169,-4.311377 1.479192,-0.372261 3.025339,0.624738 3.916918,1.8634 0.434637,0.47459 0.854667,0.974381 1.282337,1.461779 0.0061,-0.129026 0.01224,-0.258064 0.01835,-0.38709 z"
|
||||
style="fill:url(#linearGradient5137);fill-opacity:1.0;stroke:none;stroke-width:5.89736;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
@@ -68,6 +68,28 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="Gui::PrefCheckBox" name="CheckBox_RigidSubAsm">
|
||||
<property name="toolTip">
|
||||
<string>If checked, the inserted sub-assemblies will not be flexible.
|
||||
Rigid means that the sub-assembly will be considered as a solid.
|
||||
Flexible means that the sub-assembly joints will be taken into account in the main assembly.
|
||||
You can change this property of sub-assemblies at any time by right clicking them.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Rigid sub-assemblies</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>InsertRigidSubAssemblies</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Assembly</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
#include <Mod/Assembly/App/AssemblyUtils.h>
|
||||
#include <Mod/Assembly/App/JointGroup.h>
|
||||
#include <Mod/Assembly/App/ViewGroup.h>
|
||||
#include <Mod/Assembly/App/BomGroup.h>
|
||||
#include <Mod/PartDesign/App/Body.h>
|
||||
|
||||
#include "ViewProviderAssembly.h"
|
||||
@@ -1024,7 +1025,7 @@ bool ViewProviderAssembly::onDelete(const std::vector<std::string>& subNames)
|
||||
for (auto obj : getObject()->getOutList()) {
|
||||
if (obj->getTypeId() == Assembly::JointGroup::getClassTypeId()
|
||||
|| obj->getTypeId() == Assembly::ViewGroup::getClassTypeId()
|
||||
/* || obj->getTypeId() == Assembly::BomGroup::getClassTypeId()*/) {
|
||||
|| obj->getTypeId() == Assembly::BomGroup::getClassTypeId()) {
|
||||
|
||||
// Delete the group content first.
|
||||
Gui::Command::doCommand(Gui::Command::Doc,
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2024 Ondsel <[email protected]> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
#include <App/Link.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObject.h>
|
||||
#include <App/Part.h>
|
||||
|
||||
#include <Gui/ActionFunction.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/BitmapFactory.h>
|
||||
#include <Gui/CommandT.h>
|
||||
#include <Gui/MainWindow.h>
|
||||
|
||||
#include <Mod/Assembly/App/AssemblyObject.h>
|
||||
#include <Mod/Assembly/App/AssemblyLink.h>
|
||||
|
||||
#include "ViewProviderAssembly.h"
|
||||
#include "ViewProviderAssemblyLink.h"
|
||||
|
||||
|
||||
using namespace Assembly;
|
||||
using namespace AssemblyGui;
|
||||
|
||||
|
||||
PROPERTY_SOURCE(AssemblyGui::ViewProviderAssemblyLink, Gui::ViewProviderPart)
|
||||
|
||||
ViewProviderAssemblyLink::ViewProviderAssemblyLink()
|
||||
{}
|
||||
|
||||
ViewProviderAssemblyLink::~ViewProviderAssemblyLink() = default;
|
||||
|
||||
QIcon ViewProviderAssemblyLink::getIcon() const
|
||||
{
|
||||
auto* assembly = dynamic_cast<Assembly::AssemblyLink*>(getObject());
|
||||
if (assembly->isRigid()) {
|
||||
return Gui::BitmapFactory().pixmap("Assembly_AssemblyLinkRigid.svg");
|
||||
}
|
||||
else {
|
||||
return Gui::BitmapFactory().pixmap("Assembly_AssemblyLink.svg");
|
||||
}
|
||||
}
|
||||
|
||||
bool ViewProviderAssemblyLink::setEdit(int mode)
|
||||
{
|
||||
auto* assemblyLink = dynamic_cast<Assembly::AssemblyLink*>(getObject());
|
||||
|
||||
if (!assemblyLink->isRigid() && mode == (int)ViewProvider::Transform) {
|
||||
Base::Console().UserTranslatedNotification(
|
||||
"Flexible sub-assemblies cannot be transformed.");
|
||||
return true;
|
||||
}
|
||||
|
||||
return ViewProviderPart::setEdit(mode);
|
||||
}
|
||||
|
||||
bool ViewProviderAssemblyLink::doubleClicked()
|
||||
{
|
||||
auto* link = dynamic_cast<AssemblyLink*>(getObject());
|
||||
|
||||
if (!link) {
|
||||
return true;
|
||||
}
|
||||
auto* assembly = link->getLinkedAssembly();
|
||||
|
||||
auto* vpa =
|
||||
dynamic_cast<ViewProviderAssembly*>(Gui::Application::Instance->getViewProvider(assembly));
|
||||
if (!vpa) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return vpa->doubleClicked();
|
||||
}
|
||||
|
||||
bool ViewProviderAssemblyLink::onDelete(const std::vector<std::string>& subNames)
|
||||
{
|
||||
Q_UNUSED(subNames)
|
||||
|
||||
Base::Console().Warning("onDelete\n");
|
||||
|
||||
Gui::Command::doCommand(Gui::Command::Doc,
|
||||
"App.getDocument(\"%s\").getObject(\"%s\").removeObjectsFromDocument()",
|
||||
getObject()->getDocument()->getName(),
|
||||
getObject()->getNameInDocument());
|
||||
|
||||
// getObject()->purgeTouched();
|
||||
|
||||
return ViewProviderPart::onDelete(subNames);
|
||||
}
|
||||
|
||||
void ViewProviderAssemblyLink::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
|
||||
{
|
||||
auto func = new Gui::ActionFunction(menu);
|
||||
QAction* act;
|
||||
auto* assemblyLink = dynamic_cast<Assembly::AssemblyLink*>(getObject());
|
||||
if (assemblyLink->isRigid()) {
|
||||
act = menu->addAction(QObject::tr("Turn flexible"));
|
||||
act->setToolTip(QObject::tr(
|
||||
"Your sub-assembly is currently rigid. This will make it flexible instead."));
|
||||
}
|
||||
else {
|
||||
act = menu->addAction(QObject::tr("Turn rigid"));
|
||||
act->setToolTip(QObject::tr(
|
||||
"Your sub-assembly is currently flexible. This will make it rigid instead."));
|
||||
}
|
||||
|
||||
func->trigger(act, [this]() {
|
||||
auto* assemblyLink = dynamic_cast<Assembly::AssemblyLink*>(getObject());
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Toggle Rigid"));
|
||||
Gui::cmdAppObjectArgs(assemblyLink,
|
||||
"Rigid = %s",
|
||||
assemblyLink->Rigid.getValue() ? "False" : "True");
|
||||
|
||||
Gui::Command::commitCommand();
|
||||
Gui::Selection().clearSelection();
|
||||
});
|
||||
|
||||
Q_UNUSED(receiver)
|
||||
Q_UNUSED(member)
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2024 Ondsel <[email protected]> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ASSEMBLYGUI_VIEWPROVIDER_ViewProviderAssemblyLink_H
|
||||
#define ASSEMBLYGUI_VIEWPROVIDER_ViewProviderAssemblyLink_H
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <Mod/Assembly/AssemblyGlobal.h>
|
||||
|
||||
#include <Gui/ViewProviderPart.h>
|
||||
|
||||
|
||||
namespace AssemblyGui
|
||||
{
|
||||
|
||||
class AssemblyGuiExport ViewProviderAssemblyLink: public Gui::ViewProviderPart
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(AssemblyGui::ViewProviderAssemblyLink)
|
||||
PROPERTY_HEADER_WITH_OVERRIDE(AssemblyGui::ViewProviderAssemblyLink);
|
||||
|
||||
public:
|
||||
ViewProviderAssemblyLink();
|
||||
~ViewProviderAssemblyLink() override;
|
||||
|
||||
/// deliver the icon shown in the tree view. Override from ViewProvider.h
|
||||
QIcon getIcon() const override;
|
||||
|
||||
bool setEdit(int ModNum) override;
|
||||
|
||||
bool doubleClicked() override;
|
||||
|
||||
// When the assembly link is deleted, we delete all its content as well.
|
||||
bool onDelete(const std::vector<std::string>& subNames) override;
|
||||
|
||||
// Prevent deletion of the link assembly's content.
|
||||
bool canDelete(App::DocumentObject*) const override
|
||||
{
|
||||
return false;
|
||||
};
|
||||
|
||||
// Prevent drag/drop of objects within the assembly link.
|
||||
bool canDragObjects() const override
|
||||
{
|
||||
return false;
|
||||
};
|
||||
bool canDropObjects() const override
|
||||
{
|
||||
return false;
|
||||
};
|
||||
bool canDragAndDropObject(App::DocumentObject*) const override
|
||||
{
|
||||
return false;
|
||||
};
|
||||
|
||||
void setupContextMenu(QMenu*, QObject*, const char*) override;
|
||||
};
|
||||
|
||||
} // namespace AssemblyGui
|
||||
|
||||
#endif // ASSEMBLYGUI_VIEWPROVIDER_ViewProviderAssemblyLink_H
|
||||
@@ -47,10 +47,3 @@ QIcon ViewProviderJointGroup::getIcon() const
|
||||
{
|
||||
return Gui::BitmapFactory().pixmap("Assembly_JointGroup.svg");
|
||||
}
|
||||
|
||||
// Make the joint group impossible to delete.
|
||||
bool ViewProviderJointGroup::onDelete(const std::vector<std::string>& subNames)
|
||||
{
|
||||
Q_UNUSED(subNames);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,11 @@ public:
|
||||
return false;
|
||||
};
|
||||
|
||||
bool onDelete(const std::vector<std::string>& subNames) override;
|
||||
// Make the joint group impossible to delete.
|
||||
bool onDelete(const std::vector<std::string>&) override
|
||||
{
|
||||
return false;
|
||||
};
|
||||
|
||||
// protected:
|
||||
/// get called by the container whenever a property has been changed
|
||||
|
||||
@@ -1146,6 +1146,10 @@ def getMovingPart(assembly, ref):
|
||||
if obj.TypeId == "App::DocumentObjectGroup":
|
||||
continue # we ignore groups.
|
||||
|
||||
# We ignore dynamic sub-assemblies.
|
||||
if obj.isDerivedFrom("Assembly::AssemblyLink") and obj.Rigid == False:
|
||||
continue
|
||||
|
||||
# If it is a LinkGroup then we skip it
|
||||
if isLinkGroup(obj):
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user