Files
create/src/Mod/PartDesign/Gui/ReferenceSelection.cpp
wmayer b33f92898b PartDesign: [skip ci] Improve revolution function
+ Fix hard crash when selecting an edge or face of the created feature before selecting option to choose a reference.
+ In ProfileBased::getAxis() convert OCCT into FreeCAD exception to simplify handling of calling instances.
+ Change return value of getReferencedSelection() from void to bool to mkae it easier for calling instance to detect if the selection failed.
  This is needed to avoid to add invalid items to the combo box of the revolution task panel
2020-10-14 15:20:52 +02:00

336 lines
12 KiB
C++

/******************************************************************************
* Copyright (c) 2012 Konstantinos Poulios <logari81@gmail.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_
# include <TopoDS.hxx>
# include <TopoDS_Edge.hxx>
# include <TopoDS_Face.hxx>
# include <BRepAdaptor_Curve.hxx>
# include <BRepAdaptor_Surface.hxx>
# include <QDialog>
#endif
#include <App/OriginFeature.h>
#include <App/GeoFeatureGroupExtension.h>
#include <App/Origin.h>
#include <App/Part.h>
#include <Gui/Application.h>
#include <Gui/Document.h>
#include <Gui/Command.h>
#include <Gui/MainWindow.h>
#include <Mod/Part/App/TopoShape.h>
#include <Mod/Part/App/PartFeature.h>
#include <Mod/PartDesign/App/Feature.h>
#include <Mod/PartDesign/App/Body.h>
#include <Mod/PartDesign/App/DatumPoint.h>
#include <Mod/PartDesign/App/DatumLine.h>
#include <Mod/PartDesign/App/DatumPlane.h>
#include "Utils.h"
#include "ReferenceSelection.h"
#include "TaskFeaturePick.h"
#include <ui_DlgReference.h>
using namespace PartDesignGui;
using namespace Gui;
/* TRANSLATOR PartDesignGui::ReferenceSelection.cpp */
bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, const char* sSubName)
{
// TODO review this function (2015-09-04, Fat-Zer)
PartDesign::Body *body;
App::DocumentObject* originGroupObject = nullptr;
if ( support ) {
body = PartDesign::Body::findBodyOf (support);
} else {
body = PartDesignGui::getBody (false);
}
if ( body ) { // Search for Part of the body
originGroupObject = App::OriginGroupExtension::getGroupOfObject ( body ) ;
} else if ( support ) { // if no body search part for support
originGroupObject = App::OriginGroupExtension::getGroupOfObject ( support ) ;
} else { // fallback to active part
originGroupObject = PartDesignGui::getActivePart ( );
}
App::OriginGroupExtension* originGroup = nullptr;
if(originGroupObject)
originGroup = originGroupObject->getExtensionByType<App::OriginGroupExtension>();
// Don't allow selection in other document
if ( support && pDoc != support->getDocument() ) {
return false;
}
// Enable selection from origin of current part/
if ( pObj->getTypeId().isDerivedFrom(App::OriginFeature::getClassTypeId()) ) {
bool fits = false;
if ( plane && pObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) ) {
fits = true;
} else if ( edge && pObj->getTypeId().isDerivedFrom(App::Line::getClassTypeId()) ) {
fits = true;
}
if (fits) { // check that it is actually belongs to the chosen body or part
try { // here are some throwers
if (body) {
if (body->getOrigin ()->hasObject (pObj) ) {
return true;
}
} else if (originGroup ) {
if ( originGroup->getOrigin ()->hasObject (pObj) ) {
return true;
}
}
} catch (const Base::Exception&)
{ }
}
return false; // The Plane/Axis doesn't fits our needs
}
if (pObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) {
if (!body) { // Allow selecting Part::Datum features from the active Body
return false;
} else if (!allowOtherBody && !body->hasObject(pObj)) {
return false;
}
if (plane && (pObj->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())))
return true;
if (edge && (pObj->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())))
return true;
if (point && (pObj->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())))
return true;
return false;
}
if (!allowOtherBody) {
if (support == NULL)
return false;
if (pObj != support)
return false;
}
// Handle selection of geometry elements
if (!sSubName || sSubName[0] == '\0')
return whole;
std::string subName(sSubName);
if (edge && subName.size() > 4 && subName.substr(0,4) == "Edge") {
const Part::TopoShape &shape = static_cast<const Part::Feature*>(pObj)->Shape.getValue();
TopoDS_Shape sh = shape.getSubShape(subName.c_str());
const TopoDS_Edge& edgeShape = TopoDS::Edge(sh);
if (!edgeShape.IsNull()) {
if (planar) {
BRepAdaptor_Curve adapt(edgeShape);
if (adapt.GetType() == GeomAbs_Line)
return true;
} else {
return true;
}
}
}
if (plane && subName.size() > 4 && subName.substr(0,4) == "Face") {
const Part::TopoShape &shape = static_cast<const Part::Feature*>(pObj)->Shape.getValue();
TopoDS_Shape sh = shape.getSubShape(subName.c_str());
const TopoDS_Face& face = TopoDS::Face(sh);
if (!face.IsNull()) {
if (planar) {
BRepAdaptor_Surface adapt(face);
if (adapt.GetType() == GeomAbs_Plane)
return true;
} else {
return true;
}
}
}
if (point && subName.size() > 6 && subName.substr(0,6) == "Vertex") {
return true;
}
return false;
}
bool NoDependentsSelection::allow(App::Document* /*pDoc*/, App::DocumentObject* pObj, const char* /*sSubName*/)
{
if (support && support->testIfLinkDAGCompatible(pObj)) {
return true;
}
else {
this->notAllowedReason = QT_TR_NOOP("Selecting this will cause circular dependency.");
return false;
}
}
bool CombineSelectionFilterGates::allow(App::Document* pDoc, App::DocumentObject* pObj, const char* sSubName)
{
return filter1->allow(pDoc, pObj, sSubName) && filter2->allow(pDoc, pObj, sSubName);
}
namespace PartDesignGui
{
bool getReferencedSelection(const App::DocumentObject* thisObj, const Gui::SelectionChanges& msg,
App::DocumentObject*& selObj, std::vector<std::string>& selSub)
{
selObj = nullptr;
if (!thisObj)
return false;
if (strcmp(thisObj->getDocument()->getName(), msg.pDocName) != 0)
return false;
selObj = thisObj->getDocument()->getObject(msg.pObjectName);
if (selObj == thisObj)
return false;
std::string subname = msg.pSubName;
//check if the selection is an external reference and ask the user what to do
//of course only if thisObj is in a body, as otherwise the old workflow would not
//be supported
PartDesign::Body* body = PartDesignGui::getBodyFor(thisObj, false);
bool originfeature = selObj->isDerivedFrom(App::OriginFeature::getClassTypeId());
if (!originfeature && body) {
PartDesign::Body* selBody = PartDesignGui::getBodyFor(selObj, false);
if (!selBody || body != selBody) {
QDialog dia(Gui::getMainWindow());
Ui_DlgReference dlg;
dlg.setupUi(&dia);
dia.setModal(true);
int result = dia.exec();
if (result == QDialog::DialogCode::Rejected) {
selObj = nullptr;
return false;
}
if (!dlg.radioXRef->isChecked()) {
App::Document* document = thisObj->getDocument();
document->openTransaction("Make copy");
auto copy = PartDesignGui::TaskFeaturePick::makeCopy(selObj, subname, dlg.radioIndependent->isChecked());
body->addObject(copy);
selObj = copy;
subname.erase(std::remove_if(subname.begin(), subname.end(), &isdigit), subname.end());
subname.append("1");
}
}
}
// Remove subname for planes and datum features
if (PartDesign::Feature::isDatum(selObj)) {
subname = "";
}
selSub = std::vector<std::string>(1,subname);
return true;
}
QString getRefStr(const App::DocumentObject* obj, const std::vector<std::string>& sub)
{
if (obj == NULL)
return QString::fromLatin1("");
if (PartDesign::Feature::isDatum(obj))
return QString::fromLatin1(obj->getNameInDocument());
else if (sub.size()>0)
return QString::fromLatin1(obj->getNameInDocument()) + QString::fromLatin1(":") +
QString::fromLatin1(sub.front().c_str());
else
return QString();
}
std::string buildLinkSubPythonStr(const App::DocumentObject* obj, const std::vector<std::string>& subs)
{
if ( obj == NULL)
return "None";
std::string result("[");
for (const auto & sub : subs)
result += "\"" + sub + "\",";
result += "]";
return result;
}
std::string buildLinkSingleSubPythonStr(const App::DocumentObject* obj,
const std::vector<std::string>& subs)
{
if (obj == NULL)
return "None";
if (PartDesign::Feature::isDatum(obj))
return Gui::Command::getObjectCmd(obj,"(",", [''])");
else
return Gui::Command::getObjectCmd(obj,"(",", ['") + subs.front() + "'])";
}
std::string buildLinkListPythonStr(const std::vector<App::DocumentObject*> & objs)
{
if ( objs.empty() ) {
return "None";
}
std::string result("[");
for (std::vector<App::DocumentObject*>::const_iterator o = objs.begin(); o != objs.end(); o++)
result += Gui::Command::getObjectCmd(*o,0,",");
result += "]";
return result;
}
std::string buildLinkSubListPythonStr(const std::vector<App::DocumentObject*> & objs,
const std::vector<std::string>& subs)
{
if ( objs.empty() ) {
return "None";
}
std::string result("[");
assert (objs.size () == subs.size () );
for (size_t i=0, objs_sz=objs.size(); i < objs_sz; i++) {
if (objs[i] ) {
result += '(';
result += Gui::Command::getObjectCmd(objs[i]);
result += ",\"";
result += subs[i];
result += "\"),";
}
}
result += "]";
return result;
}
}