Merge pull request #18332 from Ondsel-Development/core_LCS3
Core Datums: Card4 : implement part subclasses.
This commit is contained in:
@@ -3,22 +3,21 @@
|
||||
* Copyright (c) 2015 Alexander Golubev (Fat-Zer) <fatzer2@gmail.com> *
|
||||
* Copyright (c) 2024 Ondsel (PL Boyer) <development@ondsel.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* 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. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* 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 Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
@@ -207,9 +206,9 @@ const std::vector<LocalCoordinateSystem::SetupData>& LocalCoordinateSystem::getS
|
||||
{
|
||||
static const std::vector<SetupData> setupData = {
|
||||
// clang-format off
|
||||
{App::Line::getClassTypeId(), AxisRoles[0], tr("X-axis"), Base::Rotation()},
|
||||
{App::Line::getClassTypeId(), AxisRoles[1], tr("Y-axis"), Base::Rotation(Base::Vector3d(1, 1, 1), M_PI * 2 / 3)},
|
||||
{App::Line::getClassTypeId(), AxisRoles[2], tr("Z-axis"), Base::Rotation(Base::Vector3d(1,-1, 1), M_PI * 2 / 3)},
|
||||
{App::Line::getClassTypeId(), AxisRoles[0], tr("X-axis"), Base::Rotation(Base::Vector3d(1, 1, 1), M_PI * 2 / 3)},
|
||||
{App::Line::getClassTypeId(), AxisRoles[1], tr("Y-axis"), Base::Rotation(Base::Vector3d(-1, 1, 1), M_PI * 2 / 3)},
|
||||
{App::Line::getClassTypeId(), AxisRoles[2], tr("Z-axis"), Base::Rotation()},
|
||||
{App::Plane::getClassTypeId(), PlaneRoles[0], tr("XY-plane"), Base::Rotation()},
|
||||
{App::Plane::getClassTypeId(), PlaneRoles[1], tr("XZ-plane"), Base::Rotation(1.0, 0.0, 0.0, 1.0)},
|
||||
{App::Plane::getClassTypeId(), PlaneRoles[2], tr("YZ-plane"), Base::Rotation(Base::Vector3d(1, 1, 1), M_PI * 2 / 3)},
|
||||
@@ -277,6 +276,56 @@ void LocalCoordinateSystem::unsetupObject()
|
||||
}
|
||||
}
|
||||
|
||||
void LocalCoordinateSystem::onDocumentRestored()
|
||||
{
|
||||
GeoFeature::onDocumentRestored();
|
||||
|
||||
// In 0.22 origins did not have point.
|
||||
migrateOriginPoint();
|
||||
|
||||
// In 0.22 the axis placement were wrong. The X axis had identity placement instead of the Z.
|
||||
// This was fixed but we need to migrate old files.
|
||||
migrateXAxisPlacement();
|
||||
}
|
||||
|
||||
void LocalCoordinateSystem::migrateOriginPoint()
|
||||
{
|
||||
auto features = OriginFeatures.getValues();
|
||||
|
||||
auto isOrigin = [](App::DocumentObject* obj) {
|
||||
return obj->isDerivedFrom<App::DatumElement>() &&
|
||||
strcmp(static_cast<App::DatumElement*>(obj)->Role.getValue(), PointRoles[0]) == 0;
|
||||
};
|
||||
if (std::none_of(features.begin(), features.end(), isOrigin)) {
|
||||
auto data = getData(PointRoles[0]);
|
||||
auto* origin = createDatum(data);
|
||||
features.push_back(origin);
|
||||
OriginFeatures.setValues(features);
|
||||
}
|
||||
}
|
||||
|
||||
void LocalCoordinateSystem::migrateXAxisPlacement()
|
||||
{
|
||||
auto features = OriginFeatures.getValues();
|
||||
|
||||
migrated = false;
|
||||
|
||||
const auto& setupData = getSetupData();
|
||||
for (auto* obj : features) {
|
||||
auto* feature = dynamic_cast <App::DatumElement*> (obj);
|
||||
if (!feature) { continue; }
|
||||
for (auto data : setupData) {
|
||||
// ensure the rotation is correct for the role
|
||||
if (std::strcmp(feature->Role.getValue(), data.role) == 0) {
|
||||
if (!feature->Placement.getValue().getRotation().isSame(data.rot)) {
|
||||
feature->Placement.setValue(Base::Placement(Base::Vector3d(), data.rot));
|
||||
migrated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
LocalCoordinateSystem::LCSExtension::LCSExtension(LocalCoordinateSystem* obj)
|
||||
|
||||
@@ -3,22 +3,21 @@
|
||||
* Copyright (c) 2015 Alexander Golubev (Fat-Zer) <fatzer2@gmail.com> *
|
||||
* Copyright (c) 2024 Ondsel (PL Boyer) <development@ondsel.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* 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. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* 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 Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
@@ -206,6 +205,8 @@ public:
|
||||
// Axis links
|
||||
PropertyLinkList OriginFeatures;
|
||||
|
||||
bool migrated;
|
||||
|
||||
protected:
|
||||
/// Checks integrity of the LCS
|
||||
App::DocumentObjectExecReturn* execute() override;
|
||||
@@ -213,6 +214,7 @@ protected:
|
||||
void setupObject() override;
|
||||
/// Removes all planes and axis if they are still linked to the document
|
||||
void unsetupObject() override;
|
||||
void onDocumentRestored() override;
|
||||
|
||||
private:
|
||||
struct SetupData;
|
||||
@@ -245,6 +247,9 @@ private:
|
||||
|
||||
DatumElement* createDatum(SetupData& data);
|
||||
SetupData getData(const char* role);
|
||||
|
||||
void migrateOriginPoint();
|
||||
void migrateXAxisPlacement();
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
@@ -134,7 +134,7 @@ ElementNamePair GeoFeature::_getElementName(const char* name,
|
||||
}
|
||||
}
|
||||
|
||||
DocumentObject* GeoFeature::resolveElement(DocumentObject* obj,
|
||||
DocumentObject* GeoFeature::resolveElement(const DocumentObject* obj,
|
||||
const char* subname,
|
||||
ElementNamePair& elementName,
|
||||
bool append,
|
||||
|
||||
@@ -104,7 +104,7 @@ public:
|
||||
*
|
||||
* @return Return the owner object of the element
|
||||
*/
|
||||
static DocumentObject* resolveElement(App::DocumentObject* obj,
|
||||
static DocumentObject* resolveElement(const App::DocumentObject* obj,
|
||||
const char* subname,
|
||||
ElementNamePair& elementName,
|
||||
bool append = false,
|
||||
|
||||
@@ -156,9 +156,9 @@ void StdCmdVarSet::activated(int iMsg)
|
||||
|
||||
// add the varset to a group if it is selected
|
||||
auto sels = Selection().getSelectionEx(nullptr, App::DocumentObject::getClassTypeId(),
|
||||
ResolveMode::OldStyleElement, true);
|
||||
ResolveMode::OldStyleElement, true);
|
||||
if (sels.size() == 1) {
|
||||
App::DocumentObject *obj = sels[0].getObject();
|
||||
App::DocumentObject* obj = sels[0].getObject();
|
||||
auto group = obj->getExtension<App::GroupExtension>();
|
||||
if (group) {
|
||||
Gui::Document* docGui = Application::Instance->activeDocument();
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#ifndef _PreComp_
|
||||
# include <Inventor/nodes/SoLightModel.h>
|
||||
# include <Inventor/nodes/SoSeparator.h>
|
||||
# include <QMessageBox>
|
||||
# include <QCheckBox>
|
||||
#endif
|
||||
|
||||
#include <App/Document.h>
|
||||
@@ -83,6 +85,50 @@ void ViewProviderCoordinateSystem::attach(App::DocumentObject* pcObject)
|
||||
addDisplayMaskMode(pcGroupChildren, "Base");
|
||||
}
|
||||
|
||||
void ViewProviderCoordinateSystem::finishRestoring()
|
||||
{
|
||||
showMigrationDialog();
|
||||
}
|
||||
|
||||
void ViewProviderCoordinateSystem::showMigrationDialog()
|
||||
{
|
||||
auto lcs = dynamic_cast<App::LocalCoordinateSystem*>(getObject());
|
||||
if (!lcs || !lcs->migrated) {
|
||||
return;
|
||||
}
|
||||
|
||||
static bool userWarned = false;
|
||||
|
||||
if (userWarned || !App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/View")->GetBool("ShowLCSMigrationWarning", true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Display the warning message
|
||||
QMessageBox msgBox(QMessageBox::Warning,
|
||||
QObject::tr("File Migration Warning"),
|
||||
QObject::tr("This file was created with an older version of FreeCAD. "
|
||||
"Origin axes had incorrect placements, which have now been corrected.\n\n"
|
||||
"However, if you save this file in the current version and reopen it in an"
|
||||
" older version of FreeCAD, the origin axes will be misaligned. Additionally, "
|
||||
"if your file references these origin axes, your file will likely be broken."),
|
||||
QMessageBox::Ok);
|
||||
|
||||
QCheckBox* checkBox = new QCheckBox(QObject::tr("Don't show this warning again"));
|
||||
msgBox.setCheckBox(checkBox);
|
||||
|
||||
msgBox.exec();
|
||||
|
||||
// Update static flag if the user has seen the warning
|
||||
userWarned = true;
|
||||
|
||||
// Save preference if the user selects "Don't show again"
|
||||
if (checkBox->isChecked()) {
|
||||
App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/View")->SetBool("ShowLCSMigrationWarning", false);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> ViewProviderCoordinateSystem::getDisplayModes() const
|
||||
{
|
||||
return { "Base" };
|
||||
|
||||
@@ -83,7 +83,11 @@ protected:
|
||||
void updateData(const App::Property*) override;
|
||||
bool onDelete(const std::vector<std::string> &) override;
|
||||
|
||||
void finishRestoring() override;
|
||||
|
||||
private:
|
||||
void showMigrationDialog();
|
||||
|
||||
SoGroup *pcGroupChildren;
|
||||
|
||||
std::map<Gui::ViewProvider*, bool> tempVisMap;
|
||||
|
||||
@@ -83,12 +83,12 @@ void ViewProviderLine::attach(App::DocumentObject *obj) {
|
||||
|
||||
SbVec3f verts[2];
|
||||
if (noRole) {
|
||||
verts[0] = SbVec3f(2 * size, 0, 0);
|
||||
verts[0] = SbVec3f(0, 0, 2 * size);
|
||||
verts[1] = SbVec3f(0, 0, 0);
|
||||
}
|
||||
else {
|
||||
verts[0] = SbVec3f(size, 0, 0);
|
||||
verts[1] = SbVec3f(0.2 * size, 0, 0);
|
||||
verts[0] = SbVec3f(0, 0, size);
|
||||
verts[1] = SbVec3f(0, 0, 0.2 * size);
|
||||
}
|
||||
|
||||
// indexes used to create the edges
|
||||
@@ -107,7 +107,7 @@ void ViewProviderLine::attach(App::DocumentObject *obj) {
|
||||
sep->addChild ( pLines );
|
||||
|
||||
auto textTranslation = new SoTranslation ();
|
||||
textTranslation->translation.setValue ( SbVec3f ( size * 1.1, 0, 0 ) );
|
||||
textTranslation->translation.setValue(SbVec3f(0, 0, size * 1.1));
|
||||
sep->addChild ( textTranslation );
|
||||
|
||||
auto ps = new SoPickStyle();
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <chrono>
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/Datums.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObjectGroup.h>
|
||||
#include <App/FeaturePythonPyImp.h>
|
||||
@@ -45,6 +46,7 @@
|
||||
#include <Base/Interpreter.h>
|
||||
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
#include <Mod/Part/App/AttachExtension.h>
|
||||
|
||||
#include <OndselSolver/CREATE.h>
|
||||
#include <OndselSolver/ASMTSimulationParameters.h>
|
||||
@@ -93,6 +95,10 @@ FC_LOG_LEVEL_INIT("Assembly", true, true, true)
|
||||
using namespace Assembly;
|
||||
using namespace MbD;
|
||||
|
||||
|
||||
namespace PartApp = Part;
|
||||
|
||||
|
||||
// ================================ Assembly Object ============================
|
||||
|
||||
PROPERTY_SOURCE(Assembly::AssemblyObject, App::Part)
|
||||
@@ -135,7 +141,7 @@ int AssemblyObject::solve(bool enableRedo, bool updateJCS)
|
||||
objectPartMap.clear();
|
||||
motions.clear();
|
||||
|
||||
std::vector<App::DocumentObject*> groundedObjs = fixGroundedParts();
|
||||
auto groundedObjs = fixGroundedParts();
|
||||
if (groundedObjs.empty()) {
|
||||
// If no part fixed we can't solve.
|
||||
return -6;
|
||||
@@ -178,7 +184,7 @@ int AssemblyObject::generateSimulation(App::DocumentObject* sim)
|
||||
|
||||
motions = getMotionsFromSimulation(sim);
|
||||
|
||||
std::vector<App::DocumentObject*> groundedObjs = fixGroundedParts();
|
||||
auto groundedObjs = fixGroundedParts();
|
||||
if (groundedObjs.empty()) {
|
||||
// If no part fixed we can't solve.
|
||||
return -6;
|
||||
@@ -351,7 +357,8 @@ Base::Placement AssemblyObject::getMbdPlacement(std::shared_ptr<ASMTPart> mbdPar
|
||||
bool AssemblyObject::validateNewPlacements()
|
||||
{
|
||||
// First we check if a grounded object has moved. It can happen that they flip.
|
||||
for (auto* obj : getGroundedParts()) {
|
||||
auto groundedParts = getGroundedParts();
|
||||
for (auto* obj : groundedParts) {
|
||||
auto* propPlacement =
|
||||
dynamic_cast<App::PropertyPlacement*>(obj->getPropertyByName("Placement"));
|
||||
if (propPlacement) {
|
||||
@@ -367,7 +374,8 @@ bool AssemblyObject::validateNewPlacements()
|
||||
|
||||
if (!oldPlc.isSame(newPlacement)) {
|
||||
Base::Console().Warning(
|
||||
"Assembly : Ignoring bad solve, a grounded object moved.\n");
|
||||
"Assembly : Ignoring bad solve, a grounded object (%s) moved.\n",
|
||||
obj->getFullLabel());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -749,11 +757,11 @@ std::vector<App::DocumentObject*> AssemblyObject::getJointsOfPart(App::DocumentO
|
||||
return jointsOf;
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> AssemblyObject::getGroundedParts()
|
||||
std::unordered_set<App::DocumentObject*> AssemblyObject::getGroundedParts()
|
||||
{
|
||||
std::vector<App::DocumentObject*> groundedJoints = getGroundedJoints();
|
||||
|
||||
std::vector<App::DocumentObject*> groundedObjs;
|
||||
std::unordered_set<App::DocumentObject*> groundedSet;
|
||||
for (auto gJoint : groundedJoints) {
|
||||
if (!gJoint) {
|
||||
continue;
|
||||
@@ -764,34 +772,49 @@ std::vector<App::DocumentObject*> AssemblyObject::getGroundedParts()
|
||||
|
||||
if (propObj) {
|
||||
App::DocumentObject* objToGround = propObj->getValue();
|
||||
groundedObjs.push_back(objToGround);
|
||||
if (objToGround) {
|
||||
groundedSet.insert(objToGround);
|
||||
}
|
||||
}
|
||||
}
|
||||
return groundedObjs;
|
||||
|
||||
// We also need to add all the root-level datums objects that are not attached.
|
||||
std::vector<App::DocumentObject*> objs = Group.getValues();
|
||||
for (auto* obj : objs) {
|
||||
if (obj->isDerivedFrom<App::LocalCoordinateSystem>()
|
||||
|| obj->isDerivedFrom<App::DatumElement>()) {
|
||||
auto* pcAttach = obj->getExtensionByType<PartApp::AttachExtension>();
|
||||
if (pcAttach) {
|
||||
// If it's a Part datums, we check if it's attached. If yes then we ignore it.
|
||||
std::string mode = pcAttach->MapMode.getValueAsString();
|
||||
if (mode != "Deactivated") {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
groundedSet.insert(obj);
|
||||
}
|
||||
}
|
||||
|
||||
// Origin is not in Group so we add it separately
|
||||
groundedSet.insert(Origin.getValue());
|
||||
|
||||
return groundedSet;
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> AssemblyObject::fixGroundedParts()
|
||||
std::unordered_set<App::DocumentObject*> AssemblyObject::fixGroundedParts()
|
||||
{
|
||||
std::vector<App::DocumentObject*> groundedJoints = getGroundedJoints();
|
||||
auto groundedParts = getGroundedParts();
|
||||
|
||||
std::vector<App::DocumentObject*> groundedObjs;
|
||||
for (auto obj : groundedJoints) {
|
||||
for (auto obj : groundedParts) {
|
||||
if (!obj) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* propObj = dynamic_cast<App::PropertyLink*>(obj->getPropertyByName("ObjectToGround"));
|
||||
|
||||
if (propObj) {
|
||||
App::DocumentObject* objToGround = propObj->getValue();
|
||||
|
||||
Base::Placement plc = getPlacementFromProp(obj, "Placement");
|
||||
std::string str = obj->getFullName();
|
||||
fixGroundedPart(objToGround, plc, str);
|
||||
groundedObjs.push_back(objToGround);
|
||||
}
|
||||
Base::Placement plc = getPlacementFromProp(obj, "Placement");
|
||||
std::string str = obj->getFullName();
|
||||
fixGroundedPart(obj, plc, str);
|
||||
}
|
||||
return groundedObjs;
|
||||
return groundedParts;
|
||||
}
|
||||
|
||||
void AssemblyObject::fixGroundedPart(App::DocumentObject* obj,
|
||||
@@ -902,7 +925,7 @@ bool AssemblyObject::isObjInSetOfObjRefs(App::DocumentObject* obj, const std::ve
|
||||
}
|
||||
|
||||
void AssemblyObject::removeUnconnectedJoints(std::vector<App::DocumentObject*>& joints,
|
||||
std::vector<App::DocumentObject*> groundedObjs)
|
||||
std::unordered_set<App::DocumentObject*> groundedObjs)
|
||||
{
|
||||
std::vector<ObjRef> connectedParts;
|
||||
|
||||
@@ -994,7 +1017,7 @@ bool AssemblyObject::isPartGrounded(App::DocumentObject* obj)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> groundedObjs = getGroundedParts();
|
||||
auto groundedObjs = getGroundedParts();
|
||||
|
||||
for (auto* groundedObj : groundedObjs) {
|
||||
if (groundedObj->getFullName() == obj->getFullName()) {
|
||||
@@ -1011,7 +1034,7 @@ bool AssemblyObject::isPartConnected(App::DocumentObject* obj)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> groundedObjs = getGroundedParts();
|
||||
auto groundedObjs = getGroundedParts();
|
||||
std::vector<App::DocumentObject*> joints = getJoints(false);
|
||||
|
||||
std::vector<ObjRef> connectedParts;
|
||||
@@ -1958,29 +1981,6 @@ std::vector<AssemblyLink*> AssemblyObject::getSubAssemblies()
|
||||
return subAssemblies;
|
||||
}
|
||||
|
||||
void AssemblyObject::updateGroundedJointsPlacements()
|
||||
{
|
||||
std::vector<App::DocumentObject*> groundedJoints = getGroundedJoints();
|
||||
|
||||
for (auto gJoint : groundedJoints) {
|
||||
if (!gJoint) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* propObj =
|
||||
dynamic_cast<App::PropertyLink*>(gJoint->getPropertyByName("ObjectToGround"));
|
||||
auto* propPlc =
|
||||
dynamic_cast<App::PropertyPlacement*>(gJoint->getPropertyByName("Placement"));
|
||||
|
||||
if (propObj && propPlc) {
|
||||
App::DocumentObject* obj = propObj->getValue();
|
||||
auto* propObjPlc =
|
||||
dynamic_cast<App::PropertyPlacement*>(obj->getPropertyByName("Placement"));
|
||||
propPlc->setValue(propObjPlc->getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyObject::ensureIdentityPlacements()
|
||||
{
|
||||
std::vector<App::DocumentObject*> group = Group.getValues();
|
||||
@@ -2011,36 +2011,3 @@ void AssemblyObject::ensureIdentityPlacements()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*void Part::handleChangedPropertyType(Base::XMLReader& reader, const char* TypeName, App::Property*
|
||||
prop)
|
||||
{
|
||||
App::Part::handleChangedPropertyType(reader, TypeName, prop);
|
||||
}*/
|
||||
|
||||
/* Apparently not necessary as App::Part doesn't have this.
|
||||
// Python Assembly feature ---------------------------------------------------------
|
||||
|
||||
namespace App
|
||||
{
|
||||
/// @cond DOXERR
|
||||
PROPERTY_SOURCE_TEMPLATE(Assembly::AssemblyObjectPython, Assembly::AssemblyObject)
|
||||
template<>
|
||||
const char* Assembly::AssemblyObjectPython::getViewProviderName() const
|
||||
{
|
||||
return "AssemblyGui::ViewProviderAssembly";
|
||||
}
|
||||
template<>
|
||||
PyObject* Assembly::AssemblyObjectPython::getPyObject()
|
||||
{
|
||||
if (PythonObject.is(Py::_None())) {
|
||||
// ref counter is set to 1
|
||||
PythonObject = Py::Object(new FeaturePythonPyT<AssemblyObjectPy>(this), true);
|
||||
}
|
||||
return Py::new_reference_to(PythonObject);
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
// explicit template instantiation
|
||||
template class AssemblyExport FeaturePythonT<Assembly::AssemblyObject>;
|
||||
}// namespace App*/
|
||||
|
||||
@@ -157,8 +157,8 @@ public:
|
||||
std::vector<App::DocumentObject*> getJointsOfPart(App::DocumentObject* part);
|
||||
App::DocumentObject* getJointOfPartConnectingToGround(App::DocumentObject* part,
|
||||
std::string& name);
|
||||
std::vector<App::DocumentObject*> getGroundedParts();
|
||||
std::vector<App::DocumentObject*> fixGroundedParts();
|
||||
std::unordered_set<App::DocumentObject*> getGroundedParts();
|
||||
std::unordered_set<App::DocumentObject*> fixGroundedParts();
|
||||
void fixGroundedPart(App::DocumentObject* obj, Base::Placement& plc, std::string& jointName);
|
||||
|
||||
bool isJointConnectingPartToGround(App::DocumentObject* joint, const char* partPropName);
|
||||
@@ -166,7 +166,7 @@ public:
|
||||
|
||||
bool isObjInSetOfObjRefs(App::DocumentObject* obj, const std::vector<ObjRef>& pairs);
|
||||
void removeUnconnectedJoints(std::vector<App::DocumentObject*>& joints,
|
||||
std::vector<App::DocumentObject*> groundedObjs);
|
||||
std::unordered_set<App::DocumentObject*> groundedObjs);
|
||||
void traverseAndMarkConnectedParts(App::DocumentObject* currentPart,
|
||||
std::vector<ObjRef>& connectedParts,
|
||||
const std::vector<App::DocumentObject*>& joints);
|
||||
@@ -186,7 +186,6 @@ public:
|
||||
void setObjMasses(std::vector<std::pair<App::DocumentObject*, double>> objectMasses);
|
||||
|
||||
std::vector<AssemblyLink*> getSubAssemblies();
|
||||
void updateGroundedJointsPlacements();
|
||||
|
||||
std::vector<App::DocumentObject*> getMotionsFromSimulation(App::DocumentObject* sim);
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#endif
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/Datums.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObject.h>
|
||||
#include <App/PropertyStandard.h>
|
||||
@@ -536,7 +537,9 @@ App::DocumentObject* getObjFromRef(const App::DocumentObject* obj, const std::st
|
||||
// getViewProviderName instead of isDerivedFrom to avoid dependency on sketcher
|
||||
const auto isDerivedFromVpSketch =
|
||||
strcmp(obj->getViewProviderName(), "SketcherGui::ViewProviderSketch") == 0;
|
||||
return isDerivedFromVpSketch || obj->isDerivedFrom<PartApp::Datum>();
|
||||
return isDerivedFromVpSketch || obj->isDerivedFrom<PartApp::Datum>()
|
||||
|| obj->isDerivedFrom<App::DatumElement>()
|
||||
|| obj->isDerivedFrom<App::LocalCoordinateSystem>();
|
||||
};
|
||||
|
||||
// Helper function to handle PartDesign::Body objects
|
||||
|
||||
@@ -47,11 +47,7 @@ def noOtherTaskActive():
|
||||
|
||||
|
||||
def isCreateJointActive():
|
||||
return (
|
||||
UtilsAssembly.isAssemblyGrounded()
|
||||
and UtilsAssembly.assembly_has_at_least_n_parts(2)
|
||||
and noOtherTaskActive()
|
||||
)
|
||||
return UtilsAssembly.assembly_has_at_least_n_parts(1) and noOtherTaskActive()
|
||||
|
||||
|
||||
def activateJoint(index):
|
||||
|
||||
@@ -229,12 +229,6 @@ bool ViewProviderAssembly::setEdit(int mode)
|
||||
PARTKEY,
|
||||
this->getObject()->getNameInDocument());
|
||||
|
||||
// When we set edit, we update the grounded joints placements to support :
|
||||
// - If user transformed the grounded object
|
||||
// - For nested assemblies where the grounded object moves around.
|
||||
auto* assembly = getObject<AssemblyObject>();
|
||||
assembly->updateGroundedJointsPlacements();
|
||||
|
||||
setDragger();
|
||||
|
||||
attachSelection();
|
||||
|
||||
@@ -956,18 +956,6 @@ class GroundedJoint:
|
||||
|
||||
joint.ObjectToGround = obj_to_ground
|
||||
|
||||
joint.addProperty(
|
||||
"App::PropertyPlacement",
|
||||
"Placement",
|
||||
"Ground",
|
||||
QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"This is where the part is grounded.",
|
||||
),
|
||||
)
|
||||
|
||||
joint.Placement = obj_to_ground.Placement
|
||||
|
||||
def dumps(self):
|
||||
return None
|
||||
|
||||
@@ -1160,24 +1148,33 @@ class MakeJointSelGate:
|
||||
return False
|
||||
|
||||
ref = [obj, [sub]]
|
||||
selected_object = UtilsAssembly.getObject(ref)
|
||||
sel_obj = UtilsAssembly.getObject(ref)
|
||||
|
||||
if not (
|
||||
selected_object.isDerivedFrom("Part::Feature")
|
||||
or selected_object.isDerivedFrom("App::Part")
|
||||
if UtilsAssembly.isLink(sel_obj):
|
||||
linked = sel_obj.getLinkedObject()
|
||||
if linked == sel_obj:
|
||||
return True # We accept empty links
|
||||
sel_obj = linked
|
||||
|
||||
if sel_obj.isDerivedFrom("Part::Feature") or sel_obj.isDerivedFrom("App::Part"):
|
||||
return True
|
||||
|
||||
if sel_obj.isDerivedFrom("App::LocalCoordinateSystem") or sel_obj.isDerivedFrom(
|
||||
"App::DatumElement"
|
||||
):
|
||||
if UtilsAssembly.isLink(selected_object):
|
||||
linked = selected_object.getLinkedObject()
|
||||
if linked == selected_object:
|
||||
# We accept empty links
|
||||
return True
|
||||
datum = sel_obj
|
||||
if datum.isDerivedFrom("App::DatumElement"):
|
||||
parent = datum.getParent()
|
||||
if parent.isDerivedFrom("App::LocalCoordinateSystem"):
|
||||
datum = parent
|
||||
|
||||
if not (linked.isDerivedFrom("Part::Feature") or linked.isDerivedFrom("App::Part")):
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
if self.assembly.hasObject(datum) and hasattr(datum, "MapMode"):
|
||||
# accept only datum that are not attached
|
||||
return datum.MapMode == "Deactivated"
|
||||
|
||||
return True
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
activeTask = None
|
||||
|
||||
@@ -161,6 +161,21 @@ def getObject(ref):
|
||||
if obj.TypeId in {"App::Part", "Assembly::AssemblyObject"} or isLinkGroup(obj):
|
||||
continue
|
||||
|
||||
elif obj.isDerivedFrom("App::LocalCoordinateSystem"):
|
||||
# 2 cases possible, either we have the LCS itself: "part.LCS."
|
||||
# or we have a datum: "part.LCS.X_Axis"
|
||||
if i + 1 < len(names):
|
||||
obj2 = None
|
||||
for obji in obj.OutList:
|
||||
if obji.Name == names[i + 1]:
|
||||
obj2 = obji
|
||||
break
|
||||
if obj2 and obj2.isDerivedFrom("App::DatumElement"):
|
||||
return obj2
|
||||
|
||||
elif obj.isDerivedFrom("App::DatumElement"):
|
||||
return obj
|
||||
|
||||
elif obj.TypeId == "PartDesign::Body":
|
||||
if i + 1 < len(names):
|
||||
obj2 = None
|
||||
@@ -168,7 +183,7 @@ def getObject(ref):
|
||||
if obji.Name == names[i + 1]:
|
||||
obj2 = obji
|
||||
break
|
||||
if obj2 and isBodySubObject(obj2.TypeId):
|
||||
if obj2 and isBodySubObject(obj2):
|
||||
return obj2
|
||||
return obj
|
||||
|
||||
@@ -185,7 +200,7 @@ def getObject(ref):
|
||||
if obji.Name == names[i + 1]:
|
||||
obj2 = obji
|
||||
break
|
||||
if obj2 and isBodySubObject(obj2.TypeId):
|
||||
if obj2 and isBodySubObject(obj2):
|
||||
return obj2
|
||||
return obj
|
||||
elif linked_obj.isDerivedFrom("Part::Feature"):
|
||||
@@ -197,13 +212,12 @@ def getObject(ref):
|
||||
return None
|
||||
|
||||
|
||||
def isBodySubObject(typeId):
|
||||
def isBodySubObject(obj):
|
||||
return (
|
||||
typeId == "Sketcher::SketchObject"
|
||||
or typeId == "PartDesign::Point"
|
||||
or typeId == "PartDesign::Line"
|
||||
or typeId == "PartDesign::Plane"
|
||||
or typeId == "PartDesign::CoordinateSystem"
|
||||
obj.isDerivedFrom("Sketcher::SketchObject")
|
||||
or obj.isDerivedFrom("PartDesign::Datum")
|
||||
or obj.isDerivedFrom("App::DatumElement")
|
||||
or obj.isDerivedFrom("App::LocalCoordinateSystem")
|
||||
)
|
||||
|
||||
|
||||
@@ -348,21 +362,6 @@ def getElementName(full_name):
|
||||
if parts[-1] in {"X", "Y", "Z", "Point", "Line", "Plane"}:
|
||||
return ""
|
||||
|
||||
# Case of origin objects
|
||||
if parts[-1] == "":
|
||||
if "X_Axis" in parts[-2]:
|
||||
return "X_Axis"
|
||||
if "Y_Axis" in parts[-2]:
|
||||
return "Y_Axis"
|
||||
if "Z_Axis" in parts[-2]:
|
||||
return "Z_Axis"
|
||||
if "XY_Plane" in parts[-2]:
|
||||
return "XY_Plane"
|
||||
if "XZ_Plane" in parts[-2]:
|
||||
return "XZ_Plane"
|
||||
if "YZ_Plane" in parts[-2]:
|
||||
return "YZ_Plane"
|
||||
|
||||
return parts[-1]
|
||||
|
||||
|
||||
@@ -946,16 +945,8 @@ def findPlacement(ref, ignoreVertex=False):
|
||||
elt = getElementName(ref[1][0])
|
||||
vtx = getElementName(ref[1][1])
|
||||
|
||||
# case of origin objects.
|
||||
if elt == "X_Axis" or elt == "YZ_Plane":
|
||||
return App.Placement(App.Vector(), App.Rotation(App.Vector(0, 1, 0), -90))
|
||||
if elt == "Y_Axis" or elt == "XZ_Plane":
|
||||
return App.Placement(App.Vector(), App.Rotation(App.Vector(1, 0, 0), 90))
|
||||
if elt == "Z_Axis" or elt == "XY_Plane":
|
||||
return App.Placement()
|
||||
|
||||
if not elt or not vtx:
|
||||
# case of whole parts such as PartDesign::Body or PartDesign::CordinateSystem/Point/Line/Plane.
|
||||
# case of whole parts such as PartDesign::Body or App/PartDesign::CordinateSystem/Point/Line/Plane.
|
||||
return App.Placement()
|
||||
|
||||
plc = App.Placement()
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
#include "ConicPy.h"
|
||||
#include "CustomFeature.h"
|
||||
#include "CylinderPy.h"
|
||||
#include "Datums.h"
|
||||
#include "DatumFeature.h"
|
||||
#include "EllipsePy.h"
|
||||
#include "FaceMaker.h"
|
||||
@@ -534,6 +535,10 @@ PyMOD_INIT_FUNC(Part)
|
||||
Part::GeomSurfaceOfRevolution ::init();
|
||||
Part::GeomSurfaceOfExtrusion ::init();
|
||||
Part::Datum ::init();
|
||||
Part::DatumPlane ::init();
|
||||
Part::DatumLine ::init();
|
||||
Part::DatumPoint ::init();
|
||||
Part::LocalCoordinateSystem ::init();
|
||||
|
||||
// Geometry2d types
|
||||
Part::Geometry2d ::init();
|
||||
|
||||
@@ -411,33 +411,18 @@ void AttachExtension::extensionOnChanged(const App::Property* prop)
|
||||
bool bAttached = false;
|
||||
try{
|
||||
bAttached = positionBySupport();
|
||||
} catch (Base::Exception &e) {
|
||||
}
|
||||
catch (Base::Exception &e) {
|
||||
getExtendedObject()->setStatus(App::Error, true);
|
||||
Base::Console().Error("PositionBySupport: %s\n",e.what());
|
||||
//set error message - how?
|
||||
} catch (Standard_Failure &e){
|
||||
}
|
||||
catch (Standard_Failure &e){
|
||||
getExtendedObject()->setStatus(App::Error, true);
|
||||
Base::Console().Error("PositionBySupport: %s\n",e.GetMessageString());
|
||||
}
|
||||
// Hide properties when not applicable to reduce user confusion
|
||||
|
||||
eMapMode mmode = eMapMode(this->MapMode.getValue());
|
||||
|
||||
bool modeIsPointOnCurve = mmode == mmNormalToPath ||
|
||||
mmode == mmFrenetNB || mmode == mmFrenetTN || mmode == mmFrenetTB ||
|
||||
mmode == mmRevolutionSection || mmode == mmConcentric;
|
||||
|
||||
// MapPathParameter is only used if there is a reference to one edge and not edge + vertex
|
||||
bool hasOneRef = false;
|
||||
if (_props.attacher && _props.attacher->subnames.size() == 1) {
|
||||
hasOneRef = true;
|
||||
}
|
||||
|
||||
this->MapPathParameter.setStatus(App::Property::Status::Hidden, !bAttached || !(modeIsPointOnCurve && hasOneRef));
|
||||
this->MapReversed.setStatus(App::Property::Status::Hidden, !bAttached);
|
||||
this->AttachmentOffset.setStatus(App::Property::Status::Hidden, !bAttached);
|
||||
getPlacement().setReadOnly(bAttached && mmode != mmTranslate); //for mmTranslate, orientation should remain editable even when attached.
|
||||
|
||||
updateSinglePropertyStatus(bAttached);
|
||||
}
|
||||
if (prop == &AttacherEngine) {
|
||||
AttacherType.setValue(enumToClass(AttacherEngine.getValueAsString()));
|
||||
@@ -508,27 +493,9 @@ void AttachExtension::onExtendedDocumentRestored()
|
||||
|
||||
restoreAttacherEngine(this);
|
||||
|
||||
// Hide properties when not applicable to reduce user confusion
|
||||
bool bAttached = positionBySupport();
|
||||
eMapMode mmode = eMapMode(this->MapMode.getValue());
|
||||
bool modeIsPointOnCurve =
|
||||
(mmode == mmNormalToPath ||
|
||||
mmode == mmFrenetNB ||
|
||||
mmode == mmFrenetTN ||
|
||||
mmode == mmFrenetTB ||
|
||||
mmode == mmRevolutionSection ||
|
||||
mmode == mmConcentric);
|
||||
|
||||
// MapPathParameter is only used if there is a reference to one edge and not edge + vertex
|
||||
bool hasOneRef = false;
|
||||
if (_props.attacher && _props.attacher->subnames.size() == 1) {
|
||||
hasOneRef = true;
|
||||
}
|
||||
|
||||
this->MapPathParameter.setStatus(App::Property::Status::Hidden, !bAttached || !(modeIsPointOnCurve && hasOneRef));
|
||||
this->MapReversed.setStatus(App::Property::Status::Hidden, !bAttached);
|
||||
this->AttachmentOffset.setStatus(App::Property::Status::Hidden, !bAttached);
|
||||
getPlacement().setReadOnly(bAttached && mmode != mmTranslate); //for mmTranslate, orientation should remain editable even when attached.
|
||||
updateSinglePropertyStatus(bAttached);
|
||||
}
|
||||
catch (Base::Exception&) {
|
||||
}
|
||||
@@ -536,7 +503,7 @@ void AttachExtension::onExtendedDocumentRestored()
|
||||
}
|
||||
}
|
||||
|
||||
void AttachExtension::updatePropertyStatus(bool bAttached, bool base)
|
||||
void AttachExtension::updateSinglePropertyStatus(bool bAttached, bool base)
|
||||
{
|
||||
auto& props = base ? this->_baseProps : this->_props;
|
||||
if (!props.mapMode) {
|
||||
@@ -550,12 +517,9 @@ void AttachExtension::updatePropertyStatus(bool bAttached, bool base)
|
||||
|| mmode == mmFrenetTB || mmode == mmRevolutionSection || mmode == mmConcentric);
|
||||
|
||||
// MapPathParameter is only used if there is a reference to one edge and not edge + vertex
|
||||
bool hasOneRef = false;
|
||||
if (props.attacher && props.attacher->subnames.size() == 1) {
|
||||
hasOneRef = true;
|
||||
}
|
||||
props.mapPathParameter->setStatus(App::Property::Status::Hidden,
|
||||
!bAttached || !(modeIsPointOnCurve && hasOneRef));
|
||||
bool hasOneRef = props.attacher && props.attacher->subnames.size() == 1;
|
||||
|
||||
props.mapPathParameter->setStatus(App::Property::Status::Hidden, !bAttached || !(modeIsPointOnCurve && hasOneRef));
|
||||
props.mapReversed->setStatus(App::Property::Status::Hidden, !bAttached);
|
||||
|
||||
if (base) {
|
||||
@@ -564,11 +528,18 @@ void AttachExtension::updatePropertyStatus(bool bAttached, bool base)
|
||||
else {
|
||||
this->AttachmentOffset.setStatus(App::Property::Status::Hidden, !bAttached);
|
||||
if (getExtendedContainer()) {
|
||||
getPlacement().setReadOnly(
|
||||
bAttached && mmode != mmTranslate); // for mmTranslate, orientation should remain
|
||||
// editable even when attached.
|
||||
// for mmTranslate, orientation should remain editable even when attached.
|
||||
getPlacement().setReadOnly(bAttached && mmode != mmTranslate);
|
||||
}
|
||||
updatePropertyStatus(bAttached, true);
|
||||
}
|
||||
}
|
||||
|
||||
void AttachExtension::updatePropertyStatus(bool bAttached, bool base)
|
||||
{
|
||||
updateSinglePropertyStatus(bAttached, base);
|
||||
|
||||
if (!base) {
|
||||
updateSinglePropertyStatus(bAttached, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include <Base/Placement.h>
|
||||
|
||||
#include "Attacher.h"
|
||||
#include "PartFeature.h"
|
||||
|
||||
|
||||
namespace Part
|
||||
@@ -146,7 +145,10 @@ protected:
|
||||
|
||||
public:
|
||||
void updateAttacherVals(bool base = false) const;
|
||||
// This update both _props and _baseProps if base = false
|
||||
void updatePropertyStatus(bool attached, bool base = false);
|
||||
// This update only _props if base = false
|
||||
void updateSinglePropertyStatus(bool attached, bool base = false);
|
||||
|
||||
private:
|
||||
struct _Properties: Properties
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
# include <BRepAdaptor_Surface.hxx>
|
||||
# include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
# include <BRepBuilderAPI_MakeFace.hxx>
|
||||
# include <BRepBuilderAPI_MakeVertex.hxx>
|
||||
# include <BRepExtrema_DistShapeShape.hxx>
|
||||
# include <BRepGProp.hxx>
|
||||
# include <BRepIntCurveSurface_Inter.hxx>
|
||||
@@ -300,7 +301,8 @@ Base::Placement AttachEngine::placementFactory(const gp_Dir &ZAxis,
|
||||
gp_Ax3 ax3;//OCC representation of the final placement
|
||||
if (!makeYVertical) {
|
||||
ax3 = gp_Ax3(Origin, ZAxis, XAxis);
|
||||
} else if (!makeLegacyFlatFaceOrientation) {
|
||||
}
|
||||
else if (!makeLegacyFlatFaceOrientation) {
|
||||
//align Y along Z, if possible
|
||||
gp_Vec YAxis(0.0,0.0,1.0);
|
||||
XAxis = YAxis.Crossed(gp_Vec(ZAxis));
|
||||
@@ -309,7 +311,8 @@ Base::Placement AttachEngine::placementFactory(const gp_Dir &ZAxis,
|
||||
XAxis = (gp_Vec(1,0,0)*ZAxis.Z()).Normalized();
|
||||
}
|
||||
ax3 = gp_Ax3(Origin, ZAxis, XAxis);
|
||||
} else if (makeLegacyFlatFaceOrientation) {
|
||||
}
|
||||
else if (makeLegacyFlatFaceOrientation) {
|
||||
//find out, to which axis of support Normal is closest to.
|
||||
//The result will be written into pos variable (0..2 = X..Z)
|
||||
if (!placeOfRef)
|
||||
@@ -385,13 +388,11 @@ void AttachEngine::suggestMapModes(SuggestResult &result) const
|
||||
result.message = SuggestResult::srLinkBroken;
|
||||
result.bestFitMode = mmDeactivated;
|
||||
|
||||
|
||||
std::vector<App::GeoFeature*> parts;
|
||||
std::vector<const TopoDS_Shape*> shapes;
|
||||
std::vector<TopoDS_Shape> shapeStorage;
|
||||
std::vector<eRefType> typeStr;
|
||||
try{
|
||||
readLinks(getRefObjects(),subnames, parts, shapes, shapeStorage, typeStr);
|
||||
readLinks(getRefObjects(),subnames, shapes, shapeStorage, typeStr);
|
||||
} catch (Base::Exception &err) {
|
||||
result.references_Types = typeStr;
|
||||
result.message = SuggestResult::srLinkBroken;
|
||||
@@ -577,11 +578,10 @@ eRefType AttachEngine::getShapeType(const App::DocumentObject *obj, const std::s
|
||||
//const_cast is worth here, to keep obj argument const. We are not going to write anything to obj through this temporary link.
|
||||
tmpLink.setValue(const_cast<App::DocumentObject*>(obj), subshape.c_str());
|
||||
|
||||
std::vector<App::GeoFeature*> parts;
|
||||
std::vector<const TopoDS_Shape*> shapes;
|
||||
std::vector<TopoDS_Shape> copiedShapeStorage;
|
||||
std::vector<eRefType> types;
|
||||
readLinks(tmpLink.getValues(),tmpLink.getSubValues(), parts, shapes, copiedShapeStorage, types);
|
||||
readLinks(tmpLink.getValues(), tmpLink.getSubValues(), shapes, copiedShapeStorage, types);
|
||||
|
||||
assert(types.size() == 1);
|
||||
return types[0];
|
||||
@@ -814,105 +814,79 @@ GProp_GProps AttachEngine::getInertialPropsOfShape(const std::vector<const TopoD
|
||||
|
||||
/*!
|
||||
* \brief AttachEngine3D::readLinks
|
||||
* \param parts
|
||||
* \param shapes
|
||||
* \param storage is a buffer storing what some of the pointers in shapes point to. It is needed, since
|
||||
* subshapes are copied in the process (but copying a whole shape of an object can potentially be slow).
|
||||
*/
|
||||
void AttachEngine::readLinks(const std::vector<App::DocumentObject*> &objs,
|
||||
const std::vector<std::string> &sub,
|
||||
std::vector<App::GeoFeature*> &geofs,
|
||||
void AttachEngine::readLinks(const std::vector<App::DocumentObject*>& objs,
|
||||
const std::vector<std::string> &subs,
|
||||
std::vector<const TopoDS_Shape*> &shapes,
|
||||
std::vector<TopoDS_Shape> &storage,
|
||||
std::vector<eRefType> &types)
|
||||
{
|
||||
geofs.resize(objs.size());
|
||||
storage.reserve(objs.size());
|
||||
shapes.resize(objs.size());
|
||||
types.resize(objs.size());
|
||||
for (std::size_t i = 0; i < objs.size(); i++) {
|
||||
if (!objs[i]->getTypeId().isDerivedFrom(App::GeoFeature::getClassTypeId())) {
|
||||
FC_THROWM(AttachEngineException,
|
||||
"AttachEngine3D: attached to a non App::GeoFeature '"
|
||||
<< objs[i]->getNameInDocument() << "'");
|
||||
}
|
||||
auto* geof = dynamic_cast<App::GeoFeature*>(objs[i]);
|
||||
geofs[i] = geof;
|
||||
Part::TopoShape shape;
|
||||
if (geof->isDerivedFrom(App::Plane::getClassTypeId())) {
|
||||
// obtain Z axis and origin of placement
|
||||
Base::Vector3d norm;
|
||||
geof->Placement.getValue().getRotation().multVec(Base::Vector3d(0.0, 0.0, 1.0), norm);
|
||||
Base::Vector3d org;
|
||||
geof->Placement.getValue().multVec(Base::Vector3d(), org);
|
||||
// make shape - an local-XY plane infinite face
|
||||
gp_Pln plane = gp_Pln(gp_Pnt(org.x, org.y, org.z), gp_Dir(norm.x, norm.y, norm.z));
|
||||
TopoDS_Shape myShape = BRepBuilderAPI_MakeFace(plane).Shape();
|
||||
myShape.Infinite(true);
|
||||
storage.emplace_back(myShape);
|
||||
shapes[i] = &(storage[storage.size() - 1]);
|
||||
if (!geof) {
|
||||
// Accept App::Links to GeoFeatures
|
||||
geof = dynamic_cast<App::GeoFeature*>(objs[i]->getLinkedObject());
|
||||
if (!geof) {
|
||||
FC_THROWM(AttachEngineException,
|
||||
"AttachEngine3D: attached to a non App::GeoFeature '" << objs[i]->getNameInDocument() << "'");
|
||||
}
|
||||
}
|
||||
else if (geof->isDerivedFrom(App::Line::getClassTypeId())) {
|
||||
// obtain X axis and origin of placement
|
||||
// note an inconsistency: App::Line is along local X, PartDesign::DatumLine is along
|
||||
// local Z.
|
||||
Base::Vector3d dir;
|
||||
geof->Placement.getValue().getRotation().multVec(Base::Vector3d(1.0, 0.0, 0.0), dir);
|
||||
Base::Vector3d org;
|
||||
geof->Placement.getValue().multVec(Base::Vector3d(), org);
|
||||
// make shape - an infinite line along local X axis
|
||||
gp_Lin line = gp_Lin(gp_Pnt(org.x, org.y, org.z), gp_Dir(dir.x, dir.y, dir.z));
|
||||
TopoDS_Shape myShape = BRepBuilderAPI_MakeEdge(line).Shape();
|
||||
myShape.Infinite(true);
|
||||
storage.emplace_back(myShape);
|
||||
shapes[i] = &(storage[storage.size() - 1]);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
shape = Part::Feature::getTopoShape(geof, sub[i].c_str(), true);
|
||||
for (;;) {
|
||||
if (shape.isNull()) {
|
||||
FC_THROWM(AttachEngineException,
|
||||
"AttachEngine3D: subshape not found "
|
||||
<< objs[i]->getNameInDocument() << '.' << sub[i]);
|
||||
}
|
||||
if (shape.shapeType() != TopAbs_COMPOUND
|
||||
|| shape.countSubShapes(TopAbs_SHAPE) != 1) {
|
||||
break;
|
||||
}
|
||||
// auto extract the single sub-shape from a compound
|
||||
shape = shape.getSubTopoShape(TopAbs_SHAPE, 1);
|
||||
TopoDS_Shape myShape;
|
||||
|
||||
try {
|
||||
// getTopoShape support fully qualified subnames and should return shape with correct
|
||||
// global placement.
|
||||
Part::TopoShape shape = Part::Feature::getTopoShape(objs[i], subs[i].c_str(), true);
|
||||
for (;;) {
|
||||
if (shape.isNull()) {
|
||||
FC_THROWM(AttachEngineException,
|
||||
"AttachEngine3D: subshape not found "
|
||||
<< objs[i]->getNameInDocument() << '.' << subs[i]);
|
||||
}
|
||||
storage.emplace_back(shape.getShape());
|
||||
if (shape.shapeType() != TopAbs_COMPOUND
|
||||
|| shape.countSubShapes(TopAbs_SHAPE) != 1) {
|
||||
break;
|
||||
}
|
||||
// auto extract the single sub-shape from a compound
|
||||
shape = shape.getSubTopoShape(TopAbs_SHAPE, 1);
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
FC_THROWM(AttachEngineException,
|
||||
"AttachEngine3D: subshape not found " << objs[i]->getNameInDocument()
|
||||
<< '.' << sub[i] << std::endl
|
||||
<< e.GetMessageString());
|
||||
}
|
||||
catch (Base::CADKernelError& e) {
|
||||
FC_THROWM(AttachEngineException,
|
||||
"AttachEngine3D: subshape not found " << objs[i]->getNameInDocument()
|
||||
<< '.' << sub[i] << std::endl
|
||||
<< e.what());
|
||||
}
|
||||
if (storage.back().IsNull()) {
|
||||
FC_THROWM(AttachEngineException,
|
||||
"AttachEngine3D: null subshape " << objs[i]->getNameInDocument() << '.'
|
||||
<< sub[i]);
|
||||
}
|
||||
shapes[i] = &(storage.back());
|
||||
|
||||
myShape = shape.getShape();
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
FC_THROWM(AttachEngineException,
|
||||
"AttachEngine3D: subshape not found " << objs[i]->getNameInDocument()
|
||||
<< '.' << subs[i] << std::endl
|
||||
<< e.GetMessageString());
|
||||
}
|
||||
catch (Base::CADKernelError& e) {
|
||||
FC_THROWM(AttachEngineException,
|
||||
"AttachEngine3D: subshape not found " << objs[i]->getNameInDocument()
|
||||
<< '.' << subs[i] << std::endl
|
||||
<< e.what());
|
||||
}
|
||||
if (myShape.IsNull()) {
|
||||
FC_THROWM(AttachEngineException,
|
||||
"AttachEngine3D: null subshape " << objs[i]->getNameInDocument() << '.'
|
||||
<< subs[i]);
|
||||
}
|
||||
|
||||
storage.emplace_back(myShape);
|
||||
shapes[i] = &(storage.back());
|
||||
|
||||
// FIXME: unpack single-child compounds here? Compounds are not used so far, so it should be
|
||||
// considered later, when the need arises.
|
||||
types[i] = getShapeType(*(shapes[i]));
|
||||
if (sub[i].length() == 0) {
|
||||
if (subs[i].length() == 0) {
|
||||
types[i] = eRefType(types[i] | rtFlagHasPlacement);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AttachEngine::throwWrongMode(eMapMode mmode)
|
||||
@@ -977,6 +951,7 @@ Base::Placement AttachEngine::calculateAttachedPlacement(const Base::Placement&
|
||||
for (auto obj : objs) {
|
||||
++i;
|
||||
auto& sub = subnames[i];
|
||||
obj = obj->getSubObject(sub.c_str());
|
||||
auto& shadow = shadowSubs[i];
|
||||
if (shadow.empty() || !Data::hasMissingElement(sub.c_str())) {
|
||||
continue;
|
||||
@@ -1165,20 +1140,20 @@ AttachEngine3D::_calculateAttachedPlacement(const std::vector<App::DocumentObjec
|
||||
throw ExceptionCancel(); // to be handled in positionBySupport, to not do anything if
|
||||
// disabled
|
||||
}
|
||||
std::vector<App::GeoFeature*> parts;
|
||||
std::vector<const TopoDS_Shape*> shapes;
|
||||
std::vector<TopoDS_Shape> copiedShapeStorage;
|
||||
std::vector<eRefType> types;
|
||||
readLinks(objs, subs, parts, shapes, copiedShapeStorage, types);
|
||||
readLinks(objs, subs, shapes, copiedShapeStorage, types);
|
||||
|
||||
if (parts.empty()) {
|
||||
if (shapes.empty()) {
|
||||
throw ExceptionCancel();
|
||||
}
|
||||
|
||||
// common stuff for all map modes
|
||||
gp_Pnt refOrg(0.0, 0.0, 0.0); // origin of linked object
|
||||
Base::Placement Place = parts[0]->Placement.getValue();
|
||||
refOrg = gp_Pnt(Place.getPosition().x, Place.getPosition().y, Place.getPosition().z);
|
||||
App::DocumentObject* subObj = objs[0]->getSubObject(subs[0].c_str());
|
||||
Base::Placement Place = App::GeoFeature::getGlobalPlacement(subObj, objs[0], subs[0]);
|
||||
Base::Vector3d vec = Place.getPosition();
|
||||
gp_Pnt refOrg = gp_Pnt(vec.x, vec.y, vec.z); // origin of linked object
|
||||
|
||||
// variables to derive the actual placement.
|
||||
// They are to be set, depending on the mode:
|
||||
@@ -2108,21 +2083,21 @@ AttachEngineLine::_calculateAttachedPlacement(const std::vector<App::DocumentObj
|
||||
|
||||
Base::Placement plm;
|
||||
if (!bReUsed) {
|
||||
std::vector<App::GeoFeature*> parts;
|
||||
std::vector<const TopoDS_Shape*> shapes;
|
||||
std::vector<TopoDS_Shape> copiedShapeStorage;
|
||||
std::vector<eRefType> types;
|
||||
readLinks(objs, subs, parts, shapes, copiedShapeStorage, types);
|
||||
readLinks(objs, subs, shapes, copiedShapeStorage, types);
|
||||
|
||||
if (parts.empty()) {
|
||||
if (shapes.empty()) {
|
||||
throw ExceptionCancel();
|
||||
}
|
||||
|
||||
|
||||
// common stuff for all map modes
|
||||
gp_Pnt refOrg(0.0, 0.0, 0.0);
|
||||
Base::Placement Place = parts[0]->Placement.getValue();
|
||||
refOrg = gp_Pnt(Place.getPosition().x, Place.getPosition().y, Place.getPosition().z);
|
||||
App::DocumentObject* subObj = objs[0]->getSubObject(subs[0].c_str());
|
||||
Base::Placement Place = App::GeoFeature::getGlobalPlacement(subObj, objs[0], subs[0]);
|
||||
Base::Vector3d vec = Place.getPosition();
|
||||
gp_Pnt refOrg = gp_Pnt(vec.x, vec.y, vec.z); // origin of linked object
|
||||
|
||||
// variables to derive the actual placement.
|
||||
// They are to be set, depending on the mode:
|
||||
@@ -2475,13 +2450,12 @@ AttachEnginePoint::_calculateAttachedPlacement(const std::vector<App::DocumentOb
|
||||
|
||||
Base::Placement plm;
|
||||
if (!bReUsed) {
|
||||
std::vector<App::GeoFeature*> parts;
|
||||
std::vector<const TopoDS_Shape*> shapes;
|
||||
std::vector<TopoDS_Shape> copiedShapeStorage;
|
||||
std::vector<eRefType> types;
|
||||
readLinks(objs, subs, parts, shapes, copiedShapeStorage, types);
|
||||
readLinks(objs, subs, shapes, copiedShapeStorage, types);
|
||||
|
||||
if (parts.empty()) {
|
||||
if (shapes.empty()) {
|
||||
throw ExceptionCancel();
|
||||
}
|
||||
|
||||
|
||||
@@ -429,7 +429,7 @@ protected:
|
||||
return ret;
|
||||
}
|
||||
static void readLinks(const std::vector<App::DocumentObject*> &objs,
|
||||
const std::vector<std::string> &subs, std::vector<App::GeoFeature *> &geofs,
|
||||
const std::vector<std::string> &subs,
|
||||
std::vector<const TopoDS_Shape*>& shapes, std::vector<TopoDS_Shape> &storage,
|
||||
std::vector<eRefType> &types);
|
||||
|
||||
|
||||
@@ -213,6 +213,8 @@ SET(Features_SRCS
|
||||
CustomFeature.h
|
||||
BodyBase.h
|
||||
BodyBase.cpp
|
||||
Datums.cpp
|
||||
Datums.h
|
||||
DatumFeature.cpp
|
||||
DatumFeature.h
|
||||
AttachExtension.h
|
||||
|
||||
63
src/Mod/Part/App/Datums.cpp
Normal file
63
src/Mod/Part/App/Datums.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Ondsel (PL Boyer) <development@ondsel.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include "Datums.h"
|
||||
|
||||
|
||||
using namespace Part;
|
||||
using namespace Attacher;
|
||||
|
||||
PROPERTY_SOURCE_WITH_EXTENSIONS(Part::DatumPlane, App::Plane)
|
||||
|
||||
Part::DatumPlane::DatumPlane()
|
||||
{
|
||||
AttachExtension::initExtension(this);
|
||||
this->setAttacher(new AttachEnginePlane);
|
||||
}
|
||||
|
||||
|
||||
PROPERTY_SOURCE_WITH_EXTENSIONS(Part::DatumLine, App::Line)
|
||||
|
||||
Part::DatumLine::DatumLine()
|
||||
{
|
||||
AttachExtension::initExtension(this);
|
||||
this->setAttacher(new AttachEngineLine);
|
||||
}
|
||||
|
||||
|
||||
PROPERTY_SOURCE_WITH_EXTENSIONS(Part::DatumPoint, App::Point)
|
||||
|
||||
Part::DatumPoint::DatumPoint()
|
||||
{
|
||||
AttachExtension::initExtension(this);
|
||||
this->setAttacher(new AttachEnginePoint);
|
||||
}
|
||||
|
||||
|
||||
PROPERTY_SOURCE_WITH_EXTENSIONS(Part::LocalCoordinateSystem, App::LocalCoordinateSystem)
|
||||
|
||||
Part::LocalCoordinateSystem::LocalCoordinateSystem()
|
||||
{
|
||||
AttachExtension::initExtension(this);
|
||||
}
|
||||
84
src/Mod/Part/App/Datums.h
Normal file
84
src/Mod/Part/App/Datums.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Ondsel (PL Boyer) <development@ondsel.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef PART_DATUMS_H
|
||||
#define PART_DATUMS_H
|
||||
|
||||
#include <App/Datums.h>
|
||||
|
||||
#include "AttachExtension.h"
|
||||
|
||||
namespace Part
|
||||
{
|
||||
|
||||
class PartExport DatumPlane : public App::Plane, public AttachExtension
|
||||
{
|
||||
PROPERTY_HEADER_WITH_EXTENSIONS(Part::DatumPlane);
|
||||
|
||||
public:
|
||||
DatumPlane();
|
||||
~DatumPlane() override = default;
|
||||
const char* getViewProviderName() const override {
|
||||
return "PartGui::ViewProviderPlane";
|
||||
}
|
||||
};
|
||||
|
||||
class PartExport DatumLine : public App::Line, public AttachExtension
|
||||
{
|
||||
PROPERTY_HEADER_WITH_EXTENSIONS(Part::DatumLine);
|
||||
|
||||
public:
|
||||
DatumLine();
|
||||
~DatumLine() override = default;
|
||||
const char* getViewProviderName() const override {
|
||||
return "PartGui::ViewProviderLine";
|
||||
}
|
||||
};
|
||||
|
||||
class PartExport DatumPoint : public App::Point, public AttachExtension
|
||||
{
|
||||
PROPERTY_HEADER_WITH_EXTENSIONS(Part::DatumPoint);
|
||||
|
||||
public:
|
||||
DatumPoint();
|
||||
~DatumPoint() override = default;
|
||||
const char* getViewProviderName() const override {
|
||||
return "PartGui::ViewProviderPoint";
|
||||
}
|
||||
};
|
||||
|
||||
class PartExport LocalCoordinateSystem : public App::LocalCoordinateSystem, public AttachExtension
|
||||
{
|
||||
PROPERTY_HEADER_WITH_EXTENSIONS(Part::LocalCoordinateSystem);
|
||||
|
||||
public:
|
||||
LocalCoordinateSystem();
|
||||
~LocalCoordinateSystem() override = default;
|
||||
const char* getViewProviderName() const override {
|
||||
return "PartGui::ViewProviderLCS";
|
||||
}
|
||||
};
|
||||
|
||||
} //namespace Part
|
||||
|
||||
|
||||
#endif // PART_DATUMS_H
|
||||
@@ -1018,7 +1018,7 @@ static TopoShape _getTopoShape(const App::DocumentObject* obj,
|
||||
if (linked->isDerivedFrom(App::Line::getClassTypeId())) {
|
||||
static TopoDS_Shape _shape;
|
||||
if (_shape.IsNull()) {
|
||||
BRepBuilderAPI_MakeEdge builder(gp_Lin(gp_Pnt(0, 0, 0), gp_Dir(1, 0, 0)));
|
||||
BRepBuilderAPI_MakeEdge builder(gp_Lin(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)));
|
||||
_shape = builder.Shape();
|
||||
_shape.Infinite(Standard_True);
|
||||
}
|
||||
@@ -1076,6 +1076,7 @@ static TopoShape _getTopoShape(const App::DocumentObject* obj,
|
||||
shape = TopoShape(tag, hasher, _shape);
|
||||
}
|
||||
}
|
||||
|
||||
if (!shape.isNull()) {
|
||||
shape.transformShape(mat * linkMat, false, true);
|
||||
return shape;
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "ViewProvider.h"
|
||||
#include "ViewProvider2DObject.h"
|
||||
#include "ViewProviderAttachExtension.h"
|
||||
#include "ViewProviderDatum.h"
|
||||
#include "ViewProviderGridExtension.h"
|
||||
#include "ViewProviderBoolean.h"
|
||||
#include "ViewProviderBox.h"
|
||||
@@ -167,6 +168,10 @@ PyMOD_INIT_FUNC(PartGui)
|
||||
PartGui::ViewProviderGridExtensionPython ::init();
|
||||
PartGui::ViewProviderSplineExtension ::init();
|
||||
PartGui::ViewProviderSplineExtensionPython ::init();
|
||||
PartGui::ViewProviderLine ::init();
|
||||
PartGui::ViewProviderPlane ::init();
|
||||
PartGui::ViewProviderPoint ::init();
|
||||
PartGui::ViewProviderLCS ::init();
|
||||
PartGui::ViewProviderPartExt ::init();
|
||||
PartGui::ViewProviderPart ::init();
|
||||
PartGui::ViewProviderPrimitive ::init();
|
||||
|
||||
@@ -164,6 +164,8 @@ SET(PartGui_SRCS
|
||||
ViewProvider.h
|
||||
ViewProviderAttachExtension.h
|
||||
ViewProviderAttachExtension.cpp
|
||||
ViewProviderDatum.cpp
|
||||
ViewProviderDatum.h
|
||||
ViewProviderExt.cpp
|
||||
ViewProviderExt.h
|
||||
ViewProviderReference.cpp
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#endif
|
||||
|
||||
#include <App/Document.h>
|
||||
#include <App/GeoFeature.h>
|
||||
#include <App/DocumentObjectGroup.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Exception.h>
|
||||
@@ -51,6 +52,8 @@
|
||||
#include <Gui/View3DInventorViewer.h>
|
||||
#include <Gui/WaitCursor.h>
|
||||
|
||||
#include <Mod/Part/App/Datums.h>
|
||||
|
||||
#include "BoxSelection.h"
|
||||
#include "CrossSections.h"
|
||||
#include "DlgBooleanOperation.h"
|
||||
@@ -2211,6 +2214,193 @@ bool CmdPartSectionCut::isActive()
|
||||
return hasActiveDocument();
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
// Part_CoordinateSystem
|
||||
//===========================================================================
|
||||
|
||||
namespace {
|
||||
QString getAutoGroupCommandStr()
|
||||
// Helper function to get the python code to add the newly created object to the active Part/Body object if present
|
||||
{
|
||||
App::GeoFeature* activeObj = Gui::Application::Instance->activeView()->getActiveObject<App::GeoFeature*>(PDBODYKEY);
|
||||
if (!activeObj) {
|
||||
activeObj = Gui::Application::Instance->activeView()->getActiveObject<App::GeoFeature*>(PARTKEY);
|
||||
}
|
||||
|
||||
if (activeObj) {
|
||||
QString activeName = QString::fromLatin1(activeObj->getNameInDocument());
|
||||
return QString::fromLatin1("App.ActiveDocument.getObject('%1\').addObject(obj)\n").arg(activeName);
|
||||
}
|
||||
|
||||
return QString::fromLatin1("# Object created at document root.");
|
||||
}
|
||||
}
|
||||
|
||||
DEF_STD_CMD_A(CmdPartCoordinateSystem)
|
||||
|
||||
CmdPartCoordinateSystem::CmdPartCoordinateSystem()
|
||||
: Command("Part_CoordinateSystem")
|
||||
{
|
||||
sGroup = QT_TR_NOOP("Part");
|
||||
sMenuText = QT_TR_NOOP("Create a coordinate system");
|
||||
sToolTipText = QT_TR_NOOP("A coordinate system object that can be attached to other objects.");
|
||||
sWhatsThis = "Part_CoordinateSystem";
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Std_CoordinateSystem";
|
||||
}
|
||||
|
||||
void CmdPartCoordinateSystem::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
|
||||
openCommand(QT_TRANSLATE_NOOP("Command", "Add a coordinate system"));
|
||||
|
||||
std::string name = getUniqueObjectName("LCS");
|
||||
doCommand(Doc, "obj = App.activeDocument().addObject('Part::LocalCoordinateSystem','%s')", name.c_str());
|
||||
doCommand(Doc, getAutoGroupCommandStr().toUtf8());
|
||||
doCommand(Doc, "obj.Visibility = True");
|
||||
doCommand(Doc, "obj.ViewObject.doubleClicked()");
|
||||
}
|
||||
|
||||
bool CmdPartCoordinateSystem::isActive()
|
||||
{
|
||||
return hasActiveDocument();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Part_Plane
|
||||
//===========================================================================
|
||||
DEF_STD_CMD_A(CmdPartPlane)
|
||||
|
||||
CmdPartPlane::CmdPartPlane()
|
||||
: Command("Part_Plane")
|
||||
{
|
||||
sGroup = QT_TR_NOOP("Part");
|
||||
sMenuText = QT_TR_NOOP("Create a datum plane");
|
||||
sToolTipText = QT_TR_NOOP("A plane object that can be attached to other objects.");
|
||||
sWhatsThis = "Part_Plane";
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Std_Plane";
|
||||
}
|
||||
|
||||
void CmdPartPlane::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
|
||||
openCommand(QT_TRANSLATE_NOOP("Command", "Add a datum plane"));
|
||||
|
||||
std::string name = getUniqueObjectName("Plane");
|
||||
doCommand(Doc, "obj = App.activeDocument().addObject('Part::DatumPlane','%s')", name.c_str());
|
||||
doCommand(Doc, getAutoGroupCommandStr().toUtf8());
|
||||
doCommand(Doc, "obj.ViewObject.doubleClicked()");
|
||||
}
|
||||
|
||||
bool CmdPartPlane::isActive()
|
||||
{
|
||||
return hasActiveDocument();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Part_Line
|
||||
//===========================================================================
|
||||
DEF_STD_CMD_A(CmdPartLine)
|
||||
|
||||
CmdPartLine::CmdPartLine()
|
||||
: Command("Part_Line")
|
||||
{
|
||||
sGroup = QT_TR_NOOP("Part");
|
||||
sMenuText = QT_TR_NOOP("Create a datum line");
|
||||
sToolTipText = QT_TR_NOOP("A line object that can be attached to other objects.");
|
||||
sWhatsThis = "Part_Line";
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Std_Axis";
|
||||
}
|
||||
|
||||
void CmdPartLine::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
|
||||
openCommand(QT_TRANSLATE_NOOP("Command", "Add a datum line"));
|
||||
|
||||
std::string name = getUniqueObjectName("Line");
|
||||
doCommand(Doc, "obj = App.activeDocument().addObject('Part::DatumLine','%s')", name.c_str());
|
||||
doCommand(Doc, getAutoGroupCommandStr().toUtf8());
|
||||
doCommand(Doc, "obj.ViewObject.doubleClicked()");
|
||||
}
|
||||
|
||||
bool CmdPartLine::isActive()
|
||||
{
|
||||
return hasActiveDocument();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Part_Point
|
||||
//===========================================================================
|
||||
DEF_STD_CMD_A(CmdPartPoint)
|
||||
|
||||
CmdPartPoint::CmdPartPoint()
|
||||
: Command("Part_Point")
|
||||
{
|
||||
sGroup = QT_TR_NOOP("Part");
|
||||
sMenuText = QT_TR_NOOP("Create a datum point");
|
||||
sToolTipText = QT_TR_NOOP("A point object that can be attached to other objects.");
|
||||
sWhatsThis = "Part_Point";
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Std_Point";
|
||||
}
|
||||
|
||||
void CmdPartPoint::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
|
||||
openCommand(QT_TRANSLATE_NOOP("Command", "Add a datum point"));
|
||||
|
||||
std::string name = getUniqueObjectName("Point");
|
||||
doCommand(Doc, "obj = App.activeDocument().addObject('Part::DatumPoint','%s')", name.c_str());
|
||||
doCommand(Doc, getAutoGroupCommandStr().toUtf8());
|
||||
doCommand(Doc, "obj.ViewObject.doubleClicked()");
|
||||
}
|
||||
|
||||
bool CmdPartPoint::isActive()
|
||||
{
|
||||
return hasActiveDocument();
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
// Part_Datums
|
||||
//===========================================================================
|
||||
class CmdPartDatums : public Gui::GroupCommand
|
||||
{
|
||||
public:
|
||||
CmdPartDatums()
|
||||
: GroupCommand("Part_Datums")
|
||||
{
|
||||
sGroup = QT_TR_NOOP("Part");
|
||||
sMenuText = QT_TR_NOOP("Create a datum");
|
||||
sToolTipText = QT_TR_NOOP("Create a datum object (LCS, Plane, Line, Point) that can be attached to other objects.");
|
||||
sWhatsThis = "Part_Datums";
|
||||
sStatusTip = sToolTipText;
|
||||
|
||||
setCheckable(false);
|
||||
|
||||
addCommand("Part_CoordinateSystem");
|
||||
addCommand("Part_Plane");
|
||||
addCommand("Part_Line");
|
||||
addCommand("Part_Point");
|
||||
}
|
||||
|
||||
const char* className() const override
|
||||
{
|
||||
return "CmdPartDatums";
|
||||
}
|
||||
|
||||
bool isActive() override
|
||||
{
|
||||
return hasActiveDocument();
|
||||
}
|
||||
};
|
||||
//---------------------------------------------------------------
|
||||
|
||||
void CreatePartCommands()
|
||||
@@ -2256,4 +2446,10 @@ void CreatePartCommands()
|
||||
rcCmdMgr.addCommand(new CmdBoxSelection());
|
||||
rcCmdMgr.addCommand(new CmdPartProjectionOnSurface());
|
||||
rcCmdMgr.addCommand(new CmdPartSectionCut());
|
||||
|
||||
rcCmdMgr.addCommand(new CmdPartCoordinateSystem());
|
||||
rcCmdMgr.addCommand(new CmdPartPlane());
|
||||
rcCmdMgr.addCommand(new CmdPartLine());
|
||||
rcCmdMgr.addCommand(new CmdPartPoint());
|
||||
rcCmdMgr.addCommand(new CmdPartDatums());
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/ElementNamingUtils.h>
|
||||
#include <App/ObjectIdentifier.h>
|
||||
#include <App/Datums.h>
|
||||
#include <App/Part.h>
|
||||
@@ -43,6 +44,7 @@
|
||||
#include <Gui/DocumentObserver.h>
|
||||
#include <Gui/Selection.h>
|
||||
#include <Gui/ViewProvider.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <Mod/Part/App/AttachExtension.h>
|
||||
#include <Mod/Part/App/DatumFeature.h>
|
||||
#include <Mod/Part/Gui/AttacherTexts.h>
|
||||
@@ -62,29 +64,22 @@ namespace sp = std::placeholders;
|
||||
// Create reference name from PropertyLinkSub values in a translatable fashion
|
||||
const QString makeRefString(const App::DocumentObject* obj, const std::string& sub)
|
||||
{
|
||||
if (!obj)
|
||||
if (!obj) {
|
||||
return QObject::tr("No reference selected");
|
||||
|
||||
if (obj->isDerivedFrom<App::DatumElement>() ||
|
||||
obj->isDerivedFrom<Part::Datum>())
|
||||
// App::Plane, Line or Datum feature
|
||||
return QString::fromLatin1(obj->getNameInDocument());
|
||||
|
||||
if ((sub.size() > 4) && (sub.substr(0,4) == "Face")) {
|
||||
int subId = std::atoi(&sub[4]);
|
||||
return QString::fromLatin1(obj->getNameInDocument()) + QString::fromLatin1(":") + QObject::tr("Face") + QString::number(subId);
|
||||
} else if ((sub.size() > 4) && (sub.substr(0,4) == "Edge")) {
|
||||
int subId = std::atoi(&sub[4]);
|
||||
return QString::fromLatin1(obj->getNameInDocument()) + QString::fromLatin1(":") + QObject::tr("Edge") + QString::number(subId);
|
||||
} else if ((sub.size() > 6) && (sub.substr(0,6) == "Vertex")) {
|
||||
int subId = std::atoi(&sub[6]);
|
||||
return QString::fromLatin1(obj->getNameInDocument()) + QString::fromLatin1(":") + QObject::tr("Vertex") + QString::number(subId);
|
||||
} else {
|
||||
//something else that face/edge/vertex. Can be empty string.
|
||||
return QString::fromLatin1(obj->getNameInDocument())
|
||||
+ (sub.length()>0 ? QString::fromLatin1(":") : QString())
|
||||
+ QString::fromLatin1(sub.c_str());
|
||||
}
|
||||
|
||||
if (obj->isDerivedFrom<App::DatumElement>() || obj->isDerivedFrom<Part::Datum>()) {
|
||||
return QString::fromLatin1(obj->getNameInDocument());
|
||||
}
|
||||
|
||||
// Hide the TNP string from the user. ie show "Body.Pad.Face6" and not :
|
||||
// "Body.Pad.;#a:1;:G0;XTR;:Hc94:8,F.Face6"
|
||||
App::ElementNamePair el;
|
||||
App::GeoFeature::resolveElement(obj, sub.c_str(), el, true);
|
||||
|
||||
return QString::fromLatin1(obj->getNameInDocument())
|
||||
+ (sub.length() > 0 ? QString::fromLatin1(":") : QString())
|
||||
+ QString::fromLatin1(el.oldName.c_str());
|
||||
}
|
||||
|
||||
void TaskAttacher::makeRefStrings(std::vector<QString>& refstrings, std::vector<std::string>& refnames) {
|
||||
@@ -98,17 +93,18 @@ void TaskAttacher::makeRefStrings(std::vector<QString>& refstrings, std::vector<
|
||||
// for Origin or Datum features refnames is empty but we need a non-empty return value
|
||||
if (refnames[r].empty())
|
||||
refnames[r] = refs[r]->getNameInDocument();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
refstrings.push_back(QObject::tr("No reference selected"));
|
||||
refnames.emplace_back("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TaskAttacher::TaskAttacher(Gui::ViewProviderDocumentObject *ViewProvider, QWidget *parent,
|
||||
QString picture, QString text, TaskAttacher::VisibilityFunction visFunc)
|
||||
TaskAttacher::TaskAttacher(Gui::ViewProviderDocumentObject* ViewProvider, QWidget* parent,
|
||||
QString picture, QString text, TaskAttacher::VisibilityFunction visFunc)
|
||||
: TaskBox(Gui::BitmapFactory().pixmap(picture.toLatin1()), text, true, parent)
|
||||
, SelectionObserver(ViewProvider)
|
||||
, SelectionObserver(ViewProvider, true, Gui::ResolveMode::NoResolve)
|
||||
, ViewProvider(ViewProvider)
|
||||
, ui(new Ui_TaskAttacher)
|
||||
, visibilityFunc(visFunc)
|
||||
@@ -125,37 +121,37 @@ TaskAttacher::TaskAttacher(Gui::ViewProviderDocumentObject *ViewProvider, QWidge
|
||||
|
||||
// clang-format off
|
||||
connect(ui->attachmentOffsetX, qOverload<double>(&Gui::QuantitySpinBox::valueChanged),
|
||||
this, &TaskAttacher::onAttachmentOffsetXChanged);
|
||||
this, &TaskAttacher::onAttachmentOffsetXChanged);
|
||||
connect(ui->attachmentOffsetY, qOverload<double>(&Gui::QuantitySpinBox::valueChanged),
|
||||
this, &TaskAttacher::onAttachmentOffsetYChanged);
|
||||
this, &TaskAttacher::onAttachmentOffsetYChanged);
|
||||
connect(ui->attachmentOffsetZ, qOverload<double>(&Gui::QuantitySpinBox::valueChanged),
|
||||
this, &TaskAttacher::onAttachmentOffsetZChanged);
|
||||
this, &TaskAttacher::onAttachmentOffsetZChanged);
|
||||
connect(ui->attachmentOffsetYaw, qOverload<double>(&Gui::QuantitySpinBox::valueChanged),
|
||||
this, &TaskAttacher::onAttachmentOffsetYawChanged);
|
||||
this, &TaskAttacher::onAttachmentOffsetYawChanged);
|
||||
connect(ui->attachmentOffsetPitch, qOverload<double>(&Gui::QuantitySpinBox::valueChanged),
|
||||
this, &TaskAttacher::onAttachmentOffsetPitchChanged);
|
||||
this, &TaskAttacher::onAttachmentOffsetPitchChanged);
|
||||
connect(ui->attachmentOffsetRoll, qOverload<double>(&Gui::QuantitySpinBox::valueChanged),
|
||||
this, &TaskAttacher::onAttachmentOffsetRollChanged);
|
||||
this, &TaskAttacher::onAttachmentOffsetRollChanged);
|
||||
connect(ui->checkBoxFlip, &QCheckBox::toggled,
|
||||
this, &TaskAttacher::onCheckFlip);
|
||||
this, &TaskAttacher::onCheckFlip);
|
||||
connect(ui->buttonRef1, &QPushButton::clicked,
|
||||
this, &TaskAttacher::onButtonRef1);
|
||||
this, &TaskAttacher::onButtonRef1);
|
||||
connect(ui->lineRef1, &QLineEdit::textEdited,
|
||||
this, &TaskAttacher::onRefName1);
|
||||
this, &TaskAttacher::onRefName1);
|
||||
connect(ui->buttonRef2, &QPushButton::clicked,
|
||||
this, &TaskAttacher::onButtonRef2);
|
||||
this, &TaskAttacher::onButtonRef2);
|
||||
connect(ui->lineRef2, &QLineEdit::textEdited,
|
||||
this, &TaskAttacher::onRefName2);
|
||||
this, &TaskAttacher::onRefName2);
|
||||
connect(ui->buttonRef3, &QPushButton::clicked,
|
||||
this, &TaskAttacher::onButtonRef3);
|
||||
this, &TaskAttacher::onButtonRef3);
|
||||
connect(ui->lineRef3, &QLineEdit::textEdited,
|
||||
this, &TaskAttacher::onRefName3);
|
||||
this, &TaskAttacher::onRefName3);
|
||||
connect(ui->buttonRef4, &QPushButton::clicked,
|
||||
this, &TaskAttacher::onButtonRef4);
|
||||
this, &TaskAttacher::onButtonRef4);
|
||||
connect(ui->lineRef4, &QLineEdit::textEdited,
|
||||
this, &TaskAttacher::onRefName4);
|
||||
this, &TaskAttacher::onRefName4);
|
||||
connect(ui->listOfModes, &QListWidget::itemSelectionChanged,
|
||||
this, &TaskAttacher::onModeSelect);
|
||||
this, &TaskAttacher::onModeSelect);
|
||||
// clang-format on
|
||||
|
||||
this->groupLayout()->addWidget(proxy);
|
||||
@@ -205,19 +201,20 @@ TaskAttacher::TaskAttacher(Gui::ViewProviderDocumentObject *ViewProvider, QWidge
|
||||
this->iActiveRef = 0;
|
||||
else
|
||||
this->iActiveRef = -1;
|
||||
if (pcAttach->AttachmentSupport.getSize() == 0){
|
||||
if (pcAttach->AttachmentSupport.getSize() == 0) {
|
||||
autoNext = true;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
autoNext = false;
|
||||
}
|
||||
|
||||
ui->attachmentOffsetX->bind(App::ObjectIdentifier::parse(ViewProvider->getObject(),std::string("AttachmentOffset.Base.x")));
|
||||
ui->attachmentOffsetY->bind(App::ObjectIdentifier::parse(ViewProvider->getObject(),std::string("AttachmentOffset.Base.y")));
|
||||
ui->attachmentOffsetZ->bind(App::ObjectIdentifier::parse(ViewProvider->getObject(),std::string("AttachmentOffset.Base.z")));
|
||||
ui->attachmentOffsetX->bind(App::ObjectIdentifier::parse(ViewProvider->getObject(), std::string("AttachmentOffset.Base.x")));
|
||||
ui->attachmentOffsetY->bind(App::ObjectIdentifier::parse(ViewProvider->getObject(), std::string("AttachmentOffset.Base.y")));
|
||||
ui->attachmentOffsetZ->bind(App::ObjectIdentifier::parse(ViewProvider->getObject(), std::string("AttachmentOffset.Base.z")));
|
||||
|
||||
ui->attachmentOffsetYaw->bind(App::ObjectIdentifier::parse(ViewProvider->getObject(),std::string("AttachmentOffset.Rotation.Yaw")));
|
||||
ui->attachmentOffsetPitch->bind(App::ObjectIdentifier::parse(ViewProvider->getObject(),std::string("AttachmentOffset.Rotation.Pitch")));
|
||||
ui->attachmentOffsetRoll->bind(App::ObjectIdentifier::parse(ViewProvider->getObject(),std::string("AttachmentOffset.Rotation.Roll")));
|
||||
ui->attachmentOffsetYaw->bind(App::ObjectIdentifier::parse(ViewProvider->getObject(), std::string("AttachmentOffset.Rotation.Yaw")));
|
||||
ui->attachmentOffsetPitch->bind(App::ObjectIdentifier::parse(ViewProvider->getObject(), std::string("AttachmentOffset.Rotation.Pitch")));
|
||||
ui->attachmentOffsetRoll->bind(App::ObjectIdentifier::parse(ViewProvider->getObject(), std::string("AttachmentOffset.Rotation.Roll")));
|
||||
|
||||
visibilityAutomation(true);
|
||||
updateAttachmentOffsetUI();
|
||||
@@ -234,6 +231,8 @@ TaskAttacher::TaskAttacher(Gui::ViewProviderDocumentObject *ViewProvider, QWidge
|
||||
Gui::Document* document = Gui::Application::Instance->getDocument(ViewProvider->getObject()->getDocument());
|
||||
connectDelObject = document->signalDeletedObject.connect(bnd1);
|
||||
connectDelDocument = document->signalDeleteDocument.connect(bnd2);
|
||||
|
||||
handleInitialSelection();
|
||||
}
|
||||
|
||||
TaskAttacher::~TaskAttacher()
|
||||
@@ -293,10 +292,11 @@ void TaskAttacher::updateReferencesUI()
|
||||
pcAttach->attacher().suggestMapModes(this->lastSuggestResult);
|
||||
|
||||
if (this->lastSuggestResult.message != SuggestResult::srOK) {
|
||||
if(!this->lastSuggestResult.nextRefTypeHint.empty()){
|
||||
if (!this->lastSuggestResult.nextRefTypeHint.empty()) {
|
||||
//message = "Need more references";
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
completed = true;
|
||||
}
|
||||
|
||||
@@ -314,24 +314,29 @@ bool TaskAttacher::updatePreview()
|
||||
Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType<Part::AttachExtension>();
|
||||
QString errMessage;
|
||||
bool attached = false;
|
||||
try{
|
||||
try {
|
||||
attached = pcAttach->positionBySupport();
|
||||
} catch (Base::Exception &err){
|
||||
}
|
||||
catch (Base::Exception& err) {
|
||||
errMessage = QCoreApplication::translate("Exception", err.what());
|
||||
} catch (Standard_Failure &err){
|
||||
}
|
||||
catch (Standard_Failure& err) {
|
||||
errMessage = tr("OCC error: %1").arg(QString::fromLatin1(err.GetMessageString()));
|
||||
} catch (...) {
|
||||
}
|
||||
catch (...) {
|
||||
errMessage = tr("unknown error");
|
||||
}
|
||||
if (errMessage.length()>0){
|
||||
if (errMessage.length() > 0) {
|
||||
ui->message->setText(tr("Attachment mode failed: %1").arg(errMessage));
|
||||
ui->message->setStyleSheet(QString::fromLatin1("QLabel{color: red;}"));
|
||||
} else {
|
||||
if (!attached){
|
||||
}
|
||||
else {
|
||||
if (!attached) {
|
||||
ui->message->setText(tr("Not attached"));
|
||||
ui->message->setStyleSheet(QString());
|
||||
} else {
|
||||
std::vector<QString> strs = AttacherGui::getUIStrings(pcAttach->attacher().getTypeId(),eMapMode(pcAttach->MapMode.getValue()));
|
||||
}
|
||||
else {
|
||||
std::vector<QString> strs = AttacherGui::getUIStrings(pcAttach->attacher().getTypeId(), eMapMode(pcAttach->MapMode.getValue()));
|
||||
ui->message->setText(tr("Attached with mode %1").arg(strs[0]));
|
||||
ui->message->setStyleSheet(QString::fromLatin1("QLabel{color: green;}"));
|
||||
}
|
||||
@@ -345,47 +350,193 @@ bool TaskAttacher::updatePreview()
|
||||
|
||||
QLineEdit* TaskAttacher::getLine(unsigned idx)
|
||||
{
|
||||
switch(idx) {
|
||||
case 0: return ui->lineRef1;
|
||||
case 1: return ui->lineRef2;
|
||||
case 2: return ui->lineRef3;
|
||||
case 3: return ui->lineRef4;
|
||||
default: return nullptr;
|
||||
switch (idx) {
|
||||
case 0: return ui->lineRef1;
|
||||
case 1: return ui->lineRef2;
|
||||
case 2: return ui->lineRef3;
|
||||
case 3: return ui->lineRef4;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void TaskAttacher::findCorrectObjAndSubInThisContext(App::DocumentObject*& rootObj, std::string& sub)
|
||||
{
|
||||
// The reference that we store must take into account the hierarchy of geoFeatures. For example:
|
||||
// - Part
|
||||
// - - Cube
|
||||
// - Sketch
|
||||
// if sketch is attached to Cube.Face1 then it must store Part:Cube.Face3 as Sketch is outside of Part.
|
||||
// - Part
|
||||
// - - Cube
|
||||
// - - Sketch
|
||||
// In this example it must store Cube:Face3 because Sketch is inside Part, sibling of Cube.
|
||||
// So placement of Part is already taken into account.
|
||||
// - Part1
|
||||
// - - Part2
|
||||
// - - - Cube
|
||||
// - - Sketch
|
||||
// In this example it must store Part2:Cube.Face3 since Part1 is already taken into account.
|
||||
// - Part1
|
||||
// - - Part2
|
||||
// - - - Cube
|
||||
// - - Part3
|
||||
// - - - Sketch
|
||||
// In this example it's not possible because Sketch has Part3 placement. So it should be rejected
|
||||
// So we need to take the selection object and subname, and process them to get the correct obj/sub based
|
||||
// on attached and attaching objects positions.
|
||||
|
||||
std::vector<std::string> names = Base::Tools::splitSubName(sub);
|
||||
if (!rootObj || names.size() < 2) {
|
||||
return;
|
||||
}
|
||||
names.insert(names.begin(), rootObj->getNameInDocument());
|
||||
|
||||
App::Document* doc = rootObj->getDocument();
|
||||
App::DocumentObject* attachingObj = ViewProvider->getObject(); // Attaching object
|
||||
App::DocumentObject* subObj = rootObj->getSubObject(sub.c_str()); // Object being attached.
|
||||
if (!subObj || subObj == rootObj) {
|
||||
// Case of root object. We don't need to modify it.
|
||||
return;
|
||||
}
|
||||
if (subObj == attachingObj) {
|
||||
//prevent self-referencing
|
||||
rootObj = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if attachingObj is a root object. if so we keep the full path.
|
||||
auto* group = App::GeoFeatureGroupExtension::getGroupOfObject(attachingObj);
|
||||
if (!group) {
|
||||
if (attachingObj->getDocument() != rootObj->getDocument()) {
|
||||
// If it's not in same document then it's not a good selection
|
||||
rootObj = nullptr;
|
||||
}
|
||||
// if it's same document we keep the rootObj and sub unchanged.
|
||||
return;
|
||||
}
|
||||
|
||||
bool groupPassed = false;
|
||||
for (size_t i = 0; i < names.size(); ++i) {
|
||||
App::DocumentObject* obj = doc->getObject(names[i].c_str());
|
||||
if (!obj) {
|
||||
Base::Console().TranslatedUserError("TaskAttacher",
|
||||
"Unsuitable selection: '%s' cannot be attached to '%s' from within it's group '%s'.\n",
|
||||
attachingObj->getFullLabel(), subObj->getFullLabel(), group->getFullLabel());
|
||||
rootObj = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (groupPassed) {
|
||||
rootObj = obj;
|
||||
|
||||
// Rebuild 'sub' starting from the next element after the current 'name'
|
||||
sub = "";
|
||||
for (size_t j = i + 1; j < names.size(); ++j) {
|
||||
sub += names[j];
|
||||
if (j != names.size() - 1) {
|
||||
sub += "."; // Add a period between elements
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// In case the attaching object is in a link to a part.
|
||||
// For instance :
|
||||
// - Part1
|
||||
// - - LinkToPart2
|
||||
// - - - Cube
|
||||
// - - - Sketch
|
||||
obj = obj->getLinkedObject();
|
||||
|
||||
if (obj == group) {
|
||||
groupPassed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// if we reach this point it means that attaching object's group is outside of
|
||||
// the scope of the attached object. For instance:
|
||||
// - Part1
|
||||
// - - Part2
|
||||
// - - - Cube
|
||||
// - - Part3
|
||||
// - - - Sketch
|
||||
// In this case the selection is not acceptable.
|
||||
rootObj = nullptr;
|
||||
}
|
||||
|
||||
void TaskAttacher::handleInitialSelection()
|
||||
{
|
||||
// We handle initial selection only if it is not attached yet.
|
||||
App::DocumentObject* obj = ViewProvider->getObject();
|
||||
Part::AttachExtension* pcAttach = obj->getExtensionByType<Part::AttachExtension>();
|
||||
std::vector<App::DocumentObject*> refs = pcAttach->AttachmentSupport.getValues();
|
||||
|
||||
if (!refs.empty()) {
|
||||
return;
|
||||
}
|
||||
std::vector<SubAndObjName> subAndObjNamePairs;
|
||||
|
||||
auto sel = Gui::Selection().getSelectionEx("",
|
||||
App::DocumentObject::getClassTypeId(), Gui::ResolveMode::NoResolve);
|
||||
for (auto& selObj : sel) {
|
||||
std::vector<std::string> subs = selObj.getSubNames();
|
||||
std::string objName = selObj.getFeatName();
|
||||
for (auto& sub : subs) {
|
||||
SubAndObjName objSubName = { objName, sub };
|
||||
subAndObjNamePairs.push_back(objSubName);
|
||||
}
|
||||
}
|
||||
addToReference(subAndObjNamePairs);
|
||||
}
|
||||
|
||||
void TaskAttacher::onSelectionChanged(const Gui::SelectionChanges& msg)
|
||||
{
|
||||
if (!ViewProvider)
|
||||
if (!ViewProvider) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.Type == Gui::SelectionChanges::AddSelection) {
|
||||
if (iActiveRef < 0)
|
||||
return;
|
||||
SubAndObjName pair = { msg.pObjectName, msg.pSubName };
|
||||
addToReference(pair);
|
||||
}
|
||||
}
|
||||
|
||||
// Note: The validity checking has already been done in ReferenceSelection.cpp
|
||||
Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType<Part::AttachExtension>();
|
||||
void TaskAttacher::addToReference(const std::vector<SubAndObjName>& pairs)
|
||||
{
|
||||
if (iActiveRef < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: The validity checking has already been done in ReferenceSelection.cpp
|
||||
App::DocumentObject* obj = ViewProvider->getObject();
|
||||
Part::AttachExtension* pcAttach = obj->getExtensionByType<Part::AttachExtension>();
|
||||
|
||||
for (auto& pair : pairs) {
|
||||
std::vector<App::DocumentObject*> refs = pcAttach->AttachmentSupport.getValues();
|
||||
std::vector<std::string> refnames = pcAttach->AttachmentSupport.getSubValues();
|
||||
App::DocumentObject* selObj = ViewProvider->getObject()->getDocument()->getObject(msg.pObjectName);
|
||||
if (!selObj || selObj == ViewProvider->getObject())//prevent self-referencing
|
||||
return;
|
||||
|
||||
std::string subname = msg.pSubName;
|
||||
App::DocumentObject* selObj = obj->getDocument()->getObject(pair.objName.c_str());
|
||||
std::string subname = pair.subName;
|
||||
findCorrectObjAndSubInThisContext(selObj, subname);
|
||||
if (!selObj) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove subname for planes and datum features
|
||||
if (selObj->isDerivedFrom<App::DatumElement>() ||
|
||||
selObj->isDerivedFrom<Part::Datum>())
|
||||
if (selObj->isDerivedFrom<App::DatumElement>() || selObj->isDerivedFrom<Part::Datum>()) {
|
||||
subname = "";
|
||||
}
|
||||
|
||||
// eliminate duplicate selections
|
||||
for (size_t r = 0; r < refs.size(); r++)
|
||||
if ((refs[r] == selObj) && (refnames[r] == subname))
|
||||
for (size_t r = 0; r < refs.size(); r++) {
|
||||
if ((refs[r] == selObj) && (refnames[r] == subname)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (autoNext && iActiveRef > 0 && iActiveRef == static_cast<int>(refnames.size())){
|
||||
if (refs[iActiveRef-1] == selObj
|
||||
&& refnames[iActiveRef-1].length() != 0 && subname.length() == 0){
|
||||
if (autoNext && iActiveRef > 0 && iActiveRef == static_cast<int>(refnames.size())) {
|
||||
if (refs[iActiveRef - 1] == selObj
|
||||
&& refnames[iActiveRef - 1].length() != 0 && subname.length() == 0) {
|
||||
//A whole object was selected by clicking it twice. Fill it
|
||||
//into previous reference, where a sub-named reference filled by
|
||||
//the first click is already stored.
|
||||
@@ -396,31 +547,13 @@ void TaskAttacher::onSelectionChanged(const Gui::SelectionChanges& msg)
|
||||
if (iActiveRef < static_cast<int>(refs.size())) {
|
||||
refs[iActiveRef] = selObj;
|
||||
refnames[iActiveRef] = subname;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
refs.push_back(selObj);
|
||||
refnames.push_back(subname);
|
||||
}
|
||||
|
||||
//bool error = false;
|
||||
try {
|
||||
pcAttach->AttachmentSupport.setValues(refs, refnames);
|
||||
updateListOfModes();
|
||||
eMapMode mmode = getActiveMapMode();//will be mmDeactivated, if selected or if no modes are available
|
||||
if(mmode == mmDeactivated){
|
||||
//error = true;
|
||||
this->completed = false;
|
||||
} else {
|
||||
this->completed = true;
|
||||
}
|
||||
pcAttach->MapMode.setValue(mmode);
|
||||
selectMapMode(mmode);
|
||||
updatePreview();
|
||||
}
|
||||
catch(Base::Exception& e) {
|
||||
//error = true;
|
||||
ui->message->setText(QCoreApplication::translate("Exception", e.what()));
|
||||
ui->message->setStyleSheet(QString::fromLatin1("QLabel{color: red;}"));
|
||||
}
|
||||
pcAttach->AttachmentSupport.setValues(refs, refnames);
|
||||
|
||||
QLineEdit* line = getLine(iActiveRef);
|
||||
if (line) {
|
||||
@@ -431,17 +564,43 @@ void TaskAttacher::onSelectionChanged(const Gui::SelectionChanges& msg)
|
||||
}
|
||||
|
||||
if (autoNext) {
|
||||
if (iActiveRef == -1){
|
||||
if (iActiveRef == -1) {
|
||||
//nothing to do
|
||||
} else if (iActiveRef == 4 || this->lastSuggestResult.nextRefTypeHint.empty()){
|
||||
}
|
||||
else if (iActiveRef == 4 || this->lastSuggestResult.nextRefTypeHint.empty()) {
|
||||
iActiveRef = -1;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
iActiveRef++;
|
||||
}
|
||||
}
|
||||
|
||||
updateReferencesUI();
|
||||
}
|
||||
|
||||
try {
|
||||
updateListOfModes();
|
||||
eMapMode mmode = getActiveMapMode(); //will be mmDeactivated, if selected or if no modes are available
|
||||
if (mmode == mmDeactivated) {
|
||||
//error = true;
|
||||
this->completed = false;
|
||||
}
|
||||
else {
|
||||
this->completed = true;
|
||||
}
|
||||
pcAttach->MapMode.setValue(mmode);
|
||||
selectMapMode(mmode);
|
||||
updatePreview();
|
||||
}
|
||||
catch (Base::Exception& e) {
|
||||
ui->message->setText(QCoreApplication::translate("Exception", e.what()));
|
||||
ui->message->setStyleSheet(QString::fromLatin1("QLabel{color: red;}"));
|
||||
}
|
||||
|
||||
updateReferencesUI();
|
||||
}
|
||||
|
||||
void TaskAttacher::addToReference(SubAndObjName pair)
|
||||
{
|
||||
addToReference({ pair });
|
||||
}
|
||||
|
||||
void TaskAttacher::onAttachmentOffsetChanged(double /*val*/, int idx)
|
||||
@@ -462,17 +621,17 @@ void TaskAttacher::onAttachmentOffsetChanged(double /*val*/, int idx)
|
||||
if (idx == 2) {
|
||||
pos.z = ui->attachmentOffsetZ->value().getValueAs(Base::Quantity::MilliMetre);
|
||||
}
|
||||
if (idx >= 0 && idx <= 2){
|
||||
if (idx >= 0 && idx <= 2) {
|
||||
pl.setPosition(pos);
|
||||
}
|
||||
|
||||
if (idx >= 3 && idx <= 5){
|
||||
if (idx >= 3 && idx <= 5) {
|
||||
double yaw, pitch, roll;
|
||||
yaw = ui->attachmentOffsetYaw->value().getValueAs(Base::Quantity::Degree);
|
||||
pitch = ui->attachmentOffsetPitch->value().getValueAs(Base::Quantity::Degree);
|
||||
roll = ui->attachmentOffsetRoll->value().getValueAs(Base::Quantity::Degree);
|
||||
Base::Rotation rot;
|
||||
rot.setYawPitchRoll(yaw,pitch,roll);
|
||||
rot.setYawPitchRoll(yaw, pitch, roll);
|
||||
pl.setRotation(rot);
|
||||
}
|
||||
|
||||
@@ -526,7 +685,8 @@ void TaskAttacher::onButtonRef(const bool checked, unsigned idx)
|
||||
if (checked) {
|
||||
Gui::Selection().clearSelection();
|
||||
iActiveRef = idx;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
iActiveRef = -1;
|
||||
}
|
||||
updateRefButton(0);
|
||||
@@ -619,12 +779,15 @@ void TaskAttacher::onRefName(const QString& text, unsigned idx)
|
||||
if (obj->isDerivedFrom<App::Plane>()) {
|
||||
// everything is OK (we assume a Part can only have exactly 3 App::Plane objects located at the base of the feature tree)
|
||||
subElement.clear();
|
||||
} else if (obj->isDerivedFrom<App::Line>()) {
|
||||
}
|
||||
else if (obj->isDerivedFrom<App::Line>()) {
|
||||
// everything is OK (we assume a Part can only have exactly 3 App::Line objects located at the base of the feature tree)
|
||||
subElement.clear();
|
||||
} else if (obj->isDerivedFrom<Part::Datum>()) {
|
||||
}
|
||||
else if (obj->isDerivedFrom<Part::Datum>()) {
|
||||
subElement.clear();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// TODO: check validity of the text that was entered: Does subElement actually reference to an element on the obj?
|
||||
|
||||
auto getSubshapeName = [](const QString& part) -> std::string {
|
||||
@@ -672,7 +835,8 @@ void TaskAttacher::onRefName(const QString& text, unsigned idx)
|
||||
if (idx < refs.size()) {
|
||||
refs[idx] = obj;
|
||||
refnames[idx] = subElement;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
refs.push_back(obj);
|
||||
refnames.emplace_back(subElement);
|
||||
}
|
||||
@@ -690,12 +854,12 @@ void TaskAttacher::updateRefButton(int idx)
|
||||
return;
|
||||
|
||||
QAbstractButton* b;
|
||||
switch(idx){
|
||||
case 0: b = ui->buttonRef1; break;
|
||||
case 1: b = ui->buttonRef2; break;
|
||||
case 2: b = ui->buttonRef3; break;
|
||||
case 3: b = ui->buttonRef4; break;
|
||||
default: throw Base::IndexError("button index out of range");
|
||||
switch (idx) {
|
||||
case 0: b = ui->buttonRef1; break;
|
||||
case 1: b = ui->buttonRef2; break;
|
||||
case 2: b = ui->buttonRef3; break;
|
||||
case 3: b = ui->buttonRef4; break;
|
||||
default: throw Base::IndexError("button index out of range");
|
||||
}
|
||||
|
||||
Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType<Part::AttachExtension>();
|
||||
@@ -713,10 +877,12 @@ void TaskAttacher::updateRefButton(int idx)
|
||||
|
||||
if (iActiveRef == idx) {
|
||||
b->setText(tr("Selecting..."));
|
||||
} else if (idx < static_cast<int>(this->lastSuggestResult.references_Types.size())){
|
||||
}
|
||||
else if (idx < static_cast<int>(this->lastSuggestResult.references_Types.size())) {
|
||||
b->setText(AttacherGui::getShapeTypeText(this->lastSuggestResult.references_Types[idx]));
|
||||
} else {
|
||||
b->setText(tr("Reference%1").arg(idx+1));
|
||||
}
|
||||
else {
|
||||
b->setText(tr("Reference%1").arg(idx + 1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -740,9 +906,9 @@ void TaskAttacher::updateAttachmentOffsetUI()
|
||||
ui->attachmentOffsetPitch->blockSignals(bBlock);
|
||||
ui->attachmentOffsetRoll->blockSignals(bBlock);
|
||||
|
||||
ui->attachmentOffsetX->setValue(Base::Quantity(pos.x,Base::Unit::Length));
|
||||
ui->attachmentOffsetY->setValue(Base::Quantity(pos.y,Base::Unit::Length));
|
||||
ui->attachmentOffsetZ->setValue(Base::Quantity(pos.z,Base::Unit::Length));
|
||||
ui->attachmentOffsetX->setValue(Base::Quantity(pos.x, Base::Unit::Length));
|
||||
ui->attachmentOffsetY->setValue(Base::Quantity(pos.y, Base::Unit::Length));
|
||||
ui->attachmentOffsetZ->setValue(Base::Quantity(pos.z, Base::Unit::Length));
|
||||
ui->attachmentOffsetYaw->setValue(yaw);
|
||||
ui->attachmentOffsetPitch->setValue(pitch);
|
||||
ui->attachmentOffsetRoll->setValue(roll);
|
||||
@@ -750,13 +916,13 @@ void TaskAttacher::updateAttachmentOffsetUI()
|
||||
auto expressions = ViewProvider->getObject()->ExpressionEngine.getExpressions();
|
||||
bool bRotationBound = false;
|
||||
bRotationBound = bRotationBound ||
|
||||
expressions.find(App::ObjectIdentifier::parse(ViewProvider->getObject(),std::string("AttachmentOffset.Rotation.Angle"))) != expressions.end();
|
||||
expressions.find(App::ObjectIdentifier::parse(ViewProvider->getObject(), std::string("AttachmentOffset.Rotation.Angle"))) != expressions.end();
|
||||
bRotationBound = bRotationBound ||
|
||||
expressions.find(App::ObjectIdentifier::parse(ViewProvider->getObject(),std::string("AttachmentOffset.Rotation.Axis.x"))) != expressions.end();
|
||||
expressions.find(App::ObjectIdentifier::parse(ViewProvider->getObject(), std::string("AttachmentOffset.Rotation.Axis.x"))) != expressions.end();
|
||||
bRotationBound = bRotationBound ||
|
||||
expressions.find(App::ObjectIdentifier::parse(ViewProvider->getObject(),std::string("AttachmentOffset.Rotation.Axis.y"))) != expressions.end();
|
||||
expressions.find(App::ObjectIdentifier::parse(ViewProvider->getObject(), std::string("AttachmentOffset.Rotation.Axis.y"))) != expressions.end();
|
||||
bRotationBound = bRotationBound ||
|
||||
expressions.find(App::ObjectIdentifier::parse(ViewProvider->getObject(),std::string("AttachmentOffset.Rotation.Axis.z"))) != expressions.end();
|
||||
expressions.find(App::ObjectIdentifier::parse(ViewProvider->getObject(), std::string("AttachmentOffset.Rotation.Axis.z"))) != expressions.end();
|
||||
|
||||
ui->attachmentOffsetYaw->setEnabled(!bRotationBound);
|
||||
ui->attachmentOffsetPitch->setEnabled(!bRotationBound);
|
||||
@@ -794,22 +960,23 @@ void TaskAttacher::updateListOfModes()
|
||||
this->lastSuggestResult.bestFitMode = mmDeactivated;
|
||||
size_t lastValidModeItemIndex = mmDummy_NumberOfModes;
|
||||
|
||||
if (pcAttach->AttachmentSupport.getSize() > 0){
|
||||
if (pcAttach->AttachmentSupport.getSize() > 0) {
|
||||
pcAttach->attacher().suggestMapModes(this->lastSuggestResult);
|
||||
modesInList = this->lastSuggestResult.allApplicableModes;
|
||||
modesInList.insert(modesInList.begin(), mmDeactivated); // always have the option to choose Deactivated mode
|
||||
|
||||
//add reachable modes to the list, too, but gray them out (using lastValidModeItemIndex, later)
|
||||
lastValidModeItemIndex = modesInList.size()-1;
|
||||
for(std::pair<const eMapMode, refTypeStringList> &rm: this->lastSuggestResult.reachableModes){
|
||||
lastValidModeItemIndex = modesInList.size() - 1;
|
||||
for (std::pair<const eMapMode, refTypeStringList>& rm : this->lastSuggestResult.reachableModes) {
|
||||
modesInList.push_back(rm.first);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
//no references - display all modes
|
||||
modesInList.clear();
|
||||
modesInList.push_back(mmDeactivated);
|
||||
|
||||
for( int mmode = 0 ; mmode < mmDummy_NumberOfModes ; mmode++){
|
||||
for (int mmode = 0; mmode < mmDummy_NumberOfModes; mmode++) {
|
||||
if (pcAttach->attacher().modeEnabled[mmode])
|
||||
modesInList.push_back(eMapMode(mmode));
|
||||
}
|
||||
@@ -820,40 +987,42 @@ void TaskAttacher::updateListOfModes()
|
||||
ui->listOfModes->clear();
|
||||
QListWidgetItem* iSelect = nullptr;
|
||||
if (!modesInList.empty()) {
|
||||
for (size_t i = 0 ; i < modesInList.size() ; ++i){
|
||||
for (size_t i = 0; i < modesInList.size(); ++i) {
|
||||
eMapMode mmode = modesInList[i];
|
||||
std::vector<QString> mstr = AttacherGui::getUIStrings(pcAttach->attacher().getTypeId(),mmode);
|
||||
std::vector<QString> mstr = AttacherGui::getUIStrings(pcAttach->attacher().getTypeId(), mmode);
|
||||
ui->listOfModes->addItem(mstr[0]);
|
||||
QListWidgetItem* item = ui->listOfModes->item(i);
|
||||
QString tooltip = mstr[1];
|
||||
|
||||
if (mmode != mmDeactivated) {
|
||||
tooltip += QString::fromLatin1("\n\n%1\n%2")
|
||||
.arg(tr("Reference combinations:"),
|
||||
AttacherGui::getRefListForMode(pcAttach->attacher(),mmode).join(QString::fromLatin1("\n")));
|
||||
.arg(tr("Reference combinations:"),
|
||||
AttacherGui::getRefListForMode(pcAttach->attacher(), mmode).join(QString::fromLatin1("\n")));
|
||||
}
|
||||
item->setToolTip(tooltip);
|
||||
|
||||
if (mmode == curMode && curMode != mmDeactivated)
|
||||
iSelect = ui->listOfModes->item(i);
|
||||
if (i > lastValidModeItemIndex){
|
||||
if (i > lastValidModeItemIndex) {
|
||||
//potential mode - can be reached by selecting more stuff
|
||||
item->setFlags(item->flags() & ~(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable));
|
||||
|
||||
refTypeStringList &extraRefs = this->lastSuggestResult.reachableModes[mmode];
|
||||
if (extraRefs.size() == 1){
|
||||
refTypeStringList& extraRefs = this->lastSuggestResult.reachableModes[mmode];
|
||||
if (extraRefs.size() == 1) {
|
||||
QStringList buf;
|
||||
for(eRefType rt : extraRefs[0]){
|
||||
for (eRefType rt : extraRefs[0]) {
|
||||
buf.append(AttacherGui::getShapeTypeText(rt));
|
||||
}
|
||||
item->setText(tr("%1 (add %2)").arg(
|
||||
item->text(),
|
||||
buf.join(QString::fromLatin1("+"))
|
||||
));
|
||||
} else {
|
||||
item->text(),
|
||||
buf.join(QString::fromLatin1("+"))
|
||||
));
|
||||
}
|
||||
else {
|
||||
item->setText(tr("%1 (add more references)").arg(item->text()));
|
||||
}
|
||||
} else if (mmode == this->lastSuggestResult.bestFitMode){
|
||||
}
|
||||
else if (mmode == this->lastSuggestResult.bestFitMode) {
|
||||
//suggested mode - make bold
|
||||
QFont fnt = item->font();
|
||||
fnt.setBold(true);
|
||||
@@ -873,7 +1042,7 @@ void TaskAttacher::updateListOfModes()
|
||||
void TaskAttacher::selectMapMode(eMapMode mmode) {
|
||||
ui->listOfModes->blockSignals(true);
|
||||
|
||||
for (size_t i = 0; i < modesInList.size(); ++i) {
|
||||
for (size_t i = 0; i < modesInList.size(); ++i) {
|
||||
if (modesInList[i] == mmode) {
|
||||
ui->listOfModes->item(i)->setSelected(true);
|
||||
}
|
||||
@@ -910,7 +1079,7 @@ void TaskAttacher::onRefName3(const QString& text)
|
||||
onRefName(text, 2);
|
||||
}
|
||||
|
||||
void TaskAttacher::onRefName4(const QString &text)
|
||||
void TaskAttacher::onRefName4(const QString& text)
|
||||
{
|
||||
onRefName(text, 3);
|
||||
}
|
||||
@@ -920,7 +1089,7 @@ bool TaskAttacher::getFlip() const
|
||||
return ui->checkBoxFlip->isChecked();
|
||||
}
|
||||
|
||||
void TaskAttacher::changeEvent(QEvent *e)
|
||||
void TaskAttacher::changeEvent(QEvent* e)
|
||||
{
|
||||
TaskBox::changeEvent(e);
|
||||
if (e->type() == QEvent::LanguageChange) {
|
||||
@@ -958,11 +1127,11 @@ void TaskAttacher::changeEvent(QEvent *e)
|
||||
|
||||
void TaskAttacher::visibilityAutomation(bool opening_not_closing)
|
||||
{
|
||||
auto defvisfunc = [] (bool opening_not_closing,
|
||||
const std::string &postfix,
|
||||
Gui::ViewProviderDocumentObject* vp,
|
||||
App::DocumentObject *editObj,
|
||||
const std::string& editSubName) {
|
||||
auto defvisfunc = [](bool opening_not_closing,
|
||||
const std::string& postfix,
|
||||
Gui::ViewProviderDocumentObject* vp,
|
||||
App::DocumentObject* editObj,
|
||||
const std::string& editSubName) {
|
||||
if (opening_not_closing) {
|
||||
QString code = QString::fromLatin1(
|
||||
"import Show\n"
|
||||
@@ -981,19 +1150,19 @@ void TaskAttacher::visibilityAutomation(bool opening_not_closing)
|
||||
"\t\tif len(tvObj.AttachmentSupport) > 0:\n"
|
||||
"\t\t\t_tv_%4.show([lnk[0] for lnk in tvObj.AttachmentSupport])\n"
|
||||
"del(tvObj)"
|
||||
).arg(
|
||||
QString::fromLatin1(Gui::Command::getObjectCmd(vp->getObject()).c_str()),
|
||||
QString::fromLatin1(Gui::Command::getObjectCmd(editObj).c_str()),
|
||||
QString::fromLatin1(editSubName.c_str()),
|
||||
QString::fromLatin1(postfix.c_str()));
|
||||
Gui::Command::runCommand(Gui::Command::Gui,code.toLatin1().constData());
|
||||
).arg(
|
||||
QString::fromLatin1(Gui::Command::getObjectCmd(vp->getObject()).c_str()),
|
||||
QString::fromLatin1(Gui::Command::getObjectCmd(editObj).c_str()),
|
||||
QString::fromLatin1(editSubName.c_str()),
|
||||
QString::fromLatin1(postfix.c_str()));
|
||||
Gui::Command::runCommand(Gui::Command::Gui, code.toLatin1().constData());
|
||||
}
|
||||
else if (!postfix.empty()) {
|
||||
QString code = QString::fromLatin1(
|
||||
"_tv_%1.restore()\n"
|
||||
"del(_tv_%1)"
|
||||
).arg(QString::fromLatin1(postfix.c_str()));
|
||||
Gui::Command::runCommand(Gui::Command::Gui,code.toLatin1().constData());
|
||||
).arg(QString::fromLatin1(postfix.c_str()));
|
||||
Gui::Command::runCommand(Gui::Command::Gui, code.toLatin1().constData());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1009,18 +1178,19 @@ void TaskAttacher::visibilityAutomation(bool opening_not_closing)
|
||||
return;
|
||||
|
||||
auto editDoc = Gui::Application::Instance->editDocument();
|
||||
App::DocumentObject *editObj = ViewProvider->getObject();
|
||||
App::DocumentObject* editObj = ViewProvider->getObject();
|
||||
std::string editSubName;
|
||||
auto sels = Gui::Selection().getSelection(nullptr, Gui::ResolveMode::NoResolve, true);
|
||||
if(!sels.empty() && sels[0].pResolvedObject
|
||||
&& sels[0].pResolvedObject->getLinkedObject()==editObj)
|
||||
if (!sels.empty() && sels[0].pResolvedObject
|
||||
&& sels[0].pResolvedObject->getLinkedObject() == editObj)
|
||||
{
|
||||
editObj = sels[0].pObject;
|
||||
editSubName = sels[0].SubName;
|
||||
} else {
|
||||
ViewProviderDocumentObject *editVp = nullptr;
|
||||
}
|
||||
else {
|
||||
ViewProviderDocumentObject* editVp = nullptr;
|
||||
if (editDoc) {
|
||||
editDoc->getInEdit(&editVp,&editSubName);
|
||||
editDoc->getInEdit(&editVp, &editSubName);
|
||||
if (editVp)
|
||||
editObj = editVp->getObject();
|
||||
}
|
||||
@@ -1029,7 +1199,7 @@ void TaskAttacher::visibilityAutomation(bool opening_not_closing)
|
||||
try {
|
||||
visAutoFunc(opening_not_closing, ObjectName, ViewProvider, editObj, editSubName);
|
||||
}
|
||||
catch (const Base::Exception &e){
|
||||
catch (const Base::Exception& e) {
|
||||
e.ReportException();
|
||||
}
|
||||
catch (const Py::Exception&) {
|
||||
@@ -1043,7 +1213,7 @@ void TaskAttacher::visibilityAutomation(bool opening_not_closing)
|
||||
objName.swap(ObjectName);
|
||||
visAutoFunc(opening_not_closing, objName, nullptr, nullptr, std::string());
|
||||
}
|
||||
catch (Base::Exception &e) {
|
||||
catch (Base::Exception& e) {
|
||||
e.ReportException();
|
||||
}
|
||||
}
|
||||
@@ -1054,14 +1224,14 @@ void TaskAttacher::visibilityAutomation(bool opening_not_closing)
|
||||
// TaskDialog
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
TaskDlgAttacher::TaskDlgAttacher(Gui::ViewProviderDocumentObject *ViewProvider, bool createBox)
|
||||
: TaskDialog(),ViewProvider(ViewProvider), parameter(nullptr)
|
||||
TaskDlgAttacher::TaskDlgAttacher(Gui::ViewProviderDocumentObject* ViewProvider, bool createBox)
|
||||
: TaskDialog(), ViewProvider(ViewProvider), parameter(nullptr)
|
||||
{
|
||||
assert(ViewProvider);
|
||||
setDocumentName(ViewProvider->getDocument()->getDocument()->getName());
|
||||
|
||||
if(createBox) {
|
||||
parameter = new TaskAttacher(ViewProvider, nullptr, QString(), tr("Attachment"));
|
||||
if (createBox) {
|
||||
parameter = new TaskAttacher(ViewProvider, nullptr, QString(), tr("Attachment"));
|
||||
Content.push_back(parameter);
|
||||
}
|
||||
}
|
||||
@@ -1096,11 +1266,11 @@ bool TaskDlgAttacher::accept()
|
||||
|
||||
//DeepSOIC: changed this to heavily rely on dialog constantly updating feature properties
|
||||
//if (pcAttach->AttachmentOffset.isTouched()){
|
||||
Base::Placement plm = pcAttach->AttachmentOffset.getValue();
|
||||
double yaw, pitch, roll;
|
||||
plm.getRotation().getYawPitchRoll(yaw,pitch,roll);
|
||||
Gui::cmdAppObjectArgs(obj, "AttachmentOffset = App.Placement(App.Vector(%.10f, %.10f, %.10f), App.Rotation(%.10f, %.10f, %.10f))",
|
||||
plm.getPosition().x, plm.getPosition().y, plm.getPosition().z, yaw, pitch, roll);
|
||||
Base::Placement plm = pcAttach->AttachmentOffset.getValue();
|
||||
double yaw, pitch, roll;
|
||||
plm.getRotation().getYawPitchRoll(yaw, pitch, roll);
|
||||
Gui::cmdAppObjectArgs(obj, "AttachmentOffset = App.Placement(App.Vector(%.10f, %.10f, %.10f), App.Rotation(%.10f, %.10f, %.10f))",
|
||||
plm.getPosition().x, plm.getPosition().y, plm.getPosition().z, yaw, pitch, roll);
|
||||
//}
|
||||
|
||||
Gui::cmdAppObjectArgs(obj, "MapReversed = %s", pcAttach->MapReversed.getValue() ? "True" : "False");
|
||||
|
||||
@@ -113,6 +113,15 @@ private:
|
||||
void updateRefButton(int idx);
|
||||
void updateAttachmentOffsetUI();
|
||||
|
||||
void findCorrectObjAndSubInThisContext(App::DocumentObject*& obj, std::string& sub);
|
||||
void handleInitialSelection();
|
||||
struct SubAndObjName {
|
||||
std::string objName;
|
||||
std::string subName;
|
||||
};
|
||||
void addToReference(SubAndObjName pair);
|
||||
void addToReference(const std::vector<SubAndObjName >& pairs);
|
||||
|
||||
/**
|
||||
* @brief updateListOfModes Fills the mode list with modes that apply to
|
||||
* current set of references. Maintains selection when possible.
|
||||
|
||||
@@ -113,6 +113,10 @@ void ViewProviderAttachExtension::extensionSetupContextMenu(QMenu* menu, QObject
|
||||
|
||||
void ViewProviderAttachExtension::showAttachmentEditor()
|
||||
{
|
||||
if (Gui::Control().activeDialog()) {
|
||||
Gui::Control().closeDialog();
|
||||
}
|
||||
|
||||
// See PropertyEnumAttacherItem::openTask()
|
||||
Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog();
|
||||
TaskDlgAttacher* task;
|
||||
|
||||
@@ -44,7 +44,6 @@ public:
|
||||
void extensionUpdateData(const App::Property*) override;
|
||||
void extensionSetupContextMenu(QMenu*, QObject*, const char*) override;
|
||||
|
||||
private:
|
||||
void showAttachmentEditor();
|
||||
};
|
||||
|
||||
|
||||
94
src/Mod/Part/Gui/ViewProviderDatum.cpp
Normal file
94
src/Mod/Part/Gui/ViewProviderDatum.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Ondsel (PL Boyer) <development@ondsel.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObjectGroup.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/Command.h>
|
||||
#include <Gui/Control.h>
|
||||
#include <Gui/View3DInventor.h>
|
||||
#include <Gui/View3DInventorViewer.h>
|
||||
|
||||
#include "ViewProviderDatum.h"
|
||||
|
||||
|
||||
using namespace PartGui;
|
||||
|
||||
PROPERTY_SOURCE_WITH_EXTENSIONS(PartGui::ViewProviderLine, Gui::ViewProviderLine)
|
||||
|
||||
ViewProviderLine::ViewProviderLine()
|
||||
{
|
||||
PartGui::ViewProviderAttachExtension::initExtension(this);
|
||||
}
|
||||
|
||||
bool ViewProviderLine::doubleClicked()
|
||||
{
|
||||
showAttachmentEditor();
|
||||
return true;
|
||||
}
|
||||
|
||||
PROPERTY_SOURCE_WITH_EXTENSIONS(PartGui::ViewProviderPlane, Gui::ViewProviderPlane)
|
||||
|
||||
ViewProviderPlane::ViewProviderPlane()
|
||||
{
|
||||
PartGui::ViewProviderAttachExtension::initExtension(this);
|
||||
}
|
||||
|
||||
bool ViewProviderPlane::doubleClicked()
|
||||
{
|
||||
showAttachmentEditor();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PROPERTY_SOURCE_WITH_EXTENSIONS(PartGui::ViewProviderPoint, Gui::ViewProviderPoint)
|
||||
|
||||
ViewProviderPoint::ViewProviderPoint()
|
||||
{
|
||||
PartGui::ViewProviderAttachExtension::initExtension(this);
|
||||
}
|
||||
|
||||
bool ViewProviderPoint::doubleClicked()
|
||||
{
|
||||
showAttachmentEditor();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PROPERTY_SOURCE_WITH_EXTENSIONS(PartGui::ViewProviderLCS, Gui::ViewProviderCoordinateSystem)
|
||||
|
||||
ViewProviderLCS::ViewProviderLCS()
|
||||
{
|
||||
PartGui::ViewProviderAttachExtension::initExtension(this);
|
||||
}
|
||||
|
||||
bool ViewProviderLCS::doubleClicked()
|
||||
{
|
||||
showAttachmentEditor();
|
||||
return true;
|
||||
}
|
||||
84
src/Mod/Part/Gui/ViewProviderDatum.h
Normal file
84
src/Mod/Part/Gui/ViewProviderDatum.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2024 Ondsel (PL Boyer) <development@ondsel.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef PARTGUI_ViewProviderDatum_H
|
||||
#define PARTGUI_ViewProviderDatum_H
|
||||
|
||||
#include <Gui/ViewProviderLine.h>
|
||||
#include <Gui/ViewProviderPlane.h>
|
||||
#include <Gui/ViewProviderPoint.h>
|
||||
#include <Gui/ViewProviderCoordinateSystem.h>
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <Mod/Part/Gui/ViewProviderAttachExtension.h>
|
||||
|
||||
namespace PartGui {
|
||||
|
||||
class PartGuiExport ViewProviderLine : public Gui::ViewProviderLine, PartGui::ViewProviderAttachExtension
|
||||
{
|
||||
PROPERTY_HEADER_WITH_EXTENSIONS(PartGui::ViewProviderLine);
|
||||
|
||||
public:
|
||||
ViewProviderLine();
|
||||
~ViewProviderLine() override = default;
|
||||
|
||||
bool doubleClicked() override;
|
||||
};
|
||||
|
||||
class PartGuiExport ViewProviderPlane : public Gui::ViewProviderPlane, PartGui::ViewProviderAttachExtension
|
||||
{
|
||||
PROPERTY_HEADER_WITH_EXTENSIONS(PartGui::ViewProviderPlane);
|
||||
|
||||
public:
|
||||
ViewProviderPlane();
|
||||
~ViewProviderPlane() override = default;
|
||||
|
||||
bool doubleClicked() override;
|
||||
};
|
||||
|
||||
class PartGuiExport ViewProviderPoint : public Gui::ViewProviderPoint, PartGui::ViewProviderAttachExtension
|
||||
{
|
||||
PROPERTY_HEADER_WITH_EXTENSIONS(PartGui::ViewProviderPoint);
|
||||
|
||||
public:
|
||||
ViewProviderPoint();
|
||||
~ViewProviderPoint() override = default;
|
||||
|
||||
bool doubleClicked() override;
|
||||
};
|
||||
|
||||
class PartGuiExport ViewProviderLCS : public Gui::ViewProviderCoordinateSystem, PartGui::ViewProviderAttachExtension
|
||||
{
|
||||
PROPERTY_HEADER_WITH_EXTENSIONS(PartGui::ViewProviderLCS);
|
||||
|
||||
public:
|
||||
ViewProviderLCS();
|
||||
~ViewProviderLCS() override = default;
|
||||
|
||||
bool doubleClicked() override;
|
||||
};
|
||||
|
||||
} // namespace PartGui
|
||||
|
||||
|
||||
#endif // PARTGUI_ViewProviderDatum_H
|
||||
@@ -37,6 +37,7 @@ void WorkbenchManipulator::modifyMenuBar([[maybe_unused]] Gui::MenuItem* menuBar
|
||||
void WorkbenchManipulator::modifyToolBars(Gui::ToolBarItem* toolBar)
|
||||
{
|
||||
addSelectionFilter(toolBar);
|
||||
addDatums(toolBar);
|
||||
}
|
||||
|
||||
void WorkbenchManipulator::modifyDockWindows([[maybe_unused]] Gui::DockWindowItems* dockWindow)
|
||||
@@ -71,3 +72,18 @@ void WorkbenchManipulator::addSelectionFilter(Gui::ToolBarItem* toolBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorkbenchManipulator::addDatums(Gui::ToolBarItem* toolBar)
|
||||
{
|
||||
if (auto view = toolBar->findItem("Structure")) {
|
||||
auto add = new Gui::ToolBarItem(); // NOLINT
|
||||
add->setCommand("Part_Datums");
|
||||
auto item = view->findItem("Std_Group");
|
||||
if (item) {
|
||||
view->insertItem(item, add);
|
||||
}
|
||||
else {
|
||||
view->appendItem(add);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ protected:
|
||||
private:
|
||||
static void addSectionCut(Gui::MenuItem* menuBar);
|
||||
static void addSelectionFilter(Gui::ToolBarItem* toolBar);
|
||||
static void addDatums(Gui::ToolBarItem* toolBar);
|
||||
};
|
||||
|
||||
} // namespace PartGui
|
||||
|
||||
@@ -219,7 +219,9 @@ bool Body::isAllowed(const App::DocumentObject *obj)
|
||||
//obj->isDerivedFrom<Part::FeaturePython>() // trouble with this line on Windows!? Linker fails to find getClassTypeId() of the Part::FeaturePython...
|
||||
//obj->isDerivedFrom<Part::Feature>()
|
||||
// allow VarSets for parameterization
|
||||
obj->isDerivedFrom<App::VarSet>()
|
||||
obj->isDerivedFrom<App::VarSet>() ||
|
||||
obj->isDerivedFrom<App::DatumElement>() ||
|
||||
obj->isDerivedFrom<App::LocalCoordinateSystem>()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1357,9 +1357,10 @@ void ProfileBased::getAxis(const App::DocumentObject * pcReferenceAxis, const st
|
||||
}
|
||||
|
||||
if (pcReferenceAxis->isDerivedFrom<App::Line>()) {
|
||||
const App::Line* line = static_cast<const App::Line*>(pcReferenceAxis);
|
||||
base = Base::Vector3d(0, 0, 0);
|
||||
line->Placement.getValue().multVec(Base::Vector3d(1, 0, 0), dir);
|
||||
auto* line = static_cast<const App::Line*>(pcReferenceAxis);
|
||||
Base::Placement plc = line->Placement.getValue();
|
||||
base = plc.getPosition();
|
||||
plc.getRotation().multVec(Base::Vector3d(0, 0, 1), dir);
|
||||
|
||||
verifyAxisFunc(checkAxis, sketchplane, gp_Dir(dir.x, dir.y, dir.z));
|
||||
return;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
# include <BRep_Builder.hxx>
|
||||
# include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
# include <BRepBuilderAPI_MakeFace.hxx>
|
||||
# include <BRepBuilderAPI_MakeVertex.hxx>
|
||||
#endif
|
||||
|
||||
#include <unordered_map>
|
||||
@@ -194,6 +195,10 @@ void ShapeBinder::getFilteredReferences(const App::PropertyLinkSubList* prop,
|
||||
obj = plane;
|
||||
break;
|
||||
}
|
||||
if (auto point = dynamic_cast<App::Point*>(it)) {
|
||||
obj = point;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -244,6 +249,13 @@ Part::TopoShape ShapeBinder::buildShapeFromReferences(App::GeoFeature* obj, std:
|
||||
shape.setPlacement(obj->Placement.getValue());
|
||||
return shape;
|
||||
}
|
||||
else if (obj->isDerivedFrom<App::Point>()) {
|
||||
gp_Pnt point;
|
||||
BRepBuilderAPI_MakeVertex mkPoint(point);
|
||||
Part::TopoShape shape(mkPoint.Shape());
|
||||
shape.setPlacement(obj->Placement.getValue());
|
||||
return shape;
|
||||
}
|
||||
|
||||
return TopoDS_Shape();
|
||||
}
|
||||
|
||||
@@ -148,12 +148,12 @@ bool ReferenceSelection::allowOrigin(PartDesign::Body *body, App::OriginGroupExt
|
||||
if (fits) { // check that it actually belongs to the chosen body or part
|
||||
try { // here are some throwers
|
||||
if (body) {
|
||||
if (body->getOrigin ()->hasObject (pObj) ) {
|
||||
if (body->hasObject(pObj, true) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (originGroup ) {
|
||||
if (originGroup->getOrigin()->hasObject(pObj)) {
|
||||
if (originGroup->hasObject(pObj, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,11 +342,11 @@ bool ViewProviderBody::canDropObjects() const
|
||||
{
|
||||
// if the BaseFeature property is marked as hidden or read-only then
|
||||
// it's not allowed to modify it.
|
||||
PartDesign::Body* body = getObject<PartDesign::Body>();
|
||||
if (body->BaseFeature.testStatus(App::Property::Status::Hidden))
|
||||
return false;
|
||||
if (body->BaseFeature.testStatus(App::Property::Status::ReadOnly))
|
||||
auto* body = getObject<PartDesign::Body>();
|
||||
if (body->BaseFeature.testStatus(App::Property::Status::Hidden)
|
||||
|| body->BaseFeature.testStatus(App::Property::Status::ReadOnly)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -355,7 +355,15 @@ bool ViewProviderBody::canDropObject(App::DocumentObject* obj) const
|
||||
if (obj->isDerivedFrom<App::VarSet>()) {
|
||||
return true;
|
||||
}
|
||||
if (!obj->isDerivedFrom(Part::Feature::getClassTypeId())) {
|
||||
else if (obj->isDerivedFrom(App::DatumElement::getClassTypeId())) {
|
||||
// accept only datums that are not part of a LCS.
|
||||
auto* lcs = static_cast<App::DatumElement*>(obj)->getLCS();
|
||||
return !lcs;
|
||||
}
|
||||
else if (obj->isDerivedFrom(App::LocalCoordinateSystem::getClassTypeId())) {
|
||||
return !obj->isDerivedFrom(App::Origin::getClassTypeId());
|
||||
}
|
||||
else if (!obj->isDerivedFrom(Part::Feature::getClassTypeId())) {
|
||||
return false;
|
||||
}
|
||||
else if (PartDesign::Body::findBodyOf(obj)) {
|
||||
@@ -375,8 +383,10 @@ bool ViewProviderBody::canDropObject(App::DocumentObject* obj) const
|
||||
|
||||
void ViewProviderBody::dropObject(App::DocumentObject* obj)
|
||||
{
|
||||
PartDesign::Body* body = getObject<PartDesign::Body>();
|
||||
if (obj->isDerivedFrom<Part::Part2DObject>()) {
|
||||
auto* body = getObject<PartDesign::Body>();
|
||||
if (obj->isDerivedFrom<Part::Part2DObject>()
|
||||
|| obj->isDerivedFrom<App::DatumElement>()
|
||||
|| obj->isDerivedFrom<App::LocalCoordinateSystem>()) {
|
||||
body->addObject(obj);
|
||||
}
|
||||
else if (PartDesign::Body::isAllowed(obj) && PartDesignGui::isFeatureMovable(obj)) {
|
||||
|
||||
@@ -2,22 +2,21 @@
|
||||
* Copyright (c) 2013 Jan Rheinlaender *
|
||||
* <jrheinlaender@users.sourceforge.net> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* 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. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* 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 Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
@@ -2,22 +2,21 @@
|
||||
* Copyright (c) 2013 Jan Rheinlaender *
|
||||
* <jrheinlaender@users.sourceforge.net> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* 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. *
|
||||
* *
|
||||
* This library 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 Library General Public License for more details. *
|
||||
* 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 Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
@@ -380,14 +380,6 @@ Gui::MenuItem* Workbench::setupMenuBar() const
|
||||
root->insertItem(item, part);
|
||||
part->setCommand("&Part Design");
|
||||
|
||||
// datums
|
||||
Gui::MenuItem* datums = new Gui::MenuItem;
|
||||
datums->setCommand("Create a datum");
|
||||
|
||||
*datums << "PartDesign_Point"
|
||||
<< "PartDesign_Line"
|
||||
<< "PartDesign_Plane";
|
||||
|
||||
// additives
|
||||
Gui::MenuItem* additives = new Gui::MenuItem;
|
||||
additives->setCommand("Create an additive feature");
|
||||
@@ -429,8 +421,6 @@ Gui::MenuItem* Workbench::setupMenuBar() const
|
||||
|
||||
*part << "PartDesign_Body"
|
||||
<< "Separator"
|
||||
<< datums
|
||||
<< "PartDesign_CoordinateSystem"
|
||||
<< "PartDesign_ShapeBinder"
|
||||
<< "PartDesign_SubShapeBinder"
|
||||
<< "PartDesign_Clone"
|
||||
@@ -490,8 +480,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
|
||||
<< "Sketcher_ValidateSketch"
|
||||
<< "Part_CheckGeometry"
|
||||
<< "PartDesign_SubShapeBinder"
|
||||
<< "PartDesign_Clone"
|
||||
<< "PartDesign_CompDatums";
|
||||
<< "PartDesign_Clone";
|
||||
|
||||
part = new Gui::ToolBarItem(root);
|
||||
part->setCommand("Part Design Modeling");
|
||||
|
||||
@@ -338,17 +338,17 @@ class DocumentBasicCases(unittest.TestCase):
|
||||
|
||||
res = obj.getSubObject("X_Axis", retType=2)
|
||||
self.assertEqual(
|
||||
res[1].multVec(FreeCAD.Vector(1, 0, 0)).getAngle(FreeCAD.Vector(1, 0, 0)), 0.0
|
||||
res[1].multVec(FreeCAD.Vector(0, 0, 1)).getAngle(FreeCAD.Vector(1, 0, 0)), 0.0
|
||||
)
|
||||
|
||||
res = obj.getSubObject("Y_Axis", retType=2)
|
||||
self.assertEqual(
|
||||
res[1].multVec(FreeCAD.Vector(1, 0, 0)).getAngle(FreeCAD.Vector(0, 1, 0)), 0.0
|
||||
res[1].multVec(FreeCAD.Vector(0, 0, 1)).getAngle(FreeCAD.Vector(0, 1, 0)), 0.0
|
||||
)
|
||||
|
||||
res = obj.getSubObject("Z_Axis", retType=2)
|
||||
self.assertEqual(
|
||||
res[1].multVec(FreeCAD.Vector(1, 0, 0)).getAngle(FreeCAD.Vector(0, 0, 1)), 0.0
|
||||
res[1].multVec(FreeCAD.Vector(0, 0, 1)).getAngle(FreeCAD.Vector(0, 0, 1)), 0.0
|
||||
)
|
||||
|
||||
res = obj.getSubObject("XY_Plane", retType=2)
|
||||
|
||||
Reference in New Issue
Block a user